blob: b0c25078f2e23a01c93da31a773fd7e79e3e0e6b [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
2 * valid.c : part of the code use to do the DTD handling and the validity
3 * checking
4 *
5 * See Copyright for the status of this software.
6 *
Daniel Veillardc5d64342001-06-24 12:13:24 +00007 * daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +00008 */
9
Daniel Veillard34ce8be2002-03-18 19:37:11 +000010#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000011#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000012
Owen Taylor3473f882001-02-23 17:55:21 +000013#include <string.h>
14
15#ifdef HAVE_STDLIB_H
16#include <stdlib.h>
17#endif
18
19#include <libxml/xmlmemory.h>
20#include <libxml/hash.h>
21#include <libxml/valid.h>
22#include <libxml/parser.h>
23#include <libxml/parserInternals.h>
24#include <libxml/xmlerror.h>
25#include <libxml/list.h>
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000026#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000027
Daniel Veillard4432df22003-09-28 18:58:27 +000028static xmlElementPtr xmlGetDtdElementDesc2(xmlDtdPtr dtd, const xmlChar *name,
29 int create);
Daniel Veillarde62d36c2001-05-15 08:53:16 +000030/* #define DEBUG_VALID_ALGO */
Daniel Veillard5acfd6b2002-09-18 16:29:02 +000031/* #define DEBUG_REGEXP_ALGO */
Daniel Veillarde62d36c2001-05-15 08:53:16 +000032
Daniel Veillarda646cfd2002-09-17 21:50:03 +000033#define TODO \
34 xmlGenericError(xmlGenericErrorContext, \
35 "Unimplemented block at %s:%d\n", \
36 __FILE__, __LINE__);
Owen Taylor3473f882001-02-23 17:55:21 +000037
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000038/************************************************************************
39 * *
40 * Error handling routines *
41 * *
42 ************************************************************************/
43
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000044/**
Daniel Veillardce9457f2003-10-05 21:33:18 +000045 * xmlVErrMemory:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000046 * @ctxt: an XML validation parser context
47 * @extra: extra informations
48 *
49 * Handle an out of memory error
50 */
51static void
Daniel Veillardce9457f2003-10-05 21:33:18 +000052xmlVErrMemory(xmlValidCtxtPtr ctxt, const char *extra)
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000053{
Daniel Veillardbb5abab2003-10-03 22:21:51 +000054 xmlGenericErrorFunc channel = NULL;
55 xmlParserCtxtPtr pctxt = NULL;
56 void *data = NULL;
57
58 if (ctxt != NULL) {
59 channel = ctxt->error;
60 data = ctxt->userData;
61 pctxt = ctxt->userData;
62 }
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000063 if (extra)
Daniel Veillard73000572003-10-11 11:26:42 +000064 __xmlRaiseError(NULL, channel, data,
Daniel Veillard72b9e292003-10-28 15:44:17 +000065 pctxt, NULL, XML_FROM_VALID, XML_ERR_NO_MEMORY,
Daniel Veillardbb5abab2003-10-03 22:21:51 +000066 XML_ERR_FATAL, NULL, 0, extra, NULL, NULL, 0, 0,
67 "Memory allocation failed : %s\n", extra);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000068 else
Daniel Veillard73000572003-10-11 11:26:42 +000069 __xmlRaiseError(NULL, channel, data,
Daniel Veillard72b9e292003-10-28 15:44:17 +000070 pctxt, NULL, XML_FROM_VALID, XML_ERR_NO_MEMORY,
Daniel Veillardbb5abab2003-10-03 22:21:51 +000071 XML_ERR_FATAL, NULL, 0, NULL, NULL, NULL, 0, 0,
72 "Memory allocation failed\n");
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000073}
74
75/**
76 * xmlErrValid:
77 * @ctxt: an XML validation parser context
Daniel Veillardbb5abab2003-10-03 22:21:51 +000078 * @error: the error number
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000079 * @extra: extra informations
80 *
81 * Handle a validation error
82 */
83static void
Daniel Veillardf88d8cf2003-12-08 10:25:02 +000084xmlErrValid(xmlValidCtxtPtr ctxt, xmlParserErrors error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +000085 const char *msg, const char *extra)
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000086{
Daniel Veillardbb5abab2003-10-03 22:21:51 +000087 xmlGenericErrorFunc channel = NULL;
88 xmlParserCtxtPtr pctxt = NULL;
89 void *data = NULL;
90
91 if (ctxt != NULL) {
92 channel = ctxt->error;
93 data = ctxt->userData;
94 pctxt = ctxt->userData;
95 }
Daniel Veillard2b8c4a12003-10-02 22:28:19 +000096 if (extra)
Daniel Veillard73000572003-10-11 11:26:42 +000097 __xmlRaiseError(NULL, channel, data,
Daniel Veillard72b9e292003-10-28 15:44:17 +000098 pctxt, NULL, XML_FROM_VALID, error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +000099 XML_ERR_ERROR, NULL, 0, extra, NULL, NULL, 0, 0,
100 msg, extra);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000101 else
Daniel Veillard73000572003-10-11 11:26:42 +0000102 __xmlRaiseError(NULL, channel, data,
Daniel Veillard72b9e292003-10-28 15:44:17 +0000103 pctxt, NULL, XML_FROM_VALID, error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000104 XML_ERR_ERROR, NULL, 0, NULL, NULL, NULL, 0, 0,
105 msg);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000106}
107
Daniel Veillardd61e8fb2003-10-19 21:59:17 +0000108#ifdef LIBXML_VALID_ENABLED
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000109/**
110 * xmlErrValidNodeNr:
111 * @ctxt: an XML validation parser context
112 * @node: the node raising the error
113 * @error: the error number
114 * @str1: extra informations
115 * @int2: extra informations
116 * @str3: extra informations
117 *
118 * Handle a validation error, provide contextual informations
119 */
120static void
Daniel Veillard72b9e292003-10-28 15:44:17 +0000121xmlErrValidNodeNr(xmlValidCtxtPtr ctxt,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000122 xmlNodePtr node, xmlParserErrors error,
123 const char *msg, const xmlChar * str1,
124 int int2, const xmlChar * str3)
125{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000126 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000127 xmlGenericErrorFunc channel = NULL;
128 xmlParserCtxtPtr pctxt = NULL;
129 void *data = NULL;
130
131 if (ctxt != NULL) {
132 channel = ctxt->error;
133 data = ctxt->userData;
134 pctxt = ctxt->userData;
135 }
Daniel Veillard72b9e292003-10-28 15:44:17 +0000136 __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000137 XML_ERR_ERROR, NULL, 0,
138 (const char *) str1,
139 (const char *) str3,
140 NULL, int2, 0, msg, str1, int2, str3);
141}
142/**
143 * xmlErrValidNode:
144 * @ctxt: an XML validation parser context
145 * @node: the node raising the error
146 * @error: the error number
147 * @str1: extra informations
148 * @str2: extra informations
149 * @str3: extra informations
150 *
151 * Handle a validation error, provide contextual informations
152 */
153static void
William M. Brackedb65a72004-02-06 07:36:04 +0000154xmlErrValidNode(xmlValidCtxtPtr ctxt,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000155 xmlNodePtr node, xmlParserErrors error,
156 const char *msg, const xmlChar * str1,
157 const xmlChar * str2, const xmlChar * str3)
158{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000159 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000160 xmlGenericErrorFunc channel = NULL;
161 xmlParserCtxtPtr pctxt = NULL;
162 void *data = NULL;
163
164 if (ctxt != NULL) {
165 channel = ctxt->error;
166 data = ctxt->userData;
167 pctxt = ctxt->userData;
168 }
Daniel Veillard72b9e292003-10-28 15:44:17 +0000169 __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000170 XML_ERR_ERROR, NULL, 0,
171 (const char *) str1,
172 (const char *) str1,
173 (const char *) str3, 0, 0, msg, str1, str2, str3);
174}
175/**
176 * xmlErrValidWarning:
177 * @ctxt: an XML validation parser context
178 * @node: the node raising the error
179 * @error: the error number
William M. Brackedb65a72004-02-06 07:36:04 +0000180 * @str1: extra information
181 * @str2: extra information
182 * @str3: extra information
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000183 *
William M. Brackedb65a72004-02-06 07:36:04 +0000184 * Handle a validation error, provide contextual information
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000185 */
186static void
William M. Brackedb65a72004-02-06 07:36:04 +0000187xmlErrValidWarning(xmlValidCtxtPtr ctxt,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000188 xmlNodePtr node, xmlParserErrors error,
189 const char *msg, const xmlChar * str1,
190 const xmlChar * str2, const xmlChar * str3)
191{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000192 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000193 xmlGenericErrorFunc channel = NULL;
194 xmlParserCtxtPtr pctxt = NULL;
195 void *data = NULL;
196
197 if (ctxt != NULL) {
198 channel = ctxt->error;
199 data = ctxt->userData;
200 pctxt = ctxt->userData;
201 }
Daniel Veillard72b9e292003-10-28 15:44:17 +0000202 __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000203 XML_ERR_WARNING, NULL, 0,
204 (const char *) str1,
205 (const char *) str1,
206 (const char *) str3, 0, 0, msg, str1, str2, str3);
207}
208
209
Daniel Veillardea7751d2002-12-20 00:16:24 +0000210
211#ifdef LIBXML_REGEXP_ENABLED
212/*
213 * If regexp are enabled we can do continuous validation without the
214 * need of a tree to validate the content model. this is done in each
215 * callbacks.
216 * Each xmlValidState represent the validation state associated to the
217 * set of nodes currently open from the document root to the current element.
218 */
219
220
221typedef struct _xmlValidState {
222 xmlElementPtr elemDecl; /* pointer to the content model */
223 xmlNodePtr node; /* pointer to the current node */
224 xmlRegExecCtxtPtr exec; /* regexp runtime */
225} _xmlValidState;
226
227
228static int
229vstateVPush(xmlValidCtxtPtr ctxt, xmlElementPtr elemDecl, xmlNodePtr node) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000230 if ((ctxt->vstateMax == 0) || (ctxt->vstateTab == NULL)) {
Daniel Veillardea7751d2002-12-20 00:16:24 +0000231 ctxt->vstateMax = 10;
232 ctxt->vstateTab = (xmlValidState *) xmlMalloc(ctxt->vstateMax *
233 sizeof(ctxt->vstateTab[0]));
234 if (ctxt->vstateTab == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000235 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillardea7751d2002-12-20 00:16:24 +0000236 return(-1);
237 }
238 }
239
240 if (ctxt->vstateNr >= ctxt->vstateMax) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000241 xmlValidState *tmp;
242
243 tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
244 2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
245 if (tmp == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000246 xmlVErrMemory(ctxt, "realloc failed");
Daniel Veillardea7751d2002-12-20 00:16:24 +0000247 return(-1);
248 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000249 ctxt->vstateMax *= 2;
250 ctxt->vstateTab = tmp;
Daniel Veillardea7751d2002-12-20 00:16:24 +0000251 }
252 ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr];
253 ctxt->vstateTab[ctxt->vstateNr].elemDecl = elemDecl;
254 ctxt->vstateTab[ctxt->vstateNr].node = node;
255 if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) {
256 if (elemDecl->contModel == NULL)
257 xmlValidBuildContentModel(ctxt, elemDecl);
258 if (elemDecl->contModel != NULL) {
259 ctxt->vstateTab[ctxt->vstateNr].exec =
260 xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
261 } else {
262 ctxt->vstateTab[ctxt->vstateNr].exec = NULL;
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000263 xmlErrValidNode(ctxt, (xmlNodePtr) elemDecl,
264 XML_ERR_INTERNAL_ERROR,
265 "Failed to build content model regexp for %s\n",
266 node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +0000267 }
268 }
269 return(ctxt->vstateNr++);
270}
271
272static int
273vstateVPop(xmlValidCtxtPtr ctxt) {
274 xmlElementPtr elemDecl;
275
Daniel Veillard336fc7d2002-12-27 19:37:04 +0000276 if (ctxt->vstateNr < 1) return(-1);
Daniel Veillardea7751d2002-12-20 00:16:24 +0000277 ctxt->vstateNr--;
278 elemDecl = ctxt->vstateTab[ctxt->vstateNr].elemDecl;
279 ctxt->vstateTab[ctxt->vstateNr].elemDecl = NULL;
280 ctxt->vstateTab[ctxt->vstateNr].node = NULL;
281 if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) {
282 xmlRegFreeExecCtxt(ctxt->vstateTab[ctxt->vstateNr].exec);
283 }
284 ctxt->vstateTab[ctxt->vstateNr].exec = NULL;
285 if (ctxt->vstateNr >= 1)
286 ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr - 1];
287 else
288 ctxt->vstate = NULL;
289 return(ctxt->vstateNr);
290}
291
292#else /* not LIBXML_REGEXP_ENABLED */
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000293/*
Daniel Veillard1c732d22002-11-30 11:22:59 +0000294 * If regexp are not enabled, it uses a home made algorithm less
295 * complex and easier to
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000296 * debug/maintain than a generic NFA -> DFA state based algo. The
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000297 * only restriction is on the deepness of the tree limited by the
298 * size of the occurs bitfield
299 *
300 * this is the content of a saved state for rollbacks
301 */
302
303#define ROLLBACK_OR 0
304#define ROLLBACK_PARENT 1
305
Daniel Veillardb44025c2001-10-11 22:55:55 +0000306typedef struct _xmlValidState {
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000307 xmlElementContentPtr cont; /* pointer to the content model subtree */
308 xmlNodePtr node; /* pointer to the current node in the list */
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000309 long occurs;/* bitfield for multiple occurrences */
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000310 unsigned char depth; /* current depth in the overall tree */
311 unsigned char state; /* ROLLBACK_XXX */
312} _xmlValidState;
313
Daniel Veillardfc57b412002-04-29 15:50:14 +0000314#define MAX_RECURSE 25000
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000315#define MAX_DEPTH ((sizeof(_xmlValidState.occurs)) * 8)
316#define CONT ctxt->vstate->cont
317#define NODE ctxt->vstate->node
318#define DEPTH ctxt->vstate->depth
319#define OCCURS ctxt->vstate->occurs
320#define STATE ctxt->vstate->state
321
Daniel Veillard5344c602001-12-31 16:37:34 +0000322#define OCCURRENCE (ctxt->vstate->occurs & (1 << DEPTH))
323#define PARENT_OCCURRENCE (ctxt->vstate->occurs & ((1 << DEPTH) - 1))
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000324
Daniel Veillard5344c602001-12-31 16:37:34 +0000325#define SET_OCCURRENCE ctxt->vstate->occurs |= (1 << DEPTH)
326#define RESET_OCCURRENCE ctxt->vstate->occurs &= ((1 << DEPTH) - 1)
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000327
328static int
329vstateVPush(xmlValidCtxtPtr ctxt, xmlElementContentPtr cont,
330 xmlNodePtr node, unsigned char depth, long occurs,
331 unsigned char state) {
Daniel Veillardbed7b052001-05-19 14:59:49 +0000332 int i = ctxt->vstateNr - 1;
333
Daniel Veillard940492d2002-04-15 10:15:25 +0000334 if (ctxt->vstateNr > MAX_RECURSE) {
335 return(-1);
336 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000337 if (ctxt->vstateTab == NULL) {
338 ctxt->vstateMax = 8;
339 ctxt->vstateTab = (xmlValidState *) xmlMalloc(
340 ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
341 if (ctxt->vstateTab == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000342 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000343 return(-1);
344 }
345 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000346 if (ctxt->vstateNr >= ctxt->vstateMax) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000347 xmlValidState *tmp;
348
349 tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
350 2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
351 if (tmp == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000352 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard940492d2002-04-15 10:15:25 +0000353 return(-1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000354 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000355 ctxt->vstateMax *= 2;
356 ctxt->vstateTab = tmp;
Daniel Veillard06803992001-04-22 10:35:56 +0000357 ctxt->vstate = &ctxt->vstateTab[0];
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000358 }
Daniel Veillardbed7b052001-05-19 14:59:49 +0000359 /*
360 * Don't push on the stack a state already here
361 */
362 if ((i >= 0) && (ctxt->vstateTab[i].cont == cont) &&
363 (ctxt->vstateTab[i].node == node) &&
364 (ctxt->vstateTab[i].depth == depth) &&
365 (ctxt->vstateTab[i].occurs == occurs) &&
366 (ctxt->vstateTab[i].state == state))
367 return(ctxt->vstateNr);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000368 ctxt->vstateTab[ctxt->vstateNr].cont = cont;
369 ctxt->vstateTab[ctxt->vstateNr].node = node;
370 ctxt->vstateTab[ctxt->vstateNr].depth = depth;
371 ctxt->vstateTab[ctxt->vstateNr].occurs = occurs;
372 ctxt->vstateTab[ctxt->vstateNr].state = state;
373 return(ctxt->vstateNr++);
374}
375
376static int
377vstateVPop(xmlValidCtxtPtr ctxt) {
378 if (ctxt->vstateNr <= 1) return(-1);
379 ctxt->vstateNr--;
380 ctxt->vstate = &ctxt->vstateTab[0];
381 ctxt->vstate->cont = ctxt->vstateTab[ctxt->vstateNr].cont;
382 ctxt->vstate->node = ctxt->vstateTab[ctxt->vstateNr].node;
383 ctxt->vstate->depth = ctxt->vstateTab[ctxt->vstateNr].depth;
384 ctxt->vstate->occurs = ctxt->vstateTab[ctxt->vstateNr].occurs;
385 ctxt->vstate->state = ctxt->vstateTab[ctxt->vstateNr].state;
386 return(ctxt->vstateNr);
387}
388
Daniel Veillard118aed72002-09-24 14:13:13 +0000389#endif /* LIBXML_REGEXP_ENABLED */
390
Daniel Veillard1c732d22002-11-30 11:22:59 +0000391static int
392nodeVPush(xmlValidCtxtPtr ctxt, xmlNodePtr value)
393{
394 if (ctxt->nodeMax <= 0) {
395 ctxt->nodeMax = 4;
396 ctxt->nodeTab =
397 (xmlNodePtr *) xmlMalloc(ctxt->nodeMax *
398 sizeof(ctxt->nodeTab[0]));
399 if (ctxt->nodeTab == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000400 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard1c732d22002-11-30 11:22:59 +0000401 ctxt->nodeMax = 0;
402 return (0);
403 }
404 }
405 if (ctxt->nodeNr >= ctxt->nodeMax) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000406 xmlNodePtr *tmp;
407 tmp = (xmlNodePtr *) xmlRealloc(ctxt->nodeTab,
408 ctxt->nodeMax * 2 * sizeof(ctxt->nodeTab[0]));
409 if (tmp == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000410 xmlVErrMemory(ctxt, "realloc failed");
Daniel Veillard1c732d22002-11-30 11:22:59 +0000411 return (0);
412 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000413 ctxt->nodeMax *= 2;
414 ctxt->nodeTab = tmp;
Daniel Veillard1c732d22002-11-30 11:22:59 +0000415 }
416 ctxt->nodeTab[ctxt->nodeNr] = value;
417 ctxt->node = value;
418 return (ctxt->nodeNr++);
419}
420static xmlNodePtr
421nodeVPop(xmlValidCtxtPtr ctxt)
422{
423 xmlNodePtr ret;
424
425 if (ctxt->nodeNr <= 0)
426 return (0);
427 ctxt->nodeNr--;
428 if (ctxt->nodeNr > 0)
429 ctxt->node = ctxt->nodeTab[ctxt->nodeNr - 1];
430 else
431 ctxt->node = NULL;
432 ret = ctxt->nodeTab[ctxt->nodeNr];
433 ctxt->nodeTab[ctxt->nodeNr] = 0;
434 return (ret);
435}
Owen Taylor3473f882001-02-23 17:55:21 +0000436
Owen Taylor3473f882001-02-23 17:55:21 +0000437#ifdef DEBUG_VALID_ALGO
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000438static void
439xmlValidPrintNode(xmlNodePtr cur) {
440 if (cur == NULL) {
441 xmlGenericError(xmlGenericErrorContext, "null");
442 return;
443 }
444 switch (cur->type) {
445 case XML_ELEMENT_NODE:
446 xmlGenericError(xmlGenericErrorContext, "%s ", cur->name);
447 break;
448 case XML_TEXT_NODE:
449 xmlGenericError(xmlGenericErrorContext, "text ");
450 break;
451 case XML_CDATA_SECTION_NODE:
452 xmlGenericError(xmlGenericErrorContext, "cdata ");
453 break;
454 case XML_ENTITY_REF_NODE:
455 xmlGenericError(xmlGenericErrorContext, "&%s; ", cur->name);
456 break;
457 case XML_PI_NODE:
458 xmlGenericError(xmlGenericErrorContext, "pi(%s) ", cur->name);
459 break;
460 case XML_COMMENT_NODE:
461 xmlGenericError(xmlGenericErrorContext, "comment ");
462 break;
463 case XML_ATTRIBUTE_NODE:
464 xmlGenericError(xmlGenericErrorContext, "?attr? ");
465 break;
466 case XML_ENTITY_NODE:
467 xmlGenericError(xmlGenericErrorContext, "?ent? ");
468 break;
469 case XML_DOCUMENT_NODE:
470 xmlGenericError(xmlGenericErrorContext, "?doc? ");
471 break;
472 case XML_DOCUMENT_TYPE_NODE:
473 xmlGenericError(xmlGenericErrorContext, "?doctype? ");
474 break;
475 case XML_DOCUMENT_FRAG_NODE:
476 xmlGenericError(xmlGenericErrorContext, "?frag? ");
477 break;
478 case XML_NOTATION_NODE:
479 xmlGenericError(xmlGenericErrorContext, "?nota? ");
480 break;
481 case XML_HTML_DOCUMENT_NODE:
482 xmlGenericError(xmlGenericErrorContext, "?html? ");
483 break;
Daniel Veillardce2c2f02001-10-18 14:57:24 +0000484#ifdef LIBXML_DOCB_ENABLED
485 case XML_DOCB_DOCUMENT_NODE:
486 xmlGenericError(xmlGenericErrorContext, "?docb? ");
487 break;
488#endif
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000489 case XML_DTD_NODE:
490 xmlGenericError(xmlGenericErrorContext, "?dtd? ");
491 break;
492 case XML_ELEMENT_DECL:
493 xmlGenericError(xmlGenericErrorContext, "?edecl? ");
494 break;
495 case XML_ATTRIBUTE_DECL:
496 xmlGenericError(xmlGenericErrorContext, "?adecl? ");
497 break;
498 case XML_ENTITY_DECL:
499 xmlGenericError(xmlGenericErrorContext, "?entdecl? ");
500 break;
501 case XML_NAMESPACE_DECL:
502 xmlGenericError(xmlGenericErrorContext, "?nsdecl? ");
503 break;
504 case XML_XINCLUDE_START:
505 xmlGenericError(xmlGenericErrorContext, "incstart ");
506 break;
507 case XML_XINCLUDE_END:
508 xmlGenericError(xmlGenericErrorContext, "incend ");
509 break;
510 }
511}
512
513static void
514xmlValidPrintNodeList(xmlNodePtr cur) {
Owen Taylor3473f882001-02-23 17:55:21 +0000515 if (cur == NULL)
516 xmlGenericError(xmlGenericErrorContext, "null ");
517 while (cur != NULL) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000518 xmlValidPrintNode(cur);
Owen Taylor3473f882001-02-23 17:55:21 +0000519 cur = cur->next;
520 }
521}
522
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000523static void
524xmlValidDebug(xmlNodePtr cur, xmlElementContentPtr cont) {
Daniel Veillard83391282003-03-06 21:37:30 +0000525 char expr[5000];
Owen Taylor3473f882001-02-23 17:55:21 +0000526
527 expr[0] = 0;
528 xmlGenericError(xmlGenericErrorContext, "valid: ");
529 xmlValidPrintNodeList(cur);
530 xmlGenericError(xmlGenericErrorContext, "against ");
Daniel Veillardd3d06722001-08-15 12:06:36 +0000531 xmlSnprintfElementContent(expr, 5000, cont, 1);
Owen Taylor3473f882001-02-23 17:55:21 +0000532 xmlGenericError(xmlGenericErrorContext, "%s\n", expr);
533}
534
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000535static void
536xmlValidDebugState(xmlValidStatePtr state) {
537 xmlGenericError(xmlGenericErrorContext, "(");
538 if (state->cont == NULL)
539 xmlGenericError(xmlGenericErrorContext, "null,");
540 else
541 switch (state->cont->type) {
542 case XML_ELEMENT_CONTENT_PCDATA:
543 xmlGenericError(xmlGenericErrorContext, "pcdata,");
544 break;
545 case XML_ELEMENT_CONTENT_ELEMENT:
546 xmlGenericError(xmlGenericErrorContext, "%s,",
547 state->cont->name);
548 break;
549 case XML_ELEMENT_CONTENT_SEQ:
550 xmlGenericError(xmlGenericErrorContext, "seq,");
551 break;
552 case XML_ELEMENT_CONTENT_OR:
553 xmlGenericError(xmlGenericErrorContext, "or,");
554 break;
555 }
556 xmlValidPrintNode(state->node);
557 xmlGenericError(xmlGenericErrorContext, ",%d,%X,%d)",
558 state->depth, state->occurs, state->state);
559}
560
561static void
562xmlValidStateDebug(xmlValidCtxtPtr ctxt) {
563 int i, j;
564
565 xmlGenericError(xmlGenericErrorContext, "state: ");
566 xmlValidDebugState(ctxt->vstate);
567 xmlGenericError(xmlGenericErrorContext, " stack: %d ",
568 ctxt->vstateNr - 1);
569 for (i = 0, j = ctxt->vstateNr - 1;(i < 3) && (j > 0);i++,j--)
570 xmlValidDebugState(&ctxt->vstateTab[j]);
571 xmlGenericError(xmlGenericErrorContext, "\n");
572}
573
574/*****
Owen Taylor3473f882001-02-23 17:55:21 +0000575#define DEBUG_VALID_STATE(n,c) xmlValidDebug(n,c);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000576 *****/
577
578#define DEBUG_VALID_STATE(n,c) xmlValidStateDebug(ctxt);
Daniel Veillarde356c282001-03-10 12:32:04 +0000579#define DEBUG_VALID_MSG(m) \
580 xmlGenericError(xmlGenericErrorContext, "%s\n", m);
581
Owen Taylor3473f882001-02-23 17:55:21 +0000582#else
583#define DEBUG_VALID_STATE(n,c)
Daniel Veillarde356c282001-03-10 12:32:04 +0000584#define DEBUG_VALID_MSG(m)
Owen Taylor3473f882001-02-23 17:55:21 +0000585#endif
586
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000587/* TODO: use hash table for accesses to elem and attribute definitions */
Owen Taylor3473f882001-02-23 17:55:21 +0000588
Daniel Veillardb9cd8b42002-09-05 10:58:49 +0000589
Owen Taylor3473f882001-02-23 17:55:21 +0000590#define CHECK_DTD \
591 if (doc == NULL) return(0); \
592 else if ((doc->intSubset == NULL) && \
593 (doc->extSubset == NULL)) return(0)
594
Owen Taylor3473f882001-02-23 17:55:21 +0000595xmlAttributePtr xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem);
596
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000597#ifdef LIBXML_REGEXP_ENABLED
598
599/************************************************************************
600 * *
601 * Content model validation based on the regexps *
602 * *
603 ************************************************************************/
604
605/**
606 * xmlValidBuildAContentModel:
607 * @content: the content model
608 * @ctxt: the schema parser context
609 * @name: the element name whose content is being built
610 *
611 * Generate the automata sequence needed for that type
612 *
Daniel Veillard84d70a42002-09-16 10:51:38 +0000613 * Returns 1 if successful or 0 in case of error.
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000614 */
615static int
616xmlValidBuildAContentModel(xmlElementContentPtr content,
617 xmlValidCtxtPtr ctxt,
618 const xmlChar *name) {
619 if (content == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000620 xmlErrValidNode(ctxt, NULL, XML_ERR_INTERNAL_ERROR,
621 "Found NULL content in content model of %s\n",
622 name, NULL, NULL);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000623 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000624 }
625 switch (content->type) {
626 case XML_ELEMENT_CONTENT_PCDATA:
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000627 xmlErrValidNode(ctxt, NULL, XML_ERR_INTERNAL_ERROR,
628 "Found PCDATA in content model of %s\n",
629 name, NULL, NULL);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000630 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000631 break;
632 case XML_ELEMENT_CONTENT_ELEMENT: {
633 xmlAutomataStatePtr oldstate = ctxt->state;
Daniel Veillardc00cda82003-04-07 10:22:39 +0000634 xmlChar fn[50];
635 xmlChar *fullname;
636
637 fullname = xmlBuildQName(content->name, content->prefix, fn, 50);
638 if (fullname == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000639 xmlVErrMemory(ctxt, "Building content model");
Daniel Veillardc00cda82003-04-07 10:22:39 +0000640 return(0);
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000641 }
642
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000643 switch (content->ocur) {
644 case XML_ELEMENT_CONTENT_ONCE:
645 ctxt->state = xmlAutomataNewTransition(ctxt->am,
Daniel Veillardc00cda82003-04-07 10:22:39 +0000646 ctxt->state, NULL, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000647 break;
648 case XML_ELEMENT_CONTENT_OPT:
649 ctxt->state = xmlAutomataNewTransition(ctxt->am,
Daniel Veillardc00cda82003-04-07 10:22:39 +0000650 ctxt->state, NULL, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000651 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
652 break;
653 case XML_ELEMENT_CONTENT_PLUS:
654 ctxt->state = xmlAutomataNewTransition(ctxt->am,
Daniel Veillardc00cda82003-04-07 10:22:39 +0000655 ctxt->state, NULL, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000656 xmlAutomataNewTransition(ctxt->am, ctxt->state,
Daniel Veillardc00cda82003-04-07 10:22:39 +0000657 ctxt->state, fullname, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000658 break;
659 case XML_ELEMENT_CONTENT_MULT:
660 xmlAutomataNewTransition(ctxt->am, ctxt->state,
Daniel Veillardc00cda82003-04-07 10:22:39 +0000661 ctxt->state, fullname, NULL);
Daniel Veillard57e79b32003-02-04 15:33:12 +0000662 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, ctxt->state,
663 NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000664 break;
665 }
Daniel Veillardc00cda82003-04-07 10:22:39 +0000666 if ((fullname != fn) && (fullname != content->name))
667 xmlFree(fullname);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000668 break;
669 }
670 case XML_ELEMENT_CONTENT_SEQ: {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000671 xmlAutomataStatePtr oldstate, oldend;
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000672 xmlElementContentOccur ocur;
673
674 /*
675 * Simply iterate over the content
676 */
677 oldstate = ctxt->state;
678 ocur = content->ocur;
Daniel Veillardf4be0182003-02-24 19:54:33 +0000679 if (ocur != XML_ELEMENT_CONTENT_ONCE) {
680 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
681 oldstate = ctxt->state;
682 }
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000683 do {
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000684 xmlValidBuildAContentModel(content->c1, ctxt, name);
685 content = content->c2;
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000686 } while ((content->type == XML_ELEMENT_CONTENT_SEQ) &&
687 (content->ocur == XML_ELEMENT_CONTENT_ONCE));
688 xmlValidBuildAContentModel(content, ctxt, name);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000689 oldend = ctxt->state;
690 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000691 switch (ocur) {
692 case XML_ELEMENT_CONTENT_ONCE:
693 break;
694 case XML_ELEMENT_CONTENT_OPT:
695 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
696 break;
697 case XML_ELEMENT_CONTENT_MULT:
698 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000699 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000700 break;
701 case XML_ELEMENT_CONTENT_PLUS:
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000702 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000703 break;
704 }
705 break;
706 }
707 case XML_ELEMENT_CONTENT_OR: {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000708 xmlAutomataStatePtr oldstate, oldend;
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000709 xmlElementContentOccur ocur;
710
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000711 ocur = content->ocur;
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000712 if ((ocur == XML_ELEMENT_CONTENT_PLUS) ||
713 (ocur == XML_ELEMENT_CONTENT_MULT)) {
714 ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
715 ctxt->state, NULL);
716 }
717 oldstate = ctxt->state;
718 oldend = xmlAutomataNewState(ctxt->am);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000719
720 /*
721 * iterate over the subtypes and remerge the end with an
722 * epsilon transition
723 */
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000724 do {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000725 ctxt->state = oldstate;
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000726 xmlValidBuildAContentModel(content->c1, ctxt, name);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000727 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000728 content = content->c2;
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000729 } while ((content->type == XML_ELEMENT_CONTENT_OR) &&
730 (content->ocur == XML_ELEMENT_CONTENT_ONCE));
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000731 ctxt->state = oldstate;
Daniel Veillarda646cfd2002-09-17 21:50:03 +0000732 xmlValidBuildAContentModel(content, ctxt, name);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000733 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend);
734 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000735 switch (ocur) {
736 case XML_ELEMENT_CONTENT_ONCE:
737 break;
738 case XML_ELEMENT_CONTENT_OPT:
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000739 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000740 break;
741 case XML_ELEMENT_CONTENT_MULT:
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000742 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
743 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000744 break;
745 case XML_ELEMENT_CONTENT_PLUS:
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000746 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000747 break;
748 }
749 break;
750 }
751 default:
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000752 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
753 "ContentModel broken for element %s\n",
754 (const char *) name);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000755 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000756 }
Daniel Veillard84d70a42002-09-16 10:51:38 +0000757 return(1);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000758}
759/**
760 * xmlValidBuildContentModel:
761 * @ctxt: a validation context
762 * @elem: an element declaration node
763 *
764 * (Re)Build the automata associated to the content model of this
765 * element
766 *
Daniel Veillard84d70a42002-09-16 10:51:38 +0000767 * Returns 1 in case of success, 0 in case of error
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000768 */
769int
770xmlValidBuildContentModel(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000771
772 if ((ctxt == NULL) || (elem == NULL))
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000773 return(0);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000774 if (elem->type != XML_ELEMENT_DECL)
775 return(0);
776 if (elem->etype != XML_ELEMENT_TYPE_ELEMENT)
777 return(1);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000778 /* TODO: should we rebuild in this case ? */
Daniel Veillardec498e12003-02-05 11:01:50 +0000779 if (elem->contModel != NULL) {
780 if (!xmlRegexpIsDeterminist(elem->contModel)) {
781 ctxt->valid = 0;
782 return(0);
783 }
Daniel Veillard84d70a42002-09-16 10:51:38 +0000784 return(1);
Daniel Veillardec498e12003-02-05 11:01:50 +0000785 }
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000786
787 ctxt->am = xmlNewAutomata();
788 if (ctxt->am == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000789 xmlErrValidNode(ctxt, (xmlNodePtr) elem,
790 XML_ERR_INTERNAL_ERROR,
791 "Cannot create automata for element %s\n",
792 elem->name, NULL, NULL);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000793 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000794 }
William M. Brack78637da2003-07-31 14:47:38 +0000795 ctxt->state = xmlAutomataGetInitState(ctxt->am);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000796 xmlValidBuildAContentModel(elem->content, ctxt, elem->name);
797 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
Daniel Veillard84d70a42002-09-16 10:51:38 +0000798 elem->contModel = xmlAutomataCompile(ctxt->am);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000799 if (xmlRegexpIsDeterminist(elem->contModel) != 1) {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000800 char expr[5000];
801 expr[0] = 0;
802 xmlSnprintfElementContent(expr, 5000, elem->content, 1);
Daniel Veillardbb5abab2003-10-03 22:21:51 +0000803 xmlErrValidNode(ctxt, (xmlNodePtr) elem,
804 XML_DTD_CONTENT_NOT_DETERMINIST,
805 "Content model of %s is not determinist: %s\n",
806 elem->name, BAD_CAST expr, NULL);
Daniel Veillard5acfd6b2002-09-18 16:29:02 +0000807#ifdef DEBUG_REGEXP_ALGO
808 xmlRegexpPrint(stderr, elem->contModel);
809#endif
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000810 ctxt->valid = 0;
Daniel Veillardec498e12003-02-05 11:01:50 +0000811 ctxt->state = NULL;
812 xmlFreeAutomata(ctxt->am);
813 ctxt->am = NULL;
814 return(0);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000815 }
816 ctxt->state = NULL;
817 xmlFreeAutomata(ctxt->am);
818 ctxt->am = NULL;
Daniel Veillard84d70a42002-09-16 10:51:38 +0000819 return(1);
Daniel Veillardaeb258a2002-09-13 14:48:12 +0000820}
821
822#endif /* LIBXML_REGEXP_ENABLED */
823
Owen Taylor3473f882001-02-23 17:55:21 +0000824/****************************************************************
825 * *
826 * Util functions for data allocation/deallocation *
827 * *
828 ****************************************************************/
829
830/**
Daniel Veillarda37aab82003-06-09 09:10:36 +0000831 * xmlNewValidCtxt:
832 *
833 * Allocate a validation context structure.
834 *
835 * Returns NULL if not, otherwise the new validation context structure
836 */
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000837xmlValidCtxtPtr xmlNewValidCtxt(void) {
Daniel Veillarda37aab82003-06-09 09:10:36 +0000838 xmlValidCtxtPtr ret;
839
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000840 if ((ret = xmlMalloc(sizeof (xmlValidCtxt))) == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000841 xmlVErrMemory(NULL, "malloc failed");
Daniel Veillarda37aab82003-06-09 09:10:36 +0000842 return (NULL);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000843 }
Daniel Veillarda37aab82003-06-09 09:10:36 +0000844
845 (void) memset(ret, 0, sizeof (xmlValidCtxt));
846
847 return (ret);
848}
849
850/**
851 * xmlFreeValidCtxt:
852 * @cur: the validation context to free
853 *
854 * Free a validation context structure.
855 */
856void
857xmlFreeValidCtxt(xmlValidCtxtPtr cur) {
858 xmlFree(cur);
859}
860
Daniel Veillard4432df22003-09-28 18:58:27 +0000861#endif /* LIBXML_VALID_ENABLED */
862
Daniel Veillarda37aab82003-06-09 09:10:36 +0000863/**
Owen Taylor3473f882001-02-23 17:55:21 +0000864 * xmlNewElementContent:
865 * @name: the subelement name or NULL
866 * @type: the type of element content decl
867 *
868 * Allocate an element content structure.
869 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000870 * Returns NULL if not, otherwise the new element content structure
Owen Taylor3473f882001-02-23 17:55:21 +0000871 */
872xmlElementContentPtr
Daniel Veillard2fdbd322003-08-18 12:15:38 +0000873xmlNewElementContent(const xmlChar *name, xmlElementContentType type) {
Owen Taylor3473f882001-02-23 17:55:21 +0000874 xmlElementContentPtr ret;
875
876 switch(type) {
877 case XML_ELEMENT_CONTENT_ELEMENT:
878 if (name == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000879 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
880 "xmlNewElementContent : name == NULL !\n",
881 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000882 }
883 break;
884 case XML_ELEMENT_CONTENT_PCDATA:
885 case XML_ELEMENT_CONTENT_SEQ:
886 case XML_ELEMENT_CONTENT_OR:
887 if (name != NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000888 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
889 "xmlNewElementContent : name != NULL !\n",
890 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000891 }
892 break;
893 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000894 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
895 "Internal: ELEMENT content corrupted invalid type\n",
896 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000897 return(NULL);
898 }
899 ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
900 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000901 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +0000902 return(NULL);
903 }
Daniel Veillardd54fa3e2002-02-20 16:48:52 +0000904 memset(ret, 0, sizeof(xmlElementContent));
Owen Taylor3473f882001-02-23 17:55:21 +0000905 ret->type = type;
906 ret->ocur = XML_ELEMENT_CONTENT_ONCE;
Daniel Veillardbe480fb2001-11-08 23:36:42 +0000907 if (name != NULL) {
908 xmlChar *prefix = NULL;
909 ret->name = xmlSplitQName2(name, &prefix);
910 if (ret->name == NULL)
911 ret->name = xmlStrdup(name);
912 ret->prefix = prefix;
913 } else {
Owen Taylor3473f882001-02-23 17:55:21 +0000914 ret->name = NULL;
Daniel Veillardbe480fb2001-11-08 23:36:42 +0000915 ret->prefix = NULL;
916 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000917 ret->c1 = ret->c2 = ret->parent = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +0000918 return(ret);
919}
920
921/**
922 * xmlCopyElementContent:
Daniel Veillard01c13b52002-12-10 15:19:08 +0000923 * @cur: An element content pointer.
Owen Taylor3473f882001-02-23 17:55:21 +0000924 *
925 * Build a copy of an element content description.
926 *
927 * Returns the new xmlElementContentPtr or NULL in case of error.
928 */
929xmlElementContentPtr
930xmlCopyElementContent(xmlElementContentPtr cur) {
931 xmlElementContentPtr ret;
932
933 if (cur == NULL) return(NULL);
934 ret = xmlNewElementContent((xmlChar *) cur->name, cur->type);
935 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +0000936 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +0000937 return(NULL);
938 }
Daniel Veillardbe480fb2001-11-08 23:36:42 +0000939 if (cur->prefix != NULL)
940 ret->prefix = xmlStrdup(cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000941 ret->ocur = cur->ocur;
942 if (cur->c1 != NULL) ret->c1 = xmlCopyElementContent(cur->c1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000943 if (ret->c1 != NULL)
944 ret->c1->parent = ret;
Owen Taylor3473f882001-02-23 17:55:21 +0000945 if (cur->c2 != NULL) ret->c2 = xmlCopyElementContent(cur->c2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +0000946 if (ret->c2 != NULL)
947 ret->c2->parent = ret;
Owen Taylor3473f882001-02-23 17:55:21 +0000948 return(ret);
949}
950
951/**
952 * xmlFreeElementContent:
953 * @cur: the element content tree to free
954 *
955 * Free an element content structure. This is a recursive call !
956 */
957void
958xmlFreeElementContent(xmlElementContentPtr cur) {
959 if (cur == NULL) return;
960 switch (cur->type) {
961 case XML_ELEMENT_CONTENT_PCDATA:
962 case XML_ELEMENT_CONTENT_ELEMENT:
963 case XML_ELEMENT_CONTENT_SEQ:
964 case XML_ELEMENT_CONTENT_OR:
965 break;
966 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +0000967 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
968 "Internal: ELEMENT content corrupted invalid type\n",
969 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000970 return;
971 }
972 if (cur->c1 != NULL) xmlFreeElementContent(cur->c1);
973 if (cur->c2 != NULL) xmlFreeElementContent(cur->c2);
974 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
Daniel Veillardbe480fb2001-11-08 23:36:42 +0000975 if (cur->prefix != NULL) xmlFree((xmlChar *) cur->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +0000976 xmlFree(cur);
977}
978
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000979#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000980/**
981 * xmlDumpElementContent:
982 * @buf: An XML buffer
983 * @content: An element table
984 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
985 *
986 * This will dump the content of the element table as an XML DTD definition
987 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000988static void
Owen Taylor3473f882001-02-23 17:55:21 +0000989xmlDumpElementContent(xmlBufferPtr buf, xmlElementContentPtr content, int glob) {
990 if (content == NULL) return;
991
992 if (glob) xmlBufferWriteChar(buf, "(");
993 switch (content->type) {
994 case XML_ELEMENT_CONTENT_PCDATA:
995 xmlBufferWriteChar(buf, "#PCDATA");
996 break;
997 case XML_ELEMENT_CONTENT_ELEMENT:
Daniel Veillardbe480fb2001-11-08 23:36:42 +0000998 if (content->prefix != NULL) {
999 xmlBufferWriteCHAR(buf, content->prefix);
1000 xmlBufferWriteChar(buf, ":");
1001 }
Owen Taylor3473f882001-02-23 17:55:21 +00001002 xmlBufferWriteCHAR(buf, content->name);
1003 break;
1004 case XML_ELEMENT_CONTENT_SEQ:
1005 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1006 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
1007 xmlDumpElementContent(buf, content->c1, 1);
1008 else
1009 xmlDumpElementContent(buf, content->c1, 0);
1010 xmlBufferWriteChar(buf, " , ");
1011 if (content->c2->type == XML_ELEMENT_CONTENT_OR)
1012 xmlDumpElementContent(buf, content->c2, 1);
1013 else
1014 xmlDumpElementContent(buf, content->c2, 0);
1015 break;
1016 case XML_ELEMENT_CONTENT_OR:
1017 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1018 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
1019 xmlDumpElementContent(buf, content->c1, 1);
1020 else
1021 xmlDumpElementContent(buf, content->c1, 0);
1022 xmlBufferWriteChar(buf, " | ");
1023 if (content->c2->type == XML_ELEMENT_CONTENT_SEQ)
1024 xmlDumpElementContent(buf, content->c2, 1);
1025 else
1026 xmlDumpElementContent(buf, content->c2, 0);
1027 break;
1028 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001029 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1030 "Internal: ELEMENT content corrupted invalid type\n",
1031 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001032 }
1033 if (glob)
1034 xmlBufferWriteChar(buf, ")");
1035 switch (content->ocur) {
1036 case XML_ELEMENT_CONTENT_ONCE:
1037 break;
1038 case XML_ELEMENT_CONTENT_OPT:
1039 xmlBufferWriteChar(buf, "?");
1040 break;
1041 case XML_ELEMENT_CONTENT_MULT:
1042 xmlBufferWriteChar(buf, "*");
1043 break;
1044 case XML_ELEMENT_CONTENT_PLUS:
1045 xmlBufferWriteChar(buf, "+");
1046 break;
1047 }
1048}
1049
1050/**
1051 * xmlSprintfElementContent:
1052 * @buf: an output buffer
1053 * @content: An element table
1054 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
1055 *
Daniel Veillardd3d06722001-08-15 12:06:36 +00001056 * Deprecated, unsafe, use xmlSnprintfElementContent
1057 */
1058void
1059xmlSprintfElementContent(char *buf ATTRIBUTE_UNUSED,
1060 xmlElementContentPtr content ATTRIBUTE_UNUSED,
1061 int glob ATTRIBUTE_UNUSED) {
1062}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001063#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardd3d06722001-08-15 12:06:36 +00001064
1065/**
1066 * xmlSnprintfElementContent:
1067 * @buf: an output buffer
1068 * @size: the buffer size
1069 * @content: An element table
1070 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
1071 *
Owen Taylor3473f882001-02-23 17:55:21 +00001072 * This will dump the content of the element content definition
1073 * Intended just for the debug routine
1074 */
1075void
Daniel Veillardd3d06722001-08-15 12:06:36 +00001076xmlSnprintfElementContent(char *buf, int size, xmlElementContentPtr content, int glob) {
1077 int len;
1078
Owen Taylor3473f882001-02-23 17:55:21 +00001079 if (content == NULL) return;
Daniel Veillardd3d06722001-08-15 12:06:36 +00001080 len = strlen(buf);
1081 if (size - len < 50) {
1082 if ((size - len > 4) && (buf[len - 1] != '.'))
1083 strcat(buf, " ...");
1084 return;
1085 }
Owen Taylor3473f882001-02-23 17:55:21 +00001086 if (glob) strcat(buf, "(");
1087 switch (content->type) {
1088 case XML_ELEMENT_CONTENT_PCDATA:
1089 strcat(buf, "#PCDATA");
1090 break;
1091 case XML_ELEMENT_CONTENT_ELEMENT:
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001092 if (content->prefix != NULL) {
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00001093 if (size - len < xmlStrlen(content->prefix) + 10) {
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001094 strcat(buf, " ...");
1095 return;
1096 }
1097 strcat(buf, (char *) content->prefix);
1098 strcat(buf, ":");
1099 }
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00001100 if (size - len < xmlStrlen(content->name) + 10) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00001101 strcat(buf, " ...");
1102 return;
1103 }
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001104 if (content->name != NULL)
1105 strcat(buf, (char *) content->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001106 break;
1107 case XML_ELEMENT_CONTENT_SEQ:
1108 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1109 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
Daniel Veillardd3d06722001-08-15 12:06:36 +00001110 xmlSnprintfElementContent(buf, size, content->c1, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001111 else
Daniel Veillardd3d06722001-08-15 12:06:36 +00001112 xmlSnprintfElementContent(buf, size, content->c1, 0);
1113 len = strlen(buf);
1114 if (size - len < 50) {
1115 if ((size - len > 4) && (buf[len - 1] != '.'))
1116 strcat(buf, " ...");
1117 return;
1118 }
Owen Taylor3473f882001-02-23 17:55:21 +00001119 strcat(buf, " , ");
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00001120 if (((content->c2->type == XML_ELEMENT_CONTENT_OR) ||
1121 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
1122 (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
Daniel Veillardd3d06722001-08-15 12:06:36 +00001123 xmlSnprintfElementContent(buf, size, content->c2, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001124 else
Daniel Veillardd3d06722001-08-15 12:06:36 +00001125 xmlSnprintfElementContent(buf, size, content->c2, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00001126 break;
1127 case XML_ELEMENT_CONTENT_OR:
1128 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1129 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
Daniel Veillardd3d06722001-08-15 12:06:36 +00001130 xmlSnprintfElementContent(buf, size, content->c1, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001131 else
Daniel Veillardd3d06722001-08-15 12:06:36 +00001132 xmlSnprintfElementContent(buf, size, content->c1, 0);
1133 len = strlen(buf);
1134 if (size - len < 50) {
1135 if ((size - len > 4) && (buf[len - 1] != '.'))
1136 strcat(buf, " ...");
1137 return;
1138 }
Owen Taylor3473f882001-02-23 17:55:21 +00001139 strcat(buf, " | ");
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00001140 if (((content->c2->type == XML_ELEMENT_CONTENT_SEQ) ||
1141 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
1142 (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
Daniel Veillardd3d06722001-08-15 12:06:36 +00001143 xmlSnprintfElementContent(buf, size, content->c2, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001144 else
Daniel Veillardd3d06722001-08-15 12:06:36 +00001145 xmlSnprintfElementContent(buf, size, content->c2, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00001146 break;
1147 }
1148 if (glob)
1149 strcat(buf, ")");
1150 switch (content->ocur) {
1151 case XML_ELEMENT_CONTENT_ONCE:
1152 break;
1153 case XML_ELEMENT_CONTENT_OPT:
1154 strcat(buf, "?");
1155 break;
1156 case XML_ELEMENT_CONTENT_MULT:
1157 strcat(buf, "*");
1158 break;
1159 case XML_ELEMENT_CONTENT_PLUS:
1160 strcat(buf, "+");
1161 break;
1162 }
1163}
1164
1165/****************************************************************
1166 * *
1167 * Registration of DTD declarations *
1168 * *
1169 ****************************************************************/
1170
1171/**
1172 * xmlCreateElementTable:
1173 *
1174 * create and initialize an empty element hash table.
1175 *
1176 * Returns the xmlElementTablePtr just created or NULL in case of error.
1177 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001178static xmlElementTablePtr
Owen Taylor3473f882001-02-23 17:55:21 +00001179xmlCreateElementTable(void) {
1180 return(xmlHashCreate(0));
1181}
1182
1183/**
1184 * xmlFreeElement:
1185 * @elem: An element
1186 *
1187 * Deallocate the memory used by an element definition
1188 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001189static void
Owen Taylor3473f882001-02-23 17:55:21 +00001190xmlFreeElement(xmlElementPtr elem) {
1191 if (elem == NULL) return;
1192 xmlUnlinkNode((xmlNodePtr) elem);
1193 xmlFreeElementContent(elem->content);
1194 if (elem->name != NULL)
1195 xmlFree((xmlChar *) elem->name);
1196 if (elem->prefix != NULL)
1197 xmlFree((xmlChar *) elem->prefix);
Daniel Veillard84d70a42002-09-16 10:51:38 +00001198#ifdef LIBXML_REGEXP_ENABLED
1199 if (elem->contModel != NULL)
1200 xmlRegFreeRegexp(elem->contModel);
1201#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001202 xmlFree(elem);
1203}
1204
1205
1206/**
1207 * xmlAddElementDecl:
1208 * @ctxt: the validation context
1209 * @dtd: pointer to the DTD
1210 * @name: the entity name
1211 * @type: the element type
1212 * @content: the element content tree or NULL
1213 *
1214 * Register a new element declaration
1215 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001216 * Returns NULL if not, otherwise the entity
Owen Taylor3473f882001-02-23 17:55:21 +00001217 */
1218xmlElementPtr
William M. Brackedb65a72004-02-06 07:36:04 +00001219xmlAddElementDecl(xmlValidCtxtPtr ctxt,
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001220 xmlDtdPtr dtd, const xmlChar *name,
Owen Taylor3473f882001-02-23 17:55:21 +00001221 xmlElementTypeVal type,
1222 xmlElementContentPtr content) {
1223 xmlElementPtr ret;
1224 xmlElementTablePtr table;
Daniel Veillarda10efa82001-04-18 13:09:01 +00001225 xmlAttributePtr oldAttributes = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001226 xmlChar *ns, *uqname;
1227
1228 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001229 return(NULL);
1230 }
1231 if (name == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001232 return(NULL);
1233 }
1234 switch (type) {
1235 case XML_ELEMENT_TYPE_EMPTY:
1236 if (content != NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001237 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1238 "xmlAddElementDecl: content != NULL for EMPTY\n",
1239 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001240 return(NULL);
1241 }
1242 break;
1243 case XML_ELEMENT_TYPE_ANY:
1244 if (content != NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001245 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1246 "xmlAddElementDecl: content != NULL for ANY\n",
1247 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001248 return(NULL);
1249 }
1250 break;
1251 case XML_ELEMENT_TYPE_MIXED:
1252 if (content == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001253 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1254 "xmlAddElementDecl: content == NULL for MIXED\n",
1255 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001256 return(NULL);
1257 }
1258 break;
1259 case XML_ELEMENT_TYPE_ELEMENT:
1260 if (content == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001261 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1262 "xmlAddElementDecl: content == NULL for ELEMENT\n",
1263 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001264 return(NULL);
1265 }
1266 break;
1267 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001268 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1269 "Internal: ELEMENT decl corrupted invalid type\n",
1270 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001271 return(NULL);
1272 }
1273
1274 /*
1275 * check if name is a QName
1276 */
1277 uqname = xmlSplitQName2(name, &ns);
1278 if (uqname != NULL)
1279 name = uqname;
1280
1281 /*
1282 * Create the Element table if needed.
1283 */
1284 table = (xmlElementTablePtr) dtd->elements;
1285 if (table == NULL) {
1286 table = xmlCreateElementTable();
1287 dtd->elements = (void *) table;
1288 }
1289 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001290 xmlVErrMemory(ctxt,
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001291 "xmlAddElementDecl: Table creation failed!\n");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001292 if (uqname != NULL)
1293 xmlFree(uqname);
1294 if (ns != NULL)
1295 xmlFree(ns);
Owen Taylor3473f882001-02-23 17:55:21 +00001296 return(NULL);
1297 }
1298
Daniel Veillarda10efa82001-04-18 13:09:01 +00001299 /*
1300 * lookup old attributes inserted on an undefined element in the
1301 * internal subset.
1302 */
1303 if ((dtd->doc != NULL) && (dtd->doc->intSubset != NULL)) {
1304 ret = xmlHashLookup2(dtd->doc->intSubset->elements, name, ns);
1305 if ((ret != NULL) && (ret->etype == XML_ELEMENT_TYPE_UNDEFINED)) {
1306 oldAttributes = ret->attributes;
1307 ret->attributes = NULL;
1308 xmlHashRemoveEntry2(dtd->doc->intSubset->elements, name, ns, NULL);
1309 xmlFreeElement(ret);
1310 }
Owen Taylor3473f882001-02-23 17:55:21 +00001311 }
Owen Taylor3473f882001-02-23 17:55:21 +00001312
1313 /*
Daniel Veillarda10efa82001-04-18 13:09:01 +00001314 * The element may already be present if one of its attribute
1315 * was registered first
1316 */
1317 ret = xmlHashLookup2(table, name, ns);
1318 if (ret != NULL) {
1319 if (ret->etype != XML_ELEMENT_TYPE_UNDEFINED) {
Daniel Veillard4432df22003-09-28 18:58:27 +00001320#ifdef LIBXML_VALID_ENABLED
Daniel Veillarda10efa82001-04-18 13:09:01 +00001321 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001322 * The element is already defined in this DTD.
Daniel Veillarda10efa82001-04-18 13:09:01 +00001323 */
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001324 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED,
1325 "Redefinition of element %s\n",
1326 name, NULL, NULL);
Daniel Veillard4432df22003-09-28 18:58:27 +00001327#endif /* LIBXML_VALID_ENABLED */
Daniel Veillarda10efa82001-04-18 13:09:01 +00001328 if (uqname != NULL)
1329 xmlFree(uqname);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001330 if (ns != NULL)
1331 xmlFree(ns);
Daniel Veillarda10efa82001-04-18 13:09:01 +00001332 return(NULL);
1333 }
1334 } else {
1335 ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1336 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001337 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001338 if (uqname != NULL)
1339 xmlFree(uqname);
1340 if (ns != NULL)
1341 xmlFree(ns);
Daniel Veillarda10efa82001-04-18 13:09:01 +00001342 return(NULL);
1343 }
1344 memset(ret, 0, sizeof(xmlElement));
1345 ret->type = XML_ELEMENT_DECL;
1346
1347 /*
1348 * fill the structure.
1349 */
1350 ret->name = xmlStrdup(name);
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001351 if (ret->name == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001352 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00001353 if (uqname != NULL)
1354 xmlFree(uqname);
1355 if (ns != NULL)
1356 xmlFree(ns);
1357 xmlFree(ret);
1358 return(NULL);
1359 }
Daniel Veillarda10efa82001-04-18 13:09:01 +00001360 ret->prefix = ns;
1361
1362 /*
1363 * Validity Check:
1364 * Insertion must not fail
1365 */
1366 if (xmlHashAddEntry2(table, name, ns, ret)) {
Daniel Veillard4432df22003-09-28 18:58:27 +00001367#ifdef LIBXML_VALID_ENABLED
Daniel Veillarda10efa82001-04-18 13:09:01 +00001368 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001369 * The element is already defined in this DTD.
Daniel Veillarda10efa82001-04-18 13:09:01 +00001370 */
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001371 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED,
1372 "Redefinition of element %s\n",
1373 name, NULL, NULL);
Daniel Veillard4432df22003-09-28 18:58:27 +00001374#endif /* LIBXML_VALID_ENABLED */
Daniel Veillarda10efa82001-04-18 13:09:01 +00001375 xmlFreeElement(ret);
1376 if (uqname != NULL)
1377 xmlFree(uqname);
1378 return(NULL);
1379 }
William M. Brack4e52f2f2003-09-14 18:07:39 +00001380 /*
1381 * For new element, may have attributes from earlier
1382 * definition in internal subset
1383 */
1384 ret->attributes = oldAttributes;
Daniel Veillarda10efa82001-04-18 13:09:01 +00001385 }
1386
1387 /*
1388 * Finish to fill the structure.
Owen Taylor3473f882001-02-23 17:55:21 +00001389 */
1390 ret->etype = type;
Owen Taylor3473f882001-02-23 17:55:21 +00001391 ret->content = xmlCopyElementContent(content);
Owen Taylor3473f882001-02-23 17:55:21 +00001392
1393 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001394 * Link it to the DTD
Owen Taylor3473f882001-02-23 17:55:21 +00001395 */
1396 ret->parent = dtd;
1397 ret->doc = dtd->doc;
1398 if (dtd->last == NULL) {
1399 dtd->children = dtd->last = (xmlNodePtr) ret;
1400 } else {
1401 dtd->last->next = (xmlNodePtr) ret;
1402 ret->prev = dtd->last;
1403 dtd->last = (xmlNodePtr) ret;
1404 }
1405 if (uqname != NULL)
1406 xmlFree(uqname);
1407 return(ret);
1408}
1409
1410/**
1411 * xmlFreeElementTable:
1412 * @table: An element table
1413 *
1414 * Deallocate the memory used by an element hash table.
1415 */
1416void
1417xmlFreeElementTable(xmlElementTablePtr table) {
1418 xmlHashFree(table, (xmlHashDeallocator) xmlFreeElement);
1419}
1420
Daniel Veillard652327a2003-09-29 18:02:38 +00001421#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001422/**
1423 * xmlCopyElement:
1424 * @elem: An element
1425 *
1426 * Build a copy of an element.
1427 *
1428 * Returns the new xmlElementPtr or NULL in case of error.
1429 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001430static xmlElementPtr
Owen Taylor3473f882001-02-23 17:55:21 +00001431xmlCopyElement(xmlElementPtr elem) {
1432 xmlElementPtr cur;
1433
1434 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1435 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001436 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001437 return(NULL);
1438 }
1439 memset(cur, 0, sizeof(xmlElement));
1440 cur->type = XML_ELEMENT_DECL;
1441 cur->etype = elem->etype;
1442 if (elem->name != NULL)
1443 cur->name = xmlStrdup(elem->name);
1444 else
1445 cur->name = NULL;
1446 if (elem->prefix != NULL)
1447 cur->prefix = xmlStrdup(elem->prefix);
1448 else
1449 cur->prefix = NULL;
1450 cur->content = xmlCopyElementContent(elem->content);
1451 /* TODO : rebuild the attribute list on the copy */
1452 cur->attributes = NULL;
1453 return(cur);
1454}
1455
1456/**
1457 * xmlCopyElementTable:
1458 * @table: An element table
1459 *
1460 * Build a copy of an element table.
1461 *
1462 * Returns the new xmlElementTablePtr or NULL in case of error.
1463 */
1464xmlElementTablePtr
1465xmlCopyElementTable(xmlElementTablePtr table) {
1466 return((xmlElementTablePtr) xmlHashCopy(table,
1467 (xmlHashCopier) xmlCopyElement));
1468}
Daniel Veillard652327a2003-09-29 18:02:38 +00001469#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001470
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001471#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001472/**
1473 * xmlDumpElementDecl:
1474 * @buf: the XML buffer output
1475 * @elem: An element table
1476 *
1477 * This will dump the content of the element declaration as an XML
1478 * DTD definition
1479 */
1480void
1481xmlDumpElementDecl(xmlBufferPtr buf, xmlElementPtr elem) {
1482 switch (elem->etype) {
1483 case XML_ELEMENT_TYPE_EMPTY:
1484 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001485 if (elem->prefix != NULL) {
1486 xmlBufferWriteCHAR(buf, elem->prefix);
1487 xmlBufferWriteChar(buf, ":");
1488 }
Owen Taylor3473f882001-02-23 17:55:21 +00001489 xmlBufferWriteCHAR(buf, elem->name);
1490 xmlBufferWriteChar(buf, " EMPTY>\n");
1491 break;
1492 case XML_ELEMENT_TYPE_ANY:
1493 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001494 if (elem->prefix != NULL) {
1495 xmlBufferWriteCHAR(buf, elem->prefix);
1496 xmlBufferWriteChar(buf, ":");
1497 }
Owen Taylor3473f882001-02-23 17:55:21 +00001498 xmlBufferWriteCHAR(buf, elem->name);
1499 xmlBufferWriteChar(buf, " ANY>\n");
1500 break;
1501 case XML_ELEMENT_TYPE_MIXED:
1502 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001503 if (elem->prefix != NULL) {
1504 xmlBufferWriteCHAR(buf, elem->prefix);
1505 xmlBufferWriteChar(buf, ":");
1506 }
Owen Taylor3473f882001-02-23 17:55:21 +00001507 xmlBufferWriteCHAR(buf, elem->name);
1508 xmlBufferWriteChar(buf, " ");
1509 xmlDumpElementContent(buf, elem->content, 1);
1510 xmlBufferWriteChar(buf, ">\n");
1511 break;
1512 case XML_ELEMENT_TYPE_ELEMENT:
1513 xmlBufferWriteChar(buf, "<!ELEMENT ");
Daniel Veillardbe480fb2001-11-08 23:36:42 +00001514 if (elem->prefix != NULL) {
1515 xmlBufferWriteCHAR(buf, elem->prefix);
1516 xmlBufferWriteChar(buf, ":");
1517 }
Owen Taylor3473f882001-02-23 17:55:21 +00001518 xmlBufferWriteCHAR(buf, elem->name);
1519 xmlBufferWriteChar(buf, " ");
1520 xmlDumpElementContent(buf, elem->content, 1);
1521 xmlBufferWriteChar(buf, ">\n");
1522 break;
1523 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001524 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1525 "Internal: ELEMENT struct corrupted invalid type\n",
1526 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001527 }
1528}
1529
1530/**
William M. Brack9e660592003-10-20 14:56:06 +00001531 * xmlDumpElementDeclScan:
1532 * @elem: An element table
1533 * @buf: the XML buffer output
1534 *
1535 * This routine is used by the hash scan function. It just reverses
1536 * the arguments.
1537 */
1538static void
1539xmlDumpElementDeclScan(xmlElementPtr elem, xmlBufferPtr buf) {
1540 xmlDumpElementDecl(buf, elem);
1541}
1542
1543/**
Owen Taylor3473f882001-02-23 17:55:21 +00001544 * xmlDumpElementTable:
1545 * @buf: the XML buffer output
1546 * @table: An element table
1547 *
1548 * This will dump the content of the element table as an XML DTD definition
1549 */
1550void
1551xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) {
William M. Brack9e660592003-10-20 14:56:06 +00001552 xmlHashScan(table, (xmlHashScanner) xmlDumpElementDeclScan, buf);
Owen Taylor3473f882001-02-23 17:55:21 +00001553}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001554#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001555
1556/**
1557 * xmlCreateEnumeration:
1558 * @name: the enumeration name or NULL
1559 *
1560 * create and initialize an enumeration attribute node.
1561 *
1562 * Returns the xmlEnumerationPtr just created or NULL in case
1563 * of error.
1564 */
1565xmlEnumerationPtr
Daniel Veillard2fdbd322003-08-18 12:15:38 +00001566xmlCreateEnumeration(const xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00001567 xmlEnumerationPtr ret;
1568
1569 ret = (xmlEnumerationPtr) xmlMalloc(sizeof(xmlEnumeration));
1570 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001571 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001572 return(NULL);
1573 }
1574 memset(ret, 0, sizeof(xmlEnumeration));
1575
1576 if (name != NULL)
1577 ret->name = xmlStrdup(name);
1578 return(ret);
1579}
1580
1581/**
1582 * xmlFreeEnumeration:
1583 * @cur: the tree to free.
1584 *
1585 * free an enumeration attribute node (recursive).
1586 */
1587void
1588xmlFreeEnumeration(xmlEnumerationPtr cur) {
1589 if (cur == NULL) return;
1590
1591 if (cur->next != NULL) xmlFreeEnumeration(cur->next);
1592
1593 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
Owen Taylor3473f882001-02-23 17:55:21 +00001594 xmlFree(cur);
1595}
1596
Daniel Veillard652327a2003-09-29 18:02:38 +00001597#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001598/**
1599 * xmlCopyEnumeration:
1600 * @cur: the tree to copy.
1601 *
1602 * Copy an enumeration attribute node (recursive).
1603 *
1604 * Returns the xmlEnumerationPtr just created or NULL in case
1605 * of error.
1606 */
1607xmlEnumerationPtr
1608xmlCopyEnumeration(xmlEnumerationPtr cur) {
1609 xmlEnumerationPtr ret;
1610
1611 if (cur == NULL) return(NULL);
1612 ret = xmlCreateEnumeration((xmlChar *) cur->name);
1613
1614 if (cur->next != NULL) ret->next = xmlCopyEnumeration(cur->next);
1615 else ret->next = NULL;
1616
1617 return(ret);
1618}
Daniel Veillard652327a2003-09-29 18:02:38 +00001619#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001620
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001621#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001622/**
1623 * xmlDumpEnumeration:
1624 * @buf: the XML buffer output
1625 * @enum: An enumeration
1626 *
1627 * This will dump the content of the enumeration
1628 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001629static void
Owen Taylor3473f882001-02-23 17:55:21 +00001630xmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) {
1631 if (cur == NULL) return;
1632
1633 xmlBufferWriteCHAR(buf, cur->name);
1634 if (cur->next == NULL)
1635 xmlBufferWriteChar(buf, ")");
1636 else {
1637 xmlBufferWriteChar(buf, " | ");
1638 xmlDumpEnumeration(buf, cur->next);
1639 }
1640}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001641#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001642
1643/**
1644 * xmlCreateAttributeTable:
1645 *
1646 * create and initialize an empty attribute hash table.
1647 *
1648 * Returns the xmlAttributeTablePtr just created or NULL in case
1649 * of error.
1650 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001651static xmlAttributeTablePtr
Owen Taylor3473f882001-02-23 17:55:21 +00001652xmlCreateAttributeTable(void) {
1653 return(xmlHashCreate(0));
1654}
1655
Daniel Veillard4432df22003-09-28 18:58:27 +00001656#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001657/**
1658 * xmlScanAttributeDeclCallback:
1659 * @attr: the attribute decl
1660 * @list: the list to update
1661 *
1662 * Callback called by xmlScanAttributeDecl when a new attribute
1663 * has to be entered in the list.
1664 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001665static void
Owen Taylor3473f882001-02-23 17:55:21 +00001666xmlScanAttributeDeclCallback(xmlAttributePtr attr, xmlAttributePtr *list,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00001667 const xmlChar* name ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00001668 attr->nexth = *list;
1669 *list = attr;
1670}
1671
1672/**
1673 * xmlScanAttributeDecl:
1674 * @dtd: pointer to the DTD
1675 * @elem: the element name
1676 *
1677 * When inserting a new element scan the DtD for existing attributes
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001678 * for that element and initialize the Attribute chain
Owen Taylor3473f882001-02-23 17:55:21 +00001679 *
1680 * Returns the pointer to the first attribute decl in the chain,
1681 * possibly NULL.
1682 */
1683xmlAttributePtr
1684xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem) {
1685 xmlAttributePtr ret = NULL;
1686 xmlAttributeTablePtr table;
1687
1688 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001689 return(NULL);
1690 }
1691 if (elem == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001692 return(NULL);
1693 }
1694 table = (xmlAttributeTablePtr) dtd->attributes;
1695 if (table == NULL)
1696 return(NULL);
1697
1698 /* WRONG !!! */
1699 xmlHashScan3(table, NULL, NULL, elem,
1700 (xmlHashScanner) xmlScanAttributeDeclCallback, &ret);
1701 return(ret);
1702}
1703
1704/**
1705 * xmlScanIDAttributeDecl:
1706 * @ctxt: the validation context
1707 * @elem: the element name
1708 *
1709 * Verify that the element don't have too many ID attributes
1710 * declared.
1711 *
1712 * Returns the number of ID attributes found.
1713 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001714static int
Owen Taylor3473f882001-02-23 17:55:21 +00001715xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
1716 xmlAttributePtr cur;
1717 int ret = 0;
1718
1719 if (elem == NULL) return(0);
1720 cur = elem->attributes;
1721 while (cur != NULL) {
1722 if (cur->atype == XML_ATTRIBUTE_ID) {
1723 ret ++;
1724 if (ret > 1)
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001725 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_MULTIPLE_ID,
Daniel Veillarda10efa82001-04-18 13:09:01 +00001726 "Element %s has too many ID attributes defined : %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001727 elem->name, cur->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001728 }
1729 cur = cur->nexth;
1730 }
1731 return(ret);
1732}
Daniel Veillard4432df22003-09-28 18:58:27 +00001733#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001734
1735/**
1736 * xmlFreeAttribute:
1737 * @elem: An attribute
1738 *
1739 * Deallocate the memory used by an attribute definition
1740 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001741static void
Owen Taylor3473f882001-02-23 17:55:21 +00001742xmlFreeAttribute(xmlAttributePtr attr) {
1743 if (attr == NULL) return;
1744 xmlUnlinkNode((xmlNodePtr) attr);
1745 if (attr->tree != NULL)
1746 xmlFreeEnumeration(attr->tree);
1747 if (attr->elem != NULL)
1748 xmlFree((xmlChar *) attr->elem);
1749 if (attr->name != NULL)
1750 xmlFree((xmlChar *) attr->name);
1751 if (attr->defaultValue != NULL)
1752 xmlFree((xmlChar *) attr->defaultValue);
1753 if (attr->prefix != NULL)
1754 xmlFree((xmlChar *) attr->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00001755 xmlFree(attr);
1756}
1757
1758
1759/**
1760 * xmlAddAttributeDecl:
1761 * @ctxt: the validation context
1762 * @dtd: pointer to the DTD
1763 * @elem: the element name
1764 * @name: the attribute name
1765 * @ns: the attribute namespace prefix
1766 * @type: the attribute type
1767 * @def: the attribute default type
1768 * @defaultValue: the attribute default value
1769 * @tree: if it's an enumeration, the associated list
1770 *
1771 * Register a new attribute declaration
1772 * Note that @tree becomes the ownership of the DTD
1773 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001774 * Returns NULL if not new, otherwise the attribute decl
Owen Taylor3473f882001-02-23 17:55:21 +00001775 */
1776xmlAttributePtr
William M. Brackedb65a72004-02-06 07:36:04 +00001777xmlAddAttributeDecl(xmlValidCtxtPtr ctxt,
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001778 xmlDtdPtr dtd, const xmlChar *elem,
Owen Taylor3473f882001-02-23 17:55:21 +00001779 const xmlChar *name, const xmlChar *ns,
1780 xmlAttributeType type, xmlAttributeDefault def,
1781 const xmlChar *defaultValue, xmlEnumerationPtr tree) {
1782 xmlAttributePtr ret;
1783 xmlAttributeTablePtr table;
1784 xmlElementPtr elemDef;
1785
1786 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001787 xmlFreeEnumeration(tree);
1788 return(NULL);
1789 }
1790 if (name == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001791 xmlFreeEnumeration(tree);
1792 return(NULL);
1793 }
1794 if (elem == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001795 xmlFreeEnumeration(tree);
1796 return(NULL);
1797 }
Daniel Veillardd85f4f42002-03-25 10:48:46 +00001798
Daniel Veillard4432df22003-09-28 18:58:27 +00001799#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001800 /*
1801 * Check the type and possibly the default value.
1802 */
1803 switch (type) {
1804 case XML_ATTRIBUTE_CDATA:
1805 break;
1806 case XML_ATTRIBUTE_ID:
1807 break;
1808 case XML_ATTRIBUTE_IDREF:
1809 break;
1810 case XML_ATTRIBUTE_IDREFS:
1811 break;
1812 case XML_ATTRIBUTE_ENTITY:
1813 break;
1814 case XML_ATTRIBUTE_ENTITIES:
1815 break;
1816 case XML_ATTRIBUTE_NMTOKEN:
1817 break;
1818 case XML_ATTRIBUTE_NMTOKENS:
1819 break;
1820 case XML_ATTRIBUTE_ENUMERATION:
1821 break;
1822 case XML_ATTRIBUTE_NOTATION:
1823 break;
1824 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001825 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1826 "Internal: ATTRIBUTE struct corrupted invalid type\n",
1827 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00001828 xmlFreeEnumeration(tree);
1829 return(NULL);
1830 }
1831 if ((defaultValue != NULL) &&
1832 (!xmlValidateAttributeValue(type, defaultValue))) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001833 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_DEFAULT,
1834 "Attribute %s of %s: invalid default value\n",
1835 elem, name, defaultValue);
Owen Taylor3473f882001-02-23 17:55:21 +00001836 defaultValue = NULL;
Daniel Veillardd01fd3e2002-02-18 22:27:47 +00001837 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001838 }
Daniel Veillard4432df22003-09-28 18:58:27 +00001839#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001840
1841 /*
Daniel Veillardd85f4f42002-03-25 10:48:46 +00001842 * Check first that an attribute defined in the external subset wasn't
1843 * already defined in the internal subset
1844 */
1845 if ((dtd->doc != NULL) && (dtd->doc->extSubset == dtd) &&
1846 (dtd->doc->intSubset != NULL) &&
1847 (dtd->doc->intSubset->attributes != NULL)) {
1848 ret = xmlHashLookup3(dtd->doc->intSubset->attributes, name, ns, elem);
1849 if (ret != NULL)
1850 return(NULL);
1851 }
1852
1853 /*
Owen Taylor3473f882001-02-23 17:55:21 +00001854 * Create the Attribute table if needed.
1855 */
1856 table = (xmlAttributeTablePtr) dtd->attributes;
1857 if (table == NULL) {
1858 table = xmlCreateAttributeTable();
1859 dtd->attributes = (void *) table;
1860 }
1861 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001862 xmlVErrMemory(ctxt,
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00001863 "xmlAddAttributeDecl: Table creation failed!\n");
Owen Taylor3473f882001-02-23 17:55:21 +00001864 return(NULL);
1865 }
1866
1867
1868 ret = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
1869 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001870 xmlVErrMemory(ctxt, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001871 return(NULL);
1872 }
1873 memset(ret, 0, sizeof(xmlAttribute));
1874 ret->type = XML_ATTRIBUTE_DECL;
1875
1876 /*
1877 * fill the structure.
1878 */
1879 ret->atype = type;
1880 ret->name = xmlStrdup(name);
1881 ret->prefix = xmlStrdup(ns);
1882 ret->elem = xmlStrdup(elem);
1883 ret->def = def;
1884 ret->tree = tree;
1885 if (defaultValue != NULL)
1886 ret->defaultValue = xmlStrdup(defaultValue);
1887
1888 /*
1889 * Validity Check:
1890 * Search the DTD for previous declarations of the ATTLIST
1891 */
1892 if (xmlHashAddEntry3(table, name, ns, elem, ret) < 0) {
Daniel Veillard4432df22003-09-28 18:58:27 +00001893#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001894 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001895 * The attribute is already defined in this DTD.
Owen Taylor3473f882001-02-23 17:55:21 +00001896 */
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001897 xmlErrValidWarning(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_REDEFINED,
Daniel Veillard58e44c92002-08-02 22:19:49 +00001898 "Attribute %s of element %s: already defined\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001899 name, elem, NULL);
Daniel Veillard4432df22003-09-28 18:58:27 +00001900#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001901 xmlFreeAttribute(ret);
1902 return(NULL);
1903 }
1904
1905 /*
1906 * Validity Check:
1907 * Multiple ID per element
1908 */
Daniel Veillarda10efa82001-04-18 13:09:01 +00001909 elemDef = xmlGetDtdElementDesc2(dtd, elem, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00001910 if (elemDef != NULL) {
Daniel Veillard48da9102001-08-07 01:10:10 +00001911
Daniel Veillard4432df22003-09-28 18:58:27 +00001912#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001913 if ((type == XML_ATTRIBUTE_ID) &&
Daniel Veillardc7612992002-02-17 22:47:37 +00001914 (xmlScanIDAttributeDecl(NULL, elemDef) != 0)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001915 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_MULTIPLE_ID,
Owen Taylor3473f882001-02-23 17:55:21 +00001916 "Element %s has too may ID attributes defined : %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00001917 elem, name, NULL);
Daniel Veillardc7612992002-02-17 22:47:37 +00001918 ctxt->valid = 0;
1919 }
Daniel Veillard4432df22003-09-28 18:58:27 +00001920#endif /* LIBXML_VALID_ENABLED */
Daniel Veillardc7612992002-02-17 22:47:37 +00001921
Daniel Veillard48da9102001-08-07 01:10:10 +00001922 /*
1923 * Insert namespace default def first they need to be
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001924 * processed first.
Daniel Veillard48da9102001-08-07 01:10:10 +00001925 */
1926 if ((xmlStrEqual(ret->name, BAD_CAST "xmlns")) ||
1927 ((ret->prefix != NULL &&
1928 (xmlStrEqual(ret->prefix, BAD_CAST "xmlns"))))) {
1929 ret->nexth = elemDef->attributes;
1930 elemDef->attributes = ret;
1931 } else {
1932 xmlAttributePtr tmp = elemDef->attributes;
1933
1934 while ((tmp != NULL) &&
1935 ((xmlStrEqual(tmp->name, BAD_CAST "xmlns")) ||
1936 ((ret->prefix != NULL &&
1937 (xmlStrEqual(ret->prefix, BAD_CAST "xmlns")))))) {
1938 if (tmp->nexth == NULL)
1939 break;
1940 tmp = tmp->nexth;
1941 }
1942 if (tmp != NULL) {
1943 ret->nexth = tmp->nexth;
1944 tmp->nexth = ret;
1945 } else {
1946 ret->nexth = elemDef->attributes;
1947 elemDef->attributes = ret;
1948 }
1949 }
Owen Taylor3473f882001-02-23 17:55:21 +00001950 }
1951
1952 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001953 * Link it to the DTD
Owen Taylor3473f882001-02-23 17:55:21 +00001954 */
1955 ret->parent = dtd;
1956 ret->doc = dtd->doc;
1957 if (dtd->last == NULL) {
1958 dtd->children = dtd->last = (xmlNodePtr) ret;
1959 } else {
1960 dtd->last->next = (xmlNodePtr) ret;
1961 ret->prev = dtd->last;
1962 dtd->last = (xmlNodePtr) ret;
1963 }
1964 return(ret);
1965}
1966
1967/**
1968 * xmlFreeAttributeTable:
1969 * @table: An attribute table
1970 *
1971 * Deallocate the memory used by an entities hash table.
1972 */
1973void
1974xmlFreeAttributeTable(xmlAttributeTablePtr table) {
1975 xmlHashFree(table, (xmlHashDeallocator) xmlFreeAttribute);
1976}
1977
Daniel Veillard652327a2003-09-29 18:02:38 +00001978#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001979/**
1980 * xmlCopyAttribute:
1981 * @attr: An attribute
1982 *
1983 * Build a copy of an attribute.
1984 *
1985 * Returns the new xmlAttributePtr or NULL in case of error.
1986 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001987static xmlAttributePtr
Owen Taylor3473f882001-02-23 17:55:21 +00001988xmlCopyAttribute(xmlAttributePtr attr) {
1989 xmlAttributePtr cur;
1990
1991 cur = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
1992 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00001993 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00001994 return(NULL);
1995 }
1996 memset(cur, 0, sizeof(xmlAttribute));
Daniel Veillard36065812002-01-24 15:02:46 +00001997 cur->type = XML_ATTRIBUTE_DECL;
Owen Taylor3473f882001-02-23 17:55:21 +00001998 cur->atype = attr->atype;
1999 cur->def = attr->def;
2000 cur->tree = xmlCopyEnumeration(attr->tree);
2001 if (attr->elem != NULL)
2002 cur->elem = xmlStrdup(attr->elem);
2003 if (attr->name != NULL)
2004 cur->name = xmlStrdup(attr->name);
Daniel Veillard36065812002-01-24 15:02:46 +00002005 if (attr->prefix != NULL)
2006 cur->prefix = xmlStrdup(attr->prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00002007 if (attr->defaultValue != NULL)
2008 cur->defaultValue = xmlStrdup(attr->defaultValue);
2009 return(cur);
2010}
2011
2012/**
2013 * xmlCopyAttributeTable:
2014 * @table: An attribute table
2015 *
2016 * Build a copy of an attribute table.
2017 *
2018 * Returns the new xmlAttributeTablePtr or NULL in case of error.
2019 */
2020xmlAttributeTablePtr
2021xmlCopyAttributeTable(xmlAttributeTablePtr table) {
2022 return((xmlAttributeTablePtr) xmlHashCopy(table,
2023 (xmlHashCopier) xmlCopyAttribute));
2024}
Daniel Veillard652327a2003-09-29 18:02:38 +00002025#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002026
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002027#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002028/**
2029 * xmlDumpAttributeDecl:
2030 * @buf: the XML buffer output
2031 * @attr: An attribute declaration
2032 *
2033 * This will dump the content of the attribute declaration as an XML
2034 * DTD definition
2035 */
2036void
2037xmlDumpAttributeDecl(xmlBufferPtr buf, xmlAttributePtr attr) {
2038 xmlBufferWriteChar(buf, "<!ATTLIST ");
2039 xmlBufferWriteCHAR(buf, attr->elem);
2040 xmlBufferWriteChar(buf, " ");
2041 if (attr->prefix != NULL) {
2042 xmlBufferWriteCHAR(buf, attr->prefix);
2043 xmlBufferWriteChar(buf, ":");
2044 }
2045 xmlBufferWriteCHAR(buf, attr->name);
2046 switch (attr->atype) {
2047 case XML_ATTRIBUTE_CDATA:
2048 xmlBufferWriteChar(buf, " CDATA");
2049 break;
2050 case XML_ATTRIBUTE_ID:
2051 xmlBufferWriteChar(buf, " ID");
2052 break;
2053 case XML_ATTRIBUTE_IDREF:
2054 xmlBufferWriteChar(buf, " IDREF");
2055 break;
2056 case XML_ATTRIBUTE_IDREFS:
2057 xmlBufferWriteChar(buf, " IDREFS");
2058 break;
2059 case XML_ATTRIBUTE_ENTITY:
2060 xmlBufferWriteChar(buf, " ENTITY");
2061 break;
2062 case XML_ATTRIBUTE_ENTITIES:
2063 xmlBufferWriteChar(buf, " ENTITIES");
2064 break;
2065 case XML_ATTRIBUTE_NMTOKEN:
2066 xmlBufferWriteChar(buf, " NMTOKEN");
2067 break;
2068 case XML_ATTRIBUTE_NMTOKENS:
2069 xmlBufferWriteChar(buf, " NMTOKENS");
2070 break;
2071 case XML_ATTRIBUTE_ENUMERATION:
2072 xmlBufferWriteChar(buf, " (");
2073 xmlDumpEnumeration(buf, attr->tree);
2074 break;
2075 case XML_ATTRIBUTE_NOTATION:
2076 xmlBufferWriteChar(buf, " NOTATION (");
2077 xmlDumpEnumeration(buf, attr->tree);
2078 break;
2079 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002080 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2081 "Internal: ATTRIBUTE struct corrupted invalid type\n",
2082 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002083 }
2084 switch (attr->def) {
2085 case XML_ATTRIBUTE_NONE:
2086 break;
2087 case XML_ATTRIBUTE_REQUIRED:
2088 xmlBufferWriteChar(buf, " #REQUIRED");
2089 break;
2090 case XML_ATTRIBUTE_IMPLIED:
2091 xmlBufferWriteChar(buf, " #IMPLIED");
2092 break;
2093 case XML_ATTRIBUTE_FIXED:
2094 xmlBufferWriteChar(buf, " #FIXED");
2095 break;
2096 default:
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002097 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2098 "Internal: ATTRIBUTE struct corrupted invalid def\n",
2099 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002100 }
2101 if (attr->defaultValue != NULL) {
2102 xmlBufferWriteChar(buf, " ");
2103 xmlBufferWriteQuotedString(buf, attr->defaultValue);
2104 }
2105 xmlBufferWriteChar(buf, ">\n");
2106}
2107
2108/**
William M. Brack9e660592003-10-20 14:56:06 +00002109 * xmlDumpAttributeDeclScan:
2110 * @attr: An attribute declaration
2111 * @buf: the XML buffer output
2112 *
2113 * This is used with the hash scan function - just reverses arguments
2114 */
2115static void
2116xmlDumpAttributeDeclScan(xmlAttributePtr attr, xmlBufferPtr buf) {
2117 xmlDumpAttributeDecl(buf, attr);
2118}
2119
2120/**
Owen Taylor3473f882001-02-23 17:55:21 +00002121 * xmlDumpAttributeTable:
2122 * @buf: the XML buffer output
2123 * @table: An attribute table
2124 *
2125 * This will dump the content of the attribute table as an XML DTD definition
2126 */
2127void
2128xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) {
William M. Brack9e660592003-10-20 14:56:06 +00002129 xmlHashScan(table, (xmlHashScanner) xmlDumpAttributeDeclScan, buf);
Owen Taylor3473f882001-02-23 17:55:21 +00002130}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002131#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002132
2133/************************************************************************
2134 * *
2135 * NOTATIONs *
2136 * *
2137 ************************************************************************/
2138/**
2139 * xmlCreateNotationTable:
2140 *
2141 * create and initialize an empty notation hash table.
2142 *
2143 * Returns the xmlNotationTablePtr just created or NULL in case
2144 * of error.
2145 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002146static xmlNotationTablePtr
Owen Taylor3473f882001-02-23 17:55:21 +00002147xmlCreateNotationTable(void) {
2148 return(xmlHashCreate(0));
2149}
2150
2151/**
2152 * xmlFreeNotation:
2153 * @not: A notation
2154 *
2155 * Deallocate the memory used by an notation definition
2156 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002157static void
Owen Taylor3473f882001-02-23 17:55:21 +00002158xmlFreeNotation(xmlNotationPtr nota) {
2159 if (nota == NULL) return;
2160 if (nota->name != NULL)
2161 xmlFree((xmlChar *) nota->name);
2162 if (nota->PublicID != NULL)
2163 xmlFree((xmlChar *) nota->PublicID);
2164 if (nota->SystemID != NULL)
2165 xmlFree((xmlChar *) nota->SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +00002166 xmlFree(nota);
2167}
2168
2169
2170/**
2171 * xmlAddNotationDecl:
2172 * @dtd: pointer to the DTD
2173 * @ctxt: the validation context
2174 * @name: the entity name
2175 * @PublicID: the public identifier or NULL
2176 * @SystemID: the system identifier or NULL
2177 *
2178 * Register a new notation declaration
2179 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002180 * Returns NULL if not, otherwise the entity
Owen Taylor3473f882001-02-23 17:55:21 +00002181 */
2182xmlNotationPtr
William M. Brackedb65a72004-02-06 07:36:04 +00002183xmlAddNotationDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd,
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002184 const xmlChar *name,
Owen Taylor3473f882001-02-23 17:55:21 +00002185 const xmlChar *PublicID, const xmlChar *SystemID) {
2186 xmlNotationPtr ret;
2187 xmlNotationTablePtr table;
2188
2189 if (dtd == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002190 return(NULL);
2191 }
2192 if (name == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002193 return(NULL);
2194 }
2195 if ((PublicID == NULL) && (SystemID == NULL)) {
Daniel Veillard7aea52d2002-02-17 23:07:47 +00002196 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002197 }
2198
2199 /*
2200 * Create the Notation table if needed.
2201 */
2202 table = (xmlNotationTablePtr) dtd->notations;
2203 if (table == NULL)
2204 dtd->notations = table = xmlCreateNotationTable();
2205 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002206 xmlVErrMemory(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00002207 "xmlAddNotationDecl: Table creation failed!\n");
2208 return(NULL);
2209 }
2210
2211 ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
2212 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002213 xmlVErrMemory(ctxt, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002214 return(NULL);
2215 }
2216 memset(ret, 0, sizeof(xmlNotation));
2217
2218 /*
2219 * fill the structure.
2220 */
2221 ret->name = xmlStrdup(name);
2222 if (SystemID != NULL)
2223 ret->SystemID = xmlStrdup(SystemID);
2224 if (PublicID != NULL)
2225 ret->PublicID = xmlStrdup(PublicID);
2226
2227 /*
2228 * Validity Check:
2229 * Check the DTD for previous declarations of the ATTLIST
2230 */
2231 if (xmlHashAddEntry(table, name, ret)) {
Daniel Veillard4432df22003-09-28 18:58:27 +00002232#ifdef LIBXML_VALID_ENABLED
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002233 xmlErrValid(NULL, XML_DTD_NOTATION_REDEFINED,
2234 "xmlAddNotationDecl: %s already defined\n",
2235 (const char *) name);
Daniel Veillard4432df22003-09-28 18:58:27 +00002236#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002237 xmlFreeNotation(ret);
2238 return(NULL);
2239 }
2240 return(ret);
2241}
2242
2243/**
2244 * xmlFreeNotationTable:
2245 * @table: An notation table
2246 *
2247 * Deallocate the memory used by an entities hash table.
2248 */
2249void
2250xmlFreeNotationTable(xmlNotationTablePtr table) {
2251 xmlHashFree(table, (xmlHashDeallocator) xmlFreeNotation);
2252}
2253
Daniel Veillard652327a2003-09-29 18:02:38 +00002254#ifdef LIBXML_TREE_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002255/**
2256 * xmlCopyNotation:
2257 * @nota: A notation
2258 *
2259 * Build a copy of a notation.
2260 *
2261 * Returns the new xmlNotationPtr or NULL in case of error.
2262 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002263static xmlNotationPtr
Owen Taylor3473f882001-02-23 17:55:21 +00002264xmlCopyNotation(xmlNotationPtr nota) {
2265 xmlNotationPtr cur;
2266
2267 cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
2268 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002269 xmlVErrMemory(NULL, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002270 return(NULL);
2271 }
2272 if (nota->name != NULL)
2273 cur->name = xmlStrdup(nota->name);
2274 else
2275 cur->name = NULL;
2276 if (nota->PublicID != NULL)
2277 cur->PublicID = xmlStrdup(nota->PublicID);
2278 else
2279 cur->PublicID = NULL;
2280 if (nota->SystemID != NULL)
2281 cur->SystemID = xmlStrdup(nota->SystemID);
2282 else
2283 cur->SystemID = NULL;
2284 return(cur);
2285}
2286
2287/**
2288 * xmlCopyNotationTable:
2289 * @table: A notation table
2290 *
2291 * Build a copy of a notation table.
2292 *
2293 * Returns the new xmlNotationTablePtr or NULL in case of error.
2294 */
2295xmlNotationTablePtr
2296xmlCopyNotationTable(xmlNotationTablePtr table) {
2297 return((xmlNotationTablePtr) xmlHashCopy(table,
2298 (xmlHashCopier) xmlCopyNotation));
2299}
Daniel Veillard652327a2003-09-29 18:02:38 +00002300#endif /* LIBXML_TREE_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002301
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002302#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002303/**
2304 * xmlDumpNotationDecl:
2305 * @buf: the XML buffer output
2306 * @nota: A notation declaration
2307 *
2308 * This will dump the content the notation declaration as an XML DTD definition
2309 */
2310void
2311xmlDumpNotationDecl(xmlBufferPtr buf, xmlNotationPtr nota) {
2312 xmlBufferWriteChar(buf, "<!NOTATION ");
2313 xmlBufferWriteCHAR(buf, nota->name);
2314 if (nota->PublicID != NULL) {
2315 xmlBufferWriteChar(buf, " PUBLIC ");
2316 xmlBufferWriteQuotedString(buf, nota->PublicID);
2317 if (nota->SystemID != NULL) {
2318 xmlBufferWriteChar(buf, " ");
2319 xmlBufferWriteCHAR(buf, nota->SystemID);
2320 }
2321 } else {
2322 xmlBufferWriteChar(buf, " SYSTEM ");
2323 xmlBufferWriteCHAR(buf, nota->SystemID);
2324 }
2325 xmlBufferWriteChar(buf, " >\n");
2326}
2327
2328/**
William M. Brack9e660592003-10-20 14:56:06 +00002329 * xmlDumpNotationDeclScan:
2330 * @nota: A notation declaration
2331 * @buf: the XML buffer output
2332 *
2333 * This is called with the hash scan function, and just reverses args
2334 */
2335static void
2336xmlDumpNotationDeclScan(xmlNotationPtr nota, xmlBufferPtr buf) {
2337 xmlDumpNotationDecl(buf, nota);
2338}
2339
2340/**
Owen Taylor3473f882001-02-23 17:55:21 +00002341 * xmlDumpNotationTable:
2342 * @buf: the XML buffer output
2343 * @table: A notation table
2344 *
2345 * This will dump the content of the notation table as an XML DTD definition
2346 */
2347void
2348xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
William M. Brack9e660592003-10-20 14:56:06 +00002349 xmlHashScan(table, (xmlHashScanner) xmlDumpNotationDeclScan, buf);
Owen Taylor3473f882001-02-23 17:55:21 +00002350}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002351#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002352
2353/************************************************************************
2354 * *
2355 * IDs *
2356 * *
2357 ************************************************************************/
2358/**
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002359 * DICT_FREE:
2360 * @str: a string
2361 *
2362 * Free a string if it is not owned by the "dict" dictionnary in the
2363 * current scope
2364 */
2365#define DICT_FREE(str) \
2366 if ((str) && ((!dict) || \
2367 (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \
2368 xmlFree((char *)(str));
2369
2370/**
Owen Taylor3473f882001-02-23 17:55:21 +00002371 * xmlCreateIDTable:
2372 *
2373 * create and initialize an empty id hash table.
2374 *
2375 * Returns the xmlIDTablePtr just created or NULL in case
2376 * of error.
2377 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002378static xmlIDTablePtr
Owen Taylor3473f882001-02-23 17:55:21 +00002379xmlCreateIDTable(void) {
2380 return(xmlHashCreate(0));
2381}
2382
2383/**
2384 * xmlFreeID:
2385 * @not: A id
2386 *
2387 * Deallocate the memory used by an id definition
2388 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002389static void
Owen Taylor3473f882001-02-23 17:55:21 +00002390xmlFreeID(xmlIDPtr id) {
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002391 xmlDictPtr dict = NULL;
2392
Owen Taylor3473f882001-02-23 17:55:21 +00002393 if (id == NULL) return;
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002394
2395 if (id->doc != NULL)
2396 dict = id->doc->dict;
2397
Owen Taylor3473f882001-02-23 17:55:21 +00002398 if (id->value != NULL)
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002399 DICT_FREE(id->value)
Daniel Veillardea7751d2002-12-20 00:16:24 +00002400 if (id->name != NULL)
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002401 DICT_FREE(id->name)
Owen Taylor3473f882001-02-23 17:55:21 +00002402 xmlFree(id);
2403}
2404
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002405
Owen Taylor3473f882001-02-23 17:55:21 +00002406/**
2407 * xmlAddID:
2408 * @ctxt: the validation context
2409 * @doc: pointer to the document
2410 * @value: the value name
2411 * @attr: the attribute holding the ID
2412 *
2413 * Register a new id declaration
2414 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002415 * Returns NULL if not, otherwise the new xmlIDPtr
Owen Taylor3473f882001-02-23 17:55:21 +00002416 */
2417xmlIDPtr
2418xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
2419 xmlAttrPtr attr) {
2420 xmlIDPtr ret;
2421 xmlIDTablePtr table;
2422
2423 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002424 return(NULL);
2425 }
2426 if (value == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002427 return(NULL);
2428 }
2429 if (attr == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002430 return(NULL);
2431 }
2432
2433 /*
2434 * Create the ID table if needed.
2435 */
2436 table = (xmlIDTablePtr) doc->ids;
2437 if (table == NULL)
2438 doc->ids = table = xmlCreateIDTable();
2439 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002440 xmlVErrMemory(ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00002441 "xmlAddID: Table creation failed!\n");
2442 return(NULL);
2443 }
2444
2445 ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
2446 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002447 xmlVErrMemory(ctxt, "malloc failed");
Owen Taylor3473f882001-02-23 17:55:21 +00002448 return(NULL);
2449 }
2450
2451 /*
2452 * fill the structure.
2453 */
2454 ret->value = xmlStrdup(value);
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002455 ret->doc = doc;
Daniel Veillardea7751d2002-12-20 00:16:24 +00002456 if ((ctxt != NULL) && (ctxt->vstateNr != 0)) {
2457 /*
2458 * Operating in streaming mode, attr is gonna disapear
2459 */
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002460 if (doc->dict != NULL)
2461 ret->name = xmlDictLookup(doc->dict, attr->name, -1);
2462 else
2463 ret->name = xmlStrdup(attr->name);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002464 ret->attr = NULL;
2465 } else {
2466 ret->attr = attr;
2467 ret->name = NULL;
2468 }
2469 ret->lineno = xmlGetLineNo(attr->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002470
2471 if (xmlHashAddEntry(table, value, ret) < 0) {
Daniel Veillard4432df22003-09-28 18:58:27 +00002472#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002473 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002474 * The id is already defined in this DTD.
Owen Taylor3473f882001-02-23 17:55:21 +00002475 */
Daniel Veillard76575762002-09-05 14:21:15 +00002476 if (ctxt != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00002477 xmlErrValidNode(ctxt, attr->parent, XML_DTD_ID_REDEFINED,
2478 "ID %s already defined\n",
2479 value, NULL, NULL);
Daniel Veillard76575762002-09-05 14:21:15 +00002480 }
Daniel Veillard4432df22003-09-28 18:58:27 +00002481#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002482 xmlFreeID(ret);
2483 return(NULL);
2484 }
Daniel Veillard249d7bb2003-03-19 21:02:29 +00002485 if (attr != NULL)
2486 attr->atype = XML_ATTRIBUTE_ID;
Owen Taylor3473f882001-02-23 17:55:21 +00002487 return(ret);
2488}
2489
2490/**
2491 * xmlFreeIDTable:
2492 * @table: An id table
2493 *
2494 * Deallocate the memory used by an ID hash table.
2495 */
2496void
2497xmlFreeIDTable(xmlIDTablePtr table) {
2498 xmlHashFree(table, (xmlHashDeallocator) xmlFreeID);
2499}
2500
2501/**
2502 * xmlIsID:
2503 * @doc: the document
2504 * @elem: the element carrying the attribute
2505 * @attr: the attribute
2506 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002507 * Determine whether an attribute is of type ID. In case we have DTD(s)
Daniel Veillard9dc1cf12002-10-08 08:26:11 +00002508 * then this is done if DTD loading has been requested. In the case
2509 * of HTML documents parsed with the HTML parser, then ID detection is
2510 * done systematically.
Owen Taylor3473f882001-02-23 17:55:21 +00002511 *
2512 * Returns 0 or 1 depending on the lookup result
2513 */
2514int
2515xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
2516 if (doc == NULL) return(0);
2517 if (attr == NULL) return(0);
2518 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
2519 return(0);
2520 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
Daniel Veillard9ba8e382003-10-28 21:31:45 +00002521 if (((xmlStrEqual(BAD_CAST "id", attr->name)) ||
2522 (xmlStrEqual(BAD_CAST "name", attr->name))) &&
2523 ((elem != NULL) && (!xmlStrEqual(elem->name, BAD_CAST "input"))))
Owen Taylor3473f882001-02-23 17:55:21 +00002524 return(1);
2525 return(0);
2526 } else {
2527 xmlAttributePtr attrDecl;
2528
2529 if (elem == NULL) return(0);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002530 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00002531 xmlChar fn[50];
Daniel Veillard37f961d2002-07-06 17:53:56 +00002532 xmlChar *fullname;
Daniel Veillardc00cda82003-04-07 10:22:39 +00002533
2534 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002535 if (fullname == NULL)
2536 return(0);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002537 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname,
2538 attr->name);
2539 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2540 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname,
2541 attr->name);
Daniel Veillardc00cda82003-04-07 10:22:39 +00002542 if ((fullname != fn) && (fullname != elem->name))
2543 xmlFree(fullname);
Daniel Veillard37f961d2002-07-06 17:53:56 +00002544 } else {
2545 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name,
2546 attr->name);
2547 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2548 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
2549 attr->name);
2550 }
Owen Taylor3473f882001-02-23 17:55:21 +00002551
2552 if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_ID))
2553 return(1);
2554 }
2555 return(0);
2556}
2557
2558/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00002559 * xmlRemoveID:
Owen Taylor3473f882001-02-23 17:55:21 +00002560 * @doc: the document
2561 * @attr: the attribute
2562 *
2563 * Remove the given attribute from the ID table maintained internally.
2564 *
2565 * Returns -1 if the lookup failed and 0 otherwise
2566 */
2567int
2568xmlRemoveID(xmlDocPtr doc, xmlAttrPtr attr) {
Owen Taylor3473f882001-02-23 17:55:21 +00002569 xmlIDTablePtr table;
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002570 xmlIDPtr id;
Owen Taylor3473f882001-02-23 17:55:21 +00002571 xmlChar *ID;
2572
2573 if (doc == NULL) return(-1);
2574 if (attr == NULL) return(-1);
2575 table = (xmlIDTablePtr) doc->ids;
2576 if (table == NULL)
2577 return(-1);
2578
2579 if (attr == NULL)
2580 return(-1);
2581 ID = xmlNodeListGetString(doc, attr->children, 1);
2582 if (ID == NULL)
2583 return(-1);
Daniel Veillard8d7b5c72003-11-15 18:24:36 +00002584 id = xmlHashLookup(table, ID);
2585 if (id == NULL || id->attr != attr) {
Owen Taylor3473f882001-02-23 17:55:21 +00002586 xmlFree(ID);
2587 return(-1);
2588 }
2589 xmlHashUpdateEntry(table, ID, NULL, (xmlHashDeallocator) xmlFreeID);
2590 xmlFree(ID);
2591 return(0);
2592}
2593
2594/**
2595 * xmlGetID:
2596 * @doc: pointer to the document
2597 * @ID: the ID value
2598 *
2599 * Search the attribute declaring the given ID
2600 *
2601 * Returns NULL if not found, otherwise the xmlAttrPtr defining the ID
2602 */
2603xmlAttrPtr
2604xmlGetID(xmlDocPtr doc, const xmlChar *ID) {
2605 xmlIDTablePtr table;
2606 xmlIDPtr id;
2607
2608 if (doc == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002609 return(NULL);
2610 }
2611
2612 if (ID == NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002613 return(NULL);
2614 }
2615
2616 table = (xmlIDTablePtr) doc->ids;
2617 if (table == NULL)
2618 return(NULL);
2619
2620 id = xmlHashLookup(table, ID);
2621 if (id == NULL)
2622 return(NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002623 if (id->attr == NULL) {
2624 /*
2625 * We are operating on a stream, return a well known reference
2626 * since the attribute node doesn't exist anymore
2627 */
2628 return((xmlAttrPtr) doc);
2629 }
Owen Taylor3473f882001-02-23 17:55:21 +00002630 return(id->attr);
2631}
2632
2633/************************************************************************
2634 * *
2635 * Refs *
2636 * *
2637 ************************************************************************/
Daniel Veillard8730c562001-02-26 10:49:57 +00002638typedef struct xmlRemoveMemo_t
Owen Taylor3473f882001-02-23 17:55:21 +00002639{
2640 xmlListPtr l;
2641 xmlAttrPtr ap;
Daniel Veillard8730c562001-02-26 10:49:57 +00002642} xmlRemoveMemo;
2643
2644typedef xmlRemoveMemo *xmlRemoveMemoPtr;
2645
2646typedef struct xmlValidateMemo_t
2647{
2648 xmlValidCtxtPtr ctxt;
2649 const xmlChar *name;
2650} xmlValidateMemo;
2651
2652typedef xmlValidateMemo *xmlValidateMemoPtr;
Owen Taylor3473f882001-02-23 17:55:21 +00002653
2654/**
2655 * xmlCreateRefTable:
2656 *
2657 * create and initialize an empty ref hash table.
2658 *
2659 * Returns the xmlRefTablePtr just created or NULL in case
2660 * of error.
2661 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002662static xmlRefTablePtr
Owen Taylor3473f882001-02-23 17:55:21 +00002663xmlCreateRefTable(void) {
2664 return(xmlHashCreate(0));
2665}
2666
2667/**
2668 * xmlFreeRef:
2669 * @lk: A list link
2670 *
2671 * Deallocate the memory used by a ref definition
2672 */
2673static void
2674xmlFreeRef(xmlLinkPtr lk) {
Daniel Veillard37721922001-05-04 15:21:12 +00002675 xmlRefPtr ref = (xmlRefPtr)xmlLinkGetData(lk);
2676 if (ref == NULL) return;
2677 if (ref->value != NULL)
2678 xmlFree((xmlChar *)ref->value);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002679 if (ref->name != NULL)
2680 xmlFree((xmlChar *)ref->name);
Daniel Veillard37721922001-05-04 15:21:12 +00002681 xmlFree(ref);
Owen Taylor3473f882001-02-23 17:55:21 +00002682}
2683
2684/**
2685 * xmlFreeRefList:
2686 * @list_ref: A list of references.
2687 *
2688 * Deallocate the memory used by a list of references
2689 */
2690static void
2691xmlFreeRefList(xmlListPtr list_ref) {
Daniel Veillard37721922001-05-04 15:21:12 +00002692 if (list_ref == NULL) return;
2693 xmlListDelete(list_ref);
Owen Taylor3473f882001-02-23 17:55:21 +00002694}
2695
2696/**
2697 * xmlWalkRemoveRef:
2698 * @data: Contents of current link
2699 * @user: Value supplied by the user
2700 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002701 * Returns 0 to abort the walk or 1 to continue
Owen Taylor3473f882001-02-23 17:55:21 +00002702 */
2703static int
2704xmlWalkRemoveRef(const void *data, const void *user)
2705{
Daniel Veillard37721922001-05-04 15:21:12 +00002706 xmlAttrPtr attr0 = ((xmlRefPtr)data)->attr;
2707 xmlAttrPtr attr1 = ((xmlRemoveMemoPtr)user)->ap;
2708 xmlListPtr ref_list = ((xmlRemoveMemoPtr)user)->l;
Owen Taylor3473f882001-02-23 17:55:21 +00002709
Daniel Veillard37721922001-05-04 15:21:12 +00002710 if (attr0 == attr1) { /* Matched: remove and terminate walk */
2711 xmlListRemoveFirst(ref_list, (void *)data);
2712 return 0;
2713 }
2714 return 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002715}
2716
2717/**
2718 * xmlAddRef:
2719 * @ctxt: the validation context
2720 * @doc: pointer to the document
2721 * @value: the value name
2722 * @attr: the attribute holding the Ref
2723 *
2724 * Register a new ref declaration
2725 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002726 * Returns NULL if not, otherwise the new xmlRefPtr
Owen Taylor3473f882001-02-23 17:55:21 +00002727 */
2728xmlRefPtr
William M. Brackedb65a72004-02-06 07:36:04 +00002729xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
Owen Taylor3473f882001-02-23 17:55:21 +00002730 xmlAttrPtr attr) {
Daniel Veillard37721922001-05-04 15:21:12 +00002731 xmlRefPtr ret;
2732 xmlRefTablePtr table;
2733 xmlListPtr ref_list;
Owen Taylor3473f882001-02-23 17:55:21 +00002734
Daniel Veillard37721922001-05-04 15:21:12 +00002735 if (doc == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002736 return(NULL);
2737 }
2738 if (value == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002739 return(NULL);
2740 }
2741 if (attr == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002742 return(NULL);
2743 }
Owen Taylor3473f882001-02-23 17:55:21 +00002744
Daniel Veillard37721922001-05-04 15:21:12 +00002745 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002746 * Create the Ref table if needed.
2747 */
Daniel Veillard37721922001-05-04 15:21:12 +00002748 table = (xmlRefTablePtr) doc->refs;
2749 if (table == NULL)
2750 doc->refs = table = xmlCreateRefTable();
2751 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002752 xmlVErrMemory(ctxt,
Daniel Veillard37721922001-05-04 15:21:12 +00002753 "xmlAddRef: Table creation failed!\n");
2754 return(NULL);
2755 }
Owen Taylor3473f882001-02-23 17:55:21 +00002756
Daniel Veillard37721922001-05-04 15:21:12 +00002757 ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
2758 if (ret == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00002759 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard37721922001-05-04 15:21:12 +00002760 return(NULL);
2761 }
Owen Taylor3473f882001-02-23 17:55:21 +00002762
Daniel Veillard37721922001-05-04 15:21:12 +00002763 /*
Owen Taylor3473f882001-02-23 17:55:21 +00002764 * fill the structure.
2765 */
Daniel Veillard37721922001-05-04 15:21:12 +00002766 ret->value = xmlStrdup(value);
Daniel Veillardea7751d2002-12-20 00:16:24 +00002767 if ((ctxt != NULL) && (ctxt->vstateNr != 0)) {
2768 /*
2769 * Operating in streaming mode, attr is gonna disapear
2770 */
2771 ret->name = xmlStrdup(attr->name);
2772 ret->attr = NULL;
2773 } else {
2774 ret->name = NULL;
2775 ret->attr = attr;
2776 }
2777 ret->lineno = xmlGetLineNo(attr->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00002778
Daniel Veillard37721922001-05-04 15:21:12 +00002779 /* To add a reference :-
2780 * References are maintained as a list of references,
2781 * Lookup the entry, if no entry create new nodelist
2782 * Add the owning node to the NodeList
2783 * Return the ref
2784 */
Owen Taylor3473f882001-02-23 17:55:21 +00002785
Daniel Veillard37721922001-05-04 15:21:12 +00002786 if (NULL == (ref_list = xmlHashLookup(table, value))) {
2787 if (NULL == (ref_list = xmlListCreate(xmlFreeRef, NULL))) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002788 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2789 "xmlAddRef: Reference list creation failed!\n",
2790 NULL);
Daniel Veillard37721922001-05-04 15:21:12 +00002791 return(NULL);
2792 }
2793 if (xmlHashAddEntry(table, value, ref_list) < 0) {
2794 xmlListDelete(ref_list);
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00002795 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2796 "xmlAddRef: Reference list insertion failed!\n",
2797 NULL);
Daniel Veillard37721922001-05-04 15:21:12 +00002798 return(NULL);
2799 }
2800 }
2801 xmlListInsert(ref_list, ret);
2802 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002803}
2804
2805/**
2806 * xmlFreeRefTable:
2807 * @table: An ref table
2808 *
2809 * Deallocate the memory used by an Ref hash table.
2810 */
2811void
2812xmlFreeRefTable(xmlRefTablePtr table) {
Daniel Veillard37721922001-05-04 15:21:12 +00002813 xmlHashFree(table, (xmlHashDeallocator) xmlFreeRefList);
Owen Taylor3473f882001-02-23 17:55:21 +00002814}
2815
2816/**
2817 * xmlIsRef:
2818 * @doc: the document
2819 * @elem: the element carrying the attribute
2820 * @attr: the attribute
2821 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002822 * Determine whether an attribute is of type Ref. In case we have DTD(s)
Owen Taylor3473f882001-02-23 17:55:21 +00002823 * then this is simple, otherwise we use an heuristic: name Ref (upper
2824 * or lowercase).
2825 *
2826 * Returns 0 or 1 depending on the lookup result
2827 */
2828int
2829xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
Daniel Veillard37721922001-05-04 15:21:12 +00002830 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
2831 return(0);
2832 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
2833 /* TODO @@@ */
2834 return(0);
2835 } else {
2836 xmlAttributePtr attrDecl;
Owen Taylor3473f882001-02-23 17:55:21 +00002837
Daniel Veillard37721922001-05-04 15:21:12 +00002838 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
2839 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2840 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
2841 elem->name, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00002842
Daniel Veillard37721922001-05-04 15:21:12 +00002843 if ((attrDecl != NULL) &&
2844 (attrDecl->atype == XML_ATTRIBUTE_IDREF ||
2845 attrDecl->atype == XML_ATTRIBUTE_IDREFS))
2846 return(1);
2847 }
2848 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002849}
2850
2851/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00002852 * xmlRemoveRef:
Owen Taylor3473f882001-02-23 17:55:21 +00002853 * @doc: the document
2854 * @attr: the attribute
2855 *
2856 * Remove the given attribute from the Ref table maintained internally.
2857 *
2858 * Returns -1 if the lookup failed and 0 otherwise
2859 */
2860int
2861xmlRemoveRef(xmlDocPtr doc, xmlAttrPtr attr) {
Daniel Veillard37721922001-05-04 15:21:12 +00002862 xmlListPtr ref_list;
2863 xmlRefTablePtr table;
2864 xmlChar *ID;
2865 xmlRemoveMemo target;
Owen Taylor3473f882001-02-23 17:55:21 +00002866
Daniel Veillard37721922001-05-04 15:21:12 +00002867 if (doc == NULL) return(-1);
2868 if (attr == NULL) return(-1);
2869 table = (xmlRefTablePtr) doc->refs;
2870 if (table == NULL)
2871 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002872
Daniel Veillard37721922001-05-04 15:21:12 +00002873 if (attr == NULL)
2874 return(-1);
2875 ID = xmlNodeListGetString(doc, attr->children, 1);
2876 if (ID == NULL)
2877 return(-1);
2878 ref_list = xmlHashLookup(table, ID);
Owen Taylor3473f882001-02-23 17:55:21 +00002879
Daniel Veillard37721922001-05-04 15:21:12 +00002880 if(ref_list == NULL) {
2881 xmlFree(ID);
2882 return (-1);
2883 }
2884 /* At this point, ref_list refers to a list of references which
2885 * have the same key as the supplied attr. Our list of references
2886 * is ordered by reference address and we don't have that information
2887 * here to use when removing. We'll have to walk the list and
2888 * check for a matching attribute, when we find one stop the walk
2889 * and remove the entry.
2890 * The list is ordered by reference, so that means we don't have the
2891 * key. Passing the list and the reference to the walker means we
2892 * will have enough data to be able to remove the entry.
2893 */
2894 target.l = ref_list;
2895 target.ap = attr;
2896
2897 /* Remove the supplied attr from our list */
2898 xmlListWalk(ref_list, xmlWalkRemoveRef, &target);
Owen Taylor3473f882001-02-23 17:55:21 +00002899
Daniel Veillard37721922001-05-04 15:21:12 +00002900 /*If the list is empty then remove the list entry in the hash */
2901 if (xmlListEmpty(ref_list))
2902 xmlHashUpdateEntry(table, ID, NULL, (xmlHashDeallocator)
2903 xmlFreeRefList);
2904 xmlFree(ID);
2905 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002906}
2907
2908/**
2909 * xmlGetRefs:
2910 * @doc: pointer to the document
2911 * @ID: the ID value
2912 *
2913 * Find the set of references for the supplied ID.
2914 *
2915 * Returns NULL if not found, otherwise node set for the ID.
2916 */
2917xmlListPtr
2918xmlGetRefs(xmlDocPtr doc, const xmlChar *ID) {
Daniel Veillard37721922001-05-04 15:21:12 +00002919 xmlRefTablePtr table;
Owen Taylor3473f882001-02-23 17:55:21 +00002920
Daniel Veillard37721922001-05-04 15:21:12 +00002921 if (doc == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002922 return(NULL);
2923 }
Owen Taylor3473f882001-02-23 17:55:21 +00002924
Daniel Veillard37721922001-05-04 15:21:12 +00002925 if (ID == NULL) {
Daniel Veillard37721922001-05-04 15:21:12 +00002926 return(NULL);
2927 }
Owen Taylor3473f882001-02-23 17:55:21 +00002928
Daniel Veillard37721922001-05-04 15:21:12 +00002929 table = (xmlRefTablePtr) doc->refs;
2930 if (table == NULL)
2931 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002932
Daniel Veillard37721922001-05-04 15:21:12 +00002933 return (xmlHashLookup(table, ID));
Owen Taylor3473f882001-02-23 17:55:21 +00002934}
2935
2936/************************************************************************
2937 * *
2938 * Routines for validity checking *
2939 * *
2940 ************************************************************************/
2941
2942/**
2943 * xmlGetDtdElementDesc:
2944 * @dtd: a pointer to the DtD to search
2945 * @name: the element name
2946 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002947 * Search the DTD for the description of this element
Owen Taylor3473f882001-02-23 17:55:21 +00002948 *
2949 * returns the xmlElementPtr if found or NULL
2950 */
2951
2952xmlElementPtr
2953xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) {
2954 xmlElementTablePtr table;
2955 xmlElementPtr cur;
2956 xmlChar *uqname = NULL, *prefix = NULL;
2957
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00002958 if ((dtd == NULL) || (name == NULL)) return(NULL);
Daniel Veillarda10efa82001-04-18 13:09:01 +00002959 if (dtd->elements == NULL)
2960 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002961 table = (xmlElementTablePtr) dtd->elements;
2962
2963 uqname = xmlSplitQName2(name, &prefix);
Daniel Veillarda10efa82001-04-18 13:09:01 +00002964 if (uqname != NULL)
2965 name = uqname;
2966 cur = xmlHashLookup2(table, name, prefix);
2967 if (prefix != NULL) xmlFree(prefix);
2968 if (uqname != NULL) xmlFree(uqname);
2969 return(cur);
2970}
2971/**
2972 * xmlGetDtdElementDesc2:
2973 * @dtd: a pointer to the DtD to search
2974 * @name: the element name
2975 * @create: create an empty description if not found
2976 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002977 * Search the DTD for the description of this element
Daniel Veillarda10efa82001-04-18 13:09:01 +00002978 *
2979 * returns the xmlElementPtr if found or NULL
2980 */
2981
Daniel Veillard86fd5a72001-12-13 14:55:21 +00002982static xmlElementPtr
Daniel Veillarda10efa82001-04-18 13:09:01 +00002983xmlGetDtdElementDesc2(xmlDtdPtr dtd, const xmlChar *name, int create) {
2984 xmlElementTablePtr table;
2985 xmlElementPtr cur;
2986 xmlChar *uqname = NULL, *prefix = NULL;
2987
2988 if (dtd == NULL) return(NULL);
2989 if (dtd->elements == NULL) {
2990 if (!create)
2991 return(NULL);
2992 /*
2993 * Create the Element table if needed.
2994 */
2995 table = (xmlElementTablePtr) dtd->elements;
2996 if (table == NULL) {
2997 table = xmlCreateElementTable();
2998 dtd->elements = (void *) table;
2999 }
3000 if (table == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00003001 xmlVErrMemory(NULL, "element table allocation failed");
Daniel Veillarda10efa82001-04-18 13:09:01 +00003002 return(NULL);
3003 }
3004 }
3005 table = (xmlElementTablePtr) dtd->elements;
3006
3007 uqname = xmlSplitQName2(name, &prefix);
3008 if (uqname != NULL)
3009 name = uqname;
3010 cur = xmlHashLookup2(table, name, prefix);
3011 if ((cur == NULL) && (create)) {
3012 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
3013 if (cur == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00003014 xmlVErrMemory(NULL, "malloc failed");
Daniel Veillarda10efa82001-04-18 13:09:01 +00003015 return(NULL);
3016 }
3017 memset(cur, 0, sizeof(xmlElement));
3018 cur->type = XML_ELEMENT_DECL;
3019
3020 /*
3021 * fill the structure.
3022 */
3023 cur->name = xmlStrdup(name);
3024 cur->prefix = xmlStrdup(prefix);
3025 cur->etype = XML_ELEMENT_TYPE_UNDEFINED;
3026
3027 xmlHashAddEntry2(table, name, prefix, cur);
3028 }
3029 if (prefix != NULL) xmlFree(prefix);
3030 if (uqname != NULL) xmlFree(uqname);
Owen Taylor3473f882001-02-23 17:55:21 +00003031 return(cur);
3032}
3033
3034/**
3035 * xmlGetDtdQElementDesc:
3036 * @dtd: a pointer to the DtD to search
3037 * @name: the element name
3038 * @prefix: the element namespace prefix
3039 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003040 * Search the DTD for the description of this element
Owen Taylor3473f882001-02-23 17:55:21 +00003041 *
3042 * returns the xmlElementPtr if found or NULL
3043 */
3044
Daniel Veillard48da9102001-08-07 01:10:10 +00003045xmlElementPtr
Owen Taylor3473f882001-02-23 17:55:21 +00003046xmlGetDtdQElementDesc(xmlDtdPtr dtd, const xmlChar *name,
3047 const xmlChar *prefix) {
3048 xmlElementTablePtr table;
3049
3050 if (dtd == NULL) return(NULL);
3051 if (dtd->elements == NULL) return(NULL);
3052 table = (xmlElementTablePtr) dtd->elements;
3053
3054 return(xmlHashLookup2(table, name, prefix));
3055}
3056
3057/**
3058 * xmlGetDtdAttrDesc:
3059 * @dtd: a pointer to the DtD to search
3060 * @elem: the element name
3061 * @name: the attribute name
3062 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003063 * Search the DTD for the description of this attribute on
Owen Taylor3473f882001-02-23 17:55:21 +00003064 * this element.
3065 *
3066 * returns the xmlAttributePtr if found or NULL
3067 */
3068
3069xmlAttributePtr
3070xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) {
3071 xmlAttributeTablePtr table;
3072 xmlAttributePtr cur;
3073 xmlChar *uqname = NULL, *prefix = NULL;
3074
3075 if (dtd == NULL) return(NULL);
3076 if (dtd->attributes == NULL) return(NULL);
3077
3078 table = (xmlAttributeTablePtr) dtd->attributes;
3079 if (table == NULL)
3080 return(NULL);
3081
3082 uqname = xmlSplitQName2(name, &prefix);
3083
3084 if (uqname != NULL) {
3085 cur = xmlHashLookup3(table, uqname, prefix, elem);
3086 if (prefix != NULL) xmlFree(prefix);
3087 if (uqname != NULL) xmlFree(uqname);
3088 } else
3089 cur = xmlHashLookup3(table, name, NULL, elem);
3090 return(cur);
3091}
3092
3093/**
3094 * xmlGetDtdQAttrDesc:
3095 * @dtd: a pointer to the DtD to search
3096 * @elem: the element name
3097 * @name: the attribute name
3098 * @prefix: the attribute namespace prefix
3099 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003100 * Search the DTD for the description of this qualified attribute on
Owen Taylor3473f882001-02-23 17:55:21 +00003101 * this element.
3102 *
3103 * returns the xmlAttributePtr if found or NULL
3104 */
3105
Daniel Veillard48da9102001-08-07 01:10:10 +00003106xmlAttributePtr
Owen Taylor3473f882001-02-23 17:55:21 +00003107xmlGetDtdQAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name,
3108 const xmlChar *prefix) {
3109 xmlAttributeTablePtr table;
3110
3111 if (dtd == NULL) return(NULL);
3112 if (dtd->attributes == NULL) return(NULL);
3113 table = (xmlAttributeTablePtr) dtd->attributes;
3114
3115 return(xmlHashLookup3(table, name, prefix, elem));
3116}
3117
3118/**
3119 * xmlGetDtdNotationDesc:
3120 * @dtd: a pointer to the DtD to search
3121 * @name: the notation name
3122 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003123 * Search the DTD for the description of this notation
Owen Taylor3473f882001-02-23 17:55:21 +00003124 *
3125 * returns the xmlNotationPtr if found or NULL
3126 */
3127
3128xmlNotationPtr
3129xmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) {
3130 xmlNotationTablePtr table;
3131
3132 if (dtd == NULL) return(NULL);
3133 if (dtd->notations == NULL) return(NULL);
3134 table = (xmlNotationTablePtr) dtd->notations;
3135
3136 return(xmlHashLookup(table, name));
3137}
3138
Daniel Veillard4432df22003-09-28 18:58:27 +00003139#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003140/**
3141 * xmlValidateNotationUse:
3142 * @ctxt: the validation context
3143 * @doc: the document
3144 * @notationName: the notation name to check
3145 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003146 * Validate that the given name match a notation declaration.
Owen Taylor3473f882001-02-23 17:55:21 +00003147 * - [ VC: Notation Declared ]
3148 *
3149 * returns 1 if valid or 0 otherwise
3150 */
3151
3152int
3153xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3154 const xmlChar *notationName) {
3155 xmlNotationPtr notaDecl;
3156 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
3157
3158 notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
3159 if ((notaDecl == NULL) && (doc->extSubset != NULL))
3160 notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
3161
Daniel Veillarde637c4a2003-03-30 21:10:09 +00003162 if ((notaDecl == NULL) && (ctxt != NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003163 xmlErrValidNode(ctxt, (xmlNodePtr) doc, XML_DTD_UNKNOWN_NOTATION,
3164 "NOTATION %s is not declared\n",
3165 notationName, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003166 return(0);
3167 }
3168 return(1);
3169}
Daniel Veillard4432df22003-09-28 18:58:27 +00003170#endif /* LIBXML_VALID_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003171
3172/**
Daniel Veillard01c13b52002-12-10 15:19:08 +00003173 * xmlIsMixedElement:
Owen Taylor3473f882001-02-23 17:55:21 +00003174 * @doc: the document
3175 * @name: the element name
3176 *
3177 * Search in the DtDs whether an element accept Mixed content (or ANY)
3178 * basically if it is supposed to accept text childs
3179 *
3180 * returns 0 if no, 1 if yes, and -1 if no element description is available
3181 */
3182
3183int
3184xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) {
3185 xmlElementPtr elemDecl;
3186
3187 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
3188
3189 elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
3190 if ((elemDecl == NULL) && (doc->extSubset != NULL))
3191 elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
3192 if (elemDecl == NULL) return(-1);
3193 switch (elemDecl->etype) {
Daniel Veillarda10efa82001-04-18 13:09:01 +00003194 case XML_ELEMENT_TYPE_UNDEFINED:
3195 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003196 case XML_ELEMENT_TYPE_ELEMENT:
3197 return(0);
3198 case XML_ELEMENT_TYPE_EMPTY:
3199 /*
3200 * return 1 for EMPTY since we want VC error to pop up
3201 * on <empty> </empty> for example
3202 */
3203 case XML_ELEMENT_TYPE_ANY:
3204 case XML_ELEMENT_TYPE_MIXED:
3205 return(1);
3206 }
3207 return(1);
3208}
3209
Daniel Veillard4432df22003-09-28 18:58:27 +00003210#ifdef LIBXML_VALID_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003211/**
3212 * xmlValidateNameValue:
3213 * @value: an Name value
3214 *
3215 * Validate that the given value match Name production
3216 *
3217 * returns 1 if valid or 0 otherwise
3218 */
3219
Daniel Veillard9b731d72002-04-14 12:56:08 +00003220int
Owen Taylor3473f882001-02-23 17:55:21 +00003221xmlValidateNameValue(const xmlChar *value) {
3222 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003223 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003224
3225 if (value == NULL) return(0);
3226 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003227 val = xmlStringCurrentChar(NULL, cur, &len);
3228 cur += len;
3229 if (!IS_LETTER(val) && (val != '_') &&
3230 (val != ':')) {
Owen Taylor3473f882001-02-23 17:55:21 +00003231 return(0);
3232 }
3233
Daniel Veillardd8224e02002-01-13 15:43:22 +00003234 val = xmlStringCurrentChar(NULL, cur, &len);
3235 cur += len;
3236 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3237 (val == '.') || (val == '-') ||
3238 (val == '_') || (val == ':') ||
3239 (IS_COMBINING(val)) ||
3240 (IS_EXTENDER(val))) {
3241 val = xmlStringCurrentChar(NULL, cur, &len);
3242 cur += len;
3243 }
Owen Taylor3473f882001-02-23 17:55:21 +00003244
Daniel Veillardd8224e02002-01-13 15:43:22 +00003245 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003246
3247 return(1);
3248}
3249
3250/**
3251 * xmlValidateNamesValue:
3252 * @value: an Names value
3253 *
3254 * Validate that the given value match Names production
3255 *
3256 * returns 1 if valid or 0 otherwise
3257 */
3258
Daniel Veillard9b731d72002-04-14 12:56:08 +00003259int
Owen Taylor3473f882001-02-23 17:55:21 +00003260xmlValidateNamesValue(const xmlChar *value) {
3261 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003262 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003263
3264 if (value == NULL) return(0);
3265 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003266 val = xmlStringCurrentChar(NULL, cur, &len);
3267 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003268
Daniel Veillardd8224e02002-01-13 15:43:22 +00003269 if (!IS_LETTER(val) && (val != '_') &&
3270 (val != ':')) {
Owen Taylor3473f882001-02-23 17:55:21 +00003271 return(0);
3272 }
3273
Daniel Veillardd8224e02002-01-13 15:43:22 +00003274 val = xmlStringCurrentChar(NULL, cur, &len);
3275 cur += len;
3276 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3277 (val == '.') || (val == '-') ||
3278 (val == '_') || (val == ':') ||
3279 (IS_COMBINING(val)) ||
3280 (IS_EXTENDER(val))) {
3281 val = xmlStringCurrentChar(NULL, cur, &len);
3282 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003283 }
3284
Daniel Veillardd8224e02002-01-13 15:43:22 +00003285 while (IS_BLANK(val)) {
3286 while (IS_BLANK(val)) {
3287 val = xmlStringCurrentChar(NULL, cur, &len);
3288 cur += len;
3289 }
3290
3291 if (!IS_LETTER(val) && (val != '_') &&
3292 (val != ':')) {
3293 return(0);
3294 }
3295 val = xmlStringCurrentChar(NULL, cur, &len);
3296 cur += len;
3297
3298 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3299 (val == '.') || (val == '-') ||
3300 (val == '_') || (val == ':') ||
3301 (IS_COMBINING(val)) ||
3302 (IS_EXTENDER(val))) {
3303 val = xmlStringCurrentChar(NULL, cur, &len);
3304 cur += len;
3305 }
3306 }
3307
3308 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003309
3310 return(1);
3311}
3312
3313/**
3314 * xmlValidateNmtokenValue:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003315 * @value: an Nmtoken value
Owen Taylor3473f882001-02-23 17:55:21 +00003316 *
3317 * Validate that the given value match Nmtoken production
3318 *
3319 * [ VC: Name Token ]
3320 *
3321 * returns 1 if valid or 0 otherwise
3322 */
3323
Daniel Veillard9b731d72002-04-14 12:56:08 +00003324int
Owen Taylor3473f882001-02-23 17:55:21 +00003325xmlValidateNmtokenValue(const xmlChar *value) {
3326 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003327 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003328
3329 if (value == NULL) return(0);
3330 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003331 val = xmlStringCurrentChar(NULL, cur, &len);
3332 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003333
Daniel Veillardd8224e02002-01-13 15:43:22 +00003334 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3335 (val != '.') && (val != '-') &&
3336 (val != '_') && (val != ':') &&
3337 (!IS_COMBINING(val)) &&
3338 (!IS_EXTENDER(val)))
Owen Taylor3473f882001-02-23 17:55:21 +00003339 return(0);
3340
Daniel Veillardd8224e02002-01-13 15:43:22 +00003341 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3342 (val == '.') || (val == '-') ||
3343 (val == '_') || (val == ':') ||
3344 (IS_COMBINING(val)) ||
3345 (IS_EXTENDER(val))) {
3346 val = xmlStringCurrentChar(NULL, cur, &len);
3347 cur += len;
3348 }
Owen Taylor3473f882001-02-23 17:55:21 +00003349
Daniel Veillardd8224e02002-01-13 15:43:22 +00003350 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003351
3352 return(1);
3353}
3354
3355/**
3356 * xmlValidateNmtokensValue:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003357 * @value: an Nmtokens value
Owen Taylor3473f882001-02-23 17:55:21 +00003358 *
3359 * Validate that the given value match Nmtokens production
3360 *
3361 * [ VC: Name Token ]
3362 *
3363 * returns 1 if valid or 0 otherwise
3364 */
3365
Daniel Veillard9b731d72002-04-14 12:56:08 +00003366int
Owen Taylor3473f882001-02-23 17:55:21 +00003367xmlValidateNmtokensValue(const xmlChar *value) {
3368 const xmlChar *cur;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003369 int val, len;
Owen Taylor3473f882001-02-23 17:55:21 +00003370
3371 if (value == NULL) return(0);
3372 cur = value;
Daniel Veillardd8224e02002-01-13 15:43:22 +00003373 val = xmlStringCurrentChar(NULL, cur, &len);
3374 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003375
Daniel Veillardd8224e02002-01-13 15:43:22 +00003376 while (IS_BLANK(val)) {
3377 val = xmlStringCurrentChar(NULL, cur, &len);
3378 cur += len;
Owen Taylor3473f882001-02-23 17:55:21 +00003379 }
3380
Daniel Veillardd8224e02002-01-13 15:43:22 +00003381 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3382 (val != '.') && (val != '-') &&
3383 (val != '_') && (val != ':') &&
3384 (!IS_COMBINING(val)) &&
3385 (!IS_EXTENDER(val)))
3386 return(0);
3387
3388 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3389 (val == '.') || (val == '-') ||
3390 (val == '_') || (val == ':') ||
3391 (IS_COMBINING(val)) ||
3392 (IS_EXTENDER(val))) {
3393 val = xmlStringCurrentChar(NULL, cur, &len);
3394 cur += len;
3395 }
3396
3397 while (IS_BLANK(val)) {
3398 while (IS_BLANK(val)) {
3399 val = xmlStringCurrentChar(NULL, cur, &len);
3400 cur += len;
3401 }
3402 if (val == 0) return(1);
3403
3404 if (!IS_LETTER(val) && !IS_DIGIT(val) &&
3405 (val != '.') && (val != '-') &&
3406 (val != '_') && (val != ':') &&
3407 (!IS_COMBINING(val)) &&
3408 (!IS_EXTENDER(val)))
3409 return(0);
3410
3411 while ((IS_LETTER(val)) || (IS_DIGIT(val)) ||
3412 (val == '.') || (val == '-') ||
3413 (val == '_') || (val == ':') ||
3414 (IS_COMBINING(val)) ||
3415 (IS_EXTENDER(val))) {
3416 val = xmlStringCurrentChar(NULL, cur, &len);
3417 cur += len;
3418 }
3419 }
3420
3421 if (val != 0) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003422
3423 return(1);
3424}
3425
3426/**
3427 * xmlValidateNotationDecl:
3428 * @ctxt: the validation context
3429 * @doc: a document instance
3430 * @nota: a notation definition
3431 *
3432 * Try to validate a single notation definition
3433 * basically it does the following checks as described by the
3434 * XML-1.0 recommendation:
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003435 * - it seems that no validity constraint exists on notation declarations
Owen Taylor3473f882001-02-23 17:55:21 +00003436 * But this function get called anyway ...
3437 *
3438 * returns 1 if valid or 0 otherwise
3439 */
3440
3441int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00003442xmlValidateNotationDecl(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED, xmlDocPtr doc ATTRIBUTE_UNUSED,
3443 xmlNotationPtr nota ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00003444 int ret = 1;
3445
3446 return(ret);
3447}
3448
3449/**
3450 * xmlValidateAttributeValue:
3451 * @type: an attribute type
3452 * @value: an attribute value
3453 *
3454 * Validate that the given attribute value match the proper production
3455 *
3456 * [ VC: ID ]
3457 * Values of type ID must match the Name production....
3458 *
3459 * [ VC: IDREF ]
3460 * Values of type IDREF must match the Name production, and values
3461 * of type IDREFS must match Names ...
3462 *
3463 * [ VC: Entity Name ]
3464 * Values of type ENTITY must match the Name production, values
3465 * of type ENTITIES must match Names ...
3466 *
3467 * [ VC: Name Token ]
3468 * Values of type NMTOKEN must match the Nmtoken production; values
3469 * of type NMTOKENS must match Nmtokens.
3470 *
3471 * returns 1 if valid or 0 otherwise
3472 */
3473
3474int
3475xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) {
3476 switch (type) {
3477 case XML_ATTRIBUTE_ENTITIES:
3478 case XML_ATTRIBUTE_IDREFS:
3479 return(xmlValidateNamesValue(value));
3480 case XML_ATTRIBUTE_ENTITY:
3481 case XML_ATTRIBUTE_IDREF:
3482 case XML_ATTRIBUTE_ID:
3483 case XML_ATTRIBUTE_NOTATION:
3484 return(xmlValidateNameValue(value));
3485 case XML_ATTRIBUTE_NMTOKENS:
3486 case XML_ATTRIBUTE_ENUMERATION:
3487 return(xmlValidateNmtokensValue(value));
3488 case XML_ATTRIBUTE_NMTOKEN:
3489 return(xmlValidateNmtokenValue(value));
3490 case XML_ATTRIBUTE_CDATA:
3491 break;
3492 }
3493 return(1);
3494}
3495
3496/**
3497 * xmlValidateAttributeValue2:
3498 * @ctxt: the validation context
3499 * @doc: the document
3500 * @name: the attribute name (used for error reporting only)
3501 * @type: the attribute type
3502 * @value: the attribute value
3503 *
3504 * Validate that the given attribute value match a given type.
3505 * This typically cannot be done before having finished parsing
3506 * the subsets.
3507 *
3508 * [ VC: IDREF ]
3509 * Values of type IDREF must match one of the declared IDs
3510 * Values of type IDREFS must match a sequence of the declared IDs
3511 * each Name must match the value of an ID attribute on some element
3512 * in the XML document; i.e. IDREF values must match the value of
3513 * some ID attribute
3514 *
3515 * [ VC: Entity Name ]
3516 * Values of type ENTITY must match one declared entity
3517 * Values of type ENTITIES must match a sequence of declared entities
3518 *
3519 * [ VC: Notation Attributes ]
3520 * all notation names in the declaration must be declared.
3521 *
3522 * returns 1 if valid or 0 otherwise
3523 */
3524
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003525static int
Owen Taylor3473f882001-02-23 17:55:21 +00003526xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3527 const xmlChar *name, xmlAttributeType type, const xmlChar *value) {
3528 int ret = 1;
3529 switch (type) {
3530 case XML_ATTRIBUTE_IDREFS:
3531 case XML_ATTRIBUTE_IDREF:
3532 case XML_ATTRIBUTE_ID:
3533 case XML_ATTRIBUTE_NMTOKENS:
3534 case XML_ATTRIBUTE_ENUMERATION:
3535 case XML_ATTRIBUTE_NMTOKEN:
3536 case XML_ATTRIBUTE_CDATA:
3537 break;
3538 case XML_ATTRIBUTE_ENTITY: {
3539 xmlEntityPtr ent;
3540
3541 ent = xmlGetDocEntity(doc, value);
Daniel Veillard62998c02003-09-15 12:56:36 +00003542 /* yeah it's a bit messy... */
Daniel Veillard878eab02002-02-19 13:46:09 +00003543 if ((ent == NULL) && (doc->standalone == 1)) {
3544 doc->standalone = 0;
3545 ent = xmlGetDocEntity(doc, value);
Daniel Veillard878eab02002-02-19 13:46:09 +00003546 }
Owen Taylor3473f882001-02-23 17:55:21 +00003547 if (ent == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003548 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3549 XML_DTD_UNKNOWN_ENTITY,
Owen Taylor3473f882001-02-23 17:55:21 +00003550 "ENTITY attribute %s reference an unknown entity \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003551 name, value, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003552 ret = 0;
3553 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003554 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3555 XML_DTD_ENTITY_TYPE,
Owen Taylor3473f882001-02-23 17:55:21 +00003556 "ENTITY attribute %s reference an entity \"%s\" of wrong type\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003557 name, value, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003558 ret = 0;
3559 }
3560 break;
3561 }
3562 case XML_ATTRIBUTE_ENTITIES: {
3563 xmlChar *dup, *nam = NULL, *cur, save;
3564 xmlEntityPtr ent;
3565
3566 dup = xmlStrdup(value);
3567 if (dup == NULL)
3568 return(0);
3569 cur = dup;
3570 while (*cur != 0) {
3571 nam = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00003572 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00003573 save = *cur;
3574 *cur = 0;
3575 ent = xmlGetDocEntity(doc, nam);
3576 if (ent == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003577 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3578 XML_DTD_UNKNOWN_ENTITY,
Owen Taylor3473f882001-02-23 17:55:21 +00003579 "ENTITIES attribute %s reference an unknown entity \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003580 name, nam, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003581 ret = 0;
3582 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003583 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3584 XML_DTD_ENTITY_TYPE,
Owen Taylor3473f882001-02-23 17:55:21 +00003585 "ENTITIES attribute %s reference an entity \"%s\" of wrong type\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003586 name, nam, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003587 ret = 0;
3588 }
3589 if (save == 0)
3590 break;
3591 *cur = save;
William M. Brack76e95df2003-10-18 16:20:14 +00003592 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00003593 }
3594 xmlFree(dup);
3595 break;
3596 }
3597 case XML_ATTRIBUTE_NOTATION: {
3598 xmlNotationPtr nota;
3599
3600 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
3601 if ((nota == NULL) && (doc->extSubset != NULL))
3602 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
3603
3604 if (nota == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003605 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3606 XML_DTD_UNKNOWN_NOTATION,
Owen Taylor3473f882001-02-23 17:55:21 +00003607 "NOTATION attribute %s reference an unknown notation \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003608 name, value, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003609 ret = 0;
3610 }
3611 break;
3612 }
3613 }
3614 return(ret);
3615}
3616
3617/**
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003618 * xmlValidCtxtNormalizeAttributeValue:
3619 * @ctxt: the validation context
3620 * @doc: the document
3621 * @elem: the parent
3622 * @name: the attribute name
3623 * @value: the attribute value
3624 * @ctxt: the validation context or NULL
3625 *
3626 * Does the validation related extra step of the normalization of attribute
3627 * values:
3628 *
3629 * If the declared value is not CDATA, then the XML processor must further
3630 * process the normalized attribute value by discarding any leading and
3631 * trailing space (#x20) characters, and by replacing sequences of space
3632 * (#x20) characters by single space (#x20) character.
3633 *
3634 * Also check VC: Standalone Document Declaration in P32, and update
3635 * ctxt->valid accordingly
3636 *
3637 * returns a new normalized string if normalization is needed, NULL otherwise
3638 * the caller must free the returned value.
3639 */
3640
3641xmlChar *
3642xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3643 xmlNodePtr elem, const xmlChar *name, const xmlChar *value) {
3644 xmlChar *ret, *dst;
3645 const xmlChar *src;
3646 xmlAttributePtr attrDecl = NULL;
3647 int extsubset = 0;
3648
3649 if (doc == NULL) return(NULL);
3650 if (elem == NULL) return(NULL);
3651 if (name == NULL) return(NULL);
3652 if (value == NULL) return(NULL);
3653
3654 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003655 xmlChar fn[50];
3656 xmlChar *fullname;
3657
3658 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
3659 if (fullname == NULL)
3660 return(0);
3661 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003662 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003663 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003664 if (attrDecl != NULL)
3665 extsubset = 1;
3666 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00003667 if ((fullname != fn) && (fullname != elem->name))
3668 xmlFree(fullname);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003669 }
3670 if ((attrDecl == NULL) && (doc->intSubset != NULL))
3671 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
3672 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
3673 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
3674 if (attrDecl != NULL)
3675 extsubset = 1;
3676 }
3677
3678 if (attrDecl == NULL)
3679 return(NULL);
3680 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
3681 return(NULL);
3682
3683 ret = xmlStrdup(value);
3684 if (ret == NULL)
3685 return(NULL);
3686 src = value;
3687 dst = ret;
3688 while (*src == 0x20) src++;
3689 while (*src != 0) {
3690 if (*src == 0x20) {
3691 while (*src == 0x20) src++;
3692 if (*src != 0)
3693 *dst++ = 0x20;
3694 } else {
3695 *dst++ = *src++;
3696 }
3697 }
3698 *dst = 0;
3699 if ((doc->standalone) && (extsubset == 1) && (!xmlStrEqual(value, ret))) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003700 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_STANDALONE,
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003701"standalone: %s on %s value had to be normalized based on external subset declaration\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003702 name, elem->name, NULL);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00003703 ctxt->valid = 0;
3704 }
3705 return(ret);
3706}
3707
3708/**
Owen Taylor3473f882001-02-23 17:55:21 +00003709 * xmlValidNormalizeAttributeValue:
3710 * @doc: the document
3711 * @elem: the parent
3712 * @name: the attribute name
3713 * @value: the attribute value
3714 *
3715 * Does the validation related extra step of the normalization of attribute
3716 * values:
3717 *
3718 * If the declared value is not CDATA, then the XML processor must further
3719 * process the normalized attribute value by discarding any leading and
3720 * trailing space (#x20) characters, and by replacing sequences of space
3721 * (#x20) characters by single space (#x20) character.
3722 *
Daniel Veillard652327a2003-09-29 18:02:38 +00003723 * Returns a new normalized string if normalization is needed, NULL otherwise
Owen Taylor3473f882001-02-23 17:55:21 +00003724 * the caller must free the returned value.
3725 */
3726
3727xmlChar *
3728xmlValidNormalizeAttributeValue(xmlDocPtr doc, xmlNodePtr elem,
3729 const xmlChar *name, const xmlChar *value) {
3730 xmlChar *ret, *dst;
3731 const xmlChar *src;
3732 xmlAttributePtr attrDecl = NULL;
3733
3734 if (doc == NULL) return(NULL);
3735 if (elem == NULL) return(NULL);
3736 if (name == NULL) return(NULL);
3737 if (value == NULL) return(NULL);
3738
3739 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00003740 xmlChar fn[50];
3741 xmlChar *fullname;
3742
3743 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
3744 if (fullname == NULL)
3745 return(0);
3746 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name);
Owen Taylor3473f882001-02-23 17:55:21 +00003747 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00003748 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name);
3749 if ((fullname != fn) && (fullname != elem->name))
3750 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00003751 }
3752 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
3753 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3754 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
3755
3756 if (attrDecl == NULL)
3757 return(NULL);
3758 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
3759 return(NULL);
3760
3761 ret = xmlStrdup(value);
3762 if (ret == NULL)
3763 return(NULL);
3764 src = value;
3765 dst = ret;
3766 while (*src == 0x20) src++;
3767 while (*src != 0) {
3768 if (*src == 0x20) {
3769 while (*src == 0x20) src++;
3770 if (*src != 0)
3771 *dst++ = 0x20;
3772 } else {
3773 *dst++ = *src++;
3774 }
3775 }
3776 *dst = 0;
3777 return(ret);
3778}
3779
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003780static void
Owen Taylor3473f882001-02-23 17:55:21 +00003781xmlValidateAttributeIdCallback(xmlAttributePtr attr, int *count,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00003782 const xmlChar* name ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00003783 if (attr->atype == XML_ATTRIBUTE_ID) (*count)++;
3784}
3785
3786/**
3787 * xmlValidateAttributeDecl:
3788 * @ctxt: the validation context
3789 * @doc: a document instance
3790 * @attr: an attribute definition
3791 *
3792 * Try to validate a single attribute definition
3793 * basically it does the following checks as described by the
3794 * XML-1.0 recommendation:
3795 * - [ VC: Attribute Default Legal ]
3796 * - [ VC: Enumeration ]
3797 * - [ VC: ID Attribute Default ]
3798 *
3799 * The ID/IDREF uniqueness and matching are done separately
3800 *
3801 * returns 1 if valid or 0 otherwise
3802 */
3803
3804int
3805xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3806 xmlAttributePtr attr) {
3807 int ret = 1;
3808 int val;
3809 CHECK_DTD;
3810 if(attr == NULL) return(1);
3811
3812 /* Attribute Default Legal */
3813 /* Enumeration */
3814 if (attr->defaultValue != NULL) {
3815 val = xmlValidateAttributeValue(attr->atype, attr->defaultValue);
3816 if (val == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003817 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard58e44c92002-08-02 22:19:49 +00003818 "Syntax of default value for attribute %s of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003819 attr->name, attr->elem, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003820 }
3821 ret &= val;
3822 }
3823
3824 /* ID Attribute Default */
3825 if ((attr->atype == XML_ATTRIBUTE_ID)&&
3826 (attr->def != XML_ATTRIBUTE_IMPLIED) &&
3827 (attr->def != XML_ATTRIBUTE_REQUIRED)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003828 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_FIXED,
Daniel Veillard58e44c92002-08-02 22:19:49 +00003829 "ID attribute %s of %s is not valid must be #IMPLIED or #REQUIRED\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003830 attr->name, attr->elem, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003831 ret = 0;
3832 }
3833
3834 /* One ID per Element Type */
3835 if (attr->atype == XML_ATTRIBUTE_ID) {
3836 int nbId;
3837
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003838 /* the trick is that we parse DtD as their own internal subset */
Owen Taylor3473f882001-02-23 17:55:21 +00003839 xmlElementPtr elem = xmlGetDtdElementDesc(doc->intSubset,
3840 attr->elem);
3841 if (elem != NULL) {
3842 nbId = xmlScanIDAttributeDecl(NULL, elem);
3843 } else {
3844 xmlAttributeTablePtr table;
3845
3846 /*
3847 * The attribute may be declared in the internal subset and the
3848 * element in the external subset.
3849 */
3850 nbId = 0;
3851 table = (xmlAttributeTablePtr) doc->intSubset->attributes;
3852 xmlHashScan3(table, NULL, NULL, attr->elem, (xmlHashScanner)
3853 xmlValidateAttributeIdCallback, &nbId);
3854 }
3855 if (nbId > 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003856
3857 xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
Owen Taylor3473f882001-02-23 17:55:21 +00003858 "Element %s has %d ID attribute defined in the internal subset : %s\n",
3859 attr->elem, nbId, attr->name);
3860 } else if (doc->extSubset != NULL) {
3861 int extId = 0;
3862 elem = xmlGetDtdElementDesc(doc->extSubset, attr->elem);
3863 if (elem != NULL) {
3864 extId = xmlScanIDAttributeDecl(NULL, elem);
3865 }
3866 if (extId > 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003867 xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
Owen Taylor3473f882001-02-23 17:55:21 +00003868 "Element %s has %d ID attribute defined in the external subset : %s\n",
3869 attr->elem, extId, attr->name);
3870 } else if (extId + nbId > 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003871 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
Owen Taylor3473f882001-02-23 17:55:21 +00003872"Element %s has ID attributes defined in the internal and external subset : %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003873 attr->elem, attr->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003874 }
3875 }
3876 }
3877
3878 /* Validity Constraint: Enumeration */
3879 if ((attr->defaultValue != NULL) && (attr->tree != NULL)) {
3880 xmlEnumerationPtr tree = attr->tree;
3881 while (tree != NULL) {
3882 if (xmlStrEqual(tree->name, attr->defaultValue)) break;
3883 tree = tree->next;
3884 }
3885 if (tree == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003886 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00003887"Default value \"%s\" for attribute %s of %s is not among the enumerated set\n",
Owen Taylor3473f882001-02-23 17:55:21 +00003888 attr->defaultValue, attr->name, attr->elem);
3889 ret = 0;
3890 }
3891 }
3892
3893 return(ret);
3894}
3895
3896/**
3897 * xmlValidateElementDecl:
3898 * @ctxt: the validation context
3899 * @doc: a document instance
3900 * @elem: an element definition
3901 *
3902 * Try to validate a single element definition
3903 * basically it does the following checks as described by the
3904 * XML-1.0 recommendation:
3905 * - [ VC: One ID per Element Type ]
3906 * - [ VC: No Duplicate Types ]
3907 * - [ VC: Unique Element Type Declaration ]
3908 *
3909 * returns 1 if valid or 0 otherwise
3910 */
3911
3912int
3913xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3914 xmlElementPtr elem) {
3915 int ret = 1;
3916 xmlElementPtr tst;
3917
3918 CHECK_DTD;
3919
3920 if (elem == NULL) return(1);
3921
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00003922#if 0
Daniel Veillard84d70a42002-09-16 10:51:38 +00003923#ifdef LIBXML_REGEXP_ENABLED
3924 /* Build the regexp associated to the content model */
3925 ret = xmlValidBuildContentModel(ctxt, elem);
3926#endif
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00003927#endif
Daniel Veillard84d70a42002-09-16 10:51:38 +00003928
Owen Taylor3473f882001-02-23 17:55:21 +00003929 /* No Duplicate Types */
3930 if (elem->etype == XML_ELEMENT_TYPE_MIXED) {
3931 xmlElementContentPtr cur, next;
3932 const xmlChar *name;
3933
3934 cur = elem->content;
3935 while (cur != NULL) {
3936 if (cur->type != XML_ELEMENT_CONTENT_OR) break;
3937 if (cur->c1 == NULL) break;
3938 if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
3939 name = cur->c1->name;
3940 next = cur->c2;
3941 while (next != NULL) {
3942 if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
Daniel Veillard7b68df92003-08-03 22:58:54 +00003943 if ((xmlStrEqual(next->name, name)) &&
3944 (xmlStrEqual(next->prefix, cur->prefix))) {
3945 if (cur->prefix == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003946 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Owen Taylor3473f882001-02-23 17:55:21 +00003947 "Definition of %s has duplicate references of %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003948 elem->name, name, NULL);
Daniel Veillard7b68df92003-08-03 22:58:54 +00003949 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003950 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Daniel Veillard7b68df92003-08-03 22:58:54 +00003951 "Definition of %s has duplicate references of %s:%s\n",
3952 elem->name, cur->prefix, name);
3953 }
Owen Taylor3473f882001-02-23 17:55:21 +00003954 ret = 0;
3955 }
3956 break;
3957 }
3958 if (next->c1 == NULL) break;
3959 if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
Daniel Veillard7b68df92003-08-03 22:58:54 +00003960 if ((xmlStrEqual(next->c1->name, name)) &&
3961 (xmlStrEqual(next->c1->prefix, cur->prefix))) {
3962 if (cur->prefix == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003963 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Daniel Veillard7b68df92003-08-03 22:58:54 +00003964 "Definition of %s has duplicate references to %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003965 elem->name, name, NULL);
Daniel Veillard7b68df92003-08-03 22:58:54 +00003966 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003967 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
Daniel Veillard7b68df92003-08-03 22:58:54 +00003968 "Definition of %s has duplicate references to %s:%s\n",
3969 elem->name, cur->prefix, name);
3970 }
Owen Taylor3473f882001-02-23 17:55:21 +00003971 ret = 0;
3972 }
3973 next = next->c2;
3974 }
3975 }
3976 cur = cur->c2;
3977 }
3978 }
3979
3980 /* VC: Unique Element Type Declaration */
3981 tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
Daniel Veillarda10efa82001-04-18 13:09:01 +00003982 if ((tst != NULL ) && (tst != elem) &&
Daniel Veillardbe480fb2001-11-08 23:36:42 +00003983 ((tst->prefix == elem->prefix) ||
3984 (xmlStrEqual(tst->prefix, elem->prefix))) &&
Daniel Veillarda10efa82001-04-18 13:09:01 +00003985 (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003986 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
3987 "Redefinition of element %s\n",
3988 elem->name, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003989 ret = 0;
3990 }
3991 tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
Daniel Veillarda10efa82001-04-18 13:09:01 +00003992 if ((tst != NULL ) && (tst != elem) &&
Daniel Veillardbe480fb2001-11-08 23:36:42 +00003993 ((tst->prefix == elem->prefix) ||
3994 (xmlStrEqual(tst->prefix, elem->prefix))) &&
Daniel Veillarda10efa82001-04-18 13:09:01 +00003995 (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00003996 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
3997 "Redefinition of element %s\n",
3998 elem->name, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003999 ret = 0;
4000 }
Daniel Veillarda10efa82001-04-18 13:09:01 +00004001 /* One ID per Element Type
4002 * already done when registering the attribute
Owen Taylor3473f882001-02-23 17:55:21 +00004003 if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
4004 ret = 0;
Daniel Veillarda10efa82001-04-18 13:09:01 +00004005 } */
Owen Taylor3473f882001-02-23 17:55:21 +00004006 return(ret);
4007}
4008
4009/**
4010 * xmlValidateOneAttribute:
4011 * @ctxt: the validation context
4012 * @doc: a document instance
4013 * @elem: an element instance
4014 * @attr: an attribute instance
4015 * @value: the attribute value (without entities processing)
4016 *
4017 * Try to validate a single attribute for an element
4018 * basically it does the following checks as described by the
4019 * XML-1.0 recommendation:
4020 * - [ VC: Attribute Value Type ]
4021 * - [ VC: Fixed Attribute Default ]
4022 * - [ VC: Entity Name ]
4023 * - [ VC: Name Token ]
4024 * - [ VC: ID ]
4025 * - [ VC: IDREF ]
4026 * - [ VC: Entity Name ]
4027 * - [ VC: Notation Attributes ]
4028 *
4029 * The ID/IDREF uniqueness and matching are done separately
4030 *
4031 * returns 1 if valid or 0 otherwise
4032 */
4033
4034int
4035xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
Daniel Veillard07cb8222003-09-10 10:51:05 +00004036 xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value)
4037{
Owen Taylor3473f882001-02-23 17:55:21 +00004038 xmlAttributePtr attrDecl = NULL;
4039 int val;
4040 int ret = 1;
4041
4042 CHECK_DTD;
4043 if ((elem == NULL) || (elem->name == NULL)) return(0);
4044 if ((attr == NULL) || (attr->name == NULL)) return(0);
4045
4046 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004047 xmlChar fn[50];
4048 xmlChar *fullname;
4049
4050 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
4051 if (fullname == NULL)
4052 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00004053 if (attr->ns != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004054 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
Owen Taylor3473f882001-02-23 17:55:21 +00004055 attr->name, attr->ns->prefix);
4056 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004057 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
Owen Taylor3473f882001-02-23 17:55:21 +00004058 attr->name, attr->ns->prefix);
4059 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004060 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00004061 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4062 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
Daniel Veillardc00cda82003-04-07 10:22:39 +00004063 fullname, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00004064 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00004065 if ((fullname != fn) && (fullname != elem->name))
4066 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00004067 }
4068 if (attrDecl == NULL) {
4069 if (attr->ns != NULL) {
4070 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4071 attr->name, attr->ns->prefix);
4072 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4073 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4074 attr->name, attr->ns->prefix);
4075 } else {
4076 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4077 elem->name, attr->name);
4078 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4079 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4080 elem->name, attr->name);
4081 }
4082 }
4083
4084
4085 /* Validity Constraint: Attribute Value Type */
4086 if (attrDecl == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004087 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004088 "No declaration for attribute %s of element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004089 attr->name, elem->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004090 return(0);
4091 }
4092 attr->atype = attrDecl->atype;
4093
4094 val = xmlValidateAttributeValue(attrDecl->atype, value);
4095 if (val == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004096 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004097 "Syntax of value for attribute %s of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004098 attr->name, elem->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004099 ret = 0;
4100 }
4101
4102 /* Validity constraint: Fixed Attribute Default */
4103 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4104 if (!xmlStrEqual(value, attrDecl->defaultValue)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004105 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004106 "Value for attribute %s of %s is different from default \"%s\"\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004107 attr->name, elem->name, attrDecl->defaultValue);
4108 ret = 0;
4109 }
4110 }
4111
4112 /* Validity Constraint: ID uniqueness */
4113 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4114 if (xmlAddID(ctxt, doc, value, attr) == NULL)
4115 ret = 0;
4116 }
4117
4118 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4119 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4120 if (xmlAddRef(ctxt, doc, value, attr) == NULL)
4121 ret = 0;
4122 }
4123
4124 /* Validity Constraint: Notation Attributes */
4125 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4126 xmlEnumerationPtr tree = attrDecl->tree;
4127 xmlNotationPtr nota;
4128
4129 /* First check that the given NOTATION was declared */
4130 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4131 if (nota == NULL)
4132 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4133
4134 if (nota == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004135 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004136 "Value \"%s\" for attribute %s of %s is not a declared Notation\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004137 value, attr->name, elem->name);
4138 ret = 0;
4139 }
4140
4141 /* Second, verify that it's among the list */
4142 while (tree != NULL) {
4143 if (xmlStrEqual(tree->name, value)) break;
4144 tree = tree->next;
4145 }
4146 if (tree == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004147 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004148"Value \"%s\" for attribute %s of %s is not among the enumerated notations\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004149 value, attr->name, elem->name);
4150 ret = 0;
4151 }
4152 }
4153
4154 /* Validity Constraint: Enumeration */
4155 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4156 xmlEnumerationPtr tree = attrDecl->tree;
4157 while (tree != NULL) {
4158 if (xmlStrEqual(tree->name, value)) break;
4159 tree = tree->next;
4160 }
4161 if (tree == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004162 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004163 "Value \"%s\" for attribute %s of %s is not among the enumerated set\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004164 value, attr->name, elem->name);
4165 ret = 0;
4166 }
4167 }
4168
4169 /* Fixed Attribute Default */
4170 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4171 (!xmlStrEqual(attrDecl->defaultValue, value))) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004172 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00004173 "Value for attribute %s of %s must be \"%s\"\n",
Owen Taylor3473f882001-02-23 17:55:21 +00004174 attr->name, elem->name, attrDecl->defaultValue);
4175 ret = 0;
4176 }
4177
4178 /* Extra check for the attribute value */
4179 ret &= xmlValidateAttributeValue2(ctxt, doc, attr->name,
4180 attrDecl->atype, value);
4181
4182 return(ret);
4183}
4184
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004185/**
4186 * xmlValidateOneNamespace:
4187 * @ctxt: the validation context
4188 * @doc: a document instance
4189 * @elem: an element instance
Daniel Veillarda9b66d02002-12-11 14:23:49 +00004190 * @prefix: the namespace prefix
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004191 * @ns: an namespace declaration instance
4192 * @value: the attribute value (without entities processing)
4193 *
4194 * Try to validate a single namespace declaration for an element
4195 * basically it does the following checks as described by the
4196 * XML-1.0 recommendation:
4197 * - [ VC: Attribute Value Type ]
4198 * - [ VC: Fixed Attribute Default ]
4199 * - [ VC: Entity Name ]
4200 * - [ VC: Name Token ]
4201 * - [ VC: ID ]
4202 * - [ VC: IDREF ]
4203 * - [ VC: Entity Name ]
4204 * - [ VC: Notation Attributes ]
4205 *
4206 * The ID/IDREF uniqueness and matching are done separately
4207 *
4208 * returns 1 if valid or 0 otherwise
4209 */
4210
4211int
4212xmlValidateOneNamespace(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4213xmlNodePtr elem, const xmlChar *prefix, xmlNsPtr ns, const xmlChar *value) {
4214 /* xmlElementPtr elemDecl; */
4215 xmlAttributePtr attrDecl = NULL;
4216 int val;
4217 int ret = 1;
4218
4219 CHECK_DTD;
4220 if ((elem == NULL) || (elem->name == NULL)) return(0);
4221 if ((ns == NULL) || (ns->href == NULL)) return(0);
4222
4223 if (prefix != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004224 xmlChar fn[50];
4225 xmlChar *fullname;
4226
4227 fullname = xmlBuildQName(elem->name, prefix, fn, 50);
4228 if (fullname == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00004229 xmlVErrMemory(ctxt, "Validating namespace");
Daniel Veillardc00cda82003-04-07 10:22:39 +00004230 return(0);
4231 }
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004232 if (ns->prefix != NULL) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004233 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004234 ns->prefix, BAD_CAST "xmlns");
4235 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004236 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004237 ns->prefix, BAD_CAST "xmlns");
4238 } else {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004239 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004240 BAD_CAST "xmlns");
4241 if ((attrDecl == NULL) && (doc->extSubset != NULL))
Daniel Veillardc00cda82003-04-07 10:22:39 +00004242 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004243 BAD_CAST "xmlns");
4244 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00004245 if ((fullname != fn) && (fullname != elem->name))
4246 xmlFree(fullname);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004247 }
4248 if (attrDecl == NULL) {
4249 if (ns->prefix != NULL) {
4250 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4251 ns->prefix, BAD_CAST "xmlns");
4252 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4253 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4254 ns->prefix, BAD_CAST "xmlns");
4255 } else {
4256 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4257 elem->name, BAD_CAST "xmlns");
4258 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4259 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4260 elem->name, BAD_CAST "xmlns");
4261 }
4262 }
4263
4264
4265 /* Validity Constraint: Attribute Value Type */
4266 if (attrDecl == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004267 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004268 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004269 "No declaration for attribute xmlns:%s of element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004270 ns->prefix, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004271 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004272 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004273 "No declaration for attribute xmlns of element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004274 elem->name, NULL, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004275 }
4276 return(0);
4277 }
4278
4279 val = xmlValidateAttributeValue(attrDecl->atype, value);
4280 if (val == 0) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004281 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004282 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004283 "Syntax of value for attribute xmlns:%s of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004284 ns->prefix, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004285 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004286 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004287 "Syntax of value for attribute xmlns of %s is not valid\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004288 elem->name, NULL, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004289 }
4290 ret = 0;
4291 }
4292
4293 /* Validity constraint: Fixed Attribute Default */
4294 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4295 if (!xmlStrEqual(value, attrDecl->defaultValue)) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004296 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004297 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004298 "Value for attribute xmlns:%s of %s is different from default \"%s\"\n",
4299 ns->prefix, elem->name, attrDecl->defaultValue);
4300 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004301 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004302 "Value for attribute xmlns of %s is different from default \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004303 elem->name, attrDecl->defaultValue, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004304 }
4305 ret = 0;
4306 }
4307 }
4308
4309 /* Validity Constraint: ID uniqueness */
4310 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4311 if (xmlAddID(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4312 ret = 0;
4313 }
4314
4315 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4316 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4317 if (xmlAddRef(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4318 ret = 0;
4319 }
4320
4321 /* Validity Constraint: Notation Attributes */
4322 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4323 xmlEnumerationPtr tree = attrDecl->tree;
4324 xmlNotationPtr nota;
4325
4326 /* First check that the given NOTATION was declared */
4327 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4328 if (nota == NULL)
4329 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4330
4331 if (nota == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004332 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004333 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004334 "Value \"%s\" for attribute xmlns:%s of %s is not a declared Notation\n",
4335 value, ns->prefix, elem->name);
4336 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004337 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004338 "Value \"%s\" for attribute xmlns of %s is not a declared Notation\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004339 value, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004340 }
4341 ret = 0;
4342 }
4343
4344 /* Second, verify that it's among the list */
4345 while (tree != NULL) {
4346 if (xmlStrEqual(tree->name, value)) break;
4347 tree = tree->next;
4348 }
4349 if (tree == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004350 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004351 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004352"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated notations\n",
4353 value, ns->prefix, elem->name);
4354 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004355 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004356"Value \"%s\" for attribute xmlns of %s is not among the enumerated notations\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004357 value, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004358 }
4359 ret = 0;
4360 }
4361 }
4362
4363 /* Validity Constraint: Enumeration */
4364 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4365 xmlEnumerationPtr tree = attrDecl->tree;
4366 while (tree != NULL) {
4367 if (xmlStrEqual(tree->name, value)) break;
4368 tree = tree->next;
4369 }
4370 if (tree == NULL) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004371 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004372 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004373"Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated set\n",
4374 value, ns->prefix, elem->name);
4375 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004376 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004377"Value \"%s\" for attribute xmlns of %s is not among the enumerated set\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004378 value, elem->name, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004379 }
4380 ret = 0;
4381 }
4382 }
4383
4384 /* Fixed Attribute Default */
4385 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4386 (!xmlStrEqual(attrDecl->defaultValue, value))) {
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004387 if (ns->prefix != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004388 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004389 "Value for attribute xmlns:%s of %s must be \"%s\"\n",
4390 ns->prefix, elem->name, attrDecl->defaultValue);
4391 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004392 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004393 "Value for attribute xmlns of %s must be \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00004394 elem->name, attrDecl->defaultValue, NULL);
Daniel Veillard90d68fb2002-09-26 16:10:21 +00004395 }
4396 ret = 0;
4397 }
4398
4399 /* Extra check for the attribute value */
4400 if (ns->prefix != NULL) {
4401 ret &= xmlValidateAttributeValue2(ctxt, doc, ns->prefix,
4402 attrDecl->atype, value);
4403 } else {
4404 ret &= xmlValidateAttributeValue2(ctxt, doc, BAD_CAST "xmlns",
4405 attrDecl->atype, value);
4406 }
4407
4408 return(ret);
4409}
4410
Daniel Veillard118aed72002-09-24 14:13:13 +00004411#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004412/**
4413 * xmlValidateSkipIgnorable:
4414 * @ctxt: the validation context
4415 * @child: the child list
4416 *
4417 * Skip ignorable elements w.r.t. the validation process
4418 *
4419 * returns the first element to consider for validation of the content model
4420 */
4421
4422static xmlNodePtr
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004423xmlValidateSkipIgnorable(xmlNodePtr child) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004424 while (child != NULL) {
4425 switch (child->type) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004426 /* These things are ignored (skipped) during validation. */
4427 case XML_PI_NODE:
4428 case XML_COMMENT_NODE:
4429 case XML_XINCLUDE_START:
4430 case XML_XINCLUDE_END:
4431 child = child->next;
4432 break;
4433 case XML_TEXT_NODE:
4434 if (xmlIsBlankNode(child))
4435 child = child->next;
4436 else
4437 return(child);
4438 break;
4439 /* keep current node */
4440 default:
4441 return(child);
4442 }
4443 }
4444 return(child);
4445}
4446
4447/**
4448 * xmlValidateElementType:
4449 * @ctxt: the validation context
4450 *
4451 * Try to validate the content model of an element internal function
4452 *
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004453 * returns 1 if valid or 0 ,-1 in case of error, -2 if an entity
4454 * reference is found and -3 if the validation succeeded but
4455 * the content model is not determinist.
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004456 */
4457
4458static int
4459xmlValidateElementType(xmlValidCtxtPtr ctxt) {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00004460 int ret = -1;
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004461 int determinist = 1;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004462
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004463 NODE = xmlValidateSkipIgnorable(NODE);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004464 if ((NODE == NULL) && (CONT == NULL))
4465 return(1);
4466 if ((NODE == NULL) &&
4467 ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
4468 (CONT->ocur == XML_ELEMENT_CONTENT_OPT))) {
4469 return(1);
4470 }
4471 if (CONT == NULL) return(-1);
Daniel Veillard7533cc82001-04-24 15:52:00 +00004472 if ((NODE != NULL) && (NODE->type == XML_ENTITY_REF_NODE))
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004473 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004474
4475 /*
4476 * We arrive here when more states need to be examined
4477 */
4478cont:
4479
4480 /*
4481 * We just recovered from a rollback generated by a possible
4482 * epsilon transition, go directly to the analysis phase
4483 */
4484 if (STATE == ROLLBACK_PARENT) {
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004485 DEBUG_VALID_MSG("restored parent branch");
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004486 DEBUG_VALID_STATE(NODE, CONT)
4487 ret = 1;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004488 goto analyze;
4489 }
4490
4491 DEBUG_VALID_STATE(NODE, CONT)
4492 /*
4493 * we may have to save a backup state here. This is the equivalent
4494 * of handling epsilon transition in NFAs.
4495 */
Daniel Veillarde62d36c2001-05-15 08:53:16 +00004496 if ((CONT != NULL) &&
Daniel Veillardce2c2f02001-10-18 14:57:24 +00004497 ((CONT->parent == NULL) ||
4498 (CONT->parent->type != XML_ELEMENT_CONTENT_OR)) &&
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004499 ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
Daniel Veillardca1f1722001-04-20 15:47:35 +00004500 (CONT->ocur == XML_ELEMENT_CONTENT_OPT) ||
Daniel Veillard5344c602001-12-31 16:37:34 +00004501 ((CONT->ocur == XML_ELEMENT_CONTENT_PLUS) && (OCCURRENCE)))) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004502 DEBUG_VALID_MSG("saving parent branch");
Daniel Veillard940492d2002-04-15 10:15:25 +00004503 if (vstateVPush(ctxt, CONT, NODE, DEPTH, OCCURS, ROLLBACK_PARENT) < 0)
4504 return(0);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004505 }
4506
4507
4508 /*
4509 * Check first if the content matches
4510 */
4511 switch (CONT->type) {
4512 case XML_ELEMENT_CONTENT_PCDATA:
4513 if (NODE == NULL) {
4514 DEBUG_VALID_MSG("pcdata failed no node");
4515 ret = 0;
4516 break;
4517 }
4518 if (NODE->type == XML_TEXT_NODE) {
4519 DEBUG_VALID_MSG("pcdata found, skip to next");
4520 /*
4521 * go to next element in the content model
4522 * skipping ignorable elems
4523 */
4524 do {
4525 NODE = NODE->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004526 NODE = xmlValidateSkipIgnorable(NODE);
4527 if ((NODE != NULL) &&
4528 (NODE->type == XML_ENTITY_REF_NODE))
4529 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004530 } while ((NODE != NULL) &&
4531 ((NODE->type != XML_ELEMENT_NODE) &&
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00004532 (NODE->type != XML_TEXT_NODE) &&
4533 (NODE->type != XML_CDATA_SECTION_NODE)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004534 ret = 1;
4535 break;
4536 } else {
4537 DEBUG_VALID_MSG("pcdata failed");
4538 ret = 0;
4539 break;
4540 }
4541 break;
4542 case XML_ELEMENT_CONTENT_ELEMENT:
4543 if (NODE == NULL) {
4544 DEBUG_VALID_MSG("element failed no node");
4545 ret = 0;
4546 break;
4547 }
Daniel Veillard8bdd2202001-06-11 12:47:59 +00004548 ret = ((NODE->type == XML_ELEMENT_NODE) &&
4549 (xmlStrEqual(NODE->name, CONT->name)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004550 if (ret == 1) {
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004551 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4552 ret = (CONT->prefix == NULL);
4553 } else if (CONT->prefix == NULL) {
4554 ret = 0;
4555 } else {
4556 ret = xmlStrEqual(NODE->ns->prefix, CONT->prefix);
4557 }
4558 }
4559 if (ret == 1) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004560 DEBUG_VALID_MSG("element found, skip to next");
4561 /*
4562 * go to next element in the content model
4563 * skipping ignorable elems
4564 */
4565 do {
4566 NODE = NODE->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00004567 NODE = xmlValidateSkipIgnorable(NODE);
4568 if ((NODE != NULL) &&
4569 (NODE->type == XML_ENTITY_REF_NODE))
4570 return(-2);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004571 } while ((NODE != NULL) &&
4572 ((NODE->type != XML_ELEMENT_NODE) &&
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00004573 (NODE->type != XML_TEXT_NODE) &&
4574 (NODE->type != XML_CDATA_SECTION_NODE)));
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004575 } else {
4576 DEBUG_VALID_MSG("element failed");
4577 ret = 0;
4578 break;
4579 }
4580 break;
4581 case XML_ELEMENT_CONTENT_OR:
4582 /*
Daniel Veillard85349052001-04-20 13:48:21 +00004583 * Small optimization.
4584 */
4585 if (CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
4586 if ((NODE == NULL) ||
4587 (!xmlStrEqual(NODE->name, CONT->c1->name))) {
4588 DEPTH++;
4589 CONT = CONT->c2;
4590 goto cont;
4591 }
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004592 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4593 ret = (CONT->c1->prefix == NULL);
4594 } else if (CONT->c1->prefix == NULL) {
4595 ret = 0;
4596 } else {
4597 ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
4598 }
4599 if (ret == 0) {
4600 DEPTH++;
4601 CONT = CONT->c2;
4602 goto cont;
4603 }
Daniel Veillard85349052001-04-20 13:48:21 +00004604 }
4605
4606 /*
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004607 * save the second branch 'or' branch
4608 */
4609 DEBUG_VALID_MSG("saving 'or' branch");
Daniel Veillard940492d2002-04-15 10:15:25 +00004610 if (vstateVPush(ctxt, CONT->c2, NODE, (unsigned char)(DEPTH + 1),
4611 OCCURS, ROLLBACK_OR) < 0)
4612 return(-1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004613 DEPTH++;
4614 CONT = CONT->c1;
4615 goto cont;
4616 case XML_ELEMENT_CONTENT_SEQ:
Daniel Veillard1d047672001-06-09 16:41:01 +00004617 /*
4618 * Small optimization.
4619 */
4620 if ((CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) &&
4621 ((CONT->c1->ocur == XML_ELEMENT_CONTENT_OPT) ||
4622 (CONT->c1->ocur == XML_ELEMENT_CONTENT_MULT))) {
4623 if ((NODE == NULL) ||
4624 (!xmlStrEqual(NODE->name, CONT->c1->name))) {
4625 DEPTH++;
4626 CONT = CONT->c2;
4627 goto cont;
4628 }
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004629 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4630 ret = (CONT->c1->prefix == NULL);
4631 } else if (CONT->c1->prefix == NULL) {
4632 ret = 0;
4633 } else {
4634 ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
4635 }
4636 if (ret == 0) {
4637 DEPTH++;
4638 CONT = CONT->c2;
4639 goto cont;
4640 }
Daniel Veillard1d047672001-06-09 16:41:01 +00004641 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004642 DEPTH++;
4643 CONT = CONT->c1;
4644 goto cont;
4645 }
4646
4647 /*
4648 * At this point handle going up in the tree
4649 */
4650 if (ret == -1) {
4651 DEBUG_VALID_MSG("error found returning");
4652 return(ret);
4653 }
4654analyze:
4655 while (CONT != NULL) {
4656 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00004657 * First do the analysis depending on the occurrence model at
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004658 * this level.
4659 */
4660 if (ret == 0) {
4661 switch (CONT->ocur) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004662 xmlNodePtr cur;
4663
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004664 case XML_ELEMENT_CONTENT_ONCE:
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004665 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004666 DEBUG_VALID_MSG("Once branch failed, rollback");
4667 if (vstateVPop(ctxt) < 0 ) {
4668 DEBUG_VALID_MSG("exhaustion, failed");
4669 return(0);
4670 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004671 if (cur != ctxt->vstate->node)
4672 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004673 goto cont;
4674 case XML_ELEMENT_CONTENT_PLUS:
Daniel Veillard5344c602001-12-31 16:37:34 +00004675 if (OCCURRENCE == 0) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004676 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004677 DEBUG_VALID_MSG("Plus branch failed, rollback");
4678 if (vstateVPop(ctxt) < 0 ) {
4679 DEBUG_VALID_MSG("exhaustion, failed");
4680 return(0);
4681 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004682 if (cur != ctxt->vstate->node)
4683 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004684 goto cont;
4685 }
4686 DEBUG_VALID_MSG("Plus branch found");
4687 ret = 1;
4688 break;
4689 case XML_ELEMENT_CONTENT_MULT:
4690#ifdef DEBUG_VALID_ALGO
Daniel Veillard5344c602001-12-31 16:37:34 +00004691 if (OCCURRENCE == 0) {
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004692 DEBUG_VALID_MSG("Mult branch failed");
4693 } else {
4694 DEBUG_VALID_MSG("Mult branch found");
4695 }
4696#endif
4697 ret = 1;
4698 break;
4699 case XML_ELEMENT_CONTENT_OPT:
4700 DEBUG_VALID_MSG("Option branch failed");
4701 ret = 1;
4702 break;
4703 }
4704 } else {
4705 switch (CONT->ocur) {
4706 case XML_ELEMENT_CONTENT_OPT:
4707 DEBUG_VALID_MSG("Option branch succeeded");
4708 ret = 1;
4709 break;
4710 case XML_ELEMENT_CONTENT_ONCE:
4711 DEBUG_VALID_MSG("Once branch succeeded");
4712 ret = 1;
4713 break;
4714 case XML_ELEMENT_CONTENT_PLUS:
4715 if (STATE == ROLLBACK_PARENT) {
4716 DEBUG_VALID_MSG("Plus branch rollback");
4717 ret = 1;
4718 break;
4719 }
4720 if (NODE == NULL) {
4721 DEBUG_VALID_MSG("Plus branch exhausted");
4722 ret = 1;
4723 break;
4724 }
4725 DEBUG_VALID_MSG("Plus branch succeeded, continuing");
Daniel Veillard5344c602001-12-31 16:37:34 +00004726 SET_OCCURRENCE;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004727 goto cont;
4728 case XML_ELEMENT_CONTENT_MULT:
4729 if (STATE == ROLLBACK_PARENT) {
4730 DEBUG_VALID_MSG("Mult branch rollback");
4731 ret = 1;
4732 break;
4733 }
4734 if (NODE == NULL) {
4735 DEBUG_VALID_MSG("Mult branch exhausted");
4736 ret = 1;
4737 break;
4738 }
4739 DEBUG_VALID_MSG("Mult branch succeeded, continuing");
Daniel Veillard5344c602001-12-31 16:37:34 +00004740 /* SET_OCCURRENCE; */
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004741 goto cont;
4742 }
4743 }
4744 STATE = 0;
4745
4746 /*
4747 * Then act accordingly at the parent level
4748 */
Daniel Veillard5344c602001-12-31 16:37:34 +00004749 RESET_OCCURRENCE;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004750 if (CONT->parent == NULL)
4751 break;
4752
4753 switch (CONT->parent->type) {
4754 case XML_ELEMENT_CONTENT_PCDATA:
4755 DEBUG_VALID_MSG("Error: parent pcdata");
4756 return(-1);
4757 case XML_ELEMENT_CONTENT_ELEMENT:
4758 DEBUG_VALID_MSG("Error: parent element");
4759 return(-1);
4760 case XML_ELEMENT_CONTENT_OR:
4761 if (ret == 1) {
4762 DEBUG_VALID_MSG("Or succeeded");
4763 CONT = CONT->parent;
4764 DEPTH--;
4765 } else {
4766 DEBUG_VALID_MSG("Or failed");
4767 CONT = CONT->parent;
4768 DEPTH--;
4769 }
4770 break;
4771 case XML_ELEMENT_CONTENT_SEQ:
4772 if (ret == 0) {
4773 DEBUG_VALID_MSG("Sequence failed");
4774 CONT = CONT->parent;
4775 DEPTH--;
4776 } else if (CONT == CONT->parent->c1) {
4777 DEBUG_VALID_MSG("Sequence testing 2nd branch");
4778 CONT = CONT->parent->c2;
4779 goto cont;
4780 } else {
4781 DEBUG_VALID_MSG("Sequence succeeded");
4782 CONT = CONT->parent;
4783 DEPTH--;
4784 }
4785 }
4786 }
4787 if (NODE != NULL) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004788 xmlNodePtr cur;
4789
4790 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004791 DEBUG_VALID_MSG("Failed, remaining input, rollback");
4792 if (vstateVPop(ctxt) < 0 ) {
4793 DEBUG_VALID_MSG("exhaustion, failed");
4794 return(0);
4795 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004796 if (cur != ctxt->vstate->node)
4797 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004798 goto cont;
4799 }
4800 if (ret == 0) {
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004801 xmlNodePtr cur;
4802
4803 cur = ctxt->vstate->node;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004804 DEBUG_VALID_MSG("Failure, rollback");
4805 if (vstateVPop(ctxt) < 0 ) {
4806 DEBUG_VALID_MSG("exhaustion, failed");
4807 return(0);
4808 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004809 if (cur != ctxt->vstate->node)
4810 determinist = -3;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004811 goto cont;
4812 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00004813 return(determinist);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004814}
Daniel Veillard23e73572002-09-19 19:56:43 +00004815#endif
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004816
4817/**
Daniel Veillardd3d06722001-08-15 12:06:36 +00004818 * xmlSnprintfElements:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004819 * @buf: an output buffer
Daniel Veillardd3d06722001-08-15 12:06:36 +00004820 * @size: the size of the buffer
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004821 * @content: An element
4822 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
4823 *
4824 * This will dump the list of elements to the buffer
4825 * Intended just for the debug routine
4826 */
4827static void
Daniel Veillardd3d06722001-08-15 12:06:36 +00004828xmlSnprintfElements(char *buf, int size, xmlNodePtr node, int glob) {
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004829 xmlNodePtr cur;
Daniel Veillardd3d06722001-08-15 12:06:36 +00004830 int len;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004831
4832 if (node == NULL) return;
4833 if (glob) strcat(buf, "(");
4834 cur = node;
4835 while (cur != NULL) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00004836 len = strlen(buf);
4837 if (size - len < 50) {
4838 if ((size - len > 4) && (buf[len - 1] != '.'))
4839 strcat(buf, " ...");
4840 return;
4841 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004842 switch (cur->type) {
4843 case XML_ELEMENT_NODE:
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004844 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00004845 if (size - len < xmlStrlen(cur->ns->prefix) + 10) {
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004846 if ((size - len > 4) && (buf[len - 1] != '.'))
4847 strcat(buf, " ...");
4848 return;
4849 }
4850 strcat(buf, (char *) cur->ns->prefix);
4851 strcat(buf, ":");
4852 }
Daniel Veillard4b3a84f2002-03-19 14:36:46 +00004853 if (size - len < xmlStrlen(cur->name) + 10) {
Daniel Veillardd3d06722001-08-15 12:06:36 +00004854 if ((size - len > 4) && (buf[len - 1] != '.'))
4855 strcat(buf, " ...");
4856 return;
4857 }
4858 strcat(buf, (char *) cur->name);
4859 if (cur->next != NULL)
4860 strcat(buf, " ");
4861 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004862 case XML_TEXT_NODE:
Daniel Veillardd3d06722001-08-15 12:06:36 +00004863 if (xmlIsBlankNode(cur))
4864 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004865 case XML_CDATA_SECTION_NODE:
4866 case XML_ENTITY_REF_NODE:
Daniel Veillardd3d06722001-08-15 12:06:36 +00004867 strcat(buf, "CDATA");
4868 if (cur->next != NULL)
4869 strcat(buf, " ");
4870 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004871 case XML_ATTRIBUTE_NODE:
4872 case XML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004873#ifdef LIBXML_DOCB_ENABLED
4874 case XML_DOCB_DOCUMENT_NODE:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004875#endif
4876 case XML_HTML_DOCUMENT_NODE:
4877 case XML_DOCUMENT_TYPE_NODE:
4878 case XML_DOCUMENT_FRAG_NODE:
4879 case XML_NOTATION_NODE:
4880 case XML_NAMESPACE_DECL:
Daniel Veillardd3d06722001-08-15 12:06:36 +00004881 strcat(buf, "???");
4882 if (cur->next != NULL)
4883 strcat(buf, " ");
4884 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004885 case XML_ENTITY_NODE:
4886 case XML_PI_NODE:
4887 case XML_DTD_NODE:
4888 case XML_COMMENT_NODE:
4889 case XML_ELEMENT_DECL:
4890 case XML_ATTRIBUTE_DECL:
4891 case XML_ENTITY_DECL:
4892 case XML_XINCLUDE_START:
4893 case XML_XINCLUDE_END:
Daniel Veillardd3d06722001-08-15 12:06:36 +00004894 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004895 }
4896 cur = cur->next;
4897 }
4898 if (glob) strcat(buf, ")");
4899}
4900
4901/**
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004902 * xmlValidateElementContent:
4903 * @ctxt: the validation context
4904 * @child: the child list
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004905 * @elemDecl: pointer to the element declaration
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00004906 * @warn: emit the error message
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00004907 * @parent: the parent element (for error reporting)
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004908 *
4909 * Try to validate the content model of an element
4910 *
4911 * returns 1 if valid or 0 if not and -1 in case of error
4912 */
4913
4914static int
4915xmlValidateElementContent(xmlValidCtxtPtr ctxt, xmlNodePtr child,
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00004916 xmlElementPtr elemDecl, int warn, xmlNodePtr parent) {
Daniel Veillard5acfd6b2002-09-18 16:29:02 +00004917 int ret = 1;
Daniel Veillard23e73572002-09-19 19:56:43 +00004918#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillard01992e02002-10-09 10:20:30 +00004919 xmlNodePtr repl = NULL, last = NULL, tmp;
Daniel Veillard23e73572002-09-19 19:56:43 +00004920#endif
Daniel Veillard01992e02002-10-09 10:20:30 +00004921 xmlNodePtr cur;
Daniel Veillardbe480fb2001-11-08 23:36:42 +00004922 xmlElementContentPtr cont;
4923 const xmlChar *name;
4924
4925 if (elemDecl == NULL)
4926 return(-1);
4927 cont = elemDecl->content;
4928 name = elemDecl->name;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00004929
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004930#ifdef LIBXML_REGEXP_ENABLED
4931 /* Build the regexp associated to the content model */
4932 if (elemDecl->contModel == NULL)
4933 ret = xmlValidBuildContentModel(ctxt, elemDecl);
4934 if (elemDecl->contModel == NULL) {
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00004935 return(-1);
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004936 } else {
4937 xmlRegExecCtxtPtr exec;
4938
Daniel Veillardec498e12003-02-05 11:01:50 +00004939 if (!xmlRegexpIsDeterminist(elemDecl->contModel)) {
4940 return(-1);
4941 }
Daniel Veillard01992e02002-10-09 10:20:30 +00004942 ctxt->nodeMax = 0;
4943 ctxt->nodeNr = 0;
4944 ctxt->nodeTab = NULL;
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004945 exec = xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
4946 if (exec != NULL) {
4947 cur = child;
4948 while (cur != NULL) {
4949 switch (cur->type) {
4950 case XML_ENTITY_REF_NODE:
4951 /*
4952 * Push the current node to be able to roll back
4953 * and process within the entity
4954 */
4955 if ((cur->children != NULL) &&
4956 (cur->children->children != NULL)) {
4957 nodeVPush(ctxt, cur);
4958 cur = cur->children->children;
4959 continue;
4960 }
4961 break;
4962 case XML_TEXT_NODE:
4963 if (xmlIsBlankNode(cur))
4964 break;
4965 ret = 0;
4966 goto fail;
4967 case XML_CDATA_SECTION_NODE:
Daniel Veillardea7751d2002-12-20 00:16:24 +00004968 /* TODO */
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004969 ret = 0;
4970 goto fail;
4971 case XML_ELEMENT_NODE:
4972 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00004973 xmlChar fn[50];
4974 xmlChar *fullname;
4975
4976 fullname = xmlBuildQName(cur->name,
4977 cur->ns->prefix, fn, 50);
4978 if (fullname == NULL) {
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004979 ret = -1;
4980 goto fail;
4981 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00004982 ret = xmlRegExecPushString(exec, fullname, NULL);
4983 if ((fullname != fn) && (fullname != cur->name))
4984 xmlFree(fullname);
Daniel Veillarda646cfd2002-09-17 21:50:03 +00004985 } else {
4986 ret = xmlRegExecPushString(exec, cur->name, NULL);
4987 }
4988 break;
4989 default:
4990 break;
4991 }
4992 /*
4993 * Switch to next element
4994 */
4995 cur = cur->next;
4996 while (cur == NULL) {
4997 cur = nodeVPop(ctxt);
4998 if (cur == NULL)
4999 break;
5000 cur = cur->next;
5001 }
5002 }
5003 ret = xmlRegExecPushString(exec, NULL, NULL);
5004fail:
5005 xmlRegFreeExecCtxt(exec);
5006 }
5007 }
5008#else /* LIBXML_REGEXP_ENABLED */
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005009 /*
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005010 * Allocate the stack
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005011 */
5012 ctxt->vstateMax = 8;
5013 ctxt->vstateTab = (xmlValidState *) xmlMalloc(
5014 ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
5015 if (ctxt->vstateTab == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00005016 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005017 return(-1);
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005018 }
5019 /*
5020 * The first entry in the stack is reserved to the current state
5021 */
Daniel Veillarda9142e72001-06-19 11:07:54 +00005022 ctxt->nodeMax = 0;
5023 ctxt->nodeNr = 0;
Daniel Veillard61b33d52001-04-24 13:55:12 +00005024 ctxt->nodeTab = NULL;
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005025 ctxt->vstate = &ctxt->vstateTab[0];
5026 ctxt->vstateNr = 1;
5027 CONT = cont;
5028 NODE = child;
5029 DEPTH = 0;
5030 OCCURS = 0;
5031 STATE = 0;
5032 ret = xmlValidateElementType(ctxt);
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005033 if ((ret == -3) && (warn)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005034 xmlErrValidWarning(ctxt, child, XML_DTD_CONTENT_NOT_DETERMINIST,
5035 "Content model for Element %s is ambiguous\n",
Daniel Veillard0cc72772003-10-13 14:00:21 +00005036 name, NULL, NULL);
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005037 } else if (ret == -2) {
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005038 /*
5039 * An entities reference appeared at this level.
5040 * Buid a minimal representation of this node content
5041 * sufficient to run the validation process on it
5042 */
5043 DEBUG_VALID_MSG("Found an entity reference, linearizing");
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005044 cur = child;
5045 while (cur != NULL) {
5046 switch (cur->type) {
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005047 case XML_ENTITY_REF_NODE:
5048 /*
5049 * Push the current node to be able to roll back
5050 * and process within the entity
5051 */
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005052 if ((cur->children != NULL) &&
5053 (cur->children->children != NULL)) {
5054 nodeVPush(ctxt, cur);
5055 cur = cur->children->children;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005056 continue;
5057 }
Daniel Veillard64b98c02001-06-17 17:20:21 +00005058 break;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005059 case XML_TEXT_NODE:
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005060 if (xmlIsBlankNode(cur))
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005061 break;
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005062 /* no break on purpose */
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00005063 case XML_CDATA_SECTION_NODE:
5064 /* no break on purpose */
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005065 case XML_ELEMENT_NODE:
5066 /*
5067 * Allocate a new node and minimally fills in
5068 * what's required
5069 */
5070 tmp = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
5071 if (tmp == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00005072 xmlVErrMemory(ctxt, "malloc failed");
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005073 xmlFreeNodeList(repl);
5074 ret = -1;
5075 goto done;
5076 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005077 tmp->type = cur->type;
5078 tmp->name = cur->name;
5079 tmp->ns = cur->ns;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005080 tmp->next = NULL;
Daniel Veillarded472f32001-12-13 08:48:14 +00005081 tmp->content = NULL;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005082 if (repl == NULL)
5083 repl = last = tmp;
5084 else {
5085 last->next = tmp;
5086 last = tmp;
5087 }
Daniel Veillardd6dc4cb2002-02-19 14:18:08 +00005088 if (cur->type == XML_CDATA_SECTION_NODE) {
5089 /*
5090 * E59 spaces in CDATA does not match the
5091 * nonterminal S
5092 */
5093 tmp->content = xmlStrdup(BAD_CAST "CDATA");
5094 }
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005095 break;
5096 default:
5097 break;
5098 }
5099 /*
5100 * Switch to next element
5101 */
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005102 cur = cur->next;
5103 while (cur == NULL) {
5104 cur = nodeVPop(ctxt);
5105 if (cur == NULL)
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005106 break;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005107 cur = cur->next;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005108 }
5109 }
5110
5111 /*
5112 * Relaunch the validation
5113 */
5114 ctxt->vstate = &ctxt->vstateTab[0];
5115 ctxt->vstateNr = 1;
5116 CONT = cont;
5117 NODE = repl;
5118 DEPTH = 0;
5119 OCCURS = 0;
5120 STATE = 0;
5121 ret = xmlValidateElementType(ctxt);
5122 }
Daniel Veillarda646cfd2002-09-17 21:50:03 +00005123#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005124 if ((warn) && ((ret != 1) && (ret != -3))) {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005125 if ((ctxt != NULL) && (ctxt->warning != NULL)) {
5126 char expr[5000];
5127 char list[5000];
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005128
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005129 expr[0] = 0;
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005130 xmlSnprintfElementContent(&expr[0], 5000, cont, 1);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005131 list[0] = 0;
Daniel Veillard01992e02002-10-09 10:20:30 +00005132#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005133 if (repl != NULL)
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005134 xmlSnprintfElements(&list[0], 5000, repl, 1);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005135 else
Daniel Veillard01992e02002-10-09 10:20:30 +00005136#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillarda76fe5c2003-04-24 16:06:47 +00005137 xmlSnprintfElements(&list[0], 5000, child, 1);
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005138
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005139 if (name != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005140 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5141 "Element %s content does not follow the DTD, expecting %s, got %s\n",
5142 name, BAD_CAST expr, BAD_CAST list);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005143 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005144 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5145 "Element content does not follow the DTD, expecting %s, got %s\n",
5146 BAD_CAST expr, BAD_CAST list, NULL);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005147 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005148 } else {
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005149 if (name != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005150 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
Daniel Veillard58e44c92002-08-02 22:19:49 +00005151 "Element %s content does not follow the DTD\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005152 name, NULL, NULL);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005153 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005154 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5155 "Element content does not follow the DTD\n",
5156 NULL, NULL, NULL);
Daniel Veillardb4545fd2001-11-20 09:37:09 +00005157 }
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005158 }
5159 ret = 0;
5160 }
Daniel Veillard4de4d3b2001-05-07 20:50:47 +00005161 if (ret == -3)
5162 ret = 1;
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005163
Daniel Veillard23e73572002-09-19 19:56:43 +00005164#ifndef LIBXML_REGEXP_ENABLED
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005165done:
5166 /*
5167 * Deallocate the copy if done, and free up the validation stack
5168 */
5169 while (repl != NULL) {
5170 tmp = repl->next;
5171 xmlFree(repl);
5172 repl = tmp;
5173 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005174 ctxt->vstateMax = 0;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005175 if (ctxt->vstateTab != NULL) {
5176 xmlFree(ctxt->vstateTab);
5177 ctxt->vstateTab = NULL;
5178 }
Daniel Veillard01992e02002-10-09 10:20:30 +00005179#endif
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005180 ctxt->nodeMax = 0;
Daniel Veillarda9142e72001-06-19 11:07:54 +00005181 ctxt->nodeNr = 0;
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00005182 if (ctxt->nodeTab != NULL) {
5183 xmlFree(ctxt->nodeTab);
5184 ctxt->nodeTab = NULL;
5185 }
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005186 return(ret);
Daniel Veillard1c14b8d2001-04-21 10:28:59 +00005187
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005188}
Daniel Veillarddab4cb32001-04-20 13:03:48 +00005189
Owen Taylor3473f882001-02-23 17:55:21 +00005190/**
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005191 * xmlValidateCdataElement:
5192 * @ctxt: the validation context
5193 * @doc: a document instance
5194 * @elem: an element instance
5195 *
5196 * Check that an element follows #CDATA
5197 *
5198 * returns 1 if valid or 0 otherwise
5199 */
5200static int
5201xmlValidateOneCdataElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5202 xmlNodePtr elem) {
5203 int ret = 1;
5204 xmlNodePtr cur, child;
5205
Daniel Veillardceb09b92002-10-04 11:46:37 +00005206 if ((ctxt == NULL) || (doc == NULL) || (elem == NULL))
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005207 return(0);
5208
5209 child = elem->children;
5210
5211 cur = child;
5212 while (cur != NULL) {
5213 switch (cur->type) {
5214 case XML_ENTITY_REF_NODE:
5215 /*
5216 * Push the current node to be able to roll back
5217 * and process within the entity
5218 */
5219 if ((cur->children != NULL) &&
5220 (cur->children->children != NULL)) {
5221 nodeVPush(ctxt, cur);
5222 cur = cur->children->children;
5223 continue;
5224 }
5225 break;
5226 case XML_COMMENT_NODE:
5227 case XML_PI_NODE:
5228 case XML_TEXT_NODE:
5229 case XML_CDATA_SECTION_NODE:
5230 break;
5231 default:
5232 ret = 0;
5233 goto done;
5234 }
5235 /*
5236 * Switch to next element
5237 */
5238 cur = cur->next;
5239 while (cur == NULL) {
5240 cur = nodeVPop(ctxt);
5241 if (cur == NULL)
5242 break;
5243 cur = cur->next;
5244 }
5245 }
5246done:
5247 ctxt->nodeMax = 0;
5248 ctxt->nodeNr = 0;
5249 if (ctxt->nodeTab != NULL) {
5250 xmlFree(ctxt->nodeTab);
5251 ctxt->nodeTab = NULL;
5252 }
5253 return(ret);
5254}
5255
5256/**
Daniel Veillardea7751d2002-12-20 00:16:24 +00005257 * xmlValidateCheckMixed:
5258 * @ctxt: the validation context
5259 * @cont: the mixed content model
5260 * @qname: the qualified name as appearing in the serialization
5261 *
5262 * Check if the given node is part of the content model.
5263 *
5264 * Returns 1 if yes, 0 if no, -1 in case of error
5265 */
5266static int
William M. Brackedb65a72004-02-06 07:36:04 +00005267xmlValidateCheckMixed(xmlValidCtxtPtr ctxt,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005268 xmlElementContentPtr cont, const xmlChar *qname) {
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005269 const xmlChar *name;
5270 int plen;
5271 name = xmlSplitQName3(qname, &plen);
5272
5273 if (name == NULL) {
5274 while (cont != NULL) {
5275 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5276 if ((cont->prefix == NULL) && (xmlStrEqual(cont->name, qname)))
5277 return(1);
5278 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5279 (cont->c1 != NULL) &&
5280 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5281 if ((cont->c1->prefix == NULL) &&
5282 (xmlStrEqual(cont->c1->name, qname)))
5283 return(1);
5284 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5285 (cont->c1 == NULL) ||
5286 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005287 xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT,
5288 "Internal: MIXED struct corrupted\n",
5289 NULL);
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005290 break;
5291 }
5292 cont = cont->c2;
Daniel Veillardea7751d2002-12-20 00:16:24 +00005293 }
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005294 } else {
5295 while (cont != NULL) {
5296 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5297 if ((cont->prefix != NULL) &&
5298 (xmlStrncmp(cont->prefix, qname, plen) == 0) &&
5299 (xmlStrEqual(cont->name, name)))
5300 return(1);
5301 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5302 (cont->c1 != NULL) &&
5303 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5304 if ((cont->c1->prefix != NULL) &&
5305 (xmlStrncmp(cont->c1->prefix, qname, plen) == 0) &&
5306 (xmlStrEqual(cont->c1->name, name)))
5307 return(1);
5308 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5309 (cont->c1 == NULL) ||
5310 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005311 xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT,
5312 "Internal: MIXED struct corrupted\n",
5313 NULL);
Daniel Veillard8d73bcb2003-08-04 01:06:15 +00005314 break;
5315 }
5316 cont = cont->c2;
5317 }
Daniel Veillardea7751d2002-12-20 00:16:24 +00005318 }
5319 return(0);
5320}
5321
5322/**
5323 * xmlValidGetElemDecl:
5324 * @ctxt: the validation context
5325 * @doc: a document instance
5326 * @elem: an element instance
5327 * @extsubset: pointer, (out) indicate if the declaration was found
5328 * in the external subset.
5329 *
5330 * Finds a declaration associated to an element in the document.
5331 *
5332 * returns the pointer to the declaration or NULL if not found.
5333 */
5334static xmlElementPtr
5335xmlValidGetElemDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5336 xmlNodePtr elem, int *extsubset) {
5337 xmlElementPtr elemDecl = NULL;
5338 const xmlChar *prefix = NULL;
5339
5340 if ((elem == NULL) || (elem->name == NULL)) return(NULL);
5341 if (extsubset != NULL)
5342 *extsubset = 0;
5343
5344 /*
5345 * Fetch the declaration for the qualified name
5346 */
5347 if ((elem->ns != NULL) && (elem->ns->prefix != NULL))
5348 prefix = elem->ns->prefix;
5349
5350 if (prefix != NULL) {
5351 elemDecl = xmlGetDtdQElementDesc(doc->intSubset,
5352 elem->name, prefix);
5353 if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5354 elemDecl = xmlGetDtdQElementDesc(doc->extSubset,
5355 elem->name, prefix);
5356 if ((elemDecl != NULL) && (extsubset != NULL))
5357 *extsubset = 1;
5358 }
5359 }
5360
5361 /*
5362 * Fetch the declaration for the non qualified name
5363 * This is "non-strict" validation should be done on the
5364 * full QName but in that case being flexible makes sense.
5365 */
5366 if (elemDecl == NULL) {
5367 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
5368 if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5369 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
5370 if ((elemDecl != NULL) && (extsubset != NULL))
5371 *extsubset = 1;
5372 }
5373 }
5374 if (elemDecl == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005375 xmlErrValidNode(ctxt, elem,
5376 XML_DTD_UNKNOWN_ELEM,
5377 "No declaration for element %s\n",
5378 elem->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005379 }
5380 return(elemDecl);
5381}
5382
Daniel Veillard0e298ad2003-02-04 16:14:33 +00005383#ifdef LIBXML_REGEXP_ENABLED
Daniel Veillardea7751d2002-12-20 00:16:24 +00005384/**
5385 * xmlValidatePushElement:
5386 * @ctxt: the validation context
5387 * @doc: a document instance
5388 * @elem: an element instance
5389 * @qname: the qualified name as appearing in the serialization
5390 *
5391 * Push a new element start on the validation stack.
5392 *
5393 * returns 1 if no validation problem was found or 0 otherwise
5394 */
5395int
5396xmlValidatePushElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5397 xmlNodePtr elem, const xmlChar *qname) {
5398 int ret = 1;
5399 xmlElementPtr eDecl;
5400 int extsubset = 0;
5401
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005402/* printf("PushElem %s\n", qname); */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005403 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5404 xmlValidStatePtr state = ctxt->vstate;
5405 xmlElementPtr elemDecl;
5406
5407 /*
5408 * Check the new element agaisnt the content model of the new elem.
5409 */
5410 if (state->elemDecl != NULL) {
5411 elemDecl = state->elemDecl;
5412
5413 switch(elemDecl->etype) {
5414 case XML_ELEMENT_TYPE_UNDEFINED:
5415 ret = 0;
5416 break;
5417 case XML_ELEMENT_TYPE_EMPTY:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005418 xmlErrValidNode(ctxt, state->node,
5419 XML_DTD_NOT_EMPTY,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005420 "Element %s was declared EMPTY this one has content\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005421 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005422 ret = 0;
5423 break;
5424 case XML_ELEMENT_TYPE_ANY:
5425 /* I don't think anything is required then */
5426 break;
5427 case XML_ELEMENT_TYPE_MIXED:
5428 /* simple case of declared as #PCDATA */
5429 if ((elemDecl->content != NULL) &&
5430 (elemDecl->content->type ==
5431 XML_ELEMENT_CONTENT_PCDATA)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005432 xmlErrValidNode(ctxt, state->node,
5433 XML_DTD_NOT_PCDATA,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005434 "Element %s was declared #PCDATA but contains non text nodes\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005435 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005436 ret = 0;
5437 } else {
5438 ret = xmlValidateCheckMixed(ctxt, elemDecl->content,
5439 qname);
5440 if (ret != 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005441 xmlErrValidNode(ctxt, state->node,
5442 XML_DTD_INVALID_CHILD,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005443 "Element %s is not declared in %s list of possible children\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005444 qname, state->node->name, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005445 }
5446 }
5447 break;
5448 case XML_ELEMENT_TYPE_ELEMENT:
5449 /*
5450 * TODO:
5451 * VC: Standalone Document Declaration
5452 * - element types with element content, if white space
5453 * occurs directly within any instance of those types.
5454 */
5455 if (state->exec != NULL) {
5456 ret = xmlRegExecPushString(state->exec, qname, NULL);
5457 if (ret < 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005458 xmlErrValidNode(ctxt, state->node,
5459 XML_DTD_CONTENT_MODEL,
5460 "Element %s content does not follow the DTD, Misplaced %s\n",
5461 state->node->name, qname, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005462 ret = 0;
5463 } else {
5464 ret = 1;
5465 }
5466 }
5467 break;
5468 }
5469 }
5470 }
5471 eDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
5472 vstateVPush(ctxt, eDecl, elem);
5473 return(ret);
5474}
5475
5476/**
5477 * xmlValidatePushCData:
5478 * @ctxt: the validation context
5479 * @data: some character data read
5480 * @len: the lenght of the data
5481 *
5482 * check the CData parsed for validation in the current stack
5483 *
5484 * returns 1 if no validation problem was found or 0 otherwise
5485 */
5486int
5487xmlValidatePushCData(xmlValidCtxtPtr ctxt, const xmlChar *data, int len) {
5488 int ret = 1;
5489
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005490/* printf("CDATA %s %d\n", data, len); */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005491 if (len <= 0)
5492 return(ret);
5493 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5494 xmlValidStatePtr state = ctxt->vstate;
5495 xmlElementPtr elemDecl;
5496
5497 /*
5498 * Check the new element agaisnt the content model of the new elem.
5499 */
5500 if (state->elemDecl != NULL) {
5501 elemDecl = state->elemDecl;
5502
5503 switch(elemDecl->etype) {
5504 case XML_ELEMENT_TYPE_UNDEFINED:
5505 ret = 0;
5506 break;
5507 case XML_ELEMENT_TYPE_EMPTY:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005508 xmlErrValidNode(ctxt, state->node,
5509 XML_DTD_NOT_EMPTY,
Daniel Veillardea7751d2002-12-20 00:16:24 +00005510 "Element %s was declared EMPTY this one has content\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005511 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005512 ret = 0;
5513 break;
5514 case XML_ELEMENT_TYPE_ANY:
5515 break;
5516 case XML_ELEMENT_TYPE_MIXED:
5517 break;
5518 case XML_ELEMENT_TYPE_ELEMENT:
5519 if (len > 0) {
5520 int i;
5521
5522 for (i = 0;i < len;i++) {
William M. Brack76e95df2003-10-18 16:20:14 +00005523 if (!IS_BLANK_CH(data[i])) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005524 xmlErrValidNode(ctxt, state->node,
5525 XML_DTD_CONTENT_MODEL,
5526 "Element %s content does not follow the DTD, Text not allowed\n",
5527 state->node->name, NULL, NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005528 ret = 0;
5529 goto done;
5530 }
5531 }
5532 /*
5533 * TODO:
5534 * VC: Standalone Document Declaration
5535 * element types with element content, if white space
5536 * occurs directly within any instance of those types.
5537 */
5538 }
5539 break;
5540 }
5541 }
5542 }
5543done:
5544 return(ret);
5545}
5546
5547/**
5548 * xmlValidatePopElement:
5549 * @ctxt: the validation context
5550 * @doc: a document instance
5551 * @elem: an element instance
5552 * @qname: the qualified name as appearing in the serialization
5553 *
5554 * Pop the element end from the validation stack.
5555 *
5556 * returns 1 if no validation problem was found or 0 otherwise
5557 */
5558int
5559xmlValidatePopElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc ATTRIBUTE_UNUSED,
Daniel Veillard580ced82003-03-21 21:22:48 +00005560 xmlNodePtr elem ATTRIBUTE_UNUSED,
5561 const xmlChar *qname ATTRIBUTE_UNUSED) {
Daniel Veillardea7751d2002-12-20 00:16:24 +00005562 int ret = 1;
5563
Daniel Veillardef8dd7b2003-03-23 12:02:56 +00005564/* printf("PopElem %s\n", qname); */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005565 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5566 xmlValidStatePtr state = ctxt->vstate;
5567 xmlElementPtr elemDecl;
5568
5569 /*
5570 * Check the new element agaisnt the content model of the new elem.
5571 */
5572 if (state->elemDecl != NULL) {
5573 elemDecl = state->elemDecl;
5574
5575 if (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT) {
5576 if (state->exec != NULL) {
5577 ret = xmlRegExecPushString(state->exec, NULL, NULL);
5578 if (ret == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005579 xmlErrValidNode(ctxt, state->node,
5580 XML_DTD_CONTENT_MODEL,
5581 "Element %s content does not follow the DTD, Expecting more child\n",
5582 state->node->name, NULL,NULL);
Daniel Veillardea7751d2002-12-20 00:16:24 +00005583 } else {
5584 /*
5585 * previous validation errors should not generate
5586 * a new one here
5587 */
5588 ret = 1;
5589 }
5590 }
5591 }
5592 }
5593 vstateVPop(ctxt);
5594 }
5595 return(ret);
5596}
Daniel Veillard0e298ad2003-02-04 16:14:33 +00005597#endif /* LIBXML_REGEXP_ENABLED */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005598
5599/**
Owen Taylor3473f882001-02-23 17:55:21 +00005600 * xmlValidateOneElement:
5601 * @ctxt: the validation context
5602 * @doc: a document instance
5603 * @elem: an element instance
5604 *
5605 * Try to validate a single element and it's attributes,
5606 * basically it does the following checks as described by the
5607 * XML-1.0 recommendation:
5608 * - [ VC: Element Valid ]
5609 * - [ VC: Required Attribute ]
5610 * Then call xmlValidateOneAttribute() for each attribute present.
5611 *
5612 * The ID/IDREF checkings are done separately
5613 *
5614 * returns 1 if valid or 0 otherwise
5615 */
5616
5617int
5618xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5619 xmlNodePtr elem) {
5620 xmlElementPtr elemDecl = NULL;
5621 xmlElementContentPtr cont;
5622 xmlAttributePtr attr;
5623 xmlNodePtr child;
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005624 int ret = 1, tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005625 const xmlChar *name;
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005626 int extsubset = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005627
5628 CHECK_DTD;
5629
5630 if (elem == NULL) return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005631 switch (elem->type) {
5632 case XML_ATTRIBUTE_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005633 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5634 "Attribute element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005635 return(0);
5636 case XML_TEXT_NODE:
5637 if (elem->children != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005638 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5639 "Text element has children !\n",
5640 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005641 return(0);
5642 }
5643 if (elem->properties != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005644 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5645 "Text element has attribute !\n",
5646 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005647 return(0);
5648 }
5649 if (elem->ns != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005650 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5651 "Text element has namespace !\n",
5652 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005653 return(0);
5654 }
5655 if (elem->nsDef != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005656 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5657 "Text element has namespace !\n",
5658 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005659 return(0);
5660 }
5661 if (elem->content == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005662 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5663 "Text element has no content !\n",
5664 NULL,NULL,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005665 return(0);
5666 }
5667 return(1);
5668 case XML_XINCLUDE_START:
5669 case XML_XINCLUDE_END:
5670 return(1);
5671 case XML_CDATA_SECTION_NODE:
5672 case XML_ENTITY_REF_NODE:
5673 case XML_PI_NODE:
5674 case XML_COMMENT_NODE:
5675 return(1);
5676 case XML_ENTITY_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005677 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5678 "Entity element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005679 return(0);
5680 case XML_NOTATION_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005681 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5682 "Notation element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005683 return(0);
5684 case XML_DOCUMENT_NODE:
5685 case XML_DOCUMENT_TYPE_NODE:
5686 case XML_DOCUMENT_FRAG_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005687 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5688 "Document element not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005689 return(0);
5690 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005691 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5692 "HTML Document not expected\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005693 return(0);
5694 case XML_ELEMENT_NODE:
5695 break;
5696 default:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005697 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
5698 "unknown element type\n", NULL, NULL ,NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005699 return(0);
5700 }
Owen Taylor3473f882001-02-23 17:55:21 +00005701
5702 /*
Daniel Veillardea7751d2002-12-20 00:16:24 +00005703 * Fetch the declaration
Owen Taylor3473f882001-02-23 17:55:21 +00005704 */
Daniel Veillardea7751d2002-12-20 00:16:24 +00005705 elemDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
5706 if (elemDecl == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00005707 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005708
Daniel Veillardea7751d2002-12-20 00:16:24 +00005709 /*
5710 * If vstateNr is not zero that means continuous validation is
5711 * activated, do not try to check the content model at that level.
5712 */
5713 if (ctxt->vstateNr == 0) {
Daniel Veillardcbaf3992001-12-31 16:16:02 +00005714 /* Check that the element content matches the definition */
Owen Taylor3473f882001-02-23 17:55:21 +00005715 switch (elemDecl->etype) {
Daniel Veillarda10efa82001-04-18 13:09:01 +00005716 case XML_ELEMENT_TYPE_UNDEFINED:
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005717 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ELEM,
5718 "No declaration for element %s\n",
5719 elem->name, NULL, NULL);
Daniel Veillarda10efa82001-04-18 13:09:01 +00005720 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005721 case XML_ELEMENT_TYPE_EMPTY:
5722 if (elem->children != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005723 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_EMPTY,
Owen Taylor3473f882001-02-23 17:55:21 +00005724 "Element %s was declared EMPTY this one has content\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005725 elem->name, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005726 ret = 0;
5727 }
5728 break;
5729 case XML_ELEMENT_TYPE_ANY:
5730 /* I don't think anything is required then */
5731 break;
5732 case XML_ELEMENT_TYPE_MIXED:
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005733
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005734 /* simple case of declared as #PCDATA */
5735 if ((elemDecl->content != NULL) &&
5736 (elemDecl->content->type == XML_ELEMENT_CONTENT_PCDATA)) {
5737 ret = xmlValidateOneCdataElement(ctxt, doc, elem);
5738 if (!ret) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005739 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_PCDATA,
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005740 "Element %s was declared #PCDATA but contains non text nodes\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005741 elem->name, NULL, NULL);
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005742 }
5743 break;
5744 }
Owen Taylor3473f882001-02-23 17:55:21 +00005745 child = elem->children;
Daniel Veillard04e2dae2001-07-09 20:07:25 +00005746 /* Hum, this start to get messy */
Owen Taylor3473f882001-02-23 17:55:21 +00005747 while (child != NULL) {
5748 if (child->type == XML_ELEMENT_NODE) {
5749 name = child->name;
5750 if ((child->ns != NULL) && (child->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00005751 xmlChar fn[50];
5752 xmlChar *fullname;
5753
5754 fullname = xmlBuildQName(child->name, child->ns->prefix,
5755 fn, 50);
5756 if (fullname == NULL)
5757 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00005758 cont = elemDecl->content;
5759 while (cont != NULL) {
5760 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00005761 if (xmlStrEqual(cont->name, fullname))
5762 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005763 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5764 (cont->c1 != NULL) &&
5765 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
Daniel Veillardc00cda82003-04-07 10:22:39 +00005766 if (xmlStrEqual(cont->c1->name, fullname))
5767 break;
Owen Taylor3473f882001-02-23 17:55:21 +00005768 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5769 (cont->c1 == NULL) ||
5770 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005771 xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT,
5772 "Internal: MIXED struct corrupted\n",
5773 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005774 break;
5775 }
5776 cont = cont->c2;
5777 }
Daniel Veillardc00cda82003-04-07 10:22:39 +00005778 if ((fullname != fn) && (fullname != child->name))
5779 xmlFree(fullname);
Owen Taylor3473f882001-02-23 17:55:21 +00005780 if (cont != NULL)
5781 goto child_ok;
5782 }
5783 cont = elemDecl->content;
5784 while (cont != NULL) {
5785 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5786 if (xmlStrEqual(cont->name, name)) break;
5787 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5788 (cont->c1 != NULL) &&
5789 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
5790 if (xmlStrEqual(cont->c1->name, name)) break;
5791 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5792 (cont->c1 == NULL) ||
5793 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00005794 xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT,
5795 "Internal: MIXED struct corrupted\n",
5796 NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005797 break;
5798 }
5799 cont = cont->c2;
5800 }
5801 if (cont == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005802 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_CHILD,
Daniel Veillard5e5c2d02002-02-09 18:03:01 +00005803 "Element %s is not declared in %s list of possible children\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005804 name, elem->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005805 ret = 0;
5806 }
5807 }
5808child_ok:
5809 child = child->next;
5810 }
5811 break;
5812 case XML_ELEMENT_TYPE_ELEMENT:
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005813 if ((doc->standalone == 1) && (extsubset == 1)) {
5814 /*
5815 * VC: Standalone Document Declaration
5816 * - element types with element content, if white space
5817 * occurs directly within any instance of those types.
5818 */
5819 child = elem->children;
5820 while (child != NULL) {
5821 if (child->type == XML_TEXT_NODE) {
5822 const xmlChar *content = child->content;
5823
William M. Brack76e95df2003-10-18 16:20:14 +00005824 while (IS_BLANK_CH(*content))
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005825 content++;
5826 if (*content == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005827 xmlErrValidNode(ctxt, elem,
5828 XML_DTD_STANDALONE_WHITE_SPACE,
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005829"standalone: %s declared in the external subset contains white spaces nodes\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005830 elem->name, NULL, NULL);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005831 ret = 0;
5832 break;
5833 }
5834 }
5835 child =child->next;
5836 }
5837 }
Owen Taylor3473f882001-02-23 17:55:21 +00005838 child = elem->children;
5839 cont = elemDecl->content;
Daniel Veillardb9cd8b42002-09-05 10:58:49 +00005840 tmp = xmlValidateElementContent(ctxt, child, elemDecl, 1, elem);
Daniel Veillard8dc16a62002-02-19 21:08:48 +00005841 if (tmp <= 0)
5842 ret = tmp;
Owen Taylor3473f882001-02-23 17:55:21 +00005843 break;
5844 }
Daniel Veillardea7751d2002-12-20 00:16:24 +00005845 } /* not continuous */
Owen Taylor3473f882001-02-23 17:55:21 +00005846
5847 /* [ VC: Required Attribute ] */
5848 attr = elemDecl->attributes;
5849 while (attr != NULL) {
5850 if (attr->def == XML_ATTRIBUTE_REQUIRED) {
Owen Taylor3473f882001-02-23 17:55:21 +00005851 int qualified = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00005852
Daniel Veillarde4301c82002-02-13 13:32:35 +00005853 if ((attr->prefix == NULL) &&
5854 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
5855 xmlNsPtr ns;
5856
5857 ns = elem->nsDef;
5858 while (ns != NULL) {
5859 if (ns->prefix == NULL)
Owen Taylor3473f882001-02-23 17:55:21 +00005860 goto found;
Daniel Veillarde4301c82002-02-13 13:32:35 +00005861 ns = ns->next;
Owen Taylor3473f882001-02-23 17:55:21 +00005862 }
Daniel Veillarde4301c82002-02-13 13:32:35 +00005863 } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
5864 xmlNsPtr ns;
5865
5866 ns = elem->nsDef;
5867 while (ns != NULL) {
5868 if (xmlStrEqual(attr->name, ns->prefix))
5869 goto found;
5870 ns = ns->next;
5871 }
5872 } else {
5873 xmlAttrPtr attrib;
5874
5875 attrib = elem->properties;
5876 while (attrib != NULL) {
5877 if (xmlStrEqual(attrib->name, attr->name)) {
5878 if (attr->prefix != NULL) {
5879 xmlNsPtr nameSpace = attrib->ns;
5880
5881 if (nameSpace == NULL)
5882 nameSpace = elem->ns;
5883 /*
5884 * qualified names handling is problematic, having a
5885 * different prefix should be possible but DTDs don't
5886 * allow to define the URI instead of the prefix :-(
5887 */
5888 if (nameSpace == NULL) {
5889 if (qualified < 0)
5890 qualified = 0;
5891 } else if (!xmlStrEqual(nameSpace->prefix,
5892 attr->prefix)) {
5893 if (qualified < 1)
5894 qualified = 1;
5895 } else
5896 goto found;
5897 } else {
5898 /*
5899 * We should allow applications to define namespaces
5900 * for their application even if the DTD doesn't
5901 * carry one, otherwise, basically we would always
5902 * break.
5903 */
5904 goto found;
5905 }
5906 }
5907 attrib = attrib->next;
5908 }
Owen Taylor3473f882001-02-23 17:55:21 +00005909 }
5910 if (qualified == -1) {
5911 if (attr->prefix == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005912 xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00005913 "Element %s does not carry attribute %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005914 elem->name, attr->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005915 ret = 0;
5916 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005917 xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00005918 "Element %s does not carry attribute %s:%s\n",
Owen Taylor3473f882001-02-23 17:55:21 +00005919 elem->name, attr->prefix,attr->name);
5920 ret = 0;
5921 }
5922 } else if (qualified == 0) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005923 xmlErrValidWarning(ctxt, elem, XML_DTD_NO_PREFIX,
Owen Taylor3473f882001-02-23 17:55:21 +00005924 "Element %s required attribute %s:%s has no prefix\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005925 elem->name, attr->prefix, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00005926 } else if (qualified == 1) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005927 xmlErrValidWarning(ctxt, elem, XML_DTD_DIFFERENT_PREFIX,
Owen Taylor3473f882001-02-23 17:55:21 +00005928 "Element %s required attribute %s:%s has different prefix\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005929 elem->name, attr->prefix, attr->name);
Owen Taylor3473f882001-02-23 17:55:21 +00005930 }
Daniel Veillarde4301c82002-02-13 13:32:35 +00005931 } else if (attr->def == XML_ATTRIBUTE_FIXED) {
5932 /*
5933 * Special tests checking #FIXED namespace declarations
5934 * have the right value since this is not done as an
5935 * attribute checking
5936 */
5937 if ((attr->prefix == NULL) &&
5938 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
5939 xmlNsPtr ns;
5940
5941 ns = elem->nsDef;
5942 while (ns != NULL) {
5943 if (ns->prefix == NULL) {
5944 if (!xmlStrEqual(attr->defaultValue, ns->href)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005945 xmlErrValidNode(ctxt, elem,
5946 XML_DTD_ELEM_DEFAULT_NAMESPACE,
Daniel Veillarde4301c82002-02-13 13:32:35 +00005947 "Element %s namespace name for default namespace does not match the DTD\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005948 elem->name, NULL, NULL);
Daniel Veillardc7612992002-02-17 22:47:37 +00005949 ret = 0;
Daniel Veillarde4301c82002-02-13 13:32:35 +00005950 }
5951 goto found;
5952 }
5953 ns = ns->next;
5954 }
5955 } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
5956 xmlNsPtr ns;
5957
5958 ns = elem->nsDef;
5959 while (ns != NULL) {
5960 if (xmlStrEqual(attr->name, ns->prefix)) {
5961 if (!xmlStrEqual(attr->defaultValue, ns->href)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005962 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
Daniel Veillard58e44c92002-08-02 22:19:49 +00005963 "Element %s namespace name for %s does not match the DTD\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00005964 elem->name, ns->prefix, NULL);
Daniel Veillardc7612992002-02-17 22:47:37 +00005965 ret = 0;
Daniel Veillarde4301c82002-02-13 13:32:35 +00005966 }
5967 goto found;
5968 }
5969 ns = ns->next;
5970 }
5971 }
Owen Taylor3473f882001-02-23 17:55:21 +00005972 }
5973found:
5974 attr = attr->nexth;
5975 }
5976 return(ret);
5977}
5978
5979/**
5980 * xmlValidateRoot:
5981 * @ctxt: the validation context
5982 * @doc: a document instance
5983 *
5984 * Try to validate a the root element
5985 * basically it does the following check as described by the
5986 * XML-1.0 recommendation:
5987 * - [ VC: Root Element Type ]
5988 * it doesn't try to recurse or apply other check to the element
5989 *
5990 * returns 1 if valid or 0 otherwise
5991 */
5992
5993int
5994xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
5995 xmlNodePtr root;
Daniel Veillardc00cda82003-04-07 10:22:39 +00005996 int ret;
5997
Owen Taylor3473f882001-02-23 17:55:21 +00005998 if (doc == NULL) return(0);
5999
6000 root = xmlDocGetRootElement(doc);
6001 if ((root == NULL) || (root->name == NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006002 xmlErrValid(ctxt, XML_DTD_NO_ROOT,
6003 "no root element\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006004 return(0);
6005 }
6006
6007 /*
6008 * When doing post validation against a separate DTD, those may
6009 * no internal subset has been generated
6010 */
6011 if ((doc->intSubset != NULL) &&
6012 (doc->intSubset->name != NULL)) {
6013 /*
6014 * Check first the document root against the NQName
6015 */
6016 if (!xmlStrEqual(doc->intSubset->name, root->name)) {
6017 if ((root->ns != NULL) && (root->ns->prefix != NULL)) {
Daniel Veillardc00cda82003-04-07 10:22:39 +00006018 xmlChar fn[50];
6019 xmlChar *fullname;
6020
6021 fullname = xmlBuildQName(root->name, root->ns->prefix, fn, 50);
6022 if (fullname == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00006023 xmlVErrMemory(ctxt, NULL);
Daniel Veillardc00cda82003-04-07 10:22:39 +00006024 return(0);
6025 }
6026 ret = xmlStrEqual(doc->intSubset->name, fullname);
6027 if ((fullname != fn) && (fullname != root->name))
6028 xmlFree(fullname);
6029 if (ret == 1)
Owen Taylor3473f882001-02-23 17:55:21 +00006030 goto name_ok;
6031 }
6032 if ((xmlStrEqual(doc->intSubset->name, BAD_CAST "HTML")) &&
6033 (xmlStrEqual(root->name, BAD_CAST "html")))
6034 goto name_ok;
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006035 xmlErrValidNode(ctxt, root, XML_DTD_ROOT_NAME,
6036 "root and DTD name do not match '%s' and '%s'\n",
6037 root->name, doc->intSubset->name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006038 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00006039 }
6040 }
6041name_ok:
6042 return(1);
6043}
6044
6045
6046/**
6047 * xmlValidateElement:
6048 * @ctxt: the validation context
6049 * @doc: a document instance
6050 * @elem: an element instance
6051 *
6052 * Try to validate the subtree under an element
6053 *
6054 * returns 1 if valid or 0 otherwise
6055 */
6056
6057int
6058xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
6059 xmlNodePtr child;
6060 xmlAttrPtr attr;
Daniel Veillarde133dd82003-10-30 10:42:20 +00006061 xmlNsPtr ns;
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006062 const xmlChar *value;
Owen Taylor3473f882001-02-23 17:55:21 +00006063 int ret = 1;
6064
6065 if (elem == NULL) return(0);
6066
6067 /*
6068 * XInclude elements were added after parsing in the infoset,
6069 * they don't really mean anything validation wise.
6070 */
6071 if ((elem->type == XML_XINCLUDE_START) ||
6072 (elem->type == XML_XINCLUDE_END))
6073 return(1);
6074
6075 CHECK_DTD;
6076
Daniel Veillard10ea86c2001-06-20 13:55:33 +00006077 /*
6078 * Entities references have to be handled separately
6079 */
6080 if (elem->type == XML_ENTITY_REF_NODE) {
6081 return(1);
6082 }
6083
Owen Taylor3473f882001-02-23 17:55:21 +00006084 ret &= xmlValidateOneElement(ctxt, doc, elem);
6085 attr = elem->properties;
Daniel Veillarde133dd82003-10-30 10:42:20 +00006086 while (attr != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00006087 value = xmlNodeListGetString(doc, attr->children, 0);
6088 ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
6089 if (value != NULL)
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006090 xmlFree((char *)value);
Owen Taylor3473f882001-02-23 17:55:21 +00006091 attr= attr->next;
6092 }
Daniel Veillarde133dd82003-10-30 10:42:20 +00006093 ns = elem->nsDef;
6094 while (ns != NULL) {
Daniel Veillard1f5c9892003-12-29 17:09:55 +00006095 if (elem->ns == NULL)
6096 ret &= xmlValidateOneNamespace(ctxt, doc, elem, NULL,
6097 ns, ns->href);
6098 else
6099 ret &= xmlValidateOneNamespace(ctxt, doc, elem, elem->ns->prefix,
6100 ns, ns->href);
Daniel Veillarde133dd82003-10-30 10:42:20 +00006101 ns = ns->next;
6102 }
Owen Taylor3473f882001-02-23 17:55:21 +00006103 child = elem->children;
6104 while (child != NULL) {
6105 ret &= xmlValidateElement(ctxt, doc, child);
6106 child = child->next;
6107 }
6108
6109 return(ret);
6110}
6111
Daniel Veillard8730c562001-02-26 10:49:57 +00006112/**
6113 * xmlValidateRef:
6114 * @ref: A reference to be validated
6115 * @ctxt: Validation context
6116 * @name: Name of ID we are searching for
6117 *
6118 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006119static void
Daniel Veillard8730c562001-02-26 10:49:57 +00006120xmlValidateRef(xmlRefPtr ref, xmlValidCtxtPtr ctxt,
Owen Taylor3473f882001-02-23 17:55:21 +00006121 const xmlChar *name) {
6122 xmlAttrPtr id;
6123 xmlAttrPtr attr;
6124
6125 if (ref == NULL)
6126 return;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006127 if ((ref->attr == NULL) && (ref->name == NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00006128 return;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006129 attr = ref->attr;
6130 if (attr == NULL) {
6131 xmlChar *dup, *str = NULL, *cur, save;
6132
6133 dup = xmlStrdup(name);
6134 if (dup == NULL) {
6135 ctxt->valid = 0;
6136 return;
6137 }
6138 cur = dup;
6139 while (*cur != 0) {
6140 str = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00006141 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006142 save = *cur;
6143 *cur = 0;
6144 id = xmlGetID(ctxt->doc, str);
6145 if (id == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006146 xmlErrValidNodeNr(ctxt, NULL, XML_DTD_UNKNOWN_ID,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006147 "attribute %s line %d references an unknown ID \"%s\"\n",
6148 ref->name, ref->lineno, str);
6149 ctxt->valid = 0;
6150 }
6151 if (save == 0)
6152 break;
6153 *cur = save;
William M. Brack76e95df2003-10-18 16:20:14 +00006154 while (IS_BLANK_CH(*cur)) cur++;
Daniel Veillardea7751d2002-12-20 00:16:24 +00006155 }
6156 xmlFree(dup);
6157 } else if (attr->atype == XML_ATTRIBUTE_IDREF) {
Owen Taylor3473f882001-02-23 17:55:21 +00006158 id = xmlGetID(ctxt->doc, name);
6159 if (id == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006160 xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006161 "IDREF attribute %s references an unknown ID \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006162 attr->name, name, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006163 ctxt->valid = 0;
6164 }
6165 } else if (attr->atype == XML_ATTRIBUTE_IDREFS) {
6166 xmlChar *dup, *str = NULL, *cur, save;
6167
6168 dup = xmlStrdup(name);
6169 if (dup == NULL) {
Daniel Veillardce9457f2003-10-05 21:33:18 +00006170 xmlVErrMemory(ctxt, "IDREFS split");
Owen Taylor3473f882001-02-23 17:55:21 +00006171 ctxt->valid = 0;
6172 return;
6173 }
6174 cur = dup;
6175 while (*cur != 0) {
6176 str = cur;
William M. Brack76e95df2003-10-18 16:20:14 +00006177 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00006178 save = *cur;
6179 *cur = 0;
6180 id = xmlGetID(ctxt->doc, str);
6181 if (id == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006182 xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
Daniel Veillardea7751d2002-12-20 00:16:24 +00006183 "IDREFS attribute %s references an unknown ID \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006184 attr->name, str, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006185 ctxt->valid = 0;
6186 }
6187 if (save == 0)
6188 break;
6189 *cur = save;
William M. Brack76e95df2003-10-18 16:20:14 +00006190 while (IS_BLANK_CH(*cur)) cur++;
Owen Taylor3473f882001-02-23 17:55:21 +00006191 }
6192 xmlFree(dup);
6193 }
6194}
6195
6196/**
Daniel Veillard8730c562001-02-26 10:49:57 +00006197 * xmlWalkValidateList:
6198 * @data: Contents of current link
6199 * @user: Value supplied by the user
6200 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00006201 * Returns 0 to abort the walk or 1 to continue
Daniel Veillard8730c562001-02-26 10:49:57 +00006202 */
6203static int
6204xmlWalkValidateList(const void *data, const void *user)
6205{
6206 xmlValidateMemoPtr memo = (xmlValidateMemoPtr)user;
6207 xmlValidateRef((xmlRefPtr)data, memo->ctxt, memo->name);
6208 return 1;
6209}
6210
6211/**
6212 * xmlValidateCheckRefCallback:
6213 * @ref_list: List of references
6214 * @ctxt: Validation context
6215 * @name: Name of ID we are searching for
6216 *
6217 */
6218static void
6219xmlValidateCheckRefCallback(xmlListPtr ref_list, xmlValidCtxtPtr ctxt,
6220 const xmlChar *name) {
6221 xmlValidateMemo memo;
6222
6223 if (ref_list == NULL)
6224 return;
6225 memo.ctxt = ctxt;
6226 memo.name = name;
6227
6228 xmlListWalk(ref_list, xmlWalkValidateList, &memo);
6229
6230}
6231
6232/**
Owen Taylor3473f882001-02-23 17:55:21 +00006233 * xmlValidateDocumentFinal:
6234 * @ctxt: the validation context
6235 * @doc: a document instance
6236 *
6237 * Does the final step for the document validation once all the
6238 * incremental validation steps have been completed
6239 *
6240 * basically it does the following checks described by the XML Rec
6241 *
Daniel Veillardc3da18a2003-03-18 00:31:04 +00006242 * Check all the IDREF/IDREFS attributes definition for validity
Owen Taylor3473f882001-02-23 17:55:21 +00006243 *
6244 * returns 1 if valid or 0 otherwise
6245 */
6246
6247int
6248xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6249 xmlRefTablePtr table;
6250
6251 if (doc == NULL) {
Daniel Veillard2b8c4a12003-10-02 22:28:19 +00006252 xmlErrValid(ctxt, XML_DTD_NO_DOC,
6253 "xmlValidateDocumentFinal: doc == NULL\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006254 return(0);
6255 }
6256
6257 /*
6258 * Check all the NOTATION/NOTATIONS attributes
6259 */
6260 /*
6261 * Check all the ENTITY/ENTITIES attributes definition for validity
6262 */
6263 /*
6264 * Check all the IDREF/IDREFS attributes definition for validity
6265 */
6266 table = (xmlRefTablePtr) doc->refs;
6267 ctxt->doc = doc;
6268 ctxt->valid = 1;
6269 xmlHashScan(table, (xmlHashScanner) xmlValidateCheckRefCallback, ctxt);
6270 return(ctxt->valid);
6271}
6272
6273/**
6274 * xmlValidateDtd:
6275 * @ctxt: the validation context
6276 * @doc: a document instance
6277 * @dtd: a dtd instance
6278 *
6279 * Try to validate the document against the dtd instance
6280 *
6281 * basically it does check all the definitions in the DtD.
6282 *
6283 * returns 1 if valid or 0 otherwise
6284 */
6285
6286int
6287xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
6288 int ret;
6289 xmlDtdPtr oldExt;
6290 xmlNodePtr root;
6291
6292 if (dtd == NULL) return(0);
6293 if (doc == NULL) return(0);
6294 oldExt = doc->extSubset;
6295 doc->extSubset = dtd;
6296 ret = xmlValidateRoot(ctxt, doc);
6297 if (ret == 0) {
6298 doc->extSubset = oldExt;
6299 return(ret);
6300 }
6301 if (doc->ids != NULL) {
6302 xmlFreeIDTable(doc->ids);
6303 doc->ids = NULL;
6304 }
6305 if (doc->refs != NULL) {
6306 xmlFreeRefTable(doc->refs);
6307 doc->refs = NULL;
6308 }
6309 root = xmlDocGetRootElement(doc);
6310 ret = xmlValidateElement(ctxt, doc, root);
6311 ret &= xmlValidateDocumentFinal(ctxt, doc);
6312 doc->extSubset = oldExt;
6313 return(ret);
6314}
6315
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006316static void
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006317xmlValidateNotationCallback(xmlEntityPtr cur, xmlValidCtxtPtr ctxt,
6318 const xmlChar *name ATTRIBUTE_UNUSED) {
6319 if (cur == NULL)
6320 return;
6321 if (cur->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
6322 xmlChar *notation = cur->content;
6323
Daniel Veillard878eab02002-02-19 13:46:09 +00006324 if (notation != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006325 int ret;
6326
6327 ret = xmlValidateNotationUse(ctxt, cur->doc, notation);
6328 if (ret != 1) {
Daniel Veillard878eab02002-02-19 13:46:09 +00006329 ctxt->valid = 0;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006330 }
6331 }
6332 }
6333}
6334
6335static void
Owen Taylor3473f882001-02-23 17:55:21 +00006336xmlValidateAttributeCallback(xmlAttributePtr cur, xmlValidCtxtPtr ctxt,
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00006337 const xmlChar *name ATTRIBUTE_UNUSED) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006338 int ret;
Daniel Veillard878eab02002-02-19 13:46:09 +00006339 xmlDocPtr doc;
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006340 xmlElementPtr elem = NULL;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006341
Owen Taylor3473f882001-02-23 17:55:21 +00006342 if (cur == NULL)
6343 return;
6344 switch (cur->atype) {
6345 case XML_ATTRIBUTE_CDATA:
6346 case XML_ATTRIBUTE_ID:
6347 case XML_ATTRIBUTE_IDREF :
6348 case XML_ATTRIBUTE_IDREFS:
6349 case XML_ATTRIBUTE_NMTOKEN:
6350 case XML_ATTRIBUTE_NMTOKENS:
6351 case XML_ATTRIBUTE_ENUMERATION:
6352 break;
6353 case XML_ATTRIBUTE_ENTITY:
6354 case XML_ATTRIBUTE_ENTITIES:
6355 case XML_ATTRIBUTE_NOTATION:
6356 if (cur->defaultValue != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006357
6358 ret = xmlValidateAttributeValue2(ctxt, ctxt->doc, cur->name,
6359 cur->atype, cur->defaultValue);
6360 if ((ret == 0) && (ctxt->valid == 1))
6361 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006362 }
6363 if (cur->tree != NULL) {
6364 xmlEnumerationPtr tree = cur->tree;
6365 while (tree != NULL) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006366 ret = xmlValidateAttributeValue2(ctxt, ctxt->doc,
Owen Taylor3473f882001-02-23 17:55:21 +00006367 cur->name, cur->atype, tree->name);
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006368 if ((ret == 0) && (ctxt->valid == 1))
6369 ctxt->valid = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006370 tree = tree->next;
6371 }
6372 }
6373 }
Daniel Veillard878eab02002-02-19 13:46:09 +00006374 if (cur->atype == XML_ATTRIBUTE_NOTATION) {
6375 doc = cur->doc;
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006376 if (cur->elem == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006377 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
Daniel Veillard878eab02002-02-19 13:46:09 +00006378 "xmlValidateAttributeCallback(%s): internal error\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006379 (const char *) cur->name);
Daniel Veillard878eab02002-02-19 13:46:09 +00006380 return;
6381 }
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006382
6383 if (doc != NULL)
6384 elem = xmlGetDtdElementDesc(doc->intSubset, cur->elem);
6385 if ((elem == NULL) && (doc != NULL))
Daniel Veillard878eab02002-02-19 13:46:09 +00006386 elem = xmlGetDtdElementDesc(doc->extSubset, cur->elem);
Daniel Veillarda8ff65d2003-11-03 16:20:10 +00006387 if ((elem == NULL) && (cur->parent != NULL) &&
6388 (cur->parent->type == XML_DTD_NODE))
6389 elem = xmlGetDtdElementDesc((xmlDtdPtr) cur->parent, cur->elem);
Daniel Veillard878eab02002-02-19 13:46:09 +00006390 if (elem == NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006391 xmlErrValidNode(ctxt, NULL, XML_DTD_UNKNOWN_ELEM,
Daniel Veillard878eab02002-02-19 13:46:09 +00006392 "attribute %s: could not find decl for element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006393 cur->name, cur->elem, NULL);
Daniel Veillard878eab02002-02-19 13:46:09 +00006394 return;
6395 }
6396 if (elem->etype == XML_ELEMENT_TYPE_EMPTY) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006397 xmlErrValidNode(ctxt, NULL, XML_DTD_EMPTY_NOTATION,
Daniel Veillard58e44c92002-08-02 22:19:49 +00006398 "NOTATION attribute %s declared for EMPTY element %s\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006399 cur->name, cur->elem, NULL);
Daniel Veillard878eab02002-02-19 13:46:09 +00006400 ctxt->valid = 0;
6401 }
6402 }
Owen Taylor3473f882001-02-23 17:55:21 +00006403}
6404
6405/**
6406 * xmlValidateDtdFinal:
6407 * @ctxt: the validation context
6408 * @doc: a document instance
6409 *
6410 * Does the final step for the dtds validation once all the
6411 * subsets have been parsed
6412 *
6413 * basically it does the following checks described by the XML Rec
6414 * - check that ENTITY and ENTITIES type attributes default or
6415 * possible values matches one of the defined entities.
6416 * - check that NOTATION type attributes default or
6417 * possible values matches one of the defined notations.
6418 *
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006419 * returns 1 if valid or 0 if invalid and -1 if not well-formed
Owen Taylor3473f882001-02-23 17:55:21 +00006420 */
6421
6422int
6423xmlValidateDtdFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
Owen Taylor3473f882001-02-23 17:55:21 +00006424 xmlDtdPtr dtd;
6425 xmlAttributeTablePtr table;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006426 xmlEntitiesTablePtr entities;
Owen Taylor3473f882001-02-23 17:55:21 +00006427
6428 if (doc == NULL) return(0);
6429 if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
6430 return(0);
6431 ctxt->doc = doc;
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006432 ctxt->valid = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006433 dtd = doc->intSubset;
6434 if ((dtd != NULL) && (dtd->attributes != NULL)) {
6435 table = (xmlAttributeTablePtr) dtd->attributes;
6436 xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt);
Daniel Veillard878eab02002-02-19 13:46:09 +00006437 }
6438 if ((dtd != NULL) && (dtd->entities != NULL)) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006439 entities = (xmlEntitiesTablePtr) dtd->entities;
6440 xmlHashScan(entities, (xmlHashScanner) xmlValidateNotationCallback,
6441 ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006442 }
6443 dtd = doc->extSubset;
6444 if ((dtd != NULL) && (dtd->attributes != NULL)) {
6445 table = (xmlAttributeTablePtr) dtd->attributes;
6446 xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt);
Daniel Veillard878eab02002-02-19 13:46:09 +00006447 }
6448 if ((dtd != NULL) && (dtd->entities != NULL)) {
Daniel Veillard8ab0f582002-02-18 18:31:38 +00006449 entities = (xmlEntitiesTablePtr) dtd->entities;
6450 xmlHashScan(entities, (xmlHashScanner) xmlValidateNotationCallback,
6451 ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006452 }
6453 return(ctxt->valid);
6454}
6455
6456/**
6457 * xmlValidateDocument:
6458 * @ctxt: the validation context
6459 * @doc: a document instance
6460 *
6461 * Try to validate the document instance
6462 *
6463 * basically it does the all the checks described by the XML Rec
6464 * i.e. validates the internal and external subset (if present)
6465 * and validate the document tree.
6466 *
6467 * returns 1 if valid or 0 otherwise
6468 */
6469
6470int
6471xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6472 int ret;
6473 xmlNodePtr root;
6474
Daniel Veillard2fd85422002-10-16 14:32:41 +00006475 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006476 xmlErrValid(ctxt, XML_DTD_NO_DTD,
6477 "no DTD found!\n", NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006478 return(0);
Daniel Veillard2fd85422002-10-16 14:32:41 +00006479 }
Owen Taylor3473f882001-02-23 17:55:21 +00006480 if ((doc->intSubset != NULL) && ((doc->intSubset->SystemID != NULL) ||
6481 (doc->intSubset->ExternalID != NULL)) && (doc->extSubset == NULL)) {
6482 doc->extSubset = xmlParseDTD(doc->intSubset->ExternalID,
6483 doc->intSubset->SystemID);
6484 if (doc->extSubset == NULL) {
6485 if (doc->intSubset->SystemID != NULL) {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006486 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
Owen Taylor3473f882001-02-23 17:55:21 +00006487 "Could not load the external subset \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006488 (const char *) doc->intSubset->SystemID);
Owen Taylor3473f882001-02-23 17:55:21 +00006489 } else {
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006490 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
Owen Taylor3473f882001-02-23 17:55:21 +00006491 "Could not load the external subset \"%s\"\n",
Daniel Veillardbb5abab2003-10-03 22:21:51 +00006492 (const char *) doc->intSubset->ExternalID);
Owen Taylor3473f882001-02-23 17:55:21 +00006493 }
6494 return(0);
6495 }
6496 }
6497
6498 if (doc->ids != NULL) {
6499 xmlFreeIDTable(doc->ids);
6500 doc->ids = NULL;
6501 }
6502 if (doc->refs != NULL) {
6503 xmlFreeRefTable(doc->refs);
6504 doc->refs = NULL;
6505 }
6506 ret = xmlValidateDtdFinal(ctxt, doc);
6507 if (!xmlValidateRoot(ctxt, doc)) return(0);
6508
6509 root = xmlDocGetRootElement(doc);
6510 ret &= xmlValidateElement(ctxt, doc, root);
6511 ret &= xmlValidateDocumentFinal(ctxt, doc);
6512 return(ret);
6513}
6514
Owen Taylor3473f882001-02-23 17:55:21 +00006515/************************************************************************
6516 * *
6517 * Routines for dynamic validation editing *
6518 * *
6519 ************************************************************************/
6520
6521/**
6522 * xmlValidGetPotentialChildren:
6523 * @ctree: an element content tree
6524 * @list: an array to store the list of child names
6525 * @len: a pointer to the number of element in the list
6526 * @max: the size of the array
6527 *
6528 * Build/extend a list of potential children allowed by the content tree
6529 *
6530 * returns the number of element in the list, or -1 in case of error.
6531 */
6532
6533int
6534xmlValidGetPotentialChildren(xmlElementContent *ctree, const xmlChar **list,
6535 int *len, int max) {
6536 int i;
6537
6538 if ((ctree == NULL) || (list == NULL) || (len == NULL))
6539 return(-1);
6540 if (*len >= max) return(*len);
6541
6542 switch (ctree->type) {
6543 case XML_ELEMENT_CONTENT_PCDATA:
6544 for (i = 0; i < *len;i++)
6545 if (xmlStrEqual(BAD_CAST "#PCDATA", list[i])) return(*len);
6546 list[(*len)++] = BAD_CAST "#PCDATA";
6547 break;
6548 case XML_ELEMENT_CONTENT_ELEMENT:
6549 for (i = 0; i < *len;i++)
6550 if (xmlStrEqual(ctree->name, list[i])) return(*len);
6551 list[(*len)++] = ctree->name;
6552 break;
6553 case XML_ELEMENT_CONTENT_SEQ:
6554 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
6555 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
6556 break;
6557 case XML_ELEMENT_CONTENT_OR:
6558 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
6559 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
6560 break;
6561 }
6562
6563 return(*len);
6564}
6565
6566/**
6567 * xmlValidGetValidElements:
6568 * @prev: an element to insert after
6569 * @next: an element to insert next
6570 * @list: an array to store the list of child names
6571 * @max: the size of the array
6572 *
6573 * This function returns the list of authorized children to insert
6574 * within an existing tree while respecting the validity constraints
6575 * forced by the Dtd. The insertion point is defined using @prev and
6576 * @next in the following ways:
6577 * to insert before 'node': xmlValidGetValidElements(node->prev, node, ...
6578 * to insert next 'node': xmlValidGetValidElements(node, node->next, ...
6579 * to replace 'node': xmlValidGetValidElements(node->prev, node->next, ...
6580 * to prepend a child to 'node': xmlValidGetValidElements(NULL, node->childs,
6581 * to append a child to 'node': xmlValidGetValidElements(node->last, NULL, ...
6582 *
6583 * pointers to the element names are inserted at the beginning of the array
6584 * and do not need to be freed.
6585 *
6586 * returns the number of element in the list, or -1 in case of error. If
6587 * the function returns the value @max the caller is invited to grow the
6588 * receiving array and retry.
6589 */
6590
6591int
6592xmlValidGetValidElements(xmlNode *prev, xmlNode *next, const xmlChar **list,
6593 int max) {
Daniel Veillardf69bb4b2001-05-19 13:24:56 +00006594 xmlValidCtxt vctxt;
Owen Taylor3473f882001-02-23 17:55:21 +00006595 int nb_valid_elements = 0;
6596 const xmlChar *elements[256];
6597 int nb_elements = 0, i;
Daniel Veillard5e5c2d02002-02-09 18:03:01 +00006598 const xmlChar *name;
Owen Taylor3473f882001-02-23 17:55:21 +00006599
6600 xmlNode *ref_node;
6601 xmlNode *parent;
6602 xmlNode *test_node;
6603
6604 xmlNode *prev_next;
6605 xmlNode *next_prev;
6606 xmlNode *parent_childs;
6607 xmlNode *parent_last;
6608
6609 xmlElement *element_desc;
6610
Daniel Veillardbb4e46d2002-03-10 16:49:08 +00006611 memset(&vctxt, 0, sizeof (xmlValidCtxt));
Daniel Veillardf69bb4b2001-05-19 13:24:56 +00006612
Owen Taylor3473f882001-02-23 17:55:21 +00006613 if (prev == NULL && next == NULL)
6614 return(-1);
6615
6616 if (list == NULL) return(-1);
6617 if (max <= 0) return(-1);
6618
6619 nb_valid_elements = 0;
6620 ref_node = prev ? prev : next;
6621 parent = ref_node->parent;
6622
6623 /*
6624 * Retrieves the parent element declaration
6625 */
6626 element_desc = xmlGetDtdElementDesc(parent->doc->intSubset,
6627 parent->name);
6628 if ((element_desc == NULL) && (parent->doc->extSubset != NULL))
6629 element_desc = xmlGetDtdElementDesc(parent->doc->extSubset,
6630 parent->name);
6631 if (element_desc == NULL) return(-1);
6632
6633 /*
6634 * Do a backup of the current tree structure
6635 */
6636 prev_next = prev ? prev->next : NULL;
6637 next_prev = next ? next->prev : NULL;
6638 parent_childs = parent->children;
6639 parent_last = parent->last;
6640
6641 /*
6642 * Creates a dummy node and insert it into the tree
6643 */
6644 test_node = xmlNewNode (NULL, BAD_CAST "<!dummy?>");
6645 test_node->doc = ref_node->doc;
6646 test_node->parent = parent;
6647 test_node->prev = prev;
6648 test_node->next = next;
Daniel Veillardd455d792002-02-08 13:37:46 +00006649 name = test_node->name;
Owen Taylor3473f882001-02-23 17:55:21 +00006650
6651 if (prev) prev->next = test_node;
6652 else parent->children = test_node;
6653
6654 if (next) next->prev = test_node;
6655 else parent->last = test_node;
6656
6657 /*
6658 * Insert each potential child node and check if the parent is
6659 * still valid
6660 */
6661 nb_elements = xmlValidGetPotentialChildren(element_desc->content,
6662 elements, &nb_elements, 256);
6663
6664 for (i = 0;i < nb_elements;i++) {
6665 test_node->name = elements[i];
Daniel Veillardf69bb4b2001-05-19 13:24:56 +00006666 if (xmlValidateOneElement(&vctxt, parent->doc, parent)) {
Owen Taylor3473f882001-02-23 17:55:21 +00006667 int j;
6668
6669 for (j = 0; j < nb_valid_elements;j++)
6670 if (xmlStrEqual(elements[i], list[j])) break;
6671 list[nb_valid_elements++] = elements[i];
6672 if (nb_valid_elements >= max) break;
6673 }
6674 }
6675
6676 /*
6677 * Restore the tree structure
6678 */
6679 if (prev) prev->next = prev_next;
6680 if (next) next->prev = next_prev;
6681 parent->children = parent_childs;
6682 parent->last = parent_last;
Daniel Veillardd455d792002-02-08 13:37:46 +00006683
6684 /*
6685 * Free up the dummy node
6686 */
6687 test_node->name = name;
6688 xmlFreeNode(test_node);
6689
Owen Taylor3473f882001-02-23 17:55:21 +00006690 return(nb_valid_elements);
6691}
Daniel Veillard4432df22003-09-28 18:58:27 +00006692#endif /* LIBXML_VALID_ENABLED */
6693