• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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  *
7  * daniel@veillard.com
8  */
9 
10 #define IN_LIBXML
11 #include "libxml.h"
12 
13 #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/uri.h>
22 #include <libxml/valid.h>
23 #include <libxml/parser.h>
24 #include <libxml/parserInternals.h>
25 #include <libxml/xmlerror.h>
26 #include <libxml/list.h>
27 #include <libxml/globals.h>
28 
29 static xmlElementPtr xmlGetDtdElementDesc2(xmlDtdPtr dtd, const xmlChar *name,
30 	                           int create);
31 /* #define DEBUG_VALID_ALGO */
32 /* #define DEBUG_REGEXP_ALGO */
33 
34 #define TODO								\
35     xmlGenericError(xmlGenericErrorContext,				\
36 	    "Unimplemented block at %s:%d\n",				\
37             __FILE__, __LINE__);
38 
39 #ifdef LIBXML_VALID_ENABLED
40 static int
41 xmlValidateAttributeValueInternal(xmlDocPtr doc, xmlAttributeType type,
42                                   const xmlChar *value);
43 #endif
44 /************************************************************************
45  *									*
46  *			Error handling routines				*
47  *									*
48  ************************************************************************/
49 
50 /**
51  * xmlVErrMemory:
52  * @ctxt:  an XML validation parser context
53  * @extra:  extra information
54  *
55  * Handle an out of memory error
56  */
57 static void
xmlVErrMemory(xmlValidCtxtPtr ctxt,const char * extra)58 xmlVErrMemory(xmlValidCtxtPtr ctxt, const char *extra)
59 {
60     xmlGenericErrorFunc channel = NULL;
61     xmlParserCtxtPtr pctxt = NULL;
62     void *data = NULL;
63 
64     if (ctxt != NULL) {
65         channel = ctxt->error;
66         data = ctxt->userData;
67 	/* Use the special values to detect if it is part of a parsing
68 	   context */
69 	if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
70 	    (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
71 	    long delta = (char *) ctxt - (char *) ctxt->userData;
72 	    if ((delta > 0) && (delta < 250))
73 		pctxt = ctxt->userData;
74 	}
75     }
76     if (extra)
77         __xmlRaiseError(NULL, channel, data,
78                         pctxt, NULL, XML_FROM_VALID, XML_ERR_NO_MEMORY,
79                         XML_ERR_FATAL, NULL, 0, extra, NULL, NULL, 0, 0,
80                         "Memory allocation failed : %s\n", extra);
81     else
82         __xmlRaiseError(NULL, channel, data,
83                         pctxt, NULL, XML_FROM_VALID, XML_ERR_NO_MEMORY,
84                         XML_ERR_FATAL, NULL, 0, NULL, NULL, NULL, 0, 0,
85                         "Memory allocation failed\n");
86 }
87 
88 /**
89  * xmlErrValid:
90  * @ctxt:  an XML validation parser context
91  * @error:  the error number
92  * @extra:  extra information
93  *
94  * Handle a validation error
95  */
96 static void LIBXML_ATTR_FORMAT(3,0)
xmlErrValid(xmlValidCtxtPtr ctxt,xmlParserErrors error,const char * msg,const char * extra)97 xmlErrValid(xmlValidCtxtPtr ctxt, xmlParserErrors error,
98             const char *msg, const char *extra)
99 {
100     xmlGenericErrorFunc channel = NULL;
101     xmlParserCtxtPtr pctxt = NULL;
102     void *data = NULL;
103 
104     if (ctxt != NULL) {
105         channel = ctxt->error;
106         data = ctxt->userData;
107 	/* Use the special values to detect if it is part of a parsing
108 	   context */
109 	if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
110 	    (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
111 	    long delta = (char *) ctxt - (char *) ctxt->userData;
112 	    if ((delta > 0) && (delta < 250))
113 		pctxt = ctxt->userData;
114 	}
115     }
116     if (extra)
117         __xmlRaiseError(NULL, channel, data,
118                         pctxt, NULL, XML_FROM_VALID, error,
119                         XML_ERR_ERROR, NULL, 0, extra, NULL, NULL, 0, 0,
120                         msg, extra);
121     else
122         __xmlRaiseError(NULL, channel, data,
123                         pctxt, NULL, XML_FROM_VALID, error,
124                         XML_ERR_ERROR, NULL, 0, NULL, NULL, NULL, 0, 0,
125                         "%s", msg);
126 }
127 
128 #if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
129 /**
130  * xmlErrValidNode:
131  * @ctxt:  an XML validation parser context
132  * @node:  the node raising the error
133  * @error:  the error number
134  * @str1:  extra information
135  * @str2:  extra information
136  * @str3:  extra information
137  *
138  * Handle a validation error, provide contextual information
139  */
140 static void LIBXML_ATTR_FORMAT(4,0)
xmlErrValidNode(xmlValidCtxtPtr ctxt,xmlNodePtr node,xmlParserErrors error,const char * msg,const xmlChar * str1,const xmlChar * str2,const xmlChar * str3)141 xmlErrValidNode(xmlValidCtxtPtr ctxt,
142                 xmlNodePtr node, xmlParserErrors error,
143                 const char *msg, const xmlChar * str1,
144                 const xmlChar * str2, const xmlChar * str3)
145 {
146     xmlStructuredErrorFunc schannel = NULL;
147     xmlGenericErrorFunc channel = NULL;
148     xmlParserCtxtPtr pctxt = NULL;
149     void *data = NULL;
150 
151     if (ctxt != NULL) {
152         channel = ctxt->error;
153         data = ctxt->userData;
154 	/* Use the special values to detect if it is part of a parsing
155 	   context */
156 	if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
157 	    (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
158 	    long delta = (char *) ctxt - (char *) ctxt->userData;
159 	    if ((delta > 0) && (delta < 250))
160 		pctxt = ctxt->userData;
161 	}
162     }
163     __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
164                     XML_ERR_ERROR, NULL, 0,
165                     (const char *) str1,
166                     (const char *) str2,
167                     (const char *) str3, 0, 0, msg, str1, str2, str3);
168 }
169 #endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */
170 
171 #ifdef LIBXML_VALID_ENABLED
172 /**
173  * xmlErrValidNodeNr:
174  * @ctxt:  an XML validation parser context
175  * @node:  the node raising the error
176  * @error:  the error number
177  * @str1:  extra information
178  * @int2:  extra information
179  * @str3:  extra information
180  *
181  * Handle a validation error, provide contextual information
182  */
183 static void LIBXML_ATTR_FORMAT(4,0)
xmlErrValidNodeNr(xmlValidCtxtPtr ctxt,xmlNodePtr node,xmlParserErrors error,const char * msg,const xmlChar * str1,int int2,const xmlChar * str3)184 xmlErrValidNodeNr(xmlValidCtxtPtr ctxt,
185                 xmlNodePtr node, xmlParserErrors error,
186                 const char *msg, const xmlChar * str1,
187                 int int2, const xmlChar * str3)
188 {
189     xmlStructuredErrorFunc schannel = NULL;
190     xmlGenericErrorFunc channel = NULL;
191     xmlParserCtxtPtr pctxt = NULL;
192     void *data = NULL;
193 
194     if (ctxt != NULL) {
195         channel = ctxt->error;
196         data = ctxt->userData;
197 	/* Use the special values to detect if it is part of a parsing
198 	   context */
199 	if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
200 	    (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
201 	    long delta = (char *) ctxt - (char *) ctxt->userData;
202 	    if ((delta > 0) && (delta < 250))
203 		pctxt = ctxt->userData;
204 	}
205     }
206     __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
207                     XML_ERR_ERROR, NULL, 0,
208                     (const char *) str1,
209                     (const char *) str3,
210                     NULL, int2, 0, msg, str1, int2, str3);
211 }
212 
213 /**
214  * xmlErrValidWarning:
215  * @ctxt:  an XML validation parser context
216  * @node:  the node raising the error
217  * @error:  the error number
218  * @str1:  extra information
219  * @str2:  extra information
220  * @str3:  extra information
221  *
222  * Handle a validation error, provide contextual information
223  */
224 static void LIBXML_ATTR_FORMAT(4,0)
xmlErrValidWarning(xmlValidCtxtPtr ctxt,xmlNodePtr node,xmlParserErrors error,const char * msg,const xmlChar * str1,const xmlChar * str2,const xmlChar * str3)225 xmlErrValidWarning(xmlValidCtxtPtr ctxt,
226                 xmlNodePtr node, xmlParserErrors error,
227                 const char *msg, const xmlChar * str1,
228                 const xmlChar * str2, const xmlChar * str3)
229 {
230     xmlStructuredErrorFunc schannel = NULL;
231     xmlGenericErrorFunc channel = NULL;
232     xmlParserCtxtPtr pctxt = NULL;
233     void *data = NULL;
234 
235     if (ctxt != NULL) {
236         channel = ctxt->warning;
237         data = ctxt->userData;
238 	/* Use the special values to detect if it is part of a parsing
239 	   context */
240 	if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
241 	    (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
242 	    long delta = (char *) ctxt - (char *) ctxt->userData;
243 	    if ((delta > 0) && (delta < 250))
244 		pctxt = ctxt->userData;
245 	}
246     }
247     __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
248                     XML_ERR_WARNING, NULL, 0,
249                     (const char *) str1,
250                     (const char *) str2,
251                     (const char *) str3, 0, 0, msg, str1, str2, str3);
252 }
253 
254 
255 
256 #ifdef LIBXML_REGEXP_ENABLED
257 /*
258  * If regexp are enabled we can do continuous validation without the
259  * need of a tree to validate the content model. this is done in each
260  * callbacks.
261  * Each xmlValidState represent the validation state associated to the
262  * set of nodes currently open from the document root to the current element.
263  */
264 
265 
266 typedef struct _xmlValidState {
267     xmlElementPtr	 elemDecl;	/* pointer to the content model */
268     xmlNodePtr           node;		/* pointer to the current node */
269     xmlRegExecCtxtPtr    exec;		/* regexp runtime */
270 } _xmlValidState;
271 
272 
273 static int
vstateVPush(xmlValidCtxtPtr ctxt,xmlElementPtr elemDecl,xmlNodePtr node)274 vstateVPush(xmlValidCtxtPtr ctxt, xmlElementPtr elemDecl, xmlNodePtr node) {
275     if ((ctxt->vstateMax == 0) || (ctxt->vstateTab == NULL)) {
276 	ctxt->vstateMax = 10;
277 	ctxt->vstateTab = (xmlValidState *) xmlMalloc(ctxt->vstateMax *
278 		              sizeof(ctxt->vstateTab[0]));
279         if (ctxt->vstateTab == NULL) {
280 	    xmlVErrMemory(ctxt, "malloc failed");
281 	    return(-1);
282 	}
283     }
284 
285     if (ctxt->vstateNr >= ctxt->vstateMax) {
286         xmlValidState *tmp;
287 
288 	tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
289 	             2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
290         if (tmp == NULL) {
291 	    xmlVErrMemory(ctxt, "realloc failed");
292 	    return(-1);
293 	}
294 	ctxt->vstateMax *= 2;
295 	ctxt->vstateTab = tmp;
296     }
297     ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr];
298     ctxt->vstateTab[ctxt->vstateNr].elemDecl = elemDecl;
299     ctxt->vstateTab[ctxt->vstateNr].node = node;
300     if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) {
301 	if (elemDecl->contModel == NULL)
302 	    xmlValidBuildContentModel(ctxt, elemDecl);
303 	if (elemDecl->contModel != NULL) {
304 	    ctxt->vstateTab[ctxt->vstateNr].exec =
305 		xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
306 	} else {
307 	    ctxt->vstateTab[ctxt->vstateNr].exec = NULL;
308 	    xmlErrValidNode(ctxt, (xmlNodePtr) elemDecl,
309 	                    XML_ERR_INTERNAL_ERROR,
310 			    "Failed to build content model regexp for %s\n",
311 			    node->name, NULL, NULL);
312 	}
313     }
314     return(ctxt->vstateNr++);
315 }
316 
317 static int
vstateVPop(xmlValidCtxtPtr ctxt)318 vstateVPop(xmlValidCtxtPtr ctxt) {
319     xmlElementPtr elemDecl;
320 
321     if (ctxt->vstateNr < 1) return(-1);
322     ctxt->vstateNr--;
323     elemDecl = ctxt->vstateTab[ctxt->vstateNr].elemDecl;
324     ctxt->vstateTab[ctxt->vstateNr].elemDecl = NULL;
325     ctxt->vstateTab[ctxt->vstateNr].node = NULL;
326     if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) {
327 	xmlRegFreeExecCtxt(ctxt->vstateTab[ctxt->vstateNr].exec);
328     }
329     ctxt->vstateTab[ctxt->vstateNr].exec = NULL;
330     if (ctxt->vstateNr >= 1)
331 	ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr - 1];
332     else
333 	ctxt->vstate = NULL;
334     return(ctxt->vstateNr);
335 }
336 
337 #else /* not LIBXML_REGEXP_ENABLED */
338 /*
339  * If regexp are not enabled, it uses a home made algorithm less
340  * complex and easier to
341  * debug/maintain than a generic NFA -> DFA state based algo. The
342  * only restriction is on the deepness of the tree limited by the
343  * size of the occurs bitfield
344  *
345  * this is the content of a saved state for rollbacks
346  */
347 
348 #define ROLLBACK_OR	0
349 #define ROLLBACK_PARENT	1
350 
351 typedef struct _xmlValidState {
352     xmlElementContentPtr cont;	/* pointer to the content model subtree */
353     xmlNodePtr           node;	/* pointer to the current node in the list */
354     long                 occurs;/* bitfield for multiple occurrences */
355     unsigned char        depth; /* current depth in the overall tree */
356     unsigned char        state; /* ROLLBACK_XXX */
357 } _xmlValidState;
358 
359 #define MAX_RECURSE 25000
360 #define MAX_DEPTH ((sizeof(_xmlValidState.occurs)) * 8)
361 #define CONT ctxt->vstate->cont
362 #define NODE ctxt->vstate->node
363 #define DEPTH ctxt->vstate->depth
364 #define OCCURS ctxt->vstate->occurs
365 #define STATE ctxt->vstate->state
366 
367 #define OCCURRENCE (ctxt->vstate->occurs & (1 << DEPTH))
368 #define PARENT_OCCURRENCE (ctxt->vstate->occurs & ((1 << DEPTH) - 1))
369 
370 #define SET_OCCURRENCE ctxt->vstate->occurs |= (1 << DEPTH)
371 #define RESET_OCCURRENCE ctxt->vstate->occurs &= ((1 << DEPTH) - 1)
372 
373 static int
vstateVPush(xmlValidCtxtPtr ctxt,xmlElementContentPtr cont,xmlNodePtr node,unsigned char depth,long occurs,unsigned char state)374 vstateVPush(xmlValidCtxtPtr ctxt, xmlElementContentPtr cont,
375 	    xmlNodePtr node, unsigned char depth, long occurs,
376 	    unsigned char state) {
377     int i = ctxt->vstateNr - 1;
378 
379     if (ctxt->vstateNr > MAX_RECURSE) {
380 	return(-1);
381     }
382     if (ctxt->vstateTab == NULL) {
383 	ctxt->vstateMax = 8;
384 	ctxt->vstateTab = (xmlValidState *) xmlMalloc(
385 		     ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
386 	if (ctxt->vstateTab == NULL) {
387 	    xmlVErrMemory(ctxt, "malloc failed");
388 	    return(-1);
389 	}
390     }
391     if (ctxt->vstateNr >= ctxt->vstateMax) {
392         xmlValidState *tmp;
393 
394         tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
395 	             2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
396         if (tmp == NULL) {
397 	    xmlVErrMemory(ctxt, "malloc failed");
398 	    return(-1);
399 	}
400 	ctxt->vstateMax *= 2;
401 	ctxt->vstateTab = tmp;
402 	ctxt->vstate = &ctxt->vstateTab[0];
403     }
404     /*
405      * Don't push on the stack a state already here
406      */
407     if ((i >= 0) && (ctxt->vstateTab[i].cont == cont) &&
408 	(ctxt->vstateTab[i].node == node) &&
409 	(ctxt->vstateTab[i].depth == depth) &&
410 	(ctxt->vstateTab[i].occurs == occurs) &&
411 	(ctxt->vstateTab[i].state == state))
412 	return(ctxt->vstateNr);
413     ctxt->vstateTab[ctxt->vstateNr].cont = cont;
414     ctxt->vstateTab[ctxt->vstateNr].node = node;
415     ctxt->vstateTab[ctxt->vstateNr].depth = depth;
416     ctxt->vstateTab[ctxt->vstateNr].occurs = occurs;
417     ctxt->vstateTab[ctxt->vstateNr].state = state;
418     return(ctxt->vstateNr++);
419 }
420 
421 static int
vstateVPop(xmlValidCtxtPtr ctxt)422 vstateVPop(xmlValidCtxtPtr ctxt) {
423     if (ctxt->vstateNr <= 1) return(-1);
424     ctxt->vstateNr--;
425     ctxt->vstate = &ctxt->vstateTab[0];
426     ctxt->vstate->cont =  ctxt->vstateTab[ctxt->vstateNr].cont;
427     ctxt->vstate->node = ctxt->vstateTab[ctxt->vstateNr].node;
428     ctxt->vstate->depth = ctxt->vstateTab[ctxt->vstateNr].depth;
429     ctxt->vstate->occurs = ctxt->vstateTab[ctxt->vstateNr].occurs;
430     ctxt->vstate->state = ctxt->vstateTab[ctxt->vstateNr].state;
431     return(ctxt->vstateNr);
432 }
433 
434 #endif /* LIBXML_REGEXP_ENABLED */
435 
436 static int
nodeVPush(xmlValidCtxtPtr ctxt,xmlNodePtr value)437 nodeVPush(xmlValidCtxtPtr ctxt, xmlNodePtr value)
438 {
439     if (ctxt->nodeMax <= 0) {
440         ctxt->nodeMax = 4;
441         ctxt->nodeTab =
442             (xmlNodePtr *) xmlMalloc(ctxt->nodeMax *
443                                      sizeof(ctxt->nodeTab[0]));
444         if (ctxt->nodeTab == NULL) {
445 	    xmlVErrMemory(ctxt, "malloc failed");
446             ctxt->nodeMax = 0;
447             return (0);
448         }
449     }
450     if (ctxt->nodeNr >= ctxt->nodeMax) {
451         xmlNodePtr *tmp;
452         tmp = (xmlNodePtr *) xmlRealloc(ctxt->nodeTab,
453 			      ctxt->nodeMax * 2 * sizeof(ctxt->nodeTab[0]));
454         if (tmp == NULL) {
455 	    xmlVErrMemory(ctxt, "realloc failed");
456             return (0);
457         }
458         ctxt->nodeMax *= 2;
459 	ctxt->nodeTab = tmp;
460     }
461     ctxt->nodeTab[ctxt->nodeNr] = value;
462     ctxt->node = value;
463     return (ctxt->nodeNr++);
464 }
465 static xmlNodePtr
nodeVPop(xmlValidCtxtPtr ctxt)466 nodeVPop(xmlValidCtxtPtr ctxt)
467 {
468     xmlNodePtr ret;
469 
470     if (ctxt->nodeNr <= 0)
471         return (NULL);
472     ctxt->nodeNr--;
473     if (ctxt->nodeNr > 0)
474         ctxt->node = ctxt->nodeTab[ctxt->nodeNr - 1];
475     else
476         ctxt->node = NULL;
477     ret = ctxt->nodeTab[ctxt->nodeNr];
478     ctxt->nodeTab[ctxt->nodeNr] = NULL;
479     return (ret);
480 }
481 
482 /**
483  * xmlValidNormalizeString:
484  * @str: a string
485  *
486  * Normalize a string in-place.
487  */
488 static void
xmlValidNormalizeString(xmlChar * str)489 xmlValidNormalizeString(xmlChar *str) {
490     xmlChar *dst;
491     const xmlChar *src;
492 
493     if (str == NULL)
494         return;
495     src = str;
496     dst = str;
497 
498     while (*src == 0x20) src++;
499     while (*src != 0) {
500 	if (*src == 0x20) {
501 	    while (*src == 0x20) src++;
502 	    if (*src != 0)
503 		*dst++ = 0x20;
504 	} else {
505 	    *dst++ = *src++;
506 	}
507     }
508     *dst = 0;
509 }
510 
511 #ifdef DEBUG_VALID_ALGO
512 static void
xmlValidPrintNode(xmlNodePtr cur)513 xmlValidPrintNode(xmlNodePtr cur) {
514     if (cur == NULL) {
515 	xmlGenericError(xmlGenericErrorContext, "null");
516 	return;
517     }
518     switch (cur->type) {
519 	case XML_ELEMENT_NODE:
520 	    xmlGenericError(xmlGenericErrorContext, "%s ", cur->name);
521 	    break;
522 	case XML_TEXT_NODE:
523 	    xmlGenericError(xmlGenericErrorContext, "text ");
524 	    break;
525 	case XML_CDATA_SECTION_NODE:
526 	    xmlGenericError(xmlGenericErrorContext, "cdata ");
527 	    break;
528 	case XML_ENTITY_REF_NODE:
529 	    xmlGenericError(xmlGenericErrorContext, "&%s; ", cur->name);
530 	    break;
531 	case XML_PI_NODE:
532 	    xmlGenericError(xmlGenericErrorContext, "pi(%s) ", cur->name);
533 	    break;
534 	case XML_COMMENT_NODE:
535 	    xmlGenericError(xmlGenericErrorContext, "comment ");
536 	    break;
537 	case XML_ATTRIBUTE_NODE:
538 	    xmlGenericError(xmlGenericErrorContext, "?attr? ");
539 	    break;
540 	case XML_ENTITY_NODE:
541 	    xmlGenericError(xmlGenericErrorContext, "?ent? ");
542 	    break;
543 	case XML_DOCUMENT_NODE:
544 	    xmlGenericError(xmlGenericErrorContext, "?doc? ");
545 	    break;
546 	case XML_DOCUMENT_TYPE_NODE:
547 	    xmlGenericError(xmlGenericErrorContext, "?doctype? ");
548 	    break;
549 	case XML_DOCUMENT_FRAG_NODE:
550 	    xmlGenericError(xmlGenericErrorContext, "?frag? ");
551 	    break;
552 	case XML_NOTATION_NODE:
553 	    xmlGenericError(xmlGenericErrorContext, "?nota? ");
554 	    break;
555 	case XML_HTML_DOCUMENT_NODE:
556 	    xmlGenericError(xmlGenericErrorContext, "?html? ");
557 	    break;
558 #ifdef LIBXML_DOCB_ENABLED
559 	case XML_DOCB_DOCUMENT_NODE:
560 	    xmlGenericError(xmlGenericErrorContext, "?docb? ");
561 	    break;
562 #endif
563 	case XML_DTD_NODE:
564 	    xmlGenericError(xmlGenericErrorContext, "?dtd? ");
565 	    break;
566 	case XML_ELEMENT_DECL:
567 	    xmlGenericError(xmlGenericErrorContext, "?edecl? ");
568 	    break;
569 	case XML_ATTRIBUTE_DECL:
570 	    xmlGenericError(xmlGenericErrorContext, "?adecl? ");
571 	    break;
572 	case XML_ENTITY_DECL:
573 	    xmlGenericError(xmlGenericErrorContext, "?entdecl? ");
574 	    break;
575 	case XML_NAMESPACE_DECL:
576 	    xmlGenericError(xmlGenericErrorContext, "?nsdecl? ");
577 	    break;
578 	case XML_XINCLUDE_START:
579 	    xmlGenericError(xmlGenericErrorContext, "incstart ");
580 	    break;
581 	case XML_XINCLUDE_END:
582 	    xmlGenericError(xmlGenericErrorContext, "incend ");
583 	    break;
584     }
585 }
586 
587 static void
xmlValidPrintNodeList(xmlNodePtr cur)588 xmlValidPrintNodeList(xmlNodePtr cur) {
589     if (cur == NULL)
590 	xmlGenericError(xmlGenericErrorContext, "null ");
591     while (cur != NULL) {
592 	xmlValidPrintNode(cur);
593 	cur = cur->next;
594     }
595 }
596 
597 static void
xmlValidDebug(xmlNodePtr cur,xmlElementContentPtr cont)598 xmlValidDebug(xmlNodePtr cur, xmlElementContentPtr cont) {
599     char expr[5000];
600 
601     expr[0] = 0;
602     xmlGenericError(xmlGenericErrorContext, "valid: ");
603     xmlValidPrintNodeList(cur);
604     xmlGenericError(xmlGenericErrorContext, "against ");
605     xmlSnprintfElementContent(expr, 5000, cont, 1);
606     xmlGenericError(xmlGenericErrorContext, "%s\n", expr);
607 }
608 
609 static void
xmlValidDebugState(xmlValidStatePtr state)610 xmlValidDebugState(xmlValidStatePtr state) {
611     xmlGenericError(xmlGenericErrorContext, "(");
612     if (state->cont == NULL)
613 	xmlGenericError(xmlGenericErrorContext, "null,");
614     else
615 	switch (state->cont->type) {
616             case XML_ELEMENT_CONTENT_PCDATA:
617 		xmlGenericError(xmlGenericErrorContext, "pcdata,");
618 		break;
619             case XML_ELEMENT_CONTENT_ELEMENT:
620 		xmlGenericError(xmlGenericErrorContext, "%s,",
621 			        state->cont->name);
622 		break;
623             case XML_ELEMENT_CONTENT_SEQ:
624 		xmlGenericError(xmlGenericErrorContext, "seq,");
625 		break;
626             case XML_ELEMENT_CONTENT_OR:
627 		xmlGenericError(xmlGenericErrorContext, "or,");
628 		break;
629 	}
630     xmlValidPrintNode(state->node);
631     xmlGenericError(xmlGenericErrorContext, ",%d,%X,%d)",
632 	    state->depth, state->occurs, state->state);
633 }
634 
635 static void
xmlValidStateDebug(xmlValidCtxtPtr ctxt)636 xmlValidStateDebug(xmlValidCtxtPtr ctxt) {
637     int i, j;
638 
639     xmlGenericError(xmlGenericErrorContext, "state: ");
640     xmlValidDebugState(ctxt->vstate);
641     xmlGenericError(xmlGenericErrorContext, " stack: %d ",
642 	    ctxt->vstateNr - 1);
643     for (i = 0, j = ctxt->vstateNr - 1;(i < 3) && (j > 0);i++,j--)
644 	xmlValidDebugState(&ctxt->vstateTab[j]);
645     xmlGenericError(xmlGenericErrorContext, "\n");
646 }
647 
648 /*****
649 #define DEBUG_VALID_STATE(n,c) xmlValidDebug(n,c);
650  *****/
651 
652 #define DEBUG_VALID_STATE(n,c) xmlValidStateDebug(ctxt);
653 #define DEBUG_VALID_MSG(m)					\
654     xmlGenericError(xmlGenericErrorContext, "%s\n", m);
655 
656 #else
657 #define DEBUG_VALID_STATE(n,c)
658 #define DEBUG_VALID_MSG(m)
659 #endif
660 
661 /* TODO: use hash table for accesses to elem and attribute definitions */
662 
663 
664 #define CHECK_DTD						\
665    if (doc == NULL) return(0);					\
666    else if ((doc->intSubset == NULL) &&				\
667 	    (doc->extSubset == NULL)) return(0)
668 
669 #ifdef LIBXML_REGEXP_ENABLED
670 
671 /************************************************************************
672  *									*
673  *		Content model validation based on the regexps		*
674  *									*
675  ************************************************************************/
676 
677 /**
678  * xmlValidBuildAContentModel:
679  * @content:  the content model
680  * @ctxt:  the schema parser context
681  * @name:  the element name whose content is being built
682  *
683  * Generate the automata sequence needed for that type
684  *
685  * Returns 1 if successful or 0 in case of error.
686  */
687 static int
xmlValidBuildAContentModel(xmlElementContentPtr content,xmlValidCtxtPtr ctxt,const xmlChar * name)688 xmlValidBuildAContentModel(xmlElementContentPtr content,
689 		           xmlValidCtxtPtr ctxt,
690 		           const xmlChar *name) {
691     if (content == NULL) {
692 	xmlErrValidNode(ctxt, NULL, XML_ERR_INTERNAL_ERROR,
693 			"Found NULL content in content model of %s\n",
694 			name, NULL, NULL);
695 	return(0);
696     }
697     switch (content->type) {
698 	case XML_ELEMENT_CONTENT_PCDATA:
699 	    xmlErrValidNode(ctxt, NULL, XML_ERR_INTERNAL_ERROR,
700 			    "Found PCDATA in content model of %s\n",
701 		            name, NULL, NULL);
702 	    return(0);
703 	    break;
704 	case XML_ELEMENT_CONTENT_ELEMENT: {
705 	    xmlAutomataStatePtr oldstate = ctxt->state;
706 	    xmlChar fn[50];
707 	    xmlChar *fullname;
708 
709 	    fullname = xmlBuildQName(content->name, content->prefix, fn, 50);
710 	    if (fullname == NULL) {
711 	        xmlVErrMemory(ctxt, "Building content model");
712 		return(0);
713 	    }
714 
715 	    switch (content->ocur) {
716 		case XML_ELEMENT_CONTENT_ONCE:
717 		    ctxt->state = xmlAutomataNewTransition(ctxt->am,
718 			    ctxt->state, NULL, fullname, NULL);
719 		    break;
720 		case XML_ELEMENT_CONTENT_OPT:
721 		    ctxt->state = xmlAutomataNewTransition(ctxt->am,
722 			    ctxt->state, NULL, fullname, NULL);
723 		    xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
724 		    break;
725 		case XML_ELEMENT_CONTENT_PLUS:
726 		    ctxt->state = xmlAutomataNewTransition(ctxt->am,
727 			    ctxt->state, NULL, fullname, NULL);
728 		    xmlAutomataNewTransition(ctxt->am, ctxt->state,
729 			                     ctxt->state, fullname, NULL);
730 		    break;
731 		case XML_ELEMENT_CONTENT_MULT:
732 		    ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
733 					    ctxt->state, NULL);
734 		    xmlAutomataNewTransition(ctxt->am,
735 			    ctxt->state, ctxt->state, fullname, NULL);
736 		    break;
737 	    }
738 	    if ((fullname != fn) && (fullname != content->name))
739 		xmlFree(fullname);
740 	    break;
741 	}
742 	case XML_ELEMENT_CONTENT_SEQ: {
743 	    xmlAutomataStatePtr oldstate, oldend;
744 	    xmlElementContentOccur ocur;
745 
746 	    /*
747 	     * Simply iterate over the content
748 	     */
749 	    oldstate = ctxt->state;
750 	    ocur = content->ocur;
751 	    if (ocur != XML_ELEMENT_CONTENT_ONCE) {
752 		ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
753 		oldstate = ctxt->state;
754 	    }
755 	    do {
756 		xmlValidBuildAContentModel(content->c1, ctxt, name);
757 		content = content->c2;
758 	    } while ((content->type == XML_ELEMENT_CONTENT_SEQ) &&
759 		     (content->ocur == XML_ELEMENT_CONTENT_ONCE));
760 	    xmlValidBuildAContentModel(content, ctxt, name);
761 	    oldend = ctxt->state;
762 	    ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL);
763 	    switch (ocur) {
764 		case XML_ELEMENT_CONTENT_ONCE:
765 		    break;
766 		case XML_ELEMENT_CONTENT_OPT:
767 		    xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
768 		    break;
769 		case XML_ELEMENT_CONTENT_MULT:
770 		    xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
771 		    xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
772 		    break;
773 		case XML_ELEMENT_CONTENT_PLUS:
774 		    xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
775 		    break;
776 	    }
777 	    break;
778 	}
779 	case XML_ELEMENT_CONTENT_OR: {
780 	    xmlAutomataStatePtr oldstate, oldend;
781 	    xmlElementContentOccur ocur;
782 
783 	    ocur = content->ocur;
784 	    if ((ocur == XML_ELEMENT_CONTENT_PLUS) ||
785 		(ocur == XML_ELEMENT_CONTENT_MULT)) {
786 		ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
787 			ctxt->state, NULL);
788 	    }
789 	    oldstate = ctxt->state;
790 	    oldend = xmlAutomataNewState(ctxt->am);
791 
792 	    /*
793 	     * iterate over the subtypes and remerge the end with an
794 	     * epsilon transition
795 	     */
796 	    do {
797 		ctxt->state = oldstate;
798 		xmlValidBuildAContentModel(content->c1, ctxt, name);
799 		xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend);
800 		content = content->c2;
801 	    } while ((content->type == XML_ELEMENT_CONTENT_OR) &&
802 		     (content->ocur == XML_ELEMENT_CONTENT_ONCE));
803 	    ctxt->state = oldstate;
804 	    xmlValidBuildAContentModel(content, ctxt, name);
805 	    xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend);
806 	    ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL);
807 	    switch (ocur) {
808 		case XML_ELEMENT_CONTENT_ONCE:
809 		    break;
810 		case XML_ELEMENT_CONTENT_OPT:
811 		    xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
812 		    break;
813 		case XML_ELEMENT_CONTENT_MULT:
814 		    xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
815 		    xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
816 		    break;
817 		case XML_ELEMENT_CONTENT_PLUS:
818 		    xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
819 		    break;
820 	    }
821 	    break;
822 	}
823 	default:
824 	    xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
825 	                "ContentModel broken for element %s\n",
826 			(const char *) name);
827 	    return(0);
828     }
829     return(1);
830 }
831 /**
832  * xmlValidBuildContentModel:
833  * @ctxt:  a validation context
834  * @elem:  an element declaration node
835  *
836  * (Re)Build the automata associated to the content model of this
837  * element
838  *
839  * Returns 1 in case of success, 0 in case of error
840  */
841 int
xmlValidBuildContentModel(xmlValidCtxtPtr ctxt,xmlElementPtr elem)842 xmlValidBuildContentModel(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
843 
844     if ((ctxt == NULL) || (elem == NULL))
845 	return(0);
846     if (elem->type != XML_ELEMENT_DECL)
847 	return(0);
848     if (elem->etype != XML_ELEMENT_TYPE_ELEMENT)
849 	return(1);
850     /* TODO: should we rebuild in this case ? */
851     if (elem->contModel != NULL) {
852 	if (!xmlRegexpIsDeterminist(elem->contModel)) {
853 	    ctxt->valid = 0;
854 	    return(0);
855 	}
856 	return(1);
857     }
858 
859     ctxt->am = xmlNewAutomata();
860     if (ctxt->am == NULL) {
861 	xmlErrValidNode(ctxt, (xmlNodePtr) elem,
862 	                XML_ERR_INTERNAL_ERROR,
863 	                "Cannot create automata for element %s\n",
864 		        elem->name, NULL, NULL);
865 	return(0);
866     }
867     ctxt->state = xmlAutomataGetInitState(ctxt->am);
868     xmlValidBuildAContentModel(elem->content, ctxt, elem->name);
869     xmlAutomataSetFinalState(ctxt->am, ctxt->state);
870     elem->contModel = xmlAutomataCompile(ctxt->am);
871     if (xmlRegexpIsDeterminist(elem->contModel) != 1) {
872 	char expr[5000];
873 	expr[0] = 0;
874 	xmlSnprintfElementContent(expr, 5000, elem->content, 1);
875 	xmlErrValidNode(ctxt, (xmlNodePtr) elem,
876 	                XML_DTD_CONTENT_NOT_DETERMINIST,
877 	       "Content model of %s is not determinist: %s\n",
878 	       elem->name, BAD_CAST expr, NULL);
879 #ifdef DEBUG_REGEXP_ALGO
880         xmlRegexpPrint(stderr, elem->contModel);
881 #endif
882         ctxt->valid = 0;
883 	ctxt->state = NULL;
884 	xmlFreeAutomata(ctxt->am);
885 	ctxt->am = NULL;
886 	return(0);
887     }
888     ctxt->state = NULL;
889     xmlFreeAutomata(ctxt->am);
890     ctxt->am = NULL;
891     return(1);
892 }
893 
894 #endif /* LIBXML_REGEXP_ENABLED */
895 
896 /****************************************************************
897  *								*
898  *	Util functions for data allocation/deallocation		*
899  *								*
900  ****************************************************************/
901 
902 /**
903  * xmlNewValidCtxt:
904  *
905  * Allocate a validation context structure.
906  *
907  * Returns NULL if not, otherwise the new validation context structure
908  */
xmlNewValidCtxt(void)909 xmlValidCtxtPtr xmlNewValidCtxt(void) {
910     xmlValidCtxtPtr ret;
911 
912     if ((ret = xmlMalloc(sizeof (xmlValidCtxt))) == NULL) {
913 	xmlVErrMemory(NULL, "malloc failed");
914 	return (NULL);
915     }
916 
917     (void) memset(ret, 0, sizeof (xmlValidCtxt));
918 
919     return (ret);
920 }
921 
922 /**
923  * xmlFreeValidCtxt:
924  * @cur:  the validation context to free
925  *
926  * Free a validation context structure.
927  */
928 void
xmlFreeValidCtxt(xmlValidCtxtPtr cur)929 xmlFreeValidCtxt(xmlValidCtxtPtr cur) {
930     if (cur->vstateTab != NULL)
931         xmlFree(cur->vstateTab);
932     if (cur->nodeTab != NULL)
933         xmlFree(cur->nodeTab);
934     xmlFree(cur);
935 }
936 
937 #endif /* LIBXML_VALID_ENABLED */
938 
939 /**
940  * xmlNewDocElementContent:
941  * @doc:  the document
942  * @name:  the subelement name or NULL
943  * @type:  the type of element content decl
944  *
945  * Allocate an element content structure for the document.
946  *
947  * Returns NULL if not, otherwise the new element content structure
948  */
949 xmlElementContentPtr
xmlNewDocElementContent(xmlDocPtr doc,const xmlChar * name,xmlElementContentType type)950 xmlNewDocElementContent(xmlDocPtr doc, const xmlChar *name,
951                         xmlElementContentType type) {
952     xmlElementContentPtr ret;
953     xmlDictPtr dict = NULL;
954 
955     if (doc != NULL)
956         dict = doc->dict;
957 
958     switch(type) {
959 	case XML_ELEMENT_CONTENT_ELEMENT:
960 	    if (name == NULL) {
961 	        xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
962 			"xmlNewElementContent : name == NULL !\n",
963 			NULL);
964 	    }
965 	    break;
966         case XML_ELEMENT_CONTENT_PCDATA:
967 	case XML_ELEMENT_CONTENT_SEQ:
968 	case XML_ELEMENT_CONTENT_OR:
969 	    if (name != NULL) {
970 	        xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
971 			"xmlNewElementContent : name != NULL !\n",
972 			NULL);
973 	    }
974 	    break;
975 	default:
976 	    xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
977 		    "Internal: ELEMENT content corrupted invalid type\n",
978 		    NULL);
979 	    return(NULL);
980     }
981     ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
982     if (ret == NULL) {
983 	xmlVErrMemory(NULL, "malloc failed");
984 	return(NULL);
985     }
986     memset(ret, 0, sizeof(xmlElementContent));
987     ret->type = type;
988     ret->ocur = XML_ELEMENT_CONTENT_ONCE;
989     if (name != NULL) {
990         int l;
991 	const xmlChar *tmp;
992 
993 	tmp = xmlSplitQName3(name, &l);
994 	if (tmp == NULL) {
995 	    if (dict == NULL)
996 		ret->name = xmlStrdup(name);
997 	    else
998 	        ret->name = xmlDictLookup(dict, name, -1);
999 	} else {
1000 	    if (dict == NULL) {
1001 		ret->prefix = xmlStrndup(name, l);
1002 		ret->name = xmlStrdup(tmp);
1003 	    } else {
1004 	        ret->prefix = xmlDictLookup(dict, name, l);
1005 		ret->name = xmlDictLookup(dict, tmp, -1);
1006 	    }
1007 	}
1008     }
1009     return(ret);
1010 }
1011 
1012 /**
1013  * xmlNewElementContent:
1014  * @name:  the subelement name or NULL
1015  * @type:  the type of element content decl
1016  *
1017  * Allocate an element content structure.
1018  * Deprecated in favor of xmlNewDocElementContent
1019  *
1020  * Returns NULL if not, otherwise the new element content structure
1021  */
1022 xmlElementContentPtr
xmlNewElementContent(const xmlChar * name,xmlElementContentType type)1023 xmlNewElementContent(const xmlChar *name, xmlElementContentType type) {
1024     return(xmlNewDocElementContent(NULL, name, type));
1025 }
1026 
1027 /**
1028  * xmlCopyDocElementContent:
1029  * @doc:  the document owning the element declaration
1030  * @cur:  An element content pointer.
1031  *
1032  * Build a copy of an element content description.
1033  *
1034  * Returns the new xmlElementContentPtr or NULL in case of error.
1035  */
1036 xmlElementContentPtr
xmlCopyDocElementContent(xmlDocPtr doc,xmlElementContentPtr cur)1037 xmlCopyDocElementContent(xmlDocPtr doc, xmlElementContentPtr cur) {
1038     xmlElementContentPtr ret = NULL, prev = NULL, tmp;
1039     xmlDictPtr dict = NULL;
1040 
1041     if (cur == NULL) return(NULL);
1042 
1043     if (doc != NULL)
1044         dict = doc->dict;
1045 
1046     ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
1047     if (ret == NULL) {
1048 	xmlVErrMemory(NULL, "malloc failed");
1049 	return(NULL);
1050     }
1051     memset(ret, 0, sizeof(xmlElementContent));
1052     ret->type = cur->type;
1053     ret->ocur = cur->ocur;
1054     if (cur->name != NULL) {
1055 	if (dict)
1056 	    ret->name = xmlDictLookup(dict, cur->name, -1);
1057 	else
1058 	    ret->name = xmlStrdup(cur->name);
1059     }
1060 
1061     if (cur->prefix != NULL) {
1062 	if (dict)
1063 	    ret->prefix = xmlDictLookup(dict, cur->prefix, -1);
1064 	else
1065 	    ret->prefix = xmlStrdup(cur->prefix);
1066     }
1067     if (cur->c1 != NULL)
1068         ret->c1 = xmlCopyDocElementContent(doc, cur->c1);
1069     if (ret->c1 != NULL)
1070 	ret->c1->parent = ret;
1071     if (cur->c2 != NULL) {
1072         prev = ret;
1073 	cur = cur->c2;
1074 	while (cur != NULL) {
1075 	    tmp = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
1076 	    if (tmp == NULL) {
1077 		xmlVErrMemory(NULL, "malloc failed");
1078 		return(ret);
1079 	    }
1080 	    memset(tmp, 0, sizeof(xmlElementContent));
1081 	    tmp->type = cur->type;
1082 	    tmp->ocur = cur->ocur;
1083 	    prev->c2 = tmp;
1084 	    if (cur->name != NULL) {
1085 		if (dict)
1086 		    tmp->name = xmlDictLookup(dict, cur->name, -1);
1087 		else
1088 		    tmp->name = xmlStrdup(cur->name);
1089 	    }
1090 
1091 	    if (cur->prefix != NULL) {
1092 		if (dict)
1093 		    tmp->prefix = xmlDictLookup(dict, cur->prefix, -1);
1094 		else
1095 		    tmp->prefix = xmlStrdup(cur->prefix);
1096 	    }
1097 	    if (cur->c1 != NULL)
1098 	        tmp->c1 = xmlCopyDocElementContent(doc,cur->c1);
1099 	    if (tmp->c1 != NULL)
1100 		tmp->c1->parent = ret;
1101 	    prev = tmp;
1102 	    cur = cur->c2;
1103 	}
1104     }
1105     return(ret);
1106 }
1107 
1108 /**
1109  * xmlCopyElementContent:
1110  * @cur:  An element content pointer.
1111  *
1112  * Build a copy of an element content description.
1113  * Deprecated, use xmlCopyDocElementContent instead
1114  *
1115  * Returns the new xmlElementContentPtr or NULL in case of error.
1116  */
1117 xmlElementContentPtr
xmlCopyElementContent(xmlElementContentPtr cur)1118 xmlCopyElementContent(xmlElementContentPtr cur) {
1119     return(xmlCopyDocElementContent(NULL, cur));
1120 }
1121 
1122 /**
1123  * xmlFreeDocElementContent:
1124  * @doc: the document owning the element declaration
1125  * @cur:  the element content tree to free
1126  *
1127  * Free an element content structure. The whole subtree is removed.
1128  */
1129 void
xmlFreeDocElementContent(xmlDocPtr doc,xmlElementContentPtr cur)1130 xmlFreeDocElementContent(xmlDocPtr doc, xmlElementContentPtr cur) {
1131     xmlDictPtr dict = NULL;
1132     size_t depth = 0;
1133 
1134     if (cur == NULL)
1135         return;
1136     if (doc != NULL)
1137         dict = doc->dict;
1138 
1139     while (1) {
1140         xmlElementContentPtr parent;
1141 
1142         while ((cur->c1 != NULL) || (cur->c2 != NULL)) {
1143             cur = (cur->c1 != NULL) ? cur->c1 : cur->c2;
1144             depth += 1;
1145         }
1146 
1147 	switch (cur->type) {
1148 	    case XML_ELEMENT_CONTENT_PCDATA:
1149 	    case XML_ELEMENT_CONTENT_ELEMENT:
1150 	    case XML_ELEMENT_CONTENT_SEQ:
1151 	    case XML_ELEMENT_CONTENT_OR:
1152 		break;
1153 	    default:
1154 		xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1155 			"Internal: ELEMENT content corrupted invalid type\n",
1156 			NULL);
1157 		return;
1158 	}
1159 	if (dict) {
1160 	    if ((cur->name != NULL) && (!xmlDictOwns(dict, cur->name)))
1161 	        xmlFree((xmlChar *) cur->name);
1162 	    if ((cur->prefix != NULL) && (!xmlDictOwns(dict, cur->prefix)))
1163 	        xmlFree((xmlChar *) cur->prefix);
1164 	} else {
1165 	    if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
1166 	    if (cur->prefix != NULL) xmlFree((xmlChar *) cur->prefix);
1167 	}
1168         parent = cur->parent;
1169         if ((depth == 0) || (parent == NULL)) {
1170             xmlFree(cur);
1171             break;
1172         }
1173         if (cur == parent->c1)
1174             parent->c1 = NULL;
1175         else
1176             parent->c2 = NULL;
1177 	xmlFree(cur);
1178 
1179         if (parent->c2 != NULL) {
1180 	    cur = parent->c2;
1181         } else {
1182             depth -= 1;
1183             cur = parent;
1184         }
1185     }
1186 }
1187 
1188 /**
1189  * xmlFreeElementContent:
1190  * @cur:  the element content tree to free
1191  *
1192  * Free an element content structure. The whole subtree is removed.
1193  * Deprecated, use xmlFreeDocElementContent instead
1194  */
1195 void
xmlFreeElementContent(xmlElementContentPtr cur)1196 xmlFreeElementContent(xmlElementContentPtr cur) {
1197     xmlFreeDocElementContent(NULL, cur);
1198 }
1199 
1200 #ifdef LIBXML_OUTPUT_ENABLED
1201 /**
1202  * xmlDumpElementOccur:
1203  * @buf:  An XML buffer
1204  * @cur:  An element table
1205  *
1206  * Dump the occurrence operator of an element.
1207  */
1208 static void
xmlDumpElementOccur(xmlBufferPtr buf,xmlElementContentPtr cur)1209 xmlDumpElementOccur(xmlBufferPtr buf, xmlElementContentPtr cur) {
1210     switch (cur->ocur) {
1211         case XML_ELEMENT_CONTENT_ONCE:
1212             break;
1213         case XML_ELEMENT_CONTENT_OPT:
1214             xmlBufferWriteChar(buf, "?");
1215             break;
1216         case XML_ELEMENT_CONTENT_MULT:
1217             xmlBufferWriteChar(buf, "*");
1218             break;
1219         case XML_ELEMENT_CONTENT_PLUS:
1220             xmlBufferWriteChar(buf, "+");
1221             break;
1222     }
1223 }
1224 
1225 /**
1226  * xmlDumpElementContent:
1227  * @buf:  An XML buffer
1228  * @content:  An element table
1229  *
1230  * This will dump the content of the element table as an XML DTD definition
1231  */
1232 static void
xmlDumpElementContent(xmlBufferPtr buf,xmlElementContentPtr content)1233 xmlDumpElementContent(xmlBufferPtr buf, xmlElementContentPtr content) {
1234     xmlElementContentPtr cur;
1235 
1236     if (content == NULL) return;
1237 
1238     xmlBufferWriteChar(buf, "(");
1239     cur = content;
1240 
1241     do {
1242         if (cur == NULL) return;
1243 
1244         switch (cur->type) {
1245             case XML_ELEMENT_CONTENT_PCDATA:
1246                 xmlBufferWriteChar(buf, "#PCDATA");
1247                 break;
1248             case XML_ELEMENT_CONTENT_ELEMENT:
1249                 if (cur->prefix != NULL) {
1250                     xmlBufferWriteCHAR(buf, cur->prefix);
1251                     xmlBufferWriteChar(buf, ":");
1252                 }
1253                 xmlBufferWriteCHAR(buf, cur->name);
1254                 break;
1255             case XML_ELEMENT_CONTENT_SEQ:
1256             case XML_ELEMENT_CONTENT_OR:
1257                 if ((cur != content) &&
1258                     (cur->parent != NULL) &&
1259                     ((cur->type != cur->parent->type) ||
1260                      (cur->ocur != XML_ELEMENT_CONTENT_ONCE)))
1261                     xmlBufferWriteChar(buf, "(");
1262                 cur = cur->c1;
1263                 continue;
1264             default:
1265                 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1266                         "Internal: ELEMENT cur corrupted invalid type\n",
1267                         NULL);
1268         }
1269 
1270         while (cur != content) {
1271             xmlElementContentPtr parent = cur->parent;
1272 
1273             if (parent == NULL) return;
1274 
1275             if (((cur->type == XML_ELEMENT_CONTENT_OR) ||
1276                  (cur->type == XML_ELEMENT_CONTENT_SEQ)) &&
1277                 ((cur->type != parent->type) ||
1278                  (cur->ocur != XML_ELEMENT_CONTENT_ONCE)))
1279                 xmlBufferWriteChar(buf, ")");
1280             xmlDumpElementOccur(buf, cur);
1281 
1282             if (cur == parent->c1) {
1283                 if (parent->type == XML_ELEMENT_CONTENT_SEQ)
1284                     xmlBufferWriteChar(buf, " , ");
1285                 else if (parent->type == XML_ELEMENT_CONTENT_OR)
1286                     xmlBufferWriteChar(buf, " | ");
1287 
1288                 cur = parent->c2;
1289                 break;
1290             }
1291 
1292             cur = parent;
1293         }
1294     } while (cur != content);
1295 
1296     xmlBufferWriteChar(buf, ")");
1297     xmlDumpElementOccur(buf, content);
1298 }
1299 
1300 /**
1301  * xmlSprintfElementContent:
1302  * @buf:  an output buffer
1303  * @content:  An element table
1304  * @englob: 1 if one must print the englobing parenthesis, 0 otherwise
1305  *
1306  * Deprecated, unsafe, use xmlSnprintfElementContent
1307  */
1308 void
xmlSprintfElementContent(char * buf ATTRIBUTE_UNUSED,xmlElementContentPtr content ATTRIBUTE_UNUSED,int englob ATTRIBUTE_UNUSED)1309 xmlSprintfElementContent(char *buf ATTRIBUTE_UNUSED,
1310 	                 xmlElementContentPtr content ATTRIBUTE_UNUSED,
1311 			 int englob ATTRIBUTE_UNUSED) {
1312 }
1313 #endif /* LIBXML_OUTPUT_ENABLED */
1314 
1315 /**
1316  * xmlSnprintfElementContent:
1317  * @buf:  an output buffer
1318  * @size:  the buffer size
1319  * @content:  An element table
1320  * @englob: 1 if one must print the englobing parenthesis, 0 otherwise
1321  *
1322  * This will dump the content of the element content definition
1323  * Intended just for the debug routine
1324  */
1325 void
xmlSnprintfElementContent(char * buf,int size,xmlElementContentPtr content,int englob)1326 xmlSnprintfElementContent(char *buf, int size, xmlElementContentPtr content, int englob) {
1327     int len;
1328 
1329     if (content == NULL) return;
1330     len = strlen(buf);
1331     if (size - len < 50) {
1332 	if ((size - len > 4) && (buf[len - 1] != '.'))
1333 	    strcat(buf, " ...");
1334 	return;
1335     }
1336     if (englob) strcat(buf, "(");
1337     switch (content->type) {
1338         case XML_ELEMENT_CONTENT_PCDATA:
1339             strcat(buf, "#PCDATA");
1340 	    break;
1341 	case XML_ELEMENT_CONTENT_ELEMENT: {
1342             int qnameLen = xmlStrlen(content->name);
1343 
1344 	    if (content->prefix != NULL)
1345                 qnameLen += xmlStrlen(content->prefix) + 1;
1346 	    if (size - len < qnameLen + 10) {
1347 		strcat(buf, " ...");
1348 		return;
1349 	    }
1350 	    if (content->prefix != NULL) {
1351 		strcat(buf, (char *) content->prefix);
1352 		strcat(buf, ":");
1353 	    }
1354 	    if (content->name != NULL)
1355 		strcat(buf, (char *) content->name);
1356 	    break;
1357         }
1358 	case XML_ELEMENT_CONTENT_SEQ:
1359 	    if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1360 	        (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
1361 		xmlSnprintfElementContent(buf, size, content->c1, 1);
1362 	    else
1363 		xmlSnprintfElementContent(buf, size, content->c1, 0);
1364 	    len = strlen(buf);
1365 	    if (size - len < 50) {
1366 		if ((size - len > 4) && (buf[len - 1] != '.'))
1367 		    strcat(buf, " ...");
1368 		return;
1369 	    }
1370             strcat(buf, " , ");
1371 	    if (((content->c2->type == XML_ELEMENT_CONTENT_OR) ||
1372 		 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
1373 		(content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
1374 		xmlSnprintfElementContent(buf, size, content->c2, 1);
1375 	    else
1376 		xmlSnprintfElementContent(buf, size, content->c2, 0);
1377 	    break;
1378 	case XML_ELEMENT_CONTENT_OR:
1379 	    if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1380 	        (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
1381 		xmlSnprintfElementContent(buf, size, content->c1, 1);
1382 	    else
1383 		xmlSnprintfElementContent(buf, size, content->c1, 0);
1384 	    len = strlen(buf);
1385 	    if (size - len < 50) {
1386 		if ((size - len > 4) && (buf[len - 1] != '.'))
1387 		    strcat(buf, " ...");
1388 		return;
1389 	    }
1390             strcat(buf, " | ");
1391 	    if (((content->c2->type == XML_ELEMENT_CONTENT_SEQ) ||
1392 		 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
1393 		(content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
1394 		xmlSnprintfElementContent(buf, size, content->c2, 1);
1395 	    else
1396 		xmlSnprintfElementContent(buf, size, content->c2, 0);
1397 	    break;
1398     }
1399     if (size - strlen(buf) <= 2) return;
1400     if (englob)
1401         strcat(buf, ")");
1402     switch (content->ocur) {
1403         case XML_ELEMENT_CONTENT_ONCE:
1404 	    break;
1405         case XML_ELEMENT_CONTENT_OPT:
1406 	    strcat(buf, "?");
1407 	    break;
1408         case XML_ELEMENT_CONTENT_MULT:
1409 	    strcat(buf, "*");
1410 	    break;
1411         case XML_ELEMENT_CONTENT_PLUS:
1412 	    strcat(buf, "+");
1413 	    break;
1414     }
1415 }
1416 
1417 /****************************************************************
1418  *								*
1419  *	Registration of DTD declarations			*
1420  *								*
1421  ****************************************************************/
1422 
1423 /**
1424  * xmlFreeElement:
1425  * @elem:  An element
1426  *
1427  * Deallocate the memory used by an element definition
1428  */
1429 static void
xmlFreeElement(xmlElementPtr elem)1430 xmlFreeElement(xmlElementPtr elem) {
1431     if (elem == NULL) return;
1432     xmlUnlinkNode((xmlNodePtr) elem);
1433     xmlFreeDocElementContent(elem->doc, elem->content);
1434     if (elem->name != NULL)
1435 	xmlFree((xmlChar *) elem->name);
1436     if (elem->prefix != NULL)
1437 	xmlFree((xmlChar *) elem->prefix);
1438 #ifdef LIBXML_REGEXP_ENABLED
1439     if (elem->contModel != NULL)
1440 	xmlRegFreeRegexp(elem->contModel);
1441 #endif
1442     xmlFree(elem);
1443 }
1444 
1445 
1446 /**
1447  * xmlAddElementDecl:
1448  * @ctxt:  the validation context
1449  * @dtd:  pointer to the DTD
1450  * @name:  the entity name
1451  * @type:  the element type
1452  * @content:  the element content tree or NULL
1453  *
1454  * Register a new element declaration
1455  *
1456  * Returns NULL if not, otherwise the entity
1457  */
1458 xmlElementPtr
xmlAddElementDecl(xmlValidCtxtPtr ctxt,xmlDtdPtr dtd,const xmlChar * name,xmlElementTypeVal type,xmlElementContentPtr content)1459 xmlAddElementDecl(xmlValidCtxtPtr ctxt,
1460                   xmlDtdPtr dtd, const xmlChar *name,
1461                   xmlElementTypeVal type,
1462 		  xmlElementContentPtr content) {
1463     xmlElementPtr ret;
1464     xmlElementTablePtr table;
1465     xmlAttributePtr oldAttributes = NULL;
1466     xmlChar *ns, *uqname;
1467 
1468     if (dtd == NULL) {
1469 	return(NULL);
1470     }
1471     if (name == NULL) {
1472 	return(NULL);
1473     }
1474 
1475     switch (type) {
1476         case XML_ELEMENT_TYPE_EMPTY:
1477 	    if (content != NULL) {
1478 		xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1479 		        "xmlAddElementDecl: content != NULL for EMPTY\n",
1480 			NULL);
1481 		return(NULL);
1482 	    }
1483 	    break;
1484 	case XML_ELEMENT_TYPE_ANY:
1485 	    if (content != NULL) {
1486 		xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1487 		        "xmlAddElementDecl: content != NULL for ANY\n",
1488 			NULL);
1489 		return(NULL);
1490 	    }
1491 	    break;
1492 	case XML_ELEMENT_TYPE_MIXED:
1493 	    if (content == NULL) {
1494 		xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1495 		        "xmlAddElementDecl: content == NULL for MIXED\n",
1496 			NULL);
1497 		return(NULL);
1498 	    }
1499 	    break;
1500 	case XML_ELEMENT_TYPE_ELEMENT:
1501 	    if (content == NULL) {
1502 		xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1503 		        "xmlAddElementDecl: content == NULL for ELEMENT\n",
1504 			NULL);
1505 		return(NULL);
1506 	    }
1507 	    break;
1508 	default:
1509 	    xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1510 		    "Internal: ELEMENT decl corrupted invalid type\n",
1511 		    NULL);
1512 	    return(NULL);
1513     }
1514 
1515     /*
1516      * check if name is a QName
1517      */
1518     uqname = xmlSplitQName2(name, &ns);
1519     if (uqname != NULL)
1520 	name = uqname;
1521 
1522     /*
1523      * Create the Element table if needed.
1524      */
1525     table = (xmlElementTablePtr) dtd->elements;
1526     if (table == NULL) {
1527 	xmlDictPtr dict = NULL;
1528 
1529 	if (dtd->doc != NULL)
1530 	    dict = dtd->doc->dict;
1531         table = xmlHashCreateDict(0, dict);
1532 	dtd->elements = (void *) table;
1533     }
1534     if (table == NULL) {
1535 	xmlVErrMemory(ctxt,
1536             "xmlAddElementDecl: Table creation failed!\n");
1537 	if (uqname != NULL)
1538 	    xmlFree(uqname);
1539 	if (ns != NULL)
1540 	    xmlFree(ns);
1541         return(NULL);
1542     }
1543 
1544     /*
1545      * lookup old attributes inserted on an undefined element in the
1546      * internal subset.
1547      */
1548     if ((dtd->doc != NULL) && (dtd->doc->intSubset != NULL)) {
1549 	ret = xmlHashLookup2(dtd->doc->intSubset->elements, name, ns);
1550 	if ((ret != NULL) && (ret->etype == XML_ELEMENT_TYPE_UNDEFINED)) {
1551 	    oldAttributes = ret->attributes;
1552 	    ret->attributes = NULL;
1553 	    xmlHashRemoveEntry2(dtd->doc->intSubset->elements, name, ns, NULL);
1554 	    xmlFreeElement(ret);
1555 	}
1556     }
1557 
1558     /*
1559      * The element may already be present if one of its attribute
1560      * was registered first
1561      */
1562     ret = xmlHashLookup2(table, name, ns);
1563     if (ret != NULL) {
1564 	if (ret->etype != XML_ELEMENT_TYPE_UNDEFINED) {
1565 #ifdef LIBXML_VALID_ENABLED
1566 	    /*
1567 	     * The element is already defined in this DTD.
1568 	     */
1569 	    xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED,
1570 	                    "Redefinition of element %s\n",
1571 			    name, NULL, NULL);
1572 #endif /* LIBXML_VALID_ENABLED */
1573 	    if (uqname != NULL)
1574 		xmlFree(uqname);
1575             if (ns != NULL)
1576 	        xmlFree(ns);
1577 	    return(NULL);
1578 	}
1579 	if (ns != NULL) {
1580 	    xmlFree(ns);
1581 	    ns = NULL;
1582 	}
1583     } else {
1584 	ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1585 	if (ret == NULL) {
1586 	    xmlVErrMemory(ctxt, "malloc failed");
1587 	    if (uqname != NULL)
1588 		xmlFree(uqname);
1589             if (ns != NULL)
1590 	        xmlFree(ns);
1591 	    return(NULL);
1592 	}
1593 	memset(ret, 0, sizeof(xmlElement));
1594 	ret->type = XML_ELEMENT_DECL;
1595 
1596 	/*
1597 	 * fill the structure.
1598 	 */
1599 	ret->name = xmlStrdup(name);
1600 	if (ret->name == NULL) {
1601 	    xmlVErrMemory(ctxt, "malloc failed");
1602 	    if (uqname != NULL)
1603 		xmlFree(uqname);
1604             if (ns != NULL)
1605 	        xmlFree(ns);
1606 	    xmlFree(ret);
1607 	    return(NULL);
1608 	}
1609 	ret->prefix = ns;
1610 
1611 	/*
1612 	 * Validity Check:
1613 	 * Insertion must not fail
1614 	 */
1615 	if (xmlHashAddEntry2(table, name, ns, ret)) {
1616 #ifdef LIBXML_VALID_ENABLED
1617 	    /*
1618 	     * The element is already defined in this DTD.
1619 	     */
1620 	    xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED,
1621 	                    "Redefinition of element %s\n",
1622 			    name, NULL, NULL);
1623 #endif /* LIBXML_VALID_ENABLED */
1624 	    xmlFreeElement(ret);
1625 	    if (uqname != NULL)
1626 		xmlFree(uqname);
1627 	    return(NULL);
1628 	}
1629 	/*
1630 	 * For new element, may have attributes from earlier
1631 	 * definition in internal subset
1632 	 */
1633 	ret->attributes = oldAttributes;
1634     }
1635 
1636     /*
1637      * Finish to fill the structure.
1638      */
1639     ret->etype = type;
1640     /*
1641      * Avoid a stupid copy when called by the parser
1642      * and flag it by setting a special parent value
1643      * so the parser doesn't unallocate it.
1644      */
1645     if ((ctxt != NULL) &&
1646         ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
1647          (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1))) {
1648 	ret->content = content;
1649 	if (content != NULL)
1650 	    content->parent = (xmlElementContentPtr) 1;
1651     } else {
1652 	ret->content = xmlCopyDocElementContent(dtd->doc, content);
1653     }
1654 
1655     /*
1656      * Link it to the DTD
1657      */
1658     ret->parent = dtd;
1659     ret->doc = dtd->doc;
1660     if (dtd->last == NULL) {
1661 	dtd->children = dtd->last = (xmlNodePtr) ret;
1662     } else {
1663         dtd->last->next = (xmlNodePtr) ret;
1664 	ret->prev = dtd->last;
1665 	dtd->last = (xmlNodePtr) ret;
1666     }
1667     if (uqname != NULL)
1668 	xmlFree(uqname);
1669     return(ret);
1670 }
1671 
1672 static void
xmlFreeElementTableEntry(void * elem,const xmlChar * name ATTRIBUTE_UNUSED)1673 xmlFreeElementTableEntry(void *elem, const xmlChar *name ATTRIBUTE_UNUSED) {
1674     xmlFreeElement((xmlElementPtr) elem);
1675 }
1676 
1677 /**
1678  * xmlFreeElementTable:
1679  * @table:  An element table
1680  *
1681  * Deallocate the memory used by an element hash table.
1682  */
1683 void
xmlFreeElementTable(xmlElementTablePtr table)1684 xmlFreeElementTable(xmlElementTablePtr table) {
1685     xmlHashFree(table, xmlFreeElementTableEntry);
1686 }
1687 
1688 #ifdef LIBXML_TREE_ENABLED
1689 /**
1690  * xmlCopyElement:
1691  * @elem:  An element
1692  *
1693  * Build a copy of an element.
1694  *
1695  * Returns the new xmlElementPtr or NULL in case of error.
1696  */
1697 static void *
xmlCopyElement(void * payload,const xmlChar * name ATTRIBUTE_UNUSED)1698 xmlCopyElement(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) {
1699     xmlElementPtr elem = (xmlElementPtr) payload;
1700     xmlElementPtr cur;
1701 
1702     cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1703     if (cur == NULL) {
1704 	xmlVErrMemory(NULL, "malloc failed");
1705 	return(NULL);
1706     }
1707     memset(cur, 0, sizeof(xmlElement));
1708     cur->type = XML_ELEMENT_DECL;
1709     cur->etype = elem->etype;
1710     if (elem->name != NULL)
1711 	cur->name = xmlStrdup(elem->name);
1712     else
1713 	cur->name = NULL;
1714     if (elem->prefix != NULL)
1715 	cur->prefix = xmlStrdup(elem->prefix);
1716     else
1717 	cur->prefix = NULL;
1718     cur->content = xmlCopyElementContent(elem->content);
1719     /* TODO : rebuild the attribute list on the copy */
1720     cur->attributes = NULL;
1721     return(cur);
1722 }
1723 
1724 /**
1725  * xmlCopyElementTable:
1726  * @table:  An element table
1727  *
1728  * Build a copy of an element table.
1729  *
1730  * Returns the new xmlElementTablePtr or NULL in case of error.
1731  */
1732 xmlElementTablePtr
xmlCopyElementTable(xmlElementTablePtr table)1733 xmlCopyElementTable(xmlElementTablePtr table) {
1734     return((xmlElementTablePtr) xmlHashCopy(table, xmlCopyElement));
1735 }
1736 #endif /* LIBXML_TREE_ENABLED */
1737 
1738 #ifdef LIBXML_OUTPUT_ENABLED
1739 /**
1740  * xmlDumpElementDecl:
1741  * @buf:  the XML buffer output
1742  * @elem:  An element table
1743  *
1744  * This will dump the content of the element declaration as an XML
1745  * DTD definition
1746  */
1747 void
xmlDumpElementDecl(xmlBufferPtr buf,xmlElementPtr elem)1748 xmlDumpElementDecl(xmlBufferPtr buf, xmlElementPtr elem) {
1749     if ((buf == NULL) || (elem == NULL))
1750         return;
1751     switch (elem->etype) {
1752 	case XML_ELEMENT_TYPE_EMPTY:
1753 	    xmlBufferWriteChar(buf, "<!ELEMENT ");
1754 	    if (elem->prefix != NULL) {
1755 		xmlBufferWriteCHAR(buf, elem->prefix);
1756 		xmlBufferWriteChar(buf, ":");
1757 	    }
1758 	    xmlBufferWriteCHAR(buf, elem->name);
1759 	    xmlBufferWriteChar(buf, " EMPTY>\n");
1760 	    break;
1761 	case XML_ELEMENT_TYPE_ANY:
1762 	    xmlBufferWriteChar(buf, "<!ELEMENT ");
1763 	    if (elem->prefix != NULL) {
1764 		xmlBufferWriteCHAR(buf, elem->prefix);
1765 		xmlBufferWriteChar(buf, ":");
1766 	    }
1767 	    xmlBufferWriteCHAR(buf, elem->name);
1768 	    xmlBufferWriteChar(buf, " ANY>\n");
1769 	    break;
1770 	case XML_ELEMENT_TYPE_MIXED:
1771 	    xmlBufferWriteChar(buf, "<!ELEMENT ");
1772 	    if (elem->prefix != NULL) {
1773 		xmlBufferWriteCHAR(buf, elem->prefix);
1774 		xmlBufferWriteChar(buf, ":");
1775 	    }
1776 	    xmlBufferWriteCHAR(buf, elem->name);
1777 	    xmlBufferWriteChar(buf, " ");
1778 	    xmlDumpElementContent(buf, elem->content);
1779 	    xmlBufferWriteChar(buf, ">\n");
1780 	    break;
1781 	case XML_ELEMENT_TYPE_ELEMENT:
1782 	    xmlBufferWriteChar(buf, "<!ELEMENT ");
1783 	    if (elem->prefix != NULL) {
1784 		xmlBufferWriteCHAR(buf, elem->prefix);
1785 		xmlBufferWriteChar(buf, ":");
1786 	    }
1787 	    xmlBufferWriteCHAR(buf, elem->name);
1788 	    xmlBufferWriteChar(buf, " ");
1789 	    xmlDumpElementContent(buf, elem->content);
1790 	    xmlBufferWriteChar(buf, ">\n");
1791 	    break;
1792 	default:
1793 	    xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1794 		    "Internal: ELEMENT struct corrupted invalid type\n",
1795 		    NULL);
1796     }
1797 }
1798 
1799 /**
1800  * xmlDumpElementDeclScan:
1801  * @elem:  An element table
1802  * @buf:  the XML buffer output
1803  *
1804  * This routine is used by the hash scan function.  It just reverses
1805  * the arguments.
1806  */
1807 static void
xmlDumpElementDeclScan(void * elem,void * buf,const xmlChar * name ATTRIBUTE_UNUSED)1808 xmlDumpElementDeclScan(void *elem, void *buf,
1809                        const xmlChar *name ATTRIBUTE_UNUSED) {
1810     xmlDumpElementDecl((xmlBufferPtr) buf, (xmlElementPtr) elem);
1811 }
1812 
1813 /**
1814  * xmlDumpElementTable:
1815  * @buf:  the XML buffer output
1816  * @table:  An element table
1817  *
1818  * This will dump the content of the element table as an XML DTD definition
1819  */
1820 void
xmlDumpElementTable(xmlBufferPtr buf,xmlElementTablePtr table)1821 xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) {
1822     if ((buf == NULL) || (table == NULL))
1823         return;
1824     xmlHashScan(table, xmlDumpElementDeclScan, buf);
1825 }
1826 #endif /* LIBXML_OUTPUT_ENABLED */
1827 
1828 /**
1829  * xmlCreateEnumeration:
1830  * @name:  the enumeration name or NULL
1831  *
1832  * create and initialize an enumeration attribute node.
1833  *
1834  * Returns the xmlEnumerationPtr just created or NULL in case
1835  *                of error.
1836  */
1837 xmlEnumerationPtr
xmlCreateEnumeration(const xmlChar * name)1838 xmlCreateEnumeration(const xmlChar *name) {
1839     xmlEnumerationPtr ret;
1840 
1841     ret = (xmlEnumerationPtr) xmlMalloc(sizeof(xmlEnumeration));
1842     if (ret == NULL) {
1843 	xmlVErrMemory(NULL, "malloc failed");
1844         return(NULL);
1845     }
1846     memset(ret, 0, sizeof(xmlEnumeration));
1847 
1848     if (name != NULL)
1849         ret->name = xmlStrdup(name);
1850     return(ret);
1851 }
1852 
1853 /**
1854  * xmlFreeEnumeration:
1855  * @cur:  the tree to free.
1856  *
1857  * free an enumeration attribute node (recursive).
1858  */
1859 void
xmlFreeEnumeration(xmlEnumerationPtr cur)1860 xmlFreeEnumeration(xmlEnumerationPtr cur) {
1861     if (cur == NULL) return;
1862 
1863     if (cur->next != NULL) xmlFreeEnumeration(cur->next);
1864 
1865     if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
1866     xmlFree(cur);
1867 }
1868 
1869 #ifdef LIBXML_TREE_ENABLED
1870 /**
1871  * xmlCopyEnumeration:
1872  * @cur:  the tree to copy.
1873  *
1874  * Copy an enumeration attribute node (recursive).
1875  *
1876  * Returns the xmlEnumerationPtr just created or NULL in case
1877  *                of error.
1878  */
1879 xmlEnumerationPtr
xmlCopyEnumeration(xmlEnumerationPtr cur)1880 xmlCopyEnumeration(xmlEnumerationPtr cur) {
1881     xmlEnumerationPtr ret;
1882 
1883     if (cur == NULL) return(NULL);
1884     ret = xmlCreateEnumeration((xmlChar *) cur->name);
1885     if (ret == NULL) return(NULL);
1886 
1887     if (cur->next != NULL) ret->next = xmlCopyEnumeration(cur->next);
1888     else ret->next = NULL;
1889 
1890     return(ret);
1891 }
1892 #endif /* LIBXML_TREE_ENABLED */
1893 
1894 #ifdef LIBXML_OUTPUT_ENABLED
1895 /**
1896  * xmlDumpEnumeration:
1897  * @buf:  the XML buffer output
1898  * @enum:  An enumeration
1899  *
1900  * This will dump the content of the enumeration
1901  */
1902 static void
xmlDumpEnumeration(xmlBufferPtr buf,xmlEnumerationPtr cur)1903 xmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) {
1904     if ((buf == NULL) || (cur == NULL))
1905         return;
1906 
1907     xmlBufferWriteCHAR(buf, cur->name);
1908     if (cur->next == NULL)
1909 	xmlBufferWriteChar(buf, ")");
1910     else {
1911 	xmlBufferWriteChar(buf, " | ");
1912 	xmlDumpEnumeration(buf, cur->next);
1913     }
1914 }
1915 #endif /* LIBXML_OUTPUT_ENABLED */
1916 
1917 #ifdef LIBXML_VALID_ENABLED
1918 /**
1919  * xmlScanIDAttributeDecl:
1920  * @ctxt:  the validation context
1921  * @elem:  the element name
1922  * @err: whether to raise errors here
1923  *
1924  * Verify that the element don't have too many ID attributes
1925  * declared.
1926  *
1927  * Returns the number of ID attributes found.
1928  */
1929 static int
xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt,xmlElementPtr elem,int err)1930 xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem, int err) {
1931     xmlAttributePtr cur;
1932     int ret = 0;
1933 
1934     if (elem == NULL) return(0);
1935     cur = elem->attributes;
1936     while (cur != NULL) {
1937         if (cur->atype == XML_ATTRIBUTE_ID) {
1938 	    ret ++;
1939 	    if ((ret > 1) && (err))
1940 		xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_MULTIPLE_ID,
1941 	       "Element %s has too many ID attributes defined : %s\n",
1942 		       elem->name, cur->name, NULL);
1943 	}
1944 	cur = cur->nexth;
1945     }
1946     return(ret);
1947 }
1948 #endif /* LIBXML_VALID_ENABLED */
1949 
1950 /**
1951  * xmlFreeAttribute:
1952  * @elem:  An attribute
1953  *
1954  * Deallocate the memory used by an attribute definition
1955  */
1956 static void
xmlFreeAttribute(xmlAttributePtr attr)1957 xmlFreeAttribute(xmlAttributePtr attr) {
1958     xmlDictPtr dict;
1959 
1960     if (attr == NULL) return;
1961     if (attr->doc != NULL)
1962 	dict = attr->doc->dict;
1963     else
1964 	dict = NULL;
1965     xmlUnlinkNode((xmlNodePtr) attr);
1966     if (attr->tree != NULL)
1967         xmlFreeEnumeration(attr->tree);
1968     if (dict) {
1969         if ((attr->elem != NULL) && (!xmlDictOwns(dict, attr->elem)))
1970 	    xmlFree((xmlChar *) attr->elem);
1971         if ((attr->name != NULL) && (!xmlDictOwns(dict, attr->name)))
1972 	    xmlFree((xmlChar *) attr->name);
1973         if ((attr->prefix != NULL) && (!xmlDictOwns(dict, attr->prefix)))
1974 	    xmlFree((xmlChar *) attr->prefix);
1975         if ((attr->defaultValue != NULL) &&
1976 	    (!xmlDictOwns(dict, attr->defaultValue)))
1977 	    xmlFree((xmlChar *) attr->defaultValue);
1978     } else {
1979 	if (attr->elem != NULL)
1980 	    xmlFree((xmlChar *) attr->elem);
1981 	if (attr->name != NULL)
1982 	    xmlFree((xmlChar *) attr->name);
1983 	if (attr->defaultValue != NULL)
1984 	    xmlFree((xmlChar *) attr->defaultValue);
1985 	if (attr->prefix != NULL)
1986 	    xmlFree((xmlChar *) attr->prefix);
1987     }
1988     xmlFree(attr);
1989 }
1990 
1991 
1992 /**
1993  * xmlAddAttributeDecl:
1994  * @ctxt:  the validation context
1995  * @dtd:  pointer to the DTD
1996  * @elem:  the element name
1997  * @name:  the attribute name
1998  * @ns:  the attribute namespace prefix
1999  * @type:  the attribute type
2000  * @def:  the attribute default type
2001  * @defaultValue:  the attribute default value
2002  * @tree:  if it's an enumeration, the associated list
2003  *
2004  * Register a new attribute declaration
2005  * Note that @tree becomes the ownership of the DTD
2006  *
2007  * Returns NULL if not new, otherwise the attribute decl
2008  */
2009 xmlAttributePtr
xmlAddAttributeDecl(xmlValidCtxtPtr ctxt,xmlDtdPtr dtd,const xmlChar * elem,const xmlChar * name,const xmlChar * ns,xmlAttributeType type,xmlAttributeDefault def,const xmlChar * defaultValue,xmlEnumerationPtr tree)2010 xmlAddAttributeDecl(xmlValidCtxtPtr ctxt,
2011                     xmlDtdPtr dtd, const xmlChar *elem,
2012                     const xmlChar *name, const xmlChar *ns,
2013 		    xmlAttributeType type, xmlAttributeDefault def,
2014 		    const xmlChar *defaultValue, xmlEnumerationPtr tree) {
2015     xmlAttributePtr ret;
2016     xmlAttributeTablePtr table;
2017     xmlElementPtr elemDef;
2018     xmlDictPtr dict = NULL;
2019 
2020     if (dtd == NULL) {
2021 	xmlFreeEnumeration(tree);
2022 	return(NULL);
2023     }
2024     if (name == NULL) {
2025 	xmlFreeEnumeration(tree);
2026 	return(NULL);
2027     }
2028     if (elem == NULL) {
2029 	xmlFreeEnumeration(tree);
2030 	return(NULL);
2031     }
2032     if (dtd->doc != NULL)
2033 	dict = dtd->doc->dict;
2034 
2035 #ifdef LIBXML_VALID_ENABLED
2036     /*
2037      * Check the type and possibly the default value.
2038      */
2039     switch (type) {
2040         case XML_ATTRIBUTE_CDATA:
2041 	    break;
2042         case XML_ATTRIBUTE_ID:
2043 	    break;
2044         case XML_ATTRIBUTE_IDREF:
2045 	    break;
2046         case XML_ATTRIBUTE_IDREFS:
2047 	    break;
2048         case XML_ATTRIBUTE_ENTITY:
2049 	    break;
2050         case XML_ATTRIBUTE_ENTITIES:
2051 	    break;
2052         case XML_ATTRIBUTE_NMTOKEN:
2053 	    break;
2054         case XML_ATTRIBUTE_NMTOKENS:
2055 	    break;
2056         case XML_ATTRIBUTE_ENUMERATION:
2057 	    break;
2058         case XML_ATTRIBUTE_NOTATION:
2059 	    break;
2060 	default:
2061 	    xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
2062 		    "Internal: ATTRIBUTE struct corrupted invalid type\n",
2063 		    NULL);
2064 	    xmlFreeEnumeration(tree);
2065 	    return(NULL);
2066     }
2067     if ((defaultValue != NULL) &&
2068         (!xmlValidateAttributeValueInternal(dtd->doc, type, defaultValue))) {
2069 	xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_DEFAULT,
2070 	                "Attribute %s of %s: invalid default value\n",
2071 	                elem, name, defaultValue);
2072 	defaultValue = NULL;
2073 	if (ctxt != NULL)
2074 	    ctxt->valid = 0;
2075     }
2076 #endif /* LIBXML_VALID_ENABLED */
2077 
2078     /*
2079      * Check first that an attribute defined in the external subset wasn't
2080      * already defined in the internal subset
2081      */
2082     if ((dtd->doc != NULL) && (dtd->doc->extSubset == dtd) &&
2083 	(dtd->doc->intSubset != NULL) &&
2084 	(dtd->doc->intSubset->attributes != NULL)) {
2085         ret = xmlHashLookup3(dtd->doc->intSubset->attributes, name, ns, elem);
2086 	if (ret != NULL) {
2087 	    xmlFreeEnumeration(tree);
2088 	    return(NULL);
2089 	}
2090     }
2091 
2092     /*
2093      * Create the Attribute table if needed.
2094      */
2095     table = (xmlAttributeTablePtr) dtd->attributes;
2096     if (table == NULL) {
2097         table = xmlHashCreateDict(0, dict);
2098 	dtd->attributes = (void *) table;
2099     }
2100     if (table == NULL) {
2101 	xmlVErrMemory(ctxt,
2102             "xmlAddAttributeDecl: Table creation failed!\n");
2103 	xmlFreeEnumeration(tree);
2104         return(NULL);
2105     }
2106 
2107 
2108     ret = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
2109     if (ret == NULL) {
2110 	xmlVErrMemory(ctxt, "malloc failed");
2111 	xmlFreeEnumeration(tree);
2112 	return(NULL);
2113     }
2114     memset(ret, 0, sizeof(xmlAttribute));
2115     ret->type = XML_ATTRIBUTE_DECL;
2116 
2117     /*
2118      * fill the structure.
2119      */
2120     ret->atype = type;
2121     /*
2122      * doc must be set before possible error causes call
2123      * to xmlFreeAttribute (because it's used to check on
2124      * dict use)
2125      */
2126     ret->doc = dtd->doc;
2127     if (dict) {
2128 	ret->name = xmlDictLookup(dict, name, -1);
2129 	ret->prefix = xmlDictLookup(dict, ns, -1);
2130 	ret->elem = xmlDictLookup(dict, elem, -1);
2131     } else {
2132 	ret->name = xmlStrdup(name);
2133 	ret->prefix = xmlStrdup(ns);
2134 	ret->elem = xmlStrdup(elem);
2135     }
2136     ret->def = def;
2137     ret->tree = tree;
2138     if (defaultValue != NULL) {
2139         if (dict)
2140 	    ret->defaultValue = xmlDictLookup(dict, defaultValue, -1);
2141 	else
2142 	    ret->defaultValue = xmlStrdup(defaultValue);
2143     }
2144 
2145     /*
2146      * Validity Check:
2147      * Search the DTD for previous declarations of the ATTLIST
2148      */
2149     if (xmlHashAddEntry3(table, ret->name, ret->prefix, ret->elem, ret) < 0) {
2150 #ifdef LIBXML_VALID_ENABLED
2151 	/*
2152 	 * The attribute is already defined in this DTD.
2153 	 */
2154 	xmlErrValidWarning(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_REDEFINED,
2155 		 "Attribute %s of element %s: already defined\n",
2156 		 name, elem, NULL);
2157 #endif /* LIBXML_VALID_ENABLED */
2158 	xmlFreeAttribute(ret);
2159 	return(NULL);
2160     }
2161 
2162     /*
2163      * Validity Check:
2164      * Multiple ID per element
2165      */
2166     elemDef = xmlGetDtdElementDesc2(dtd, elem, 1);
2167     if (elemDef != NULL) {
2168 
2169 #ifdef LIBXML_VALID_ENABLED
2170         if ((type == XML_ATTRIBUTE_ID) &&
2171 	    (xmlScanIDAttributeDecl(NULL, elemDef, 1) != 0)) {
2172 	    xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_MULTIPLE_ID,
2173 	   "Element %s has too may ID attributes defined : %s\n",
2174 		   elem, name, NULL);
2175 	    if (ctxt != NULL)
2176 		ctxt->valid = 0;
2177 	}
2178 #endif /* LIBXML_VALID_ENABLED */
2179 
2180 	/*
2181 	 * Insert namespace default def first they need to be
2182 	 * processed first.
2183 	 */
2184 	if ((xmlStrEqual(ret->name, BAD_CAST "xmlns")) ||
2185 	    ((ret->prefix != NULL &&
2186 	     (xmlStrEqual(ret->prefix, BAD_CAST "xmlns"))))) {
2187 	    ret->nexth = elemDef->attributes;
2188 	    elemDef->attributes = ret;
2189 	} else {
2190 	    xmlAttributePtr tmp = elemDef->attributes;
2191 
2192 	    while ((tmp != NULL) &&
2193 		   ((xmlStrEqual(tmp->name, BAD_CAST "xmlns")) ||
2194 		    ((ret->prefix != NULL &&
2195 		     (xmlStrEqual(ret->prefix, BAD_CAST "xmlns")))))) {
2196 		if (tmp->nexth == NULL)
2197 		    break;
2198 		tmp = tmp->nexth;
2199 	    }
2200 	    if (tmp != NULL) {
2201 		ret->nexth = tmp->nexth;
2202 	        tmp->nexth = ret;
2203 	    } else {
2204 		ret->nexth = elemDef->attributes;
2205 		elemDef->attributes = ret;
2206 	    }
2207 	}
2208     }
2209 
2210     /*
2211      * Link it to the DTD
2212      */
2213     ret->parent = dtd;
2214     if (dtd->last == NULL) {
2215 	dtd->children = dtd->last = (xmlNodePtr) ret;
2216     } else {
2217         dtd->last->next = (xmlNodePtr) ret;
2218 	ret->prev = dtd->last;
2219 	dtd->last = (xmlNodePtr) ret;
2220     }
2221     return(ret);
2222 }
2223 
2224 static void
xmlFreeAttributeTableEntry(void * attr,const xmlChar * name ATTRIBUTE_UNUSED)2225 xmlFreeAttributeTableEntry(void *attr, const xmlChar *name ATTRIBUTE_UNUSED) {
2226     xmlFreeAttribute((xmlAttributePtr) attr);
2227 }
2228 
2229 /**
2230  * xmlFreeAttributeTable:
2231  * @table:  An attribute table
2232  *
2233  * Deallocate the memory used by an entities hash table.
2234  */
2235 void
xmlFreeAttributeTable(xmlAttributeTablePtr table)2236 xmlFreeAttributeTable(xmlAttributeTablePtr table) {
2237     xmlHashFree(table, xmlFreeAttributeTableEntry);
2238 }
2239 
2240 #ifdef LIBXML_TREE_ENABLED
2241 /**
2242  * xmlCopyAttribute:
2243  * @attr:  An attribute
2244  *
2245  * Build a copy of an attribute.
2246  *
2247  * Returns the new xmlAttributePtr or NULL in case of error.
2248  */
2249 static void *
xmlCopyAttribute(void * payload,const xmlChar * name ATTRIBUTE_UNUSED)2250 xmlCopyAttribute(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) {
2251     xmlAttributePtr attr = (xmlAttributePtr) payload;
2252     xmlAttributePtr cur;
2253 
2254     cur = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
2255     if (cur == NULL) {
2256 	xmlVErrMemory(NULL, "malloc failed");
2257 	return(NULL);
2258     }
2259     memset(cur, 0, sizeof(xmlAttribute));
2260     cur->type = XML_ATTRIBUTE_DECL;
2261     cur->atype = attr->atype;
2262     cur->def = attr->def;
2263     cur->tree = xmlCopyEnumeration(attr->tree);
2264     if (attr->elem != NULL)
2265 	cur->elem = xmlStrdup(attr->elem);
2266     if (attr->name != NULL)
2267 	cur->name = xmlStrdup(attr->name);
2268     if (attr->prefix != NULL)
2269 	cur->prefix = xmlStrdup(attr->prefix);
2270     if (attr->defaultValue != NULL)
2271 	cur->defaultValue = xmlStrdup(attr->defaultValue);
2272     return(cur);
2273 }
2274 
2275 /**
2276  * xmlCopyAttributeTable:
2277  * @table:  An attribute table
2278  *
2279  * Build a copy of an attribute table.
2280  *
2281  * Returns the new xmlAttributeTablePtr or NULL in case of error.
2282  */
2283 xmlAttributeTablePtr
xmlCopyAttributeTable(xmlAttributeTablePtr table)2284 xmlCopyAttributeTable(xmlAttributeTablePtr table) {
2285     return((xmlAttributeTablePtr) xmlHashCopy(table, xmlCopyAttribute));
2286 }
2287 #endif /* LIBXML_TREE_ENABLED */
2288 
2289 #ifdef LIBXML_OUTPUT_ENABLED
2290 /**
2291  * xmlDumpAttributeDecl:
2292  * @buf:  the XML buffer output
2293  * @attr:  An attribute declaration
2294  *
2295  * This will dump the content of the attribute declaration as an XML
2296  * DTD definition
2297  */
2298 void
xmlDumpAttributeDecl(xmlBufferPtr buf,xmlAttributePtr attr)2299 xmlDumpAttributeDecl(xmlBufferPtr buf, xmlAttributePtr attr) {
2300     if ((buf == NULL) || (attr == NULL))
2301         return;
2302     xmlBufferWriteChar(buf, "<!ATTLIST ");
2303     xmlBufferWriteCHAR(buf, attr->elem);
2304     xmlBufferWriteChar(buf, " ");
2305     if (attr->prefix != NULL) {
2306 	xmlBufferWriteCHAR(buf, attr->prefix);
2307 	xmlBufferWriteChar(buf, ":");
2308     }
2309     xmlBufferWriteCHAR(buf, attr->name);
2310     switch (attr->atype) {
2311 	case XML_ATTRIBUTE_CDATA:
2312 	    xmlBufferWriteChar(buf, " CDATA");
2313 	    break;
2314 	case XML_ATTRIBUTE_ID:
2315 	    xmlBufferWriteChar(buf, " ID");
2316 	    break;
2317 	case XML_ATTRIBUTE_IDREF:
2318 	    xmlBufferWriteChar(buf, " IDREF");
2319 	    break;
2320 	case XML_ATTRIBUTE_IDREFS:
2321 	    xmlBufferWriteChar(buf, " IDREFS");
2322 	    break;
2323 	case XML_ATTRIBUTE_ENTITY:
2324 	    xmlBufferWriteChar(buf, " ENTITY");
2325 	    break;
2326 	case XML_ATTRIBUTE_ENTITIES:
2327 	    xmlBufferWriteChar(buf, " ENTITIES");
2328 	    break;
2329 	case XML_ATTRIBUTE_NMTOKEN:
2330 	    xmlBufferWriteChar(buf, " NMTOKEN");
2331 	    break;
2332 	case XML_ATTRIBUTE_NMTOKENS:
2333 	    xmlBufferWriteChar(buf, " NMTOKENS");
2334 	    break;
2335 	case XML_ATTRIBUTE_ENUMERATION:
2336 	    xmlBufferWriteChar(buf, " (");
2337 	    xmlDumpEnumeration(buf, attr->tree);
2338 	    break;
2339 	case XML_ATTRIBUTE_NOTATION:
2340 	    xmlBufferWriteChar(buf, " NOTATION (");
2341 	    xmlDumpEnumeration(buf, attr->tree);
2342 	    break;
2343 	default:
2344 	    xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2345 		    "Internal: ATTRIBUTE struct corrupted invalid type\n",
2346 		    NULL);
2347     }
2348     switch (attr->def) {
2349 	case XML_ATTRIBUTE_NONE:
2350 	    break;
2351 	case XML_ATTRIBUTE_REQUIRED:
2352 	    xmlBufferWriteChar(buf, " #REQUIRED");
2353 	    break;
2354 	case XML_ATTRIBUTE_IMPLIED:
2355 	    xmlBufferWriteChar(buf, " #IMPLIED");
2356 	    break;
2357 	case XML_ATTRIBUTE_FIXED:
2358 	    xmlBufferWriteChar(buf, " #FIXED");
2359 	    break;
2360 	default:
2361 	    xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2362 		    "Internal: ATTRIBUTE struct corrupted invalid def\n",
2363 		    NULL);
2364     }
2365     if (attr->defaultValue != NULL) {
2366 	xmlBufferWriteChar(buf, " ");
2367 	xmlBufferWriteQuotedString(buf, attr->defaultValue);
2368     }
2369     xmlBufferWriteChar(buf, ">\n");
2370 }
2371 
2372 /**
2373  * xmlDumpAttributeDeclScan:
2374  * @attr:  An attribute declaration
2375  * @buf:  the XML buffer output
2376  *
2377  * This is used with the hash scan function - just reverses arguments
2378  */
2379 static void
xmlDumpAttributeDeclScan(void * attr,void * buf,const xmlChar * name ATTRIBUTE_UNUSED)2380 xmlDumpAttributeDeclScan(void *attr, void *buf,
2381                          const xmlChar *name ATTRIBUTE_UNUSED) {
2382     xmlDumpAttributeDecl((xmlBufferPtr) buf, (xmlAttributePtr) attr);
2383 }
2384 
2385 /**
2386  * xmlDumpAttributeTable:
2387  * @buf:  the XML buffer output
2388  * @table:  An attribute table
2389  *
2390  * This will dump the content of the attribute table as an XML DTD definition
2391  */
2392 void
xmlDumpAttributeTable(xmlBufferPtr buf,xmlAttributeTablePtr table)2393 xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) {
2394     if ((buf == NULL) || (table == NULL))
2395         return;
2396     xmlHashScan(table, xmlDumpAttributeDeclScan, buf);
2397 }
2398 #endif /* LIBXML_OUTPUT_ENABLED */
2399 
2400 /************************************************************************
2401  *									*
2402  *				NOTATIONs				*
2403  *									*
2404  ************************************************************************/
2405 /**
2406  * xmlFreeNotation:
2407  * @not:  A notation
2408  *
2409  * Deallocate the memory used by an notation definition
2410  */
2411 static void
xmlFreeNotation(xmlNotationPtr nota)2412 xmlFreeNotation(xmlNotationPtr nota) {
2413     if (nota == NULL) return;
2414     if (nota->name != NULL)
2415 	xmlFree((xmlChar *) nota->name);
2416     if (nota->PublicID != NULL)
2417 	xmlFree((xmlChar *) nota->PublicID);
2418     if (nota->SystemID != NULL)
2419 	xmlFree((xmlChar *) nota->SystemID);
2420     xmlFree(nota);
2421 }
2422 
2423 
2424 /**
2425  * xmlAddNotationDecl:
2426  * @dtd:  pointer to the DTD
2427  * @ctxt:  the validation context
2428  * @name:  the entity name
2429  * @PublicID:  the public identifier or NULL
2430  * @SystemID:  the system identifier or NULL
2431  *
2432  * Register a new notation declaration
2433  *
2434  * Returns NULL if not, otherwise the entity
2435  */
2436 xmlNotationPtr
xmlAddNotationDecl(xmlValidCtxtPtr ctxt,xmlDtdPtr dtd,const xmlChar * name,const xmlChar * PublicID,const xmlChar * SystemID)2437 xmlAddNotationDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd,
2438 	           const xmlChar *name,
2439                    const xmlChar *PublicID, const xmlChar *SystemID) {
2440     xmlNotationPtr ret;
2441     xmlNotationTablePtr table;
2442 
2443     if (dtd == NULL) {
2444 	return(NULL);
2445     }
2446     if (name == NULL) {
2447 	return(NULL);
2448     }
2449     if ((PublicID == NULL) && (SystemID == NULL)) {
2450 	return(NULL);
2451     }
2452 
2453     /*
2454      * Create the Notation table if needed.
2455      */
2456     table = (xmlNotationTablePtr) dtd->notations;
2457     if (table == NULL) {
2458 	xmlDictPtr dict = NULL;
2459 	if (dtd->doc != NULL)
2460 	    dict = dtd->doc->dict;
2461 
2462         dtd->notations = table = xmlHashCreateDict(0, dict);
2463     }
2464     if (table == NULL) {
2465 	xmlVErrMemory(ctxt,
2466 		"xmlAddNotationDecl: Table creation failed!\n");
2467         return(NULL);
2468     }
2469 
2470     ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
2471     if (ret == NULL) {
2472 	xmlVErrMemory(ctxt, "malloc failed");
2473 	return(NULL);
2474     }
2475     memset(ret, 0, sizeof(xmlNotation));
2476 
2477     /*
2478      * fill the structure.
2479      */
2480     ret->name = xmlStrdup(name);
2481     if (SystemID != NULL)
2482         ret->SystemID = xmlStrdup(SystemID);
2483     if (PublicID != NULL)
2484         ret->PublicID = xmlStrdup(PublicID);
2485 
2486     /*
2487      * Validity Check:
2488      * Check the DTD for previous declarations of the ATTLIST
2489      */
2490     if (xmlHashAddEntry(table, name, ret)) {
2491 #ifdef LIBXML_VALID_ENABLED
2492 	xmlErrValid(NULL, XML_DTD_NOTATION_REDEFINED,
2493 		    "xmlAddNotationDecl: %s already defined\n",
2494 		    (const char *) name);
2495 #endif /* LIBXML_VALID_ENABLED */
2496 	xmlFreeNotation(ret);
2497 	return(NULL);
2498     }
2499     return(ret);
2500 }
2501 
2502 static void
xmlFreeNotationTableEntry(void * nota,const xmlChar * name ATTRIBUTE_UNUSED)2503 xmlFreeNotationTableEntry(void *nota, const xmlChar *name ATTRIBUTE_UNUSED) {
2504     xmlFreeNotation((xmlNotationPtr) nota);
2505 }
2506 
2507 /**
2508  * xmlFreeNotationTable:
2509  * @table:  An notation table
2510  *
2511  * Deallocate the memory used by an entities hash table.
2512  */
2513 void
xmlFreeNotationTable(xmlNotationTablePtr table)2514 xmlFreeNotationTable(xmlNotationTablePtr table) {
2515     xmlHashFree(table, xmlFreeNotationTableEntry);
2516 }
2517 
2518 #ifdef LIBXML_TREE_ENABLED
2519 /**
2520  * xmlCopyNotation:
2521  * @nota:  A notation
2522  *
2523  * Build a copy of a notation.
2524  *
2525  * Returns the new xmlNotationPtr or NULL in case of error.
2526  */
2527 static void *
xmlCopyNotation(void * payload,const xmlChar * name ATTRIBUTE_UNUSED)2528 xmlCopyNotation(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) {
2529     xmlNotationPtr nota = (xmlNotationPtr) payload;
2530     xmlNotationPtr cur;
2531 
2532     cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
2533     if (cur == NULL) {
2534 	xmlVErrMemory(NULL, "malloc failed");
2535 	return(NULL);
2536     }
2537     if (nota->name != NULL)
2538 	cur->name = xmlStrdup(nota->name);
2539     else
2540 	cur->name = NULL;
2541     if (nota->PublicID != NULL)
2542 	cur->PublicID = xmlStrdup(nota->PublicID);
2543     else
2544 	cur->PublicID = NULL;
2545     if (nota->SystemID != NULL)
2546 	cur->SystemID = xmlStrdup(nota->SystemID);
2547     else
2548 	cur->SystemID = NULL;
2549     return(cur);
2550 }
2551 
2552 /**
2553  * xmlCopyNotationTable:
2554  * @table:  A notation table
2555  *
2556  * Build a copy of a notation table.
2557  *
2558  * Returns the new xmlNotationTablePtr or NULL in case of error.
2559  */
2560 xmlNotationTablePtr
xmlCopyNotationTable(xmlNotationTablePtr table)2561 xmlCopyNotationTable(xmlNotationTablePtr table) {
2562     return((xmlNotationTablePtr) xmlHashCopy(table, xmlCopyNotation));
2563 }
2564 #endif /* LIBXML_TREE_ENABLED */
2565 
2566 #ifdef LIBXML_OUTPUT_ENABLED
2567 /**
2568  * xmlDumpNotationDecl:
2569  * @buf:  the XML buffer output
2570  * @nota:  A notation declaration
2571  *
2572  * This will dump the content the notation declaration as an XML DTD definition
2573  */
2574 void
xmlDumpNotationDecl(xmlBufferPtr buf,xmlNotationPtr nota)2575 xmlDumpNotationDecl(xmlBufferPtr buf, xmlNotationPtr nota) {
2576     if ((buf == NULL) || (nota == NULL))
2577         return;
2578     xmlBufferWriteChar(buf, "<!NOTATION ");
2579     xmlBufferWriteCHAR(buf, nota->name);
2580     if (nota->PublicID != NULL) {
2581 	xmlBufferWriteChar(buf, " PUBLIC ");
2582 	xmlBufferWriteQuotedString(buf, nota->PublicID);
2583 	if (nota->SystemID != NULL) {
2584 	    xmlBufferWriteChar(buf, " ");
2585 	    xmlBufferWriteQuotedString(buf, nota->SystemID);
2586 	}
2587     } else {
2588 	xmlBufferWriteChar(buf, " SYSTEM ");
2589 	xmlBufferWriteQuotedString(buf, nota->SystemID);
2590     }
2591     xmlBufferWriteChar(buf, " >\n");
2592 }
2593 
2594 /**
2595  * xmlDumpNotationDeclScan:
2596  * @nota:  A notation declaration
2597  * @buf:  the XML buffer output
2598  *
2599  * This is called with the hash scan function, and just reverses args
2600  */
2601 static void
xmlDumpNotationDeclScan(void * nota,void * buf,const xmlChar * name ATTRIBUTE_UNUSED)2602 xmlDumpNotationDeclScan(void *nota, void *buf,
2603                         const xmlChar *name ATTRIBUTE_UNUSED) {
2604     xmlDumpNotationDecl((xmlBufferPtr) buf, (xmlNotationPtr) nota);
2605 }
2606 
2607 /**
2608  * xmlDumpNotationTable:
2609  * @buf:  the XML buffer output
2610  * @table:  A notation table
2611  *
2612  * This will dump the content of the notation table as an XML DTD definition
2613  */
2614 void
xmlDumpNotationTable(xmlBufferPtr buf,xmlNotationTablePtr table)2615 xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
2616     if ((buf == NULL) || (table == NULL))
2617         return;
2618     xmlHashScan(table, xmlDumpNotationDeclScan, buf);
2619 }
2620 #endif /* LIBXML_OUTPUT_ENABLED */
2621 
2622 /************************************************************************
2623  *									*
2624  *				IDs					*
2625  *									*
2626  ************************************************************************/
2627 /**
2628  * DICT_FREE:
2629  * @str:  a string
2630  *
2631  * Free a string if it is not owned by the "dict" dictionary in the
2632  * current scope
2633  */
2634 #define DICT_FREE(str)						\
2635 	if ((str) && ((!dict) ||				\
2636 	    (xmlDictOwns(dict, (const xmlChar *)(str)) == 0)))	\
2637 	    xmlFree((char *)(str));
2638 
2639 static int
xmlIsStreaming(xmlValidCtxtPtr ctxt)2640 xmlIsStreaming(xmlValidCtxtPtr ctxt) {
2641     xmlParserCtxtPtr pctxt;
2642 
2643     if (ctxt == NULL)
2644         return(0);
2645     /*
2646      * These magic values are also abused to detect whether we're validating
2647      * while parsing a document. In this case, userData points to the parser
2648      * context.
2649      */
2650     if ((ctxt->finishDtd != XML_CTXT_FINISH_DTD_0) &&
2651         (ctxt->finishDtd != XML_CTXT_FINISH_DTD_1))
2652         return(0);
2653     pctxt = ctxt->userData;
2654     return(pctxt->parseMode == XML_PARSE_READER);
2655 }
2656 
2657 /**
2658  * xmlFreeID:
2659  * @not:  A id
2660  *
2661  * Deallocate the memory used by an id definition
2662  */
2663 static void
xmlFreeID(xmlIDPtr id)2664 xmlFreeID(xmlIDPtr id) {
2665     xmlDictPtr dict = NULL;
2666 
2667     if (id == NULL) return;
2668 
2669     if (id->doc != NULL)
2670         dict = id->doc->dict;
2671 
2672     if (id->value != NULL)
2673 	DICT_FREE(id->value)
2674     if (id->name != NULL)
2675 	DICT_FREE(id->name)
2676     xmlFree(id);
2677 }
2678 
2679 
2680 /**
2681  * xmlAddID:
2682  * @ctxt:  the validation context
2683  * @doc:  pointer to the document
2684  * @value:  the value name
2685  * @attr:  the attribute holding the ID
2686  *
2687  * Register a new id declaration
2688  *
2689  * Returns NULL if not, otherwise the new xmlIDPtr
2690  */
2691 xmlIDPtr
xmlAddID(xmlValidCtxtPtr ctxt,xmlDocPtr doc,const xmlChar * value,xmlAttrPtr attr)2692 xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
2693          xmlAttrPtr attr) {
2694     xmlIDPtr ret;
2695     xmlIDTablePtr table;
2696 
2697     if (doc == NULL) {
2698 	return(NULL);
2699     }
2700     if ((value == NULL) || (value[0] == 0)) {
2701 	return(NULL);
2702     }
2703     if (attr == NULL) {
2704 	return(NULL);
2705     }
2706 
2707     /*
2708      * Create the ID table if needed.
2709      */
2710     table = (xmlIDTablePtr) doc->ids;
2711     if (table == NULL)  {
2712         doc->ids = table = xmlHashCreateDict(0, doc->dict);
2713     }
2714     if (table == NULL) {
2715 	xmlVErrMemory(ctxt,
2716 		"xmlAddID: Table creation failed!\n");
2717         return(NULL);
2718     }
2719 
2720     ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
2721     if (ret == NULL) {
2722 	xmlVErrMemory(ctxt, "malloc failed");
2723 	return(NULL);
2724     }
2725 
2726     /*
2727      * fill the structure.
2728      */
2729     ret->value = xmlStrdup(value);
2730     ret->doc = doc;
2731     if (xmlIsStreaming(ctxt)) {
2732 	/*
2733 	 * Operating in streaming mode, attr is gonna disappear
2734 	 */
2735 	if (doc->dict != NULL)
2736 	    ret->name = xmlDictLookup(doc->dict, attr->name, -1);
2737 	else
2738 	    ret->name = xmlStrdup(attr->name);
2739 	ret->attr = NULL;
2740     } else {
2741 	ret->attr = attr;
2742 	ret->name = NULL;
2743     }
2744     ret->lineno = xmlGetLineNo(attr->parent);
2745 
2746     if (xmlHashAddEntry(table, value, ret) < 0) {
2747 #ifdef LIBXML_VALID_ENABLED
2748 	/*
2749 	 * The id is already defined in this DTD.
2750 	 */
2751 	if (ctxt != NULL) {
2752 	    xmlErrValidNode(ctxt, attr->parent, XML_DTD_ID_REDEFINED,
2753 			    "ID %s already defined\n", value, NULL, NULL);
2754 	}
2755 #endif /* LIBXML_VALID_ENABLED */
2756 	xmlFreeID(ret);
2757 	return(NULL);
2758     }
2759     if (attr != NULL)
2760 	attr->atype = XML_ATTRIBUTE_ID;
2761     return(ret);
2762 }
2763 
2764 static void
xmlFreeIDTableEntry(void * id,const xmlChar * name ATTRIBUTE_UNUSED)2765 xmlFreeIDTableEntry(void *id, const xmlChar *name ATTRIBUTE_UNUSED) {
2766     xmlFreeID((xmlIDPtr) id);
2767 }
2768 
2769 /**
2770  * xmlFreeIDTable:
2771  * @table:  An id table
2772  *
2773  * Deallocate the memory used by an ID hash table.
2774  */
2775 void
xmlFreeIDTable(xmlIDTablePtr table)2776 xmlFreeIDTable(xmlIDTablePtr table) {
2777     xmlHashFree(table, xmlFreeIDTableEntry);
2778 }
2779 
2780 /**
2781  * xmlIsID:
2782  * @doc:  the document
2783  * @elem:  the element carrying the attribute
2784  * @attr:  the attribute
2785  *
2786  * Determine whether an attribute is of type ID. In case we have DTD(s)
2787  * then this is done if DTD loading has been requested. In the case
2788  * of HTML documents parsed with the HTML parser, then ID detection is
2789  * done systematically.
2790  *
2791  * Returns 0 or 1 depending on the lookup result
2792  */
2793 int
xmlIsID(xmlDocPtr doc,xmlNodePtr elem,xmlAttrPtr attr)2794 xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
2795     if ((attr == NULL) || (attr->name == NULL)) return(0);
2796     if ((attr->ns != NULL) && (attr->ns->prefix != NULL) &&
2797         (!strcmp((char *) attr->name, "id")) &&
2798         (!strcmp((char *) attr->ns->prefix, "xml")))
2799 	return(1);
2800     if (doc == NULL) return(0);
2801     if ((doc->intSubset == NULL) && (doc->extSubset == NULL) &&
2802         (doc->type != XML_HTML_DOCUMENT_NODE)) {
2803 	return(0);
2804     } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
2805         if ((xmlStrEqual(BAD_CAST "id", attr->name)) ||
2806 	    ((xmlStrEqual(BAD_CAST "name", attr->name)) &&
2807 	    ((elem == NULL) || (xmlStrEqual(elem->name, BAD_CAST "a")))))
2808 	    return(1);
2809 	return(0);
2810     } else if (elem == NULL) {
2811 	return(0);
2812     } else {
2813 	xmlAttributePtr attrDecl = NULL;
2814 
2815 	xmlChar felem[50], fattr[50];
2816 	xmlChar *fullelemname, *fullattrname;
2817 
2818 	fullelemname = (elem->ns != NULL && elem->ns->prefix != NULL) ?
2819 	    xmlBuildQName(elem->name, elem->ns->prefix, felem, 50) :
2820 	    (xmlChar *)elem->name;
2821 
2822 	fullattrname = (attr->ns != NULL && attr->ns->prefix != NULL) ?
2823 	    xmlBuildQName(attr->name, attr->ns->prefix, fattr, 50) :
2824 	    (xmlChar *)attr->name;
2825 
2826 	if (fullelemname != NULL && fullattrname != NULL) {
2827 	    attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullelemname,
2828 		                         fullattrname);
2829 	    if ((attrDecl == NULL) && (doc->extSubset != NULL))
2830 		attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullelemname,
2831 					     fullattrname);
2832 	}
2833 
2834 	if ((fullattrname != fattr) && (fullattrname != attr->name))
2835 	    xmlFree(fullattrname);
2836 	if ((fullelemname != felem) && (fullelemname != elem->name))
2837 	    xmlFree(fullelemname);
2838 
2839         if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_ID))
2840 	    return(1);
2841     }
2842     return(0);
2843 }
2844 
2845 /**
2846  * xmlRemoveID:
2847  * @doc:  the document
2848  * @attr:  the attribute
2849  *
2850  * Remove the given attribute from the ID table maintained internally.
2851  *
2852  * Returns -1 if the lookup failed and 0 otherwise
2853  */
2854 int
xmlRemoveID(xmlDocPtr doc,xmlAttrPtr attr)2855 xmlRemoveID(xmlDocPtr doc, xmlAttrPtr attr) {
2856     xmlIDTablePtr table;
2857     xmlIDPtr id;
2858     xmlChar *ID;
2859 
2860     if (doc == NULL) return(-1);
2861     if (attr == NULL) return(-1);
2862 
2863     table = (xmlIDTablePtr) doc->ids;
2864     if (table == NULL)
2865         return(-1);
2866 
2867     ID = xmlNodeListGetString(doc, attr->children, 1);
2868     if (ID == NULL)
2869         return(-1);
2870     xmlValidNormalizeString(ID);
2871 
2872     id = xmlHashLookup(table, ID);
2873     if (id == NULL || id->attr != attr) {
2874         xmlFree(ID);
2875         return(-1);
2876     }
2877 
2878     xmlHashRemoveEntry(table, ID, xmlFreeIDTableEntry);
2879     xmlFree(ID);
2880     attr->atype = 0;
2881     return(0);
2882 }
2883 
2884 /**
2885  * xmlGetID:
2886  * @doc:  pointer to the document
2887  * @ID:  the ID value
2888  *
2889  * Search the attribute declaring the given ID
2890  *
2891  * Returns NULL if not found, otherwise the xmlAttrPtr defining the ID
2892  */
2893 xmlAttrPtr
xmlGetID(xmlDocPtr doc,const xmlChar * ID)2894 xmlGetID(xmlDocPtr doc, const xmlChar *ID) {
2895     xmlIDTablePtr table;
2896     xmlIDPtr id;
2897 
2898     if (doc == NULL) {
2899 	return(NULL);
2900     }
2901 
2902     if (ID == NULL) {
2903 	return(NULL);
2904     }
2905 
2906     table = (xmlIDTablePtr) doc->ids;
2907     if (table == NULL)
2908         return(NULL);
2909 
2910     id = xmlHashLookup(table, ID);
2911     if (id == NULL)
2912 	return(NULL);
2913     if (id->attr == NULL) {
2914 	/*
2915 	 * We are operating on a stream, return a well known reference
2916 	 * since the attribute node doesn't exist anymore
2917 	 */
2918 	return((xmlAttrPtr) doc);
2919     }
2920     return(id->attr);
2921 }
2922 
2923 /************************************************************************
2924  *									*
2925  *				Refs					*
2926  *									*
2927  ************************************************************************/
2928 typedef struct xmlRemoveMemo_t
2929 {
2930 	xmlListPtr l;
2931 	xmlAttrPtr ap;
2932 } xmlRemoveMemo;
2933 
2934 typedef xmlRemoveMemo *xmlRemoveMemoPtr;
2935 
2936 typedef struct xmlValidateMemo_t
2937 {
2938     xmlValidCtxtPtr ctxt;
2939     const xmlChar *name;
2940 } xmlValidateMemo;
2941 
2942 typedef xmlValidateMemo *xmlValidateMemoPtr;
2943 
2944 /**
2945  * xmlFreeRef:
2946  * @lk:  A list link
2947  *
2948  * Deallocate the memory used by a ref definition
2949  */
2950 static void
xmlFreeRef(xmlLinkPtr lk)2951 xmlFreeRef(xmlLinkPtr lk) {
2952     xmlRefPtr ref = (xmlRefPtr)xmlLinkGetData(lk);
2953     if (ref == NULL) return;
2954     if (ref->value != NULL)
2955         xmlFree((xmlChar *)ref->value);
2956     if (ref->name != NULL)
2957         xmlFree((xmlChar *)ref->name);
2958     xmlFree(ref);
2959 }
2960 
2961 /**
2962  * xmlFreeRefTableEntry:
2963  * @list_ref:  A list of references.
2964  *
2965  * Deallocate the memory used by a list of references
2966  */
2967 static void
xmlFreeRefTableEntry(void * payload,const xmlChar * name ATTRIBUTE_UNUSED)2968 xmlFreeRefTableEntry(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) {
2969     xmlListPtr list_ref = (xmlListPtr) payload;
2970     if (list_ref == NULL) return;
2971     xmlListDelete(list_ref);
2972 }
2973 
2974 /**
2975  * xmlWalkRemoveRef:
2976  * @data:  Contents of current link
2977  * @user:  Value supplied by the user
2978  *
2979  * Returns 0 to abort the walk or 1 to continue
2980  */
2981 static int
xmlWalkRemoveRef(const void * data,void * user)2982 xmlWalkRemoveRef(const void *data, void *user)
2983 {
2984     xmlAttrPtr attr0 = ((xmlRefPtr)data)->attr;
2985     xmlAttrPtr attr1 = ((xmlRemoveMemoPtr)user)->ap;
2986     xmlListPtr ref_list = ((xmlRemoveMemoPtr)user)->l;
2987 
2988     if (attr0 == attr1) { /* Matched: remove and terminate walk */
2989         xmlListRemoveFirst(ref_list, (void *)data);
2990         return 0;
2991     }
2992     return 1;
2993 }
2994 
2995 /**
2996  * xmlDummyCompare
2997  * @data0:  Value supplied by the user
2998  * @data1:  Value supplied by the user
2999  *
3000  * Do nothing, return 0. Used to create unordered lists.
3001  */
3002 static int
xmlDummyCompare(const void * data0 ATTRIBUTE_UNUSED,const void * data1 ATTRIBUTE_UNUSED)3003 xmlDummyCompare(const void *data0 ATTRIBUTE_UNUSED,
3004                 const void *data1 ATTRIBUTE_UNUSED)
3005 {
3006     return (0);
3007 }
3008 
3009 /**
3010  * xmlAddRef:
3011  * @ctxt:  the validation context
3012  * @doc:  pointer to the document
3013  * @value:  the value name
3014  * @attr:  the attribute holding the Ref
3015  *
3016  * Register a new ref declaration
3017  *
3018  * Returns NULL if not, otherwise the new xmlRefPtr
3019  */
3020 xmlRefPtr
xmlAddRef(xmlValidCtxtPtr ctxt,xmlDocPtr doc,const xmlChar * value,xmlAttrPtr attr)3021 xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
3022     xmlAttrPtr attr) {
3023     xmlRefPtr ret;
3024     xmlRefTablePtr table;
3025     xmlListPtr ref_list;
3026 
3027     if (doc == NULL) {
3028         return(NULL);
3029     }
3030     if (value == NULL) {
3031         return(NULL);
3032     }
3033     if (attr == NULL) {
3034         return(NULL);
3035     }
3036 
3037     /*
3038      * Create the Ref table if needed.
3039      */
3040     table = (xmlRefTablePtr) doc->refs;
3041     if (table == NULL) {
3042         doc->refs = table = xmlHashCreateDict(0, doc->dict);
3043     }
3044     if (table == NULL) {
3045 	xmlVErrMemory(ctxt,
3046             "xmlAddRef: Table creation failed!\n");
3047         return(NULL);
3048     }
3049 
3050     ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
3051     if (ret == NULL) {
3052 	xmlVErrMemory(ctxt, "malloc failed");
3053         return(NULL);
3054     }
3055 
3056     /*
3057      * fill the structure.
3058      */
3059     ret->value = xmlStrdup(value);
3060     if (xmlIsStreaming(ctxt)) {
3061 	/*
3062 	 * Operating in streaming mode, attr is gonna disappear
3063 	 */
3064 	ret->name = xmlStrdup(attr->name);
3065 	ret->attr = NULL;
3066     } else {
3067 	ret->name = NULL;
3068 	ret->attr = attr;
3069     }
3070     ret->lineno = xmlGetLineNo(attr->parent);
3071 
3072     /* To add a reference :-
3073      * References are maintained as a list of references,
3074      * Lookup the entry, if no entry create new nodelist
3075      * Add the owning node to the NodeList
3076      * Return the ref
3077      */
3078 
3079     if (NULL == (ref_list = xmlHashLookup(table, value))) {
3080         if (NULL == (ref_list = xmlListCreate(xmlFreeRef, xmlDummyCompare))) {
3081 	    xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
3082 		    "xmlAddRef: Reference list creation failed!\n",
3083 		    NULL);
3084 	    goto failed;
3085         }
3086         if (xmlHashAddEntry(table, value, ref_list) < 0) {
3087             xmlListDelete(ref_list);
3088 	    xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
3089 		    "xmlAddRef: Reference list insertion failed!\n",
3090 		    NULL);
3091 	    goto failed;
3092         }
3093     }
3094     if (xmlListAppend(ref_list, ret) != 0) {
3095 	xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
3096 		    "xmlAddRef: Reference list insertion failed!\n",
3097 		    NULL);
3098         goto failed;
3099     }
3100     return(ret);
3101 failed:
3102     if (ret != NULL) {
3103         if (ret->value != NULL)
3104 	    xmlFree((char *)ret->value);
3105         if (ret->name != NULL)
3106 	    xmlFree((char *)ret->name);
3107         xmlFree(ret);
3108     }
3109     return(NULL);
3110 }
3111 
3112 /**
3113  * xmlFreeRefTable:
3114  * @table:  An ref table
3115  *
3116  * Deallocate the memory used by an Ref hash table.
3117  */
3118 void
xmlFreeRefTable(xmlRefTablePtr table)3119 xmlFreeRefTable(xmlRefTablePtr table) {
3120     xmlHashFree(table, xmlFreeRefTableEntry);
3121 }
3122 
3123 /**
3124  * xmlIsRef:
3125  * @doc:  the document
3126  * @elem:  the element carrying the attribute
3127  * @attr:  the attribute
3128  *
3129  * Determine whether an attribute is of type Ref. In case we have DTD(s)
3130  * then this is simple, otherwise we use an heuristic: name Ref (upper
3131  * or lowercase).
3132  *
3133  * Returns 0 or 1 depending on the lookup result
3134  */
3135 int
xmlIsRef(xmlDocPtr doc,xmlNodePtr elem,xmlAttrPtr attr)3136 xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
3137     if (attr == NULL)
3138         return(0);
3139     if (doc == NULL) {
3140         doc = attr->doc;
3141 	if (doc == NULL) return(0);
3142     }
3143 
3144     if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
3145         return(0);
3146     } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
3147         /* TODO @@@ */
3148         return(0);
3149     } else {
3150         xmlAttributePtr attrDecl;
3151 
3152         if (elem == NULL) return(0);
3153         attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
3154         if ((attrDecl == NULL) && (doc->extSubset != NULL))
3155             attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
3156 		                         elem->name, attr->name);
3157 
3158 	if ((attrDecl != NULL) &&
3159 	    (attrDecl->atype == XML_ATTRIBUTE_IDREF ||
3160 	     attrDecl->atype == XML_ATTRIBUTE_IDREFS))
3161 	return(1);
3162     }
3163     return(0);
3164 }
3165 
3166 /**
3167  * xmlRemoveRef:
3168  * @doc:  the document
3169  * @attr:  the attribute
3170  *
3171  * Remove the given attribute from the Ref table maintained internally.
3172  *
3173  * Returns -1 if the lookup failed and 0 otherwise
3174  */
3175 int
xmlRemoveRef(xmlDocPtr doc,xmlAttrPtr attr)3176 xmlRemoveRef(xmlDocPtr doc, xmlAttrPtr attr) {
3177     xmlListPtr ref_list;
3178     xmlRefTablePtr table;
3179     xmlChar *ID;
3180     xmlRemoveMemo target;
3181 
3182     if (doc == NULL) return(-1);
3183     if (attr == NULL) return(-1);
3184 
3185     table = (xmlRefTablePtr) doc->refs;
3186     if (table == NULL)
3187         return(-1);
3188 
3189     ID = xmlNodeListGetString(doc, attr->children, 1);
3190     if (ID == NULL)
3191         return(-1);
3192 
3193     ref_list = xmlHashLookup(table, ID);
3194     if(ref_list == NULL) {
3195         xmlFree(ID);
3196         return (-1);
3197     }
3198 
3199     /* At this point, ref_list refers to a list of references which
3200      * have the same key as the supplied attr. Our list of references
3201      * is ordered by reference address and we don't have that information
3202      * here to use when removing. We'll have to walk the list and
3203      * check for a matching attribute, when we find one stop the walk
3204      * and remove the entry.
3205      * The list is ordered by reference, so that means we don't have the
3206      * key. Passing the list and the reference to the walker means we
3207      * will have enough data to be able to remove the entry.
3208      */
3209     target.l = ref_list;
3210     target.ap = attr;
3211 
3212     /* Remove the supplied attr from our list */
3213     xmlListWalk(ref_list, xmlWalkRemoveRef, &target);
3214 
3215     /*If the list is empty then remove the list entry in the hash */
3216     if (xmlListEmpty(ref_list))
3217         xmlHashUpdateEntry(table, ID, NULL, xmlFreeRefTableEntry);
3218     xmlFree(ID);
3219     return(0);
3220 }
3221 
3222 /**
3223  * xmlGetRefs:
3224  * @doc:  pointer to the document
3225  * @ID:  the ID value
3226  *
3227  * Find the set of references for the supplied ID.
3228  *
3229  * Returns NULL if not found, otherwise node set for the ID.
3230  */
3231 xmlListPtr
xmlGetRefs(xmlDocPtr doc,const xmlChar * ID)3232 xmlGetRefs(xmlDocPtr doc, const xmlChar *ID) {
3233     xmlRefTablePtr table;
3234 
3235     if (doc == NULL) {
3236         return(NULL);
3237     }
3238 
3239     if (ID == NULL) {
3240         return(NULL);
3241     }
3242 
3243     table = (xmlRefTablePtr) doc->refs;
3244     if (table == NULL)
3245         return(NULL);
3246 
3247     return (xmlHashLookup(table, ID));
3248 }
3249 
3250 /************************************************************************
3251  *									*
3252  *		Routines for validity checking				*
3253  *									*
3254  ************************************************************************/
3255 
3256 /**
3257  * xmlGetDtdElementDesc:
3258  * @dtd:  a pointer to the DtD to search
3259  * @name:  the element name
3260  *
3261  * Search the DTD for the description of this element
3262  *
3263  * returns the xmlElementPtr if found or NULL
3264  */
3265 
3266 xmlElementPtr
xmlGetDtdElementDesc(xmlDtdPtr dtd,const xmlChar * name)3267 xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) {
3268     xmlElementTablePtr table;
3269     xmlElementPtr cur;
3270     xmlChar *uqname = NULL, *prefix = NULL;
3271 
3272     if ((dtd == NULL) || (name == NULL)) return(NULL);
3273     if (dtd->elements == NULL)
3274 	return(NULL);
3275     table = (xmlElementTablePtr) dtd->elements;
3276 
3277     uqname = xmlSplitQName2(name, &prefix);
3278     if (uqname != NULL)
3279         name = uqname;
3280     cur = xmlHashLookup2(table, name, prefix);
3281     if (prefix != NULL) xmlFree(prefix);
3282     if (uqname != NULL) xmlFree(uqname);
3283     return(cur);
3284 }
3285 /**
3286  * xmlGetDtdElementDesc2:
3287  * @dtd:  a pointer to the DtD to search
3288  * @name:  the element name
3289  * @create:  create an empty description if not found
3290  *
3291  * Search the DTD for the description of this element
3292  *
3293  * returns the xmlElementPtr if found or NULL
3294  */
3295 
3296 static xmlElementPtr
xmlGetDtdElementDesc2(xmlDtdPtr dtd,const xmlChar * name,int create)3297 xmlGetDtdElementDesc2(xmlDtdPtr dtd, const xmlChar *name, int create) {
3298     xmlElementTablePtr table;
3299     xmlElementPtr cur;
3300     xmlChar *uqname = NULL, *prefix = NULL;
3301 
3302     if (dtd == NULL) return(NULL);
3303     if (dtd->elements == NULL) {
3304 	xmlDictPtr dict = NULL;
3305 
3306 	if (dtd->doc != NULL)
3307 	    dict = dtd->doc->dict;
3308 
3309 	if (!create)
3310 	    return(NULL);
3311 	/*
3312 	 * Create the Element table if needed.
3313 	 */
3314 	table = (xmlElementTablePtr) dtd->elements;
3315 	if (table == NULL) {
3316 	    table = xmlHashCreateDict(0, dict);
3317 	    dtd->elements = (void *) table;
3318 	}
3319 	if (table == NULL) {
3320 	    xmlVErrMemory(NULL, "element table allocation failed");
3321 	    return(NULL);
3322 	}
3323     }
3324     table = (xmlElementTablePtr) dtd->elements;
3325 
3326     uqname = xmlSplitQName2(name, &prefix);
3327     if (uqname != NULL)
3328         name = uqname;
3329     cur = xmlHashLookup2(table, name, prefix);
3330     if ((cur == NULL) && (create)) {
3331 	cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
3332 	if (cur == NULL) {
3333 	    xmlVErrMemory(NULL, "malloc failed");
3334 	    return(NULL);
3335 	}
3336 	memset(cur, 0, sizeof(xmlElement));
3337 	cur->type = XML_ELEMENT_DECL;
3338 
3339 	/*
3340 	 * fill the structure.
3341 	 */
3342 	cur->name = xmlStrdup(name);
3343 	cur->prefix = xmlStrdup(prefix);
3344 	cur->etype = XML_ELEMENT_TYPE_UNDEFINED;
3345 
3346 	xmlHashAddEntry2(table, name, prefix, cur);
3347     }
3348     if (prefix != NULL) xmlFree(prefix);
3349     if (uqname != NULL) xmlFree(uqname);
3350     return(cur);
3351 }
3352 
3353 /**
3354  * xmlGetDtdQElementDesc:
3355  * @dtd:  a pointer to the DtD to search
3356  * @name:  the element name
3357  * @prefix:  the element namespace prefix
3358  *
3359  * Search the DTD for the description of this element
3360  *
3361  * returns the xmlElementPtr if found or NULL
3362  */
3363 
3364 xmlElementPtr
xmlGetDtdQElementDesc(xmlDtdPtr dtd,const xmlChar * name,const xmlChar * prefix)3365 xmlGetDtdQElementDesc(xmlDtdPtr dtd, const xmlChar *name,
3366 	              const xmlChar *prefix) {
3367     xmlElementTablePtr table;
3368 
3369     if (dtd == NULL) return(NULL);
3370     if (dtd->elements == NULL) return(NULL);
3371     table = (xmlElementTablePtr) dtd->elements;
3372 
3373     return(xmlHashLookup2(table, name, prefix));
3374 }
3375 
3376 /**
3377  * xmlGetDtdAttrDesc:
3378  * @dtd:  a pointer to the DtD to search
3379  * @elem:  the element name
3380  * @name:  the attribute name
3381  *
3382  * Search the DTD for the description of this attribute on
3383  * this element.
3384  *
3385  * returns the xmlAttributePtr if found or NULL
3386  */
3387 
3388 xmlAttributePtr
xmlGetDtdAttrDesc(xmlDtdPtr dtd,const xmlChar * elem,const xmlChar * name)3389 xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) {
3390     xmlAttributeTablePtr table;
3391     xmlAttributePtr cur;
3392     xmlChar *uqname = NULL, *prefix = NULL;
3393 
3394     if (dtd == NULL) return(NULL);
3395     if (dtd->attributes == NULL) return(NULL);
3396 
3397     table = (xmlAttributeTablePtr) dtd->attributes;
3398     if (table == NULL)
3399 	return(NULL);
3400 
3401     uqname = xmlSplitQName2(name, &prefix);
3402 
3403     if (uqname != NULL) {
3404 	cur = xmlHashLookup3(table, uqname, prefix, elem);
3405 	if (prefix != NULL) xmlFree(prefix);
3406 	if (uqname != NULL) xmlFree(uqname);
3407     } else
3408 	cur = xmlHashLookup3(table, name, NULL, elem);
3409     return(cur);
3410 }
3411 
3412 /**
3413  * xmlGetDtdQAttrDesc:
3414  * @dtd:  a pointer to the DtD to search
3415  * @elem:  the element name
3416  * @name:  the attribute name
3417  * @prefix:  the attribute namespace prefix
3418  *
3419  * Search the DTD for the description of this qualified attribute on
3420  * this element.
3421  *
3422  * returns the xmlAttributePtr if found or NULL
3423  */
3424 
3425 xmlAttributePtr
xmlGetDtdQAttrDesc(xmlDtdPtr dtd,const xmlChar * elem,const xmlChar * name,const xmlChar * prefix)3426 xmlGetDtdQAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name,
3427 	          const xmlChar *prefix) {
3428     xmlAttributeTablePtr table;
3429 
3430     if (dtd == NULL) return(NULL);
3431     if (dtd->attributes == NULL) return(NULL);
3432     table = (xmlAttributeTablePtr) dtd->attributes;
3433 
3434     return(xmlHashLookup3(table, name, prefix, elem));
3435 }
3436 
3437 /**
3438  * xmlGetDtdNotationDesc:
3439  * @dtd:  a pointer to the DtD to search
3440  * @name:  the notation name
3441  *
3442  * Search the DTD for the description of this notation
3443  *
3444  * returns the xmlNotationPtr if found or NULL
3445  */
3446 
3447 xmlNotationPtr
xmlGetDtdNotationDesc(xmlDtdPtr dtd,const xmlChar * name)3448 xmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) {
3449     xmlNotationTablePtr table;
3450 
3451     if (dtd == NULL) return(NULL);
3452     if (dtd->notations == NULL) return(NULL);
3453     table = (xmlNotationTablePtr) dtd->notations;
3454 
3455     return(xmlHashLookup(table, name));
3456 }
3457 
3458 #if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
3459 /**
3460  * xmlValidateNotationUse:
3461  * @ctxt:  the validation context
3462  * @doc:  the document
3463  * @notationName:  the notation name to check
3464  *
3465  * Validate that the given name match a notation declaration.
3466  * - [ VC: Notation Declared ]
3467  *
3468  * returns 1 if valid or 0 otherwise
3469  */
3470 
3471 int
xmlValidateNotationUse(xmlValidCtxtPtr ctxt,xmlDocPtr doc,const xmlChar * notationName)3472 xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3473                        const xmlChar *notationName) {
3474     xmlNotationPtr notaDecl;
3475     if ((doc == NULL) || (doc->intSubset == NULL) ||
3476         (notationName == NULL)) return(-1);
3477 
3478     notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
3479     if ((notaDecl == NULL) && (doc->extSubset != NULL))
3480 	notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
3481 
3482     if ((notaDecl == NULL) && (ctxt != NULL)) {
3483 	xmlErrValidNode(ctxt, (xmlNodePtr) doc, XML_DTD_UNKNOWN_NOTATION,
3484 	                "NOTATION %s is not declared\n",
3485 		        notationName, NULL, NULL);
3486 	return(0);
3487     }
3488     return(1);
3489 }
3490 #endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */
3491 
3492 /**
3493  * xmlIsMixedElement:
3494  * @doc:  the document
3495  * @name:  the element name
3496  *
3497  * Search in the DtDs whether an element accept Mixed content (or ANY)
3498  * basically if it is supposed to accept text childs
3499  *
3500  * returns 0 if no, 1 if yes, and -1 if no element description is available
3501  */
3502 
3503 int
xmlIsMixedElement(xmlDocPtr doc,const xmlChar * name)3504 xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) {
3505     xmlElementPtr elemDecl;
3506 
3507     if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
3508 
3509     elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
3510     if ((elemDecl == NULL) && (doc->extSubset != NULL))
3511 	elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
3512     if (elemDecl == NULL) return(-1);
3513     switch (elemDecl->etype) {
3514 	case XML_ELEMENT_TYPE_UNDEFINED:
3515 	    return(-1);
3516 	case XML_ELEMENT_TYPE_ELEMENT:
3517 	    return(0);
3518         case XML_ELEMENT_TYPE_EMPTY:
3519 	    /*
3520 	     * return 1 for EMPTY since we want VC error to pop up
3521 	     * on <empty>     </empty> for example
3522 	     */
3523 	case XML_ELEMENT_TYPE_ANY:
3524 	case XML_ELEMENT_TYPE_MIXED:
3525 	    return(1);
3526     }
3527     return(1);
3528 }
3529 
3530 #ifdef LIBXML_VALID_ENABLED
3531 
3532 static int
xmlIsDocNameStartChar(xmlDocPtr doc,int c)3533 xmlIsDocNameStartChar(xmlDocPtr doc, int c) {
3534     if ((doc == NULL) || (doc->properties & XML_DOC_OLD10) == 0) {
3535         /*
3536 	 * Use the new checks of production [4] [4a] amd [5] of the
3537 	 * Update 5 of XML-1.0
3538 	 */
3539 	if (((c >= 'a') && (c <= 'z')) ||
3540 	    ((c >= 'A') && (c <= 'Z')) ||
3541 	    (c == '_') || (c == ':') ||
3542 	    ((c >= 0xC0) && (c <= 0xD6)) ||
3543 	    ((c >= 0xD8) && (c <= 0xF6)) ||
3544 	    ((c >= 0xF8) && (c <= 0x2FF)) ||
3545 	    ((c >= 0x370) && (c <= 0x37D)) ||
3546 	    ((c >= 0x37F) && (c <= 0x1FFF)) ||
3547 	    ((c >= 0x200C) && (c <= 0x200D)) ||
3548 	    ((c >= 0x2070) && (c <= 0x218F)) ||
3549 	    ((c >= 0x2C00) && (c <= 0x2FEF)) ||
3550 	    ((c >= 0x3001) && (c <= 0xD7FF)) ||
3551 	    ((c >= 0xF900) && (c <= 0xFDCF)) ||
3552 	    ((c >= 0xFDF0) && (c <= 0xFFFD)) ||
3553 	    ((c >= 0x10000) && (c <= 0xEFFFF)))
3554 	    return(1);
3555     } else {
3556         if (IS_LETTER(c) || (c == '_') || (c == ':'))
3557 	    return(1);
3558     }
3559     return(0);
3560 }
3561 
3562 static int
xmlIsDocNameChar(xmlDocPtr doc,int c)3563 xmlIsDocNameChar(xmlDocPtr doc, int c) {
3564     if ((doc == NULL) || (doc->properties & XML_DOC_OLD10) == 0) {
3565         /*
3566 	 * Use the new checks of production [4] [4a] amd [5] of the
3567 	 * Update 5 of XML-1.0
3568 	 */
3569 	if (((c >= 'a') && (c <= 'z')) ||
3570 	    ((c >= 'A') && (c <= 'Z')) ||
3571 	    ((c >= '0') && (c <= '9')) || /* !start */
3572 	    (c == '_') || (c == ':') ||
3573 	    (c == '-') || (c == '.') || (c == 0xB7) || /* !start */
3574 	    ((c >= 0xC0) && (c <= 0xD6)) ||
3575 	    ((c >= 0xD8) && (c <= 0xF6)) ||
3576 	    ((c >= 0xF8) && (c <= 0x2FF)) ||
3577 	    ((c >= 0x300) && (c <= 0x36F)) || /* !start */
3578 	    ((c >= 0x370) && (c <= 0x37D)) ||
3579 	    ((c >= 0x37F) && (c <= 0x1FFF)) ||
3580 	    ((c >= 0x200C) && (c <= 0x200D)) ||
3581 	    ((c >= 0x203F) && (c <= 0x2040)) || /* !start */
3582 	    ((c >= 0x2070) && (c <= 0x218F)) ||
3583 	    ((c >= 0x2C00) && (c <= 0x2FEF)) ||
3584 	    ((c >= 0x3001) && (c <= 0xD7FF)) ||
3585 	    ((c >= 0xF900) && (c <= 0xFDCF)) ||
3586 	    ((c >= 0xFDF0) && (c <= 0xFFFD)) ||
3587 	    ((c >= 0x10000) && (c <= 0xEFFFF)))
3588 	     return(1);
3589     } else {
3590         if ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
3591             (c == '.') || (c == '-') ||
3592 	    (c == '_') || (c == ':') ||
3593 	    (IS_COMBINING(c)) ||
3594 	    (IS_EXTENDER(c)))
3595 	    return(1);
3596     }
3597     return(0);
3598 }
3599 
3600 /**
3601  * xmlValidateNameValue:
3602  * @doc:  pointer to the document or NULL
3603  * @value:  an Name value
3604  *
3605  * Validate that the given value match Name production
3606  *
3607  * returns 1 if valid or 0 otherwise
3608  */
3609 
3610 static int
xmlValidateNameValueInternal(xmlDocPtr doc,const xmlChar * value)3611 xmlValidateNameValueInternal(xmlDocPtr doc, const xmlChar *value) {
3612     const xmlChar *cur;
3613     int val, len;
3614 
3615     if (value == NULL) return(0);
3616     cur = value;
3617     val = xmlStringCurrentChar(NULL, cur, &len);
3618     cur += len;
3619     if (!xmlIsDocNameStartChar(doc, val))
3620 	return(0);
3621 
3622     val = xmlStringCurrentChar(NULL, cur, &len);
3623     cur += len;
3624     while (xmlIsDocNameChar(doc, val)) {
3625 	val = xmlStringCurrentChar(NULL, cur, &len);
3626 	cur += len;
3627     }
3628 
3629     if (val != 0) return(0);
3630 
3631     return(1);
3632 }
3633 
3634 /**
3635  * xmlValidateNameValue:
3636  * @value:  an Name value
3637  *
3638  * Validate that the given value match Name production
3639  *
3640  * returns 1 if valid or 0 otherwise
3641  */
3642 
3643 int
xmlValidateNameValue(const xmlChar * value)3644 xmlValidateNameValue(const xmlChar *value) {
3645     return(xmlValidateNameValueInternal(NULL, value));
3646 }
3647 
3648 /**
3649  * xmlValidateNamesValueInternal:
3650  * @doc:  pointer to the document or NULL
3651  * @value:  an Names value
3652  *
3653  * Validate that the given value match Names production
3654  *
3655  * returns 1 if valid or 0 otherwise
3656  */
3657 
3658 static int
xmlValidateNamesValueInternal(xmlDocPtr doc,const xmlChar * value)3659 xmlValidateNamesValueInternal(xmlDocPtr doc, const xmlChar *value) {
3660     const xmlChar *cur;
3661     int val, len;
3662 
3663     if (value == NULL) return(0);
3664     cur = value;
3665     val = xmlStringCurrentChar(NULL, cur, &len);
3666     cur += len;
3667 
3668     if (!xmlIsDocNameStartChar(doc, val))
3669 	return(0);
3670 
3671     val = xmlStringCurrentChar(NULL, cur, &len);
3672     cur += len;
3673     while (xmlIsDocNameChar(doc, val)) {
3674 	val = xmlStringCurrentChar(NULL, cur, &len);
3675 	cur += len;
3676     }
3677 
3678     /* Should not test IS_BLANK(val) here -- see erratum E20*/
3679     while (val == 0x20) {
3680 	while (val == 0x20) {
3681 	    val = xmlStringCurrentChar(NULL, cur, &len);
3682 	    cur += len;
3683 	}
3684 
3685 	if (!xmlIsDocNameStartChar(doc, val))
3686 	    return(0);
3687 
3688 	val = xmlStringCurrentChar(NULL, cur, &len);
3689 	cur += len;
3690 
3691 	while (xmlIsDocNameChar(doc, val)) {
3692 	    val = xmlStringCurrentChar(NULL, cur, &len);
3693 	    cur += len;
3694 	}
3695     }
3696 
3697     if (val != 0) return(0);
3698 
3699     return(1);
3700 }
3701 
3702 /**
3703  * xmlValidateNamesValue:
3704  * @value:  an Names value
3705  *
3706  * Validate that the given value match Names production
3707  *
3708  * returns 1 if valid or 0 otherwise
3709  */
3710 
3711 int
xmlValidateNamesValue(const xmlChar * value)3712 xmlValidateNamesValue(const xmlChar *value) {
3713     return(xmlValidateNamesValueInternal(NULL, value));
3714 }
3715 
3716 /**
3717  * xmlValidateNmtokenValueInternal:
3718  * @doc:  pointer to the document or NULL
3719  * @value:  an Nmtoken value
3720  *
3721  * Validate that the given value match Nmtoken production
3722  *
3723  * [ VC: Name Token ]
3724  *
3725  * returns 1 if valid or 0 otherwise
3726  */
3727 
3728 static int
xmlValidateNmtokenValueInternal(xmlDocPtr doc,const xmlChar * value)3729 xmlValidateNmtokenValueInternal(xmlDocPtr doc, const xmlChar *value) {
3730     const xmlChar *cur;
3731     int val, len;
3732 
3733     if (value == NULL) return(0);
3734     cur = value;
3735     val = xmlStringCurrentChar(NULL, cur, &len);
3736     cur += len;
3737 
3738     if (!xmlIsDocNameChar(doc, val))
3739 	return(0);
3740 
3741     val = xmlStringCurrentChar(NULL, cur, &len);
3742     cur += len;
3743     while (xmlIsDocNameChar(doc, val)) {
3744 	val = xmlStringCurrentChar(NULL, cur, &len);
3745 	cur += len;
3746     }
3747 
3748     if (val != 0) return(0);
3749 
3750     return(1);
3751 }
3752 
3753 /**
3754  * xmlValidateNmtokenValue:
3755  * @value:  an Nmtoken value
3756  *
3757  * Validate that the given value match Nmtoken production
3758  *
3759  * [ VC: Name Token ]
3760  *
3761  * returns 1 if valid or 0 otherwise
3762  */
3763 
3764 int
xmlValidateNmtokenValue(const xmlChar * value)3765 xmlValidateNmtokenValue(const xmlChar *value) {
3766     return(xmlValidateNmtokenValueInternal(NULL, value));
3767 }
3768 
3769 /**
3770  * xmlValidateNmtokensValueInternal:
3771  * @doc:  pointer to the document or NULL
3772  * @value:  an Nmtokens value
3773  *
3774  * Validate that the given value match Nmtokens production
3775  *
3776  * [ VC: Name Token ]
3777  *
3778  * returns 1 if valid or 0 otherwise
3779  */
3780 
3781 static int
xmlValidateNmtokensValueInternal(xmlDocPtr doc,const xmlChar * value)3782 xmlValidateNmtokensValueInternal(xmlDocPtr doc, const xmlChar *value) {
3783     const xmlChar *cur;
3784     int val, len;
3785 
3786     if (value == NULL) return(0);
3787     cur = value;
3788     val = xmlStringCurrentChar(NULL, cur, &len);
3789     cur += len;
3790 
3791     while (IS_BLANK(val)) {
3792 	val = xmlStringCurrentChar(NULL, cur, &len);
3793 	cur += len;
3794     }
3795 
3796     if (!xmlIsDocNameChar(doc, val))
3797 	return(0);
3798 
3799     while (xmlIsDocNameChar(doc, val)) {
3800 	val = xmlStringCurrentChar(NULL, cur, &len);
3801 	cur += len;
3802     }
3803 
3804     /* Should not test IS_BLANK(val) here -- see erratum E20*/
3805     while (val == 0x20) {
3806 	while (val == 0x20) {
3807 	    val = xmlStringCurrentChar(NULL, cur, &len);
3808 	    cur += len;
3809 	}
3810 	if (val == 0) return(1);
3811 
3812 	if (!xmlIsDocNameChar(doc, val))
3813 	    return(0);
3814 
3815 	val = xmlStringCurrentChar(NULL, cur, &len);
3816 	cur += len;
3817 
3818 	while (xmlIsDocNameChar(doc, val)) {
3819 	    val = xmlStringCurrentChar(NULL, cur, &len);
3820 	    cur += len;
3821 	}
3822     }
3823 
3824     if (val != 0) return(0);
3825 
3826     return(1);
3827 }
3828 
3829 /**
3830  * xmlValidateNmtokensValue:
3831  * @value:  an Nmtokens value
3832  *
3833  * Validate that the given value match Nmtokens production
3834  *
3835  * [ VC: Name Token ]
3836  *
3837  * returns 1 if valid or 0 otherwise
3838  */
3839 
3840 int
xmlValidateNmtokensValue(const xmlChar * value)3841 xmlValidateNmtokensValue(const xmlChar *value) {
3842     return(xmlValidateNmtokensValueInternal(NULL, value));
3843 }
3844 
3845 /**
3846  * xmlValidateNotationDecl:
3847  * @ctxt:  the validation context
3848  * @doc:  a document instance
3849  * @nota:  a notation definition
3850  *
3851  * Try to validate a single notation definition
3852  * basically it does the following checks as described by the
3853  * XML-1.0 recommendation:
3854  *  - it seems that no validity constraint exists on notation declarations
3855  * But this function get called anyway ...
3856  *
3857  * returns 1 if valid or 0 otherwise
3858  */
3859 
3860 int
xmlValidateNotationDecl(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED,xmlDocPtr doc ATTRIBUTE_UNUSED,xmlNotationPtr nota ATTRIBUTE_UNUSED)3861 xmlValidateNotationDecl(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED, xmlDocPtr doc ATTRIBUTE_UNUSED,
3862                          xmlNotationPtr nota ATTRIBUTE_UNUSED) {
3863     int ret = 1;
3864 
3865     return(ret);
3866 }
3867 
3868 /**
3869  * xmlValidateAttributeValueInternal:
3870  * @doc: the document
3871  * @type:  an attribute type
3872  * @value:  an attribute value
3873  *
3874  * Validate that the given attribute value match  the proper production
3875  *
3876  * returns 1 if valid or 0 otherwise
3877  */
3878 
3879 static int
xmlValidateAttributeValueInternal(xmlDocPtr doc,xmlAttributeType type,const xmlChar * value)3880 xmlValidateAttributeValueInternal(xmlDocPtr doc, xmlAttributeType type,
3881                                   const xmlChar *value) {
3882     switch (type) {
3883 	case XML_ATTRIBUTE_ENTITIES:
3884 	case XML_ATTRIBUTE_IDREFS:
3885 	    return(xmlValidateNamesValueInternal(doc, value));
3886 	case XML_ATTRIBUTE_ENTITY:
3887 	case XML_ATTRIBUTE_IDREF:
3888 	case XML_ATTRIBUTE_ID:
3889 	case XML_ATTRIBUTE_NOTATION:
3890 	    return(xmlValidateNameValueInternal(doc, value));
3891 	case XML_ATTRIBUTE_NMTOKENS:
3892 	case XML_ATTRIBUTE_ENUMERATION:
3893 	    return(xmlValidateNmtokensValueInternal(doc, value));
3894 	case XML_ATTRIBUTE_NMTOKEN:
3895 	    return(xmlValidateNmtokenValueInternal(doc, value));
3896         case XML_ATTRIBUTE_CDATA:
3897 	    break;
3898     }
3899     return(1);
3900 }
3901 
3902 /**
3903  * xmlValidateAttributeValue:
3904  * @type:  an attribute type
3905  * @value:  an attribute value
3906  *
3907  * Validate that the given attribute value match  the proper production
3908  *
3909  * [ VC: ID ]
3910  * Values of type ID must match the Name production....
3911  *
3912  * [ VC: IDREF ]
3913  * Values of type IDREF must match the Name production, and values
3914  * of type IDREFS must match Names ...
3915  *
3916  * [ VC: Entity Name ]
3917  * Values of type ENTITY must match the Name production, values
3918  * of type ENTITIES must match Names ...
3919  *
3920  * [ VC: Name Token ]
3921  * Values of type NMTOKEN must match the Nmtoken production; values
3922  * of type NMTOKENS must match Nmtokens.
3923  *
3924  * returns 1 if valid or 0 otherwise
3925  */
3926 int
xmlValidateAttributeValue(xmlAttributeType type,const xmlChar * value)3927 xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) {
3928     return(xmlValidateAttributeValueInternal(NULL, type, value));
3929 }
3930 
3931 /**
3932  * xmlValidateAttributeValue2:
3933  * @ctxt:  the validation context
3934  * @doc:  the document
3935  * @name:  the attribute name (used for error reporting only)
3936  * @type:  the attribute type
3937  * @value:  the attribute value
3938  *
3939  * Validate that the given attribute value match a given type.
3940  * This typically cannot be done before having finished parsing
3941  * the subsets.
3942  *
3943  * [ VC: IDREF ]
3944  * Values of type IDREF must match one of the declared IDs
3945  * Values of type IDREFS must match a sequence of the declared IDs
3946  * each Name must match the value of an ID attribute on some element
3947  * in the XML document; i.e. IDREF values must match the value of
3948  * some ID attribute
3949  *
3950  * [ VC: Entity Name ]
3951  * Values of type ENTITY must match one declared entity
3952  * Values of type ENTITIES must match a sequence of declared entities
3953  *
3954  * [ VC: Notation Attributes ]
3955  * all notation names in the declaration must be declared.
3956  *
3957  * returns 1 if valid or 0 otherwise
3958  */
3959 
3960 static int
xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt,xmlDocPtr doc,const xmlChar * name,xmlAttributeType type,const xmlChar * value)3961 xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3962       const xmlChar *name, xmlAttributeType type, const xmlChar *value) {
3963     int ret = 1;
3964     switch (type) {
3965 	case XML_ATTRIBUTE_IDREFS:
3966 	case XML_ATTRIBUTE_IDREF:
3967 	case XML_ATTRIBUTE_ID:
3968 	case XML_ATTRIBUTE_NMTOKENS:
3969 	case XML_ATTRIBUTE_ENUMERATION:
3970 	case XML_ATTRIBUTE_NMTOKEN:
3971         case XML_ATTRIBUTE_CDATA:
3972 	    break;
3973 	case XML_ATTRIBUTE_ENTITY: {
3974 	    xmlEntityPtr ent;
3975 
3976 	    ent = xmlGetDocEntity(doc, value);
3977 	    /* yeah it's a bit messy... */
3978 	    if ((ent == NULL) && (doc->standalone == 1)) {
3979 		doc->standalone = 0;
3980 		ent = xmlGetDocEntity(doc, value);
3981 	    }
3982 	    if (ent == NULL) {
3983 		xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3984 				XML_DTD_UNKNOWN_ENTITY,
3985    "ENTITY attribute %s reference an unknown entity \"%s\"\n",
3986 		       name, value, NULL);
3987 		ret = 0;
3988 	    } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
3989 		xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3990 				XML_DTD_ENTITY_TYPE,
3991    "ENTITY attribute %s reference an entity \"%s\" of wrong type\n",
3992 		       name, value, NULL);
3993 		ret = 0;
3994 	    }
3995 	    break;
3996         }
3997 	case XML_ATTRIBUTE_ENTITIES: {
3998 	    xmlChar *dup, *nam = NULL, *cur, save;
3999 	    xmlEntityPtr ent;
4000 
4001 	    dup = xmlStrdup(value);
4002 	    if (dup == NULL)
4003 		return(0);
4004 	    cur = dup;
4005 	    while (*cur != 0) {
4006 		nam = cur;
4007 		while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
4008 		save = *cur;
4009 		*cur = 0;
4010 		ent = xmlGetDocEntity(doc, nam);
4011 		if (ent == NULL) {
4012 		    xmlErrValidNode(ctxt, (xmlNodePtr) doc,
4013 				    XML_DTD_UNKNOWN_ENTITY,
4014        "ENTITIES attribute %s reference an unknown entity \"%s\"\n",
4015 			   name, nam, NULL);
4016 		    ret = 0;
4017 		} else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
4018 		    xmlErrValidNode(ctxt, (xmlNodePtr) doc,
4019 				    XML_DTD_ENTITY_TYPE,
4020        "ENTITIES attribute %s reference an entity \"%s\" of wrong type\n",
4021 			   name, nam, NULL);
4022 		    ret = 0;
4023 		}
4024 		if (save == 0)
4025 		    break;
4026 		*cur = save;
4027 		while (IS_BLANK_CH(*cur)) cur++;
4028 	    }
4029 	    xmlFree(dup);
4030 	    break;
4031 	}
4032 	case XML_ATTRIBUTE_NOTATION: {
4033 	    xmlNotationPtr nota;
4034 
4035 	    nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4036 	    if ((nota == NULL) && (doc->extSubset != NULL))
4037 		nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4038 
4039 	    if (nota == NULL) {
4040 		xmlErrValidNode(ctxt, (xmlNodePtr) doc,
4041 		                XML_DTD_UNKNOWN_NOTATION,
4042        "NOTATION attribute %s reference an unknown notation \"%s\"\n",
4043 		       name, value, NULL);
4044 		ret = 0;
4045 	    }
4046 	    break;
4047         }
4048     }
4049     return(ret);
4050 }
4051 
4052 /**
4053  * xmlValidCtxtNormalizeAttributeValue:
4054  * @ctxt: the validation context
4055  * @doc:  the document
4056  * @elem:  the parent
4057  * @name:  the attribute name
4058  * @value:  the attribute value
4059  * @ctxt:  the validation context or NULL
4060  *
4061  * Does the validation related extra step of the normalization of attribute
4062  * values:
4063  *
4064  * If the declared value is not CDATA, then the XML processor must further
4065  * process the normalized attribute value by discarding any leading and
4066  * trailing space (#x20) characters, and by replacing sequences of space
4067  * (#x20) characters by single space (#x20) character.
4068  *
4069  * Also  check VC: Standalone Document Declaration in P32, and update
4070  *  ctxt->valid accordingly
4071  *
4072  * returns a new normalized string if normalization is needed, NULL otherwise
4073  *      the caller must free the returned value.
4074  */
4075 
4076 xmlChar *
xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt,xmlDocPtr doc,xmlNodePtr elem,const xmlChar * name,const xmlChar * value)4077 xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4078 	     xmlNodePtr elem, const xmlChar *name, const xmlChar *value) {
4079     xmlChar *ret;
4080     xmlAttributePtr attrDecl = NULL;
4081     int extsubset = 0;
4082 
4083     if (doc == NULL) return(NULL);
4084     if (elem == NULL) return(NULL);
4085     if (name == NULL) return(NULL);
4086     if (value == NULL) return(NULL);
4087 
4088     if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
4089 	xmlChar fn[50];
4090 	xmlChar *fullname;
4091 
4092 	fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
4093 	if (fullname == NULL)
4094 	    return(NULL);
4095 	attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name);
4096 	if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
4097 	    attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name);
4098 	    if (attrDecl != NULL)
4099 		extsubset = 1;
4100 	}
4101 	if ((fullname != fn) && (fullname != elem->name))
4102 	    xmlFree(fullname);
4103     }
4104     if ((attrDecl == NULL) && (doc->intSubset != NULL))
4105 	attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
4106     if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
4107 	attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
4108 	if (attrDecl != NULL)
4109 	    extsubset = 1;
4110     }
4111 
4112     if (attrDecl == NULL)
4113 	return(NULL);
4114     if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
4115 	return(NULL);
4116 
4117     ret = xmlStrdup(value);
4118     if (ret == NULL)
4119 	return(NULL);
4120     xmlValidNormalizeString(ret);
4121     if ((doc->standalone) && (extsubset == 1) && (!xmlStrEqual(value, ret))) {
4122 	xmlErrValidNode(ctxt, elem, XML_DTD_NOT_STANDALONE,
4123 "standalone: %s on %s value had to be normalized based on external subset declaration\n",
4124 	       name, elem->name, NULL);
4125 	ctxt->valid = 0;
4126     }
4127     return(ret);
4128 }
4129 
4130 /**
4131  * xmlValidNormalizeAttributeValue:
4132  * @doc:  the document
4133  * @elem:  the parent
4134  * @name:  the attribute name
4135  * @value:  the attribute value
4136  *
4137  * Does the validation related extra step of the normalization of attribute
4138  * values:
4139  *
4140  * If the declared value is not CDATA, then the XML processor must further
4141  * process the normalized attribute value by discarding any leading and
4142  * trailing space (#x20) characters, and by replacing sequences of space
4143  * (#x20) characters by single space (#x20) character.
4144  *
4145  * Returns a new normalized string if normalization is needed, NULL otherwise
4146  *      the caller must free the returned value.
4147  */
4148 
4149 xmlChar *
xmlValidNormalizeAttributeValue(xmlDocPtr doc,xmlNodePtr elem,const xmlChar * name,const xmlChar * value)4150 xmlValidNormalizeAttributeValue(xmlDocPtr doc, xmlNodePtr elem,
4151 			        const xmlChar *name, const xmlChar *value) {
4152     xmlChar *ret;
4153     xmlAttributePtr attrDecl = NULL;
4154 
4155     if (doc == NULL) return(NULL);
4156     if (elem == NULL) return(NULL);
4157     if (name == NULL) return(NULL);
4158     if (value == NULL) return(NULL);
4159 
4160     if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
4161 	xmlChar fn[50];
4162 	xmlChar *fullname;
4163 
4164 	fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
4165 	if (fullname == NULL)
4166 	    return(NULL);
4167 	if ((fullname != fn) && (fullname != elem->name))
4168 	    xmlFree(fullname);
4169     }
4170     attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
4171     if ((attrDecl == NULL) && (doc->extSubset != NULL))
4172 	attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
4173 
4174     if (attrDecl == NULL)
4175 	return(NULL);
4176     if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
4177 	return(NULL);
4178 
4179     ret = xmlStrdup(value);
4180     if (ret == NULL)
4181 	return(NULL);
4182     xmlValidNormalizeString(ret);
4183     return(ret);
4184 }
4185 
4186 static void
xmlValidateAttributeIdCallback(void * payload,void * data,const xmlChar * name ATTRIBUTE_UNUSED)4187 xmlValidateAttributeIdCallback(void *payload, void *data,
4188 	                       const xmlChar *name ATTRIBUTE_UNUSED) {
4189     xmlAttributePtr attr = (xmlAttributePtr) payload;
4190     int *count = (int *) data;
4191     if (attr->atype == XML_ATTRIBUTE_ID) (*count)++;
4192 }
4193 
4194 /**
4195  * xmlValidateAttributeDecl:
4196  * @ctxt:  the validation context
4197  * @doc:  a document instance
4198  * @attr:  an attribute definition
4199  *
4200  * Try to validate a single attribute definition
4201  * basically it does the following checks as described by the
4202  * XML-1.0 recommendation:
4203  *  - [ VC: Attribute Default Legal ]
4204  *  - [ VC: Enumeration ]
4205  *  - [ VC: ID Attribute Default ]
4206  *
4207  * The ID/IDREF uniqueness and matching are done separately
4208  *
4209  * returns 1 if valid or 0 otherwise
4210  */
4211 
4212 int
xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt,xmlDocPtr doc,xmlAttributePtr attr)4213 xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4214                          xmlAttributePtr attr) {
4215     int ret = 1;
4216     int val;
4217     CHECK_DTD;
4218     if(attr == NULL) return(1);
4219 
4220     /* Attribute Default Legal */
4221     /* Enumeration */
4222     if (attr->defaultValue != NULL) {
4223 	val = xmlValidateAttributeValueInternal(doc, attr->atype,
4224 	                                        attr->defaultValue);
4225 	if (val == 0) {
4226 	    xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_DEFAULT,
4227 	       "Syntax of default value for attribute %s of %s is not valid\n",
4228 	           attr->name, attr->elem, NULL);
4229 	}
4230         ret &= val;
4231     }
4232 
4233     /* ID Attribute Default */
4234     if ((attr->atype == XML_ATTRIBUTE_ID)&&
4235         (attr->def != XML_ATTRIBUTE_IMPLIED) &&
4236 	(attr->def != XML_ATTRIBUTE_REQUIRED)) {
4237 	xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_FIXED,
4238           "ID attribute %s of %s is not valid must be #IMPLIED or #REQUIRED\n",
4239 	       attr->name, attr->elem, NULL);
4240 	ret = 0;
4241     }
4242 
4243     /* One ID per Element Type */
4244     if (attr->atype == XML_ATTRIBUTE_ID) {
4245         int nbId;
4246 
4247 	/* the trick is that we parse DtD as their own internal subset */
4248         xmlElementPtr elem = xmlGetDtdElementDesc(doc->intSubset,
4249 	                                          attr->elem);
4250 	if (elem != NULL) {
4251 	    nbId = xmlScanIDAttributeDecl(NULL, elem, 0);
4252 	} else {
4253 	    xmlAttributeTablePtr table;
4254 
4255 	    /*
4256 	     * The attribute may be declared in the internal subset and the
4257 	     * element in the external subset.
4258 	     */
4259 	    nbId = 0;
4260 	    if (doc->intSubset != NULL) {
4261 		table = (xmlAttributeTablePtr) doc->intSubset->attributes;
4262 		xmlHashScan3(table, NULL, NULL, attr->elem,
4263 			     xmlValidateAttributeIdCallback, &nbId);
4264 	    }
4265 	}
4266 	if (nbId > 1) {
4267 
4268 	    xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
4269        "Element %s has %d ID attribute defined in the internal subset : %s\n",
4270 		   attr->elem, nbId, attr->name);
4271 	} else if (doc->extSubset != NULL) {
4272 	    int extId = 0;
4273 	    elem = xmlGetDtdElementDesc(doc->extSubset, attr->elem);
4274 	    if (elem != NULL) {
4275 		extId = xmlScanIDAttributeDecl(NULL, elem, 0);
4276 	    }
4277 	    if (extId > 1) {
4278 		xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
4279        "Element %s has %d ID attribute defined in the external subset : %s\n",
4280 		       attr->elem, extId, attr->name);
4281 	    } else if (extId + nbId > 1) {
4282 		xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
4283 "Element %s has ID attributes defined in the internal and external subset : %s\n",
4284 		       attr->elem, attr->name, NULL);
4285 	    }
4286 	}
4287     }
4288 
4289     /* Validity Constraint: Enumeration */
4290     if ((attr->defaultValue != NULL) && (attr->tree != NULL)) {
4291         xmlEnumerationPtr tree = attr->tree;
4292 	while (tree != NULL) {
4293 	    if (xmlStrEqual(tree->name, attr->defaultValue)) break;
4294 	    tree = tree->next;
4295 	}
4296 	if (tree == NULL) {
4297 	    xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_VALUE,
4298 "Default value \"%s\" for attribute %s of %s is not among the enumerated set\n",
4299 		   attr->defaultValue, attr->name, attr->elem);
4300 	    ret = 0;
4301 	}
4302     }
4303 
4304     return(ret);
4305 }
4306 
4307 /**
4308  * xmlValidateElementDecl:
4309  * @ctxt:  the validation context
4310  * @doc:  a document instance
4311  * @elem:  an element definition
4312  *
4313  * Try to validate a single element definition
4314  * basically it does the following checks as described by the
4315  * XML-1.0 recommendation:
4316  *  - [ VC: One ID per Element Type ]
4317  *  - [ VC: No Duplicate Types ]
4318  *  - [ VC: Unique Element Type Declaration ]
4319  *
4320  * returns 1 if valid or 0 otherwise
4321  */
4322 
4323 int
xmlValidateElementDecl(xmlValidCtxtPtr ctxt,xmlDocPtr doc,xmlElementPtr elem)4324 xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4325                        xmlElementPtr elem) {
4326     int ret = 1;
4327     xmlElementPtr tst;
4328 
4329     CHECK_DTD;
4330 
4331     if (elem == NULL) return(1);
4332 
4333 #if 0
4334 #ifdef LIBXML_REGEXP_ENABLED
4335     /* Build the regexp associated to the content model */
4336     ret = xmlValidBuildContentModel(ctxt, elem);
4337 #endif
4338 #endif
4339 
4340     /* No Duplicate Types */
4341     if (elem->etype == XML_ELEMENT_TYPE_MIXED) {
4342 	xmlElementContentPtr cur, next;
4343         const xmlChar *name;
4344 
4345 	cur = elem->content;
4346 	while (cur != NULL) {
4347 	    if (cur->type != XML_ELEMENT_CONTENT_OR) break;
4348 	    if (cur->c1 == NULL) break;
4349 	    if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
4350 		name = cur->c1->name;
4351 		next = cur->c2;
4352 		while (next != NULL) {
4353 		    if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
4354 		        if ((xmlStrEqual(next->name, name)) &&
4355 			    (xmlStrEqual(next->prefix, cur->c1->prefix))) {
4356 			    if (cur->c1->prefix == NULL) {
4357 				xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
4358 		   "Definition of %s has duplicate references of %s\n",
4359 				       elem->name, name, NULL);
4360 			    } else {
4361 				xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
4362 		   "Definition of %s has duplicate references of %s:%s\n",
4363 				       elem->name, cur->c1->prefix, name);
4364 			    }
4365 			    ret = 0;
4366 			}
4367 			break;
4368 		    }
4369 		    if (next->c1 == NULL) break;
4370 		    if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
4371 		    if ((xmlStrEqual(next->c1->name, name)) &&
4372 		        (xmlStrEqual(next->c1->prefix, cur->c1->prefix))) {
4373 			if (cur->c1->prefix == NULL) {
4374 			    xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
4375 	       "Definition of %s has duplicate references to %s\n",
4376 				   elem->name, name, NULL);
4377 			} else {
4378 			    xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
4379 	       "Definition of %s has duplicate references to %s:%s\n",
4380 				   elem->name, cur->c1->prefix, name);
4381 			}
4382 			ret = 0;
4383 		    }
4384 		    next = next->c2;
4385 		}
4386 	    }
4387 	    cur = cur->c2;
4388 	}
4389     }
4390 
4391     /* VC: Unique Element Type Declaration */
4392     tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
4393     if ((tst != NULL ) && (tst != elem) &&
4394 	((tst->prefix == elem->prefix) ||
4395 	 (xmlStrEqual(tst->prefix, elem->prefix))) &&
4396 	(tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
4397 	xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
4398 	                "Redefinition of element %s\n",
4399 		       elem->name, NULL, NULL);
4400 	ret = 0;
4401     }
4402     tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
4403     if ((tst != NULL ) && (tst != elem) &&
4404 	((tst->prefix == elem->prefix) ||
4405 	 (xmlStrEqual(tst->prefix, elem->prefix))) &&
4406 	(tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
4407 	xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
4408 	                "Redefinition of element %s\n",
4409 		       elem->name, NULL, NULL);
4410 	ret = 0;
4411     }
4412     /* One ID per Element Type
4413      * already done when registering the attribute
4414     if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
4415 	ret = 0;
4416     } */
4417     return(ret);
4418 }
4419 
4420 /**
4421  * xmlValidateOneAttribute:
4422  * @ctxt:  the validation context
4423  * @doc:  a document instance
4424  * @elem:  an element instance
4425  * @attr:  an attribute instance
4426  * @value:  the attribute value (without entities processing)
4427  *
4428  * Try to validate a single attribute for an element
4429  * basically it does the following checks as described by the
4430  * XML-1.0 recommendation:
4431  *  - [ VC: Attribute Value Type ]
4432  *  - [ VC: Fixed Attribute Default ]
4433  *  - [ VC: Entity Name ]
4434  *  - [ VC: Name Token ]
4435  *  - [ VC: ID ]
4436  *  - [ VC: IDREF ]
4437  *  - [ VC: Entity Name ]
4438  *  - [ VC: Notation Attributes ]
4439  *
4440  * The ID/IDREF uniqueness and matching are done separately
4441  *
4442  * returns 1 if valid or 0 otherwise
4443  */
4444 
4445 int
xmlValidateOneAttribute(xmlValidCtxtPtr ctxt,xmlDocPtr doc,xmlNodePtr elem,xmlAttrPtr attr,const xmlChar * value)4446 xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4447                         xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value)
4448 {
4449     xmlAttributePtr attrDecl =  NULL;
4450     int val;
4451     int ret = 1;
4452 
4453     CHECK_DTD;
4454     if ((elem == NULL) || (elem->name == NULL)) return(0);
4455     if ((attr == NULL) || (attr->name == NULL)) return(0);
4456 
4457     if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
4458 	xmlChar fn[50];
4459 	xmlChar *fullname;
4460 
4461 	fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
4462 	if (fullname == NULL)
4463 	    return(0);
4464 	if (attr->ns != NULL) {
4465 	    attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
4466 		                          attr->name, attr->ns->prefix);
4467 	    if ((attrDecl == NULL) && (doc->extSubset != NULL))
4468 		attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
4469 					      attr->name, attr->ns->prefix);
4470 	} else {
4471 	    attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, attr->name);
4472 	    if ((attrDecl == NULL) && (doc->extSubset != NULL))
4473 		attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4474 					     fullname, attr->name);
4475 	}
4476 	if ((fullname != fn) && (fullname != elem->name))
4477 	    xmlFree(fullname);
4478     }
4479     if (attrDecl == NULL) {
4480 	if (attr->ns != NULL) {
4481 	    attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4482 		                          attr->name, attr->ns->prefix);
4483 	    if ((attrDecl == NULL) && (doc->extSubset != NULL))
4484 		attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4485 					      attr->name, attr->ns->prefix);
4486 	} else {
4487 	    attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4488 		                         elem->name, attr->name);
4489 	    if ((attrDecl == NULL) && (doc->extSubset != NULL))
4490 		attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4491 					     elem->name, attr->name);
4492 	}
4493     }
4494 
4495 
4496     /* Validity Constraint: Attribute Value Type */
4497     if (attrDecl == NULL) {
4498 	xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
4499 	       "No declaration for attribute %s of element %s\n",
4500 	       attr->name, elem->name, NULL);
4501 	return(0);
4502     }
4503     attr->atype = attrDecl->atype;
4504 
4505     val = xmlValidateAttributeValueInternal(doc, attrDecl->atype, value);
4506     if (val == 0) {
4507 	    xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
4508 	   "Syntax of value for attribute %s of %s is not valid\n",
4509 	       attr->name, elem->name, NULL);
4510         ret = 0;
4511     }
4512 
4513     /* Validity constraint: Fixed Attribute Default */
4514     if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4515 	if (!xmlStrEqual(value, attrDecl->defaultValue)) {
4516 	    xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
4517 	   "Value for attribute %s of %s is different from default \"%s\"\n",
4518 		   attr->name, elem->name, attrDecl->defaultValue);
4519 	    ret = 0;
4520 	}
4521     }
4522 
4523     /* Validity Constraint: ID uniqueness */
4524     if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4525         if (xmlAddID(ctxt, doc, value, attr) == NULL)
4526 	    ret = 0;
4527     }
4528 
4529     if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4530 	(attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4531         if (xmlAddRef(ctxt, doc, value, attr) == NULL)
4532 	    ret = 0;
4533     }
4534 
4535     /* Validity Constraint: Notation Attributes */
4536     if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4537         xmlEnumerationPtr tree = attrDecl->tree;
4538         xmlNotationPtr nota;
4539 
4540         /* First check that the given NOTATION was declared */
4541 	nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4542 	if (nota == NULL)
4543 	    nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4544 
4545 	if (nota == NULL) {
4546 	    xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
4547        "Value \"%s\" for attribute %s of %s is not a declared Notation\n",
4548 		   value, attr->name, elem->name);
4549 	    ret = 0;
4550         }
4551 
4552 	/* Second, verify that it's among the list */
4553 	while (tree != NULL) {
4554 	    if (xmlStrEqual(tree->name, value)) break;
4555 	    tree = tree->next;
4556 	}
4557 	if (tree == NULL) {
4558 	    xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
4559 "Value \"%s\" for attribute %s of %s is not among the enumerated notations\n",
4560 		   value, attr->name, elem->name);
4561 	    ret = 0;
4562 	}
4563     }
4564 
4565     /* Validity Constraint: Enumeration */
4566     if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4567         xmlEnumerationPtr tree = attrDecl->tree;
4568 	while (tree != NULL) {
4569 	    if (xmlStrEqual(tree->name, value)) break;
4570 	    tree = tree->next;
4571 	}
4572 	if (tree == NULL) {
4573 	    xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
4574        "Value \"%s\" for attribute %s of %s is not among the enumerated set\n",
4575 		   value, attr->name, elem->name);
4576 	    ret = 0;
4577 	}
4578     }
4579 
4580     /* Fixed Attribute Default */
4581     if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4582         (!xmlStrEqual(attrDecl->defaultValue, value))) {
4583 	xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
4584 	   "Value for attribute %s of %s must be \"%s\"\n",
4585 	       attr->name, elem->name, attrDecl->defaultValue);
4586         ret = 0;
4587     }
4588 
4589     /* Extra check for the attribute value */
4590     ret &= xmlValidateAttributeValue2(ctxt, doc, attr->name,
4591 				      attrDecl->atype, value);
4592 
4593     return(ret);
4594 }
4595 
4596 /**
4597  * xmlValidateOneNamespace:
4598  * @ctxt:  the validation context
4599  * @doc:  a document instance
4600  * @elem:  an element instance
4601  * @prefix:  the namespace prefix
4602  * @ns:  an namespace declaration instance
4603  * @value:  the attribute value (without entities processing)
4604  *
4605  * Try to validate a single namespace declaration for an element
4606  * basically it does the following checks as described by the
4607  * XML-1.0 recommendation:
4608  *  - [ VC: Attribute Value Type ]
4609  *  - [ VC: Fixed Attribute Default ]
4610  *  - [ VC: Entity Name ]
4611  *  - [ VC: Name Token ]
4612  *  - [ VC: ID ]
4613  *  - [ VC: IDREF ]
4614  *  - [ VC: Entity Name ]
4615  *  - [ VC: Notation Attributes ]
4616  *
4617  * The ID/IDREF uniqueness and matching are done separately
4618  *
4619  * returns 1 if valid or 0 otherwise
4620  */
4621 
4622 int
xmlValidateOneNamespace(xmlValidCtxtPtr ctxt,xmlDocPtr doc,xmlNodePtr elem,const xmlChar * prefix,xmlNsPtr ns,const xmlChar * value)4623 xmlValidateOneNamespace(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4624 xmlNodePtr elem, const xmlChar *prefix, xmlNsPtr ns, const xmlChar *value) {
4625     /* xmlElementPtr elemDecl; */
4626     xmlAttributePtr attrDecl =  NULL;
4627     int val;
4628     int ret = 1;
4629 
4630     CHECK_DTD;
4631     if ((elem == NULL) || (elem->name == NULL)) return(0);
4632     if ((ns == NULL) || (ns->href == NULL)) return(0);
4633 
4634     if (prefix != NULL) {
4635 	xmlChar fn[50];
4636 	xmlChar *fullname;
4637 
4638 	fullname = xmlBuildQName(elem->name, prefix, fn, 50);
4639 	if (fullname == NULL) {
4640 	    xmlVErrMemory(ctxt, "Validating namespace");
4641 	    return(0);
4642 	}
4643 	if (ns->prefix != NULL) {
4644 	    attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
4645 		                          ns->prefix, BAD_CAST "xmlns");
4646 	    if ((attrDecl == NULL) && (doc->extSubset != NULL))
4647 		attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
4648 					  ns->prefix, BAD_CAST "xmlns");
4649 	} else {
4650 	    attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname,
4651 		                         BAD_CAST "xmlns");
4652 	    if ((attrDecl == NULL) && (doc->extSubset != NULL))
4653 		attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname,
4654 			                 BAD_CAST "xmlns");
4655 	}
4656 	if ((fullname != fn) && (fullname != elem->name))
4657 	    xmlFree(fullname);
4658     }
4659     if (attrDecl == NULL) {
4660 	if (ns->prefix != NULL) {
4661 	    attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4662 		                          ns->prefix, BAD_CAST "xmlns");
4663 	    if ((attrDecl == NULL) && (doc->extSubset != NULL))
4664 		attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4665 					      ns->prefix, BAD_CAST "xmlns");
4666 	} else {
4667 	    attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4668 		                         elem->name, BAD_CAST "xmlns");
4669 	    if ((attrDecl == NULL) && (doc->extSubset != NULL))
4670 		attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4671 					     elem->name, BAD_CAST "xmlns");
4672 	}
4673     }
4674 
4675 
4676     /* Validity Constraint: Attribute Value Type */
4677     if (attrDecl == NULL) {
4678 	if (ns->prefix != NULL) {
4679 	    xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
4680 		   "No declaration for attribute xmlns:%s of element %s\n",
4681 		   ns->prefix, elem->name, NULL);
4682 	} else {
4683 	    xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
4684 		   "No declaration for attribute xmlns of element %s\n",
4685 		   elem->name, NULL, NULL);
4686 	}
4687 	return(0);
4688     }
4689 
4690     val = xmlValidateAttributeValueInternal(doc, attrDecl->atype, value);
4691     if (val == 0) {
4692 	if (ns->prefix != NULL) {
4693 	    xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
4694 	       "Syntax of value for attribute xmlns:%s of %s is not valid\n",
4695 		   ns->prefix, elem->name, NULL);
4696 	} else {
4697 	    xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
4698 	       "Syntax of value for attribute xmlns of %s is not valid\n",
4699 		   elem->name, NULL, NULL);
4700 	}
4701         ret = 0;
4702     }
4703 
4704     /* Validity constraint: Fixed Attribute Default */
4705     if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4706 	if (!xmlStrEqual(value, attrDecl->defaultValue)) {
4707 	    if (ns->prefix != NULL) {
4708 		xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
4709        "Value for attribute xmlns:%s of %s is different from default \"%s\"\n",
4710 		       ns->prefix, elem->name, attrDecl->defaultValue);
4711 	    } else {
4712 		xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
4713        "Value for attribute xmlns of %s is different from default \"%s\"\n",
4714 		       elem->name, attrDecl->defaultValue, NULL);
4715 	    }
4716 	    ret = 0;
4717 	}
4718     }
4719 
4720     /*
4721      * Casting ns to xmlAttrPtr is wrong. We'd need separate functions
4722      * xmlAddID and xmlAddRef for namespace declarations, but it makes
4723      * no practical sense to use ID types anyway.
4724      */
4725 #if 0
4726     /* Validity Constraint: ID uniqueness */
4727     if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4728         if (xmlAddID(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4729 	    ret = 0;
4730     }
4731 
4732     if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4733 	(attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4734         if (xmlAddRef(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4735 	    ret = 0;
4736     }
4737 #endif
4738 
4739     /* Validity Constraint: Notation Attributes */
4740     if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4741         xmlEnumerationPtr tree = attrDecl->tree;
4742         xmlNotationPtr nota;
4743 
4744         /* First check that the given NOTATION was declared */
4745 	nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4746 	if (nota == NULL)
4747 	    nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4748 
4749 	if (nota == NULL) {
4750 	    if (ns->prefix != NULL) {
4751 		xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
4752        "Value \"%s\" for attribute xmlns:%s of %s is not a declared Notation\n",
4753 		       value, ns->prefix, elem->name);
4754 	    } else {
4755 		xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
4756        "Value \"%s\" for attribute xmlns of %s is not a declared Notation\n",
4757 		       value, elem->name, NULL);
4758 	    }
4759 	    ret = 0;
4760         }
4761 
4762 	/* Second, verify that it's among the list */
4763 	while (tree != NULL) {
4764 	    if (xmlStrEqual(tree->name, value)) break;
4765 	    tree = tree->next;
4766 	}
4767 	if (tree == NULL) {
4768 	    if (ns->prefix != NULL) {
4769 		xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
4770 "Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated notations\n",
4771 		       value, ns->prefix, elem->name);
4772 	    } else {
4773 		xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
4774 "Value \"%s\" for attribute xmlns of %s is not among the enumerated notations\n",
4775 		       value, elem->name, NULL);
4776 	    }
4777 	    ret = 0;
4778 	}
4779     }
4780 
4781     /* Validity Constraint: Enumeration */
4782     if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4783         xmlEnumerationPtr tree = attrDecl->tree;
4784 	while (tree != NULL) {
4785 	    if (xmlStrEqual(tree->name, value)) break;
4786 	    tree = tree->next;
4787 	}
4788 	if (tree == NULL) {
4789 	    if (ns->prefix != NULL) {
4790 		xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
4791 "Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated set\n",
4792 		       value, ns->prefix, elem->name);
4793 	    } else {
4794 		xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
4795 "Value \"%s\" for attribute xmlns of %s is not among the enumerated set\n",
4796 		       value, elem->name, NULL);
4797 	    }
4798 	    ret = 0;
4799 	}
4800     }
4801 
4802     /* Fixed Attribute Default */
4803     if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4804         (!xmlStrEqual(attrDecl->defaultValue, value))) {
4805 	if (ns->prefix != NULL) {
4806 	    xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
4807 		   "Value for attribute xmlns:%s of %s must be \"%s\"\n",
4808 		   ns->prefix, elem->name, attrDecl->defaultValue);
4809 	} else {
4810 	    xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
4811 		   "Value for attribute xmlns of %s must be \"%s\"\n",
4812 		   elem->name, attrDecl->defaultValue, NULL);
4813 	}
4814         ret = 0;
4815     }
4816 
4817     /* Extra check for the attribute value */
4818     if (ns->prefix != NULL) {
4819 	ret &= xmlValidateAttributeValue2(ctxt, doc, ns->prefix,
4820 					  attrDecl->atype, value);
4821     } else {
4822 	ret &= xmlValidateAttributeValue2(ctxt, doc, BAD_CAST "xmlns",
4823 					  attrDecl->atype, value);
4824     }
4825 
4826     return(ret);
4827 }
4828 
4829 #ifndef  LIBXML_REGEXP_ENABLED
4830 /**
4831  * xmlValidateSkipIgnorable:
4832  * @ctxt:  the validation context
4833  * @child:  the child list
4834  *
4835  * Skip ignorable elements w.r.t. the validation process
4836  *
4837  * returns the first element to consider for validation of the content model
4838  */
4839 
4840 static xmlNodePtr
xmlValidateSkipIgnorable(xmlNodePtr child)4841 xmlValidateSkipIgnorable(xmlNodePtr child) {
4842     while (child != NULL) {
4843 	switch (child->type) {
4844 	    /* These things are ignored (skipped) during validation.  */
4845 	    case XML_PI_NODE:
4846 	    case XML_COMMENT_NODE:
4847 	    case XML_XINCLUDE_START:
4848 	    case XML_XINCLUDE_END:
4849 		child = child->next;
4850 		break;
4851 	    case XML_TEXT_NODE:
4852 		if (xmlIsBlankNode(child))
4853 		    child = child->next;
4854 		else
4855 		    return(child);
4856 		break;
4857 	    /* keep current node */
4858 	    default:
4859 		return(child);
4860 	}
4861     }
4862     return(child);
4863 }
4864 
4865 /**
4866  * xmlValidateElementType:
4867  * @ctxt:  the validation context
4868  *
4869  * Try to validate the content model of an element internal function
4870  *
4871  * returns 1 if valid or 0 ,-1 in case of error, -2 if an entity
4872  *           reference is found and -3 if the validation succeeded but
4873  *           the content model is not determinist.
4874  */
4875 
4876 static int
xmlValidateElementType(xmlValidCtxtPtr ctxt)4877 xmlValidateElementType(xmlValidCtxtPtr ctxt) {
4878     int ret = -1;
4879     int determinist = 1;
4880 
4881     NODE = xmlValidateSkipIgnorable(NODE);
4882     if ((NODE == NULL) && (CONT == NULL))
4883 	return(1);
4884     if ((NODE == NULL) &&
4885 	((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
4886 	 (CONT->ocur == XML_ELEMENT_CONTENT_OPT))) {
4887 	return(1);
4888     }
4889     if (CONT == NULL) return(-1);
4890     if ((NODE != NULL) && (NODE->type == XML_ENTITY_REF_NODE))
4891 	return(-2);
4892 
4893     /*
4894      * We arrive here when more states need to be examined
4895      */
4896 cont:
4897 
4898     /*
4899      * We just recovered from a rollback generated by a possible
4900      * epsilon transition, go directly to the analysis phase
4901      */
4902     if (STATE == ROLLBACK_PARENT) {
4903 	DEBUG_VALID_MSG("restored parent branch");
4904 	DEBUG_VALID_STATE(NODE, CONT)
4905 	ret = 1;
4906 	goto analyze;
4907     }
4908 
4909     DEBUG_VALID_STATE(NODE, CONT)
4910     /*
4911      * we may have to save a backup state here. This is the equivalent
4912      * of handling epsilon transition in NFAs.
4913      */
4914     if ((CONT != NULL) &&
4915 	((CONT->parent == NULL) ||
4916 	 (CONT->parent->type != XML_ELEMENT_CONTENT_OR)) &&
4917 	((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
4918 	 (CONT->ocur == XML_ELEMENT_CONTENT_OPT) ||
4919 	 ((CONT->ocur == XML_ELEMENT_CONTENT_PLUS) && (OCCURRENCE)))) {
4920 	DEBUG_VALID_MSG("saving parent branch");
4921 	if (vstateVPush(ctxt, CONT, NODE, DEPTH, OCCURS, ROLLBACK_PARENT) < 0)
4922 	    return(0);
4923     }
4924 
4925 
4926     /*
4927      * Check first if the content matches
4928      */
4929     switch (CONT->type) {
4930 	case XML_ELEMENT_CONTENT_PCDATA:
4931 	    if (NODE == NULL) {
4932 		DEBUG_VALID_MSG("pcdata failed no node");
4933 		ret = 0;
4934 		break;
4935 	    }
4936 	    if (NODE->type == XML_TEXT_NODE) {
4937 		DEBUG_VALID_MSG("pcdata found, skip to next");
4938 		/*
4939 		 * go to next element in the content model
4940 		 * skipping ignorable elems
4941 		 */
4942 		do {
4943 		    NODE = NODE->next;
4944 		    NODE = xmlValidateSkipIgnorable(NODE);
4945 		    if ((NODE != NULL) &&
4946 			(NODE->type == XML_ENTITY_REF_NODE))
4947 			return(-2);
4948 		} while ((NODE != NULL) &&
4949 			 ((NODE->type != XML_ELEMENT_NODE) &&
4950 			  (NODE->type != XML_TEXT_NODE) &&
4951 			  (NODE->type != XML_CDATA_SECTION_NODE)));
4952                 ret = 1;
4953 		break;
4954 	    } else {
4955 		DEBUG_VALID_MSG("pcdata failed");
4956 		ret = 0;
4957 		break;
4958 	    }
4959 	    break;
4960 	case XML_ELEMENT_CONTENT_ELEMENT:
4961 	    if (NODE == NULL) {
4962 		DEBUG_VALID_MSG("element failed no node");
4963 		ret = 0;
4964 		break;
4965 	    }
4966 	    ret = ((NODE->type == XML_ELEMENT_NODE) &&
4967 		   (xmlStrEqual(NODE->name, CONT->name)));
4968 	    if (ret == 1) {
4969 		if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4970 		    ret = (CONT->prefix == NULL);
4971 		} else if (CONT->prefix == NULL) {
4972 		    ret = 0;
4973 		} else {
4974 		    ret = xmlStrEqual(NODE->ns->prefix, CONT->prefix);
4975 		}
4976 	    }
4977 	    if (ret == 1) {
4978 		DEBUG_VALID_MSG("element found, skip to next");
4979 		/*
4980 		 * go to next element in the content model
4981 		 * skipping ignorable elems
4982 		 */
4983 		do {
4984 		    NODE = NODE->next;
4985 		    NODE = xmlValidateSkipIgnorable(NODE);
4986 		    if ((NODE != NULL) &&
4987 			(NODE->type == XML_ENTITY_REF_NODE))
4988 			return(-2);
4989 		} while ((NODE != NULL) &&
4990 			 ((NODE->type != XML_ELEMENT_NODE) &&
4991 			  (NODE->type != XML_TEXT_NODE) &&
4992 			  (NODE->type != XML_CDATA_SECTION_NODE)));
4993 	    } else {
4994 		DEBUG_VALID_MSG("element failed");
4995 		ret = 0;
4996 		break;
4997 	    }
4998 	    break;
4999 	case XML_ELEMENT_CONTENT_OR:
5000 	    /*
5001 	     * Small optimization.
5002 	     */
5003 	    if (CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
5004 		if ((NODE == NULL) ||
5005 		    (!xmlStrEqual(NODE->name, CONT->c1->name))) {
5006 		    DEPTH++;
5007 		    CONT = CONT->c2;
5008 		    goto cont;
5009 		}
5010 		if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
5011 		    ret = (CONT->c1->prefix == NULL);
5012 		} else if (CONT->c1->prefix == NULL) {
5013 		    ret = 0;
5014 		} else {
5015 		    ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
5016 		}
5017 		if (ret == 0) {
5018 		    DEPTH++;
5019 		    CONT = CONT->c2;
5020 		    goto cont;
5021 		}
5022 	    }
5023 
5024 	    /*
5025 	     * save the second branch 'or' branch
5026 	     */
5027 	    DEBUG_VALID_MSG("saving 'or' branch");
5028 	    if (vstateVPush(ctxt, CONT->c2, NODE, (unsigned char)(DEPTH + 1),
5029 			    OCCURS, ROLLBACK_OR) < 0)
5030 		return(-1);
5031 	    DEPTH++;
5032 	    CONT = CONT->c1;
5033 	    goto cont;
5034 	case XML_ELEMENT_CONTENT_SEQ:
5035 	    /*
5036 	     * Small optimization.
5037 	     */
5038 	    if ((CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) &&
5039 		((CONT->c1->ocur == XML_ELEMENT_CONTENT_OPT) ||
5040 		 (CONT->c1->ocur == XML_ELEMENT_CONTENT_MULT))) {
5041 		if ((NODE == NULL) ||
5042 		    (!xmlStrEqual(NODE->name, CONT->c1->name))) {
5043 		    DEPTH++;
5044 		    CONT = CONT->c2;
5045 		    goto cont;
5046 		}
5047 		if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
5048 		    ret = (CONT->c1->prefix == NULL);
5049 		} else if (CONT->c1->prefix == NULL) {
5050 		    ret = 0;
5051 		} else {
5052 		    ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
5053 		}
5054 		if (ret == 0) {
5055 		    DEPTH++;
5056 		    CONT = CONT->c2;
5057 		    goto cont;
5058 		}
5059 	    }
5060 	    DEPTH++;
5061 	    CONT = CONT->c1;
5062 	    goto cont;
5063     }
5064 
5065     /*
5066      * At this point handle going up in the tree
5067      */
5068     if (ret == -1) {
5069 	DEBUG_VALID_MSG("error found returning");
5070 	return(ret);
5071     }
5072 analyze:
5073     while (CONT != NULL) {
5074 	/*
5075 	 * First do the analysis depending on the occurrence model at
5076 	 * this level.
5077 	 */
5078 	if (ret == 0) {
5079 	    switch (CONT->ocur) {
5080 		xmlNodePtr cur;
5081 
5082 		case XML_ELEMENT_CONTENT_ONCE:
5083 		    cur = ctxt->vstate->node;
5084 		    DEBUG_VALID_MSG("Once branch failed, rollback");
5085 		    if (vstateVPop(ctxt) < 0 ) {
5086 			DEBUG_VALID_MSG("exhaustion, failed");
5087 			return(0);
5088 		    }
5089 		    if (cur != ctxt->vstate->node)
5090 			determinist = -3;
5091 		    goto cont;
5092 		case XML_ELEMENT_CONTENT_PLUS:
5093 		    if (OCCURRENCE == 0) {
5094 			cur = ctxt->vstate->node;
5095 			DEBUG_VALID_MSG("Plus branch failed, rollback");
5096 			if (vstateVPop(ctxt) < 0 ) {
5097 			    DEBUG_VALID_MSG("exhaustion, failed");
5098 			    return(0);
5099 			}
5100 			if (cur != ctxt->vstate->node)
5101 			    determinist = -3;
5102 			goto cont;
5103 		    }
5104 		    DEBUG_VALID_MSG("Plus branch found");
5105 		    ret = 1;
5106 		    break;
5107 		case XML_ELEMENT_CONTENT_MULT:
5108 #ifdef DEBUG_VALID_ALGO
5109 		    if (OCCURRENCE == 0) {
5110 			DEBUG_VALID_MSG("Mult branch failed");
5111 		    } else {
5112 			DEBUG_VALID_MSG("Mult branch found");
5113 		    }
5114 #endif
5115 		    ret = 1;
5116 		    break;
5117 		case XML_ELEMENT_CONTENT_OPT:
5118 		    DEBUG_VALID_MSG("Option branch failed");
5119 		    ret = 1;
5120 		    break;
5121 	    }
5122 	} else {
5123 	    switch (CONT->ocur) {
5124 		case XML_ELEMENT_CONTENT_OPT:
5125 		    DEBUG_VALID_MSG("Option branch succeeded");
5126 		    ret = 1;
5127 		    break;
5128 		case XML_ELEMENT_CONTENT_ONCE:
5129 		    DEBUG_VALID_MSG("Once branch succeeded");
5130 		    ret = 1;
5131 		    break;
5132 		case XML_ELEMENT_CONTENT_PLUS:
5133 		    if (STATE == ROLLBACK_PARENT) {
5134 			DEBUG_VALID_MSG("Plus branch rollback");
5135 			ret = 1;
5136 			break;
5137 		    }
5138 		    if (NODE == NULL) {
5139 			DEBUG_VALID_MSG("Plus branch exhausted");
5140 			ret = 1;
5141 			break;
5142 		    }
5143 		    DEBUG_VALID_MSG("Plus branch succeeded, continuing");
5144 		    SET_OCCURRENCE;
5145 		    goto cont;
5146 		case XML_ELEMENT_CONTENT_MULT:
5147 		    if (STATE == ROLLBACK_PARENT) {
5148 			DEBUG_VALID_MSG("Mult branch rollback");
5149 			ret = 1;
5150 			break;
5151 		    }
5152 		    if (NODE == NULL) {
5153 			DEBUG_VALID_MSG("Mult branch exhausted");
5154 			ret = 1;
5155 			break;
5156 		    }
5157 		    DEBUG_VALID_MSG("Mult branch succeeded, continuing");
5158 		    /* SET_OCCURRENCE; */
5159 		    goto cont;
5160 	    }
5161 	}
5162 	STATE = 0;
5163 
5164 	/*
5165 	 * Then act accordingly at the parent level
5166 	 */
5167 	RESET_OCCURRENCE;
5168 	if (CONT->parent == NULL)
5169 	    break;
5170 
5171 	switch (CONT->parent->type) {
5172 	    case XML_ELEMENT_CONTENT_PCDATA:
5173 		DEBUG_VALID_MSG("Error: parent pcdata");
5174 		return(-1);
5175 	    case XML_ELEMENT_CONTENT_ELEMENT:
5176 		DEBUG_VALID_MSG("Error: parent element");
5177 		return(-1);
5178 	    case XML_ELEMENT_CONTENT_OR:
5179 		if (ret == 1) {
5180 		    DEBUG_VALID_MSG("Or succeeded");
5181 		    CONT = CONT->parent;
5182 		    DEPTH--;
5183 		} else {
5184 		    DEBUG_VALID_MSG("Or failed");
5185 		    CONT = CONT->parent;
5186 		    DEPTH--;
5187 		}
5188 		break;
5189 	    case XML_ELEMENT_CONTENT_SEQ:
5190 		if (ret == 0) {
5191 		    DEBUG_VALID_MSG("Sequence failed");
5192 		    CONT = CONT->parent;
5193 		    DEPTH--;
5194 		} else if (CONT == CONT->parent->c1) {
5195 		    DEBUG_VALID_MSG("Sequence testing 2nd branch");
5196 		    CONT = CONT->parent->c2;
5197 		    goto cont;
5198 		} else {
5199 		    DEBUG_VALID_MSG("Sequence succeeded");
5200 		    CONT = CONT->parent;
5201 		    DEPTH--;
5202 		}
5203 	}
5204     }
5205     if (NODE != NULL) {
5206 	xmlNodePtr cur;
5207 
5208 	cur = ctxt->vstate->node;
5209 	DEBUG_VALID_MSG("Failed, remaining input, rollback");
5210 	if (vstateVPop(ctxt) < 0 ) {
5211 	    DEBUG_VALID_MSG("exhaustion, failed");
5212 	    return(0);
5213 	}
5214 	if (cur != ctxt->vstate->node)
5215 	    determinist = -3;
5216 	goto cont;
5217     }
5218     if (ret == 0) {
5219 	xmlNodePtr cur;
5220 
5221 	cur = ctxt->vstate->node;
5222 	DEBUG_VALID_MSG("Failure, rollback");
5223 	if (vstateVPop(ctxt) < 0 ) {
5224 	    DEBUG_VALID_MSG("exhaustion, failed");
5225 	    return(0);
5226 	}
5227 	if (cur != ctxt->vstate->node)
5228 	    determinist = -3;
5229 	goto cont;
5230     }
5231     return(determinist);
5232 }
5233 #endif
5234 
5235 /**
5236  * xmlSnprintfElements:
5237  * @buf:  an output buffer
5238  * @size:  the size of the buffer
5239  * @content:  An element
5240  * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
5241  *
5242  * This will dump the list of elements to the buffer
5243  * Intended just for the debug routine
5244  */
5245 static void
xmlSnprintfElements(char * buf,int size,xmlNodePtr node,int glob)5246 xmlSnprintfElements(char *buf, int size, xmlNodePtr node, int glob) {
5247     xmlNodePtr cur;
5248     int len;
5249 
5250     if (node == NULL) return;
5251     if (glob) strcat(buf, "(");
5252     cur = node;
5253     while (cur != NULL) {
5254 	len = strlen(buf);
5255 	if (size - len < 50) {
5256 	    if ((size - len > 4) && (buf[len - 1] != '.'))
5257 		strcat(buf, " ...");
5258 	    return;
5259 	}
5260         switch (cur->type) {
5261             case XML_ELEMENT_NODE:
5262 		if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5263 		    if (size - len < xmlStrlen(cur->ns->prefix) + 10) {
5264 			if ((size - len > 4) && (buf[len - 1] != '.'))
5265 			    strcat(buf, " ...");
5266 			return;
5267 		    }
5268 		    strcat(buf, (char *) cur->ns->prefix);
5269 		    strcat(buf, ":");
5270 		}
5271                 if (size - len < xmlStrlen(cur->name) + 10) {
5272 		    if ((size - len > 4) && (buf[len - 1] != '.'))
5273 			strcat(buf, " ...");
5274 		    return;
5275 		}
5276 	        strcat(buf, (char *) cur->name);
5277 		if (cur->next != NULL)
5278 		    strcat(buf, " ");
5279 		break;
5280             case XML_TEXT_NODE:
5281 		if (xmlIsBlankNode(cur))
5282 		    break;
5283                 /* Falls through. */
5284             case XML_CDATA_SECTION_NODE:
5285             case XML_ENTITY_REF_NODE:
5286 	        strcat(buf, "CDATA");
5287 		if (cur->next != NULL)
5288 		    strcat(buf, " ");
5289 		break;
5290             case XML_ATTRIBUTE_NODE:
5291             case XML_DOCUMENT_NODE:
5292 #ifdef LIBXML_DOCB_ENABLED
5293 	    case XML_DOCB_DOCUMENT_NODE:
5294 #endif
5295 	    case XML_HTML_DOCUMENT_NODE:
5296             case XML_DOCUMENT_TYPE_NODE:
5297             case XML_DOCUMENT_FRAG_NODE:
5298             case XML_NOTATION_NODE:
5299 	    case XML_NAMESPACE_DECL:
5300 	        strcat(buf, "???");
5301 		if (cur->next != NULL)
5302 		    strcat(buf, " ");
5303 		break;
5304             case XML_ENTITY_NODE:
5305             case XML_PI_NODE:
5306             case XML_DTD_NODE:
5307             case XML_COMMENT_NODE:
5308 	    case XML_ELEMENT_DECL:
5309 	    case XML_ATTRIBUTE_DECL:
5310 	    case XML_ENTITY_DECL:
5311 	    case XML_XINCLUDE_START:
5312 	    case XML_XINCLUDE_END:
5313 		break;
5314 	}
5315 	cur = cur->next;
5316     }
5317     if (glob) strcat(buf, ")");
5318 }
5319 
5320 /**
5321  * xmlValidateElementContent:
5322  * @ctxt:  the validation context
5323  * @child:  the child list
5324  * @elemDecl:  pointer to the element declaration
5325  * @warn:  emit the error message
5326  * @parent: the parent element (for error reporting)
5327  *
5328  * Try to validate the content model of an element
5329  *
5330  * returns 1 if valid or 0 if not and -1 in case of error
5331  */
5332 
5333 static int
xmlValidateElementContent(xmlValidCtxtPtr ctxt,xmlNodePtr child,xmlElementPtr elemDecl,int warn,xmlNodePtr parent)5334 xmlValidateElementContent(xmlValidCtxtPtr ctxt, xmlNodePtr child,
5335        xmlElementPtr elemDecl, int warn, xmlNodePtr parent) {
5336     int ret = 1;
5337 #ifndef  LIBXML_REGEXP_ENABLED
5338     xmlNodePtr repl = NULL, last = NULL, tmp;
5339 #endif
5340     xmlNodePtr cur;
5341     xmlElementContentPtr cont;
5342     const xmlChar *name;
5343 
5344     if ((elemDecl == NULL) || (parent == NULL) || (ctxt == NULL))
5345 	return(-1);
5346     cont = elemDecl->content;
5347     name = elemDecl->name;
5348 
5349 #ifdef LIBXML_REGEXP_ENABLED
5350     /* Build the regexp associated to the content model */
5351     if (elemDecl->contModel == NULL)
5352 	ret = xmlValidBuildContentModel(ctxt, elemDecl);
5353     if (elemDecl->contModel == NULL) {
5354 	return(-1);
5355     } else {
5356 	xmlRegExecCtxtPtr exec;
5357 
5358 	if (!xmlRegexpIsDeterminist(elemDecl->contModel)) {
5359 	    return(-1);
5360 	}
5361 	ctxt->nodeMax = 0;
5362 	ctxt->nodeNr = 0;
5363 	ctxt->nodeTab = NULL;
5364 	exec = xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
5365 	if (exec != NULL) {
5366 	    cur = child;
5367 	    while (cur != NULL) {
5368 		switch (cur->type) {
5369 		    case XML_ENTITY_REF_NODE:
5370 			/*
5371 			 * Push the current node to be able to roll back
5372 			 * and process within the entity
5373 			 */
5374 			if ((cur->children != NULL) &&
5375 			    (cur->children->children != NULL)) {
5376 			    nodeVPush(ctxt, cur);
5377 			    cur = cur->children->children;
5378 			    continue;
5379 			}
5380 			break;
5381 		    case XML_TEXT_NODE:
5382 			if (xmlIsBlankNode(cur))
5383 			    break;
5384 			ret = 0;
5385 			goto fail;
5386 		    case XML_CDATA_SECTION_NODE:
5387 			/* TODO */
5388 			ret = 0;
5389 			goto fail;
5390 		    case XML_ELEMENT_NODE:
5391 			if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5392 			    xmlChar fn[50];
5393 			    xmlChar *fullname;
5394 
5395 			    fullname = xmlBuildQName(cur->name,
5396 				                     cur->ns->prefix, fn, 50);
5397 			    if (fullname == NULL) {
5398 				ret = -1;
5399 				goto fail;
5400 			    }
5401                             ret = xmlRegExecPushString(exec, fullname, NULL);
5402 			    if ((fullname != fn) && (fullname != cur->name))
5403 				xmlFree(fullname);
5404 			} else {
5405 			    ret = xmlRegExecPushString(exec, cur->name, NULL);
5406 			}
5407 			break;
5408 		    default:
5409 			break;
5410 		}
5411 		/*
5412 		 * Switch to next element
5413 		 */
5414 		cur = cur->next;
5415 		while (cur == NULL) {
5416 		    cur = nodeVPop(ctxt);
5417 		    if (cur == NULL)
5418 			break;
5419 		    cur = cur->next;
5420 		}
5421 	    }
5422 	    ret = xmlRegExecPushString(exec, NULL, NULL);
5423 fail:
5424 	    xmlRegFreeExecCtxt(exec);
5425 	}
5426     }
5427 #else  /* LIBXML_REGEXP_ENABLED */
5428     /*
5429      * Allocate the stack
5430      */
5431     ctxt->vstateMax = 8;
5432     ctxt->vstateTab = (xmlValidState *) xmlMalloc(
5433 		 ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
5434     if (ctxt->vstateTab == NULL) {
5435 	xmlVErrMemory(ctxt, "malloc failed");
5436 	return(-1);
5437     }
5438     /*
5439      * The first entry in the stack is reserved to the current state
5440      */
5441     ctxt->nodeMax = 0;
5442     ctxt->nodeNr = 0;
5443     ctxt->nodeTab = NULL;
5444     ctxt->vstate = &ctxt->vstateTab[0];
5445     ctxt->vstateNr = 1;
5446     CONT = cont;
5447     NODE = child;
5448     DEPTH = 0;
5449     OCCURS = 0;
5450     STATE = 0;
5451     ret = xmlValidateElementType(ctxt);
5452     if ((ret == -3) && (warn)) {
5453 	xmlErrValidWarning(ctxt, child, XML_DTD_CONTENT_NOT_DETERMINIST,
5454 	       "Content model for Element %s is ambiguous\n",
5455 	                   name, NULL, NULL);
5456     } else if (ret == -2) {
5457 	/*
5458 	 * An entities reference appeared at this level.
5459 	 * Build a minimal representation of this node content
5460 	 * sufficient to run the validation process on it
5461 	 */
5462 	DEBUG_VALID_MSG("Found an entity reference, linearizing");
5463 	cur = child;
5464 	while (cur != NULL) {
5465 	    switch (cur->type) {
5466 		case XML_ENTITY_REF_NODE:
5467 		    /*
5468 		     * Push the current node to be able to roll back
5469 		     * and process within the entity
5470 		     */
5471 		    if ((cur->children != NULL) &&
5472 			(cur->children->children != NULL)) {
5473 			nodeVPush(ctxt, cur);
5474 			cur = cur->children->children;
5475 			continue;
5476 		    }
5477 		    break;
5478 		case XML_TEXT_NODE:
5479 		    if (xmlIsBlankNode(cur))
5480 			break;
5481 		    /* no break on purpose */
5482 		case XML_CDATA_SECTION_NODE:
5483 		    /* no break on purpose */
5484 		case XML_ELEMENT_NODE:
5485 		    /*
5486 		     * Allocate a new node and minimally fills in
5487 		     * what's required
5488 		     */
5489 		    tmp = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
5490 		    if (tmp == NULL) {
5491 			xmlVErrMemory(ctxt, "malloc failed");
5492 			xmlFreeNodeList(repl);
5493 			ret = -1;
5494 			goto done;
5495 		    }
5496 		    tmp->type = cur->type;
5497 		    tmp->name = cur->name;
5498 		    tmp->ns = cur->ns;
5499 		    tmp->next = NULL;
5500 		    tmp->content = NULL;
5501 		    if (repl == NULL)
5502 			repl = last = tmp;
5503 		    else {
5504 			last->next = tmp;
5505 			last = tmp;
5506 		    }
5507 		    if (cur->type == XML_CDATA_SECTION_NODE) {
5508 			/*
5509 			 * E59 spaces in CDATA does not match the
5510 			 * nonterminal S
5511 			 */
5512 			tmp->content = xmlStrdup(BAD_CAST "CDATA");
5513 		    }
5514 		    break;
5515 		default:
5516 		    break;
5517 	    }
5518 	    /*
5519 	     * Switch to next element
5520 	     */
5521 	    cur = cur->next;
5522 	    while (cur == NULL) {
5523 		cur = nodeVPop(ctxt);
5524 		if (cur == NULL)
5525 		    break;
5526 		cur = cur->next;
5527 	    }
5528 	}
5529 
5530 	/*
5531 	 * Relaunch the validation
5532 	 */
5533 	ctxt->vstate = &ctxt->vstateTab[0];
5534 	ctxt->vstateNr = 1;
5535 	CONT = cont;
5536 	NODE = repl;
5537 	DEPTH = 0;
5538 	OCCURS = 0;
5539 	STATE = 0;
5540 	ret = xmlValidateElementType(ctxt);
5541     }
5542 #endif /* LIBXML_REGEXP_ENABLED */
5543     if ((warn) && ((ret != 1) && (ret != -3))) {
5544 	if (ctxt != NULL) {
5545 	    char expr[5000];
5546 	    char list[5000];
5547 
5548 	    expr[0] = 0;
5549 	    xmlSnprintfElementContent(&expr[0], 5000, cont, 1);
5550 	    list[0] = 0;
5551 #ifndef LIBXML_REGEXP_ENABLED
5552 	    if (repl != NULL)
5553 		xmlSnprintfElements(&list[0], 5000, repl, 1);
5554 	    else
5555 #endif /* LIBXML_REGEXP_ENABLED */
5556 		xmlSnprintfElements(&list[0], 5000, child, 1);
5557 
5558 	    if (name != NULL) {
5559 		xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5560 	   "Element %s content does not follow the DTD, expecting %s, got %s\n",
5561 		       name, BAD_CAST expr, BAD_CAST list);
5562 	    } else {
5563 		xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5564 	   "Element content does not follow the DTD, expecting %s, got %s\n",
5565 		       BAD_CAST expr, BAD_CAST list, NULL);
5566 	    }
5567 	} else {
5568 	    if (name != NULL) {
5569 		xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5570 		       "Element %s content does not follow the DTD\n",
5571 		       name, NULL, NULL);
5572 	    } else {
5573 		xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5574 		       "Element content does not follow the DTD\n",
5575 		                NULL, NULL, NULL);
5576 	    }
5577 	}
5578 	ret = 0;
5579     }
5580     if (ret == -3)
5581 	ret = 1;
5582 
5583 #ifndef  LIBXML_REGEXP_ENABLED
5584 done:
5585     /*
5586      * Deallocate the copy if done, and free up the validation stack
5587      */
5588     while (repl != NULL) {
5589 	tmp = repl->next;
5590 	xmlFree(repl);
5591 	repl = tmp;
5592     }
5593     ctxt->vstateMax = 0;
5594     if (ctxt->vstateTab != NULL) {
5595 	xmlFree(ctxt->vstateTab);
5596 	ctxt->vstateTab = NULL;
5597     }
5598 #endif
5599     ctxt->nodeMax = 0;
5600     ctxt->nodeNr = 0;
5601     if (ctxt->nodeTab != NULL) {
5602 	xmlFree(ctxt->nodeTab);
5603 	ctxt->nodeTab = NULL;
5604     }
5605     return(ret);
5606 
5607 }
5608 
5609 /**
5610  * xmlValidateCdataElement:
5611  * @ctxt:  the validation context
5612  * @doc:  a document instance
5613  * @elem:  an element instance
5614  *
5615  * Check that an element follows #CDATA
5616  *
5617  * returns 1 if valid or 0 otherwise
5618  */
5619 static int
xmlValidateOneCdataElement(xmlValidCtxtPtr ctxt,xmlDocPtr doc,xmlNodePtr elem)5620 xmlValidateOneCdataElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5621                            xmlNodePtr elem) {
5622     int ret = 1;
5623     xmlNodePtr cur, child;
5624 
5625     if ((ctxt == NULL) || (doc == NULL) || (elem == NULL) ||
5626         (elem->type != XML_ELEMENT_NODE))
5627 	return(0);
5628 
5629     child = elem->children;
5630 
5631     cur = child;
5632     while (cur != NULL) {
5633 	switch (cur->type) {
5634 	    case XML_ENTITY_REF_NODE:
5635 		/*
5636 		 * Push the current node to be able to roll back
5637 		 * and process within the entity
5638 		 */
5639 		if ((cur->children != NULL) &&
5640 		    (cur->children->children != NULL)) {
5641 		    nodeVPush(ctxt, cur);
5642 		    cur = cur->children->children;
5643 		    continue;
5644 		}
5645 		break;
5646 	    case XML_COMMENT_NODE:
5647 	    case XML_PI_NODE:
5648 	    case XML_TEXT_NODE:
5649 	    case XML_CDATA_SECTION_NODE:
5650 		break;
5651 	    default:
5652 		ret = 0;
5653 		goto done;
5654 	}
5655 	/*
5656 	 * Switch to next element
5657 	 */
5658 	cur = cur->next;
5659 	while (cur == NULL) {
5660 	    cur = nodeVPop(ctxt);
5661 	    if (cur == NULL)
5662 		break;
5663 	    cur = cur->next;
5664 	}
5665     }
5666 done:
5667     ctxt->nodeMax = 0;
5668     ctxt->nodeNr = 0;
5669     if (ctxt->nodeTab != NULL) {
5670 	xmlFree(ctxt->nodeTab);
5671 	ctxt->nodeTab = NULL;
5672     }
5673     return(ret);
5674 }
5675 
5676 /**
5677  * xmlValidateCheckMixed:
5678  * @ctxt:  the validation context
5679  * @cont:  the mixed content model
5680  * @qname:  the qualified name as appearing in the serialization
5681  *
5682  * Check if the given node is part of the content model.
5683  *
5684  * Returns 1 if yes, 0 if no, -1 in case of error
5685  */
5686 static int
xmlValidateCheckMixed(xmlValidCtxtPtr ctxt,xmlElementContentPtr cont,const xmlChar * qname)5687 xmlValidateCheckMixed(xmlValidCtxtPtr ctxt,
5688 	              xmlElementContentPtr cont, const xmlChar *qname) {
5689     const xmlChar *name;
5690     int plen;
5691     name = xmlSplitQName3(qname, &plen);
5692 
5693     if (name == NULL) {
5694 	while (cont != NULL) {
5695 	    if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5696 		if ((cont->prefix == NULL) && (xmlStrEqual(cont->name, qname)))
5697 		    return(1);
5698 	    } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5699 	       (cont->c1 != NULL) &&
5700 	       (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5701 		if ((cont->c1->prefix == NULL) &&
5702 		    (xmlStrEqual(cont->c1->name, qname)))
5703 		    return(1);
5704 	    } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5705 		(cont->c1 == NULL) ||
5706 		(cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
5707 		xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT,
5708 			"Internal: MIXED struct corrupted\n",
5709 			NULL);
5710 		break;
5711 	    }
5712 	    cont = cont->c2;
5713 	}
5714     } else {
5715 	while (cont != NULL) {
5716 	    if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5717 		if ((cont->prefix != NULL) &&
5718 		    (xmlStrncmp(cont->prefix, qname, plen) == 0) &&
5719 		    (xmlStrEqual(cont->name, name)))
5720 		    return(1);
5721 	    } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5722 	       (cont->c1 != NULL) &&
5723 	       (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5724 		if ((cont->c1->prefix != NULL) &&
5725 		    (xmlStrncmp(cont->c1->prefix, qname, plen) == 0) &&
5726 		    (xmlStrEqual(cont->c1->name, name)))
5727 		    return(1);
5728 	    } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5729 		(cont->c1 == NULL) ||
5730 		(cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
5731 		xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT,
5732 			"Internal: MIXED struct corrupted\n",
5733 			NULL);
5734 		break;
5735 	    }
5736 	    cont = cont->c2;
5737 	}
5738     }
5739     return(0);
5740 }
5741 
5742 /**
5743  * xmlValidGetElemDecl:
5744  * @ctxt:  the validation context
5745  * @doc:  a document instance
5746  * @elem:  an element instance
5747  * @extsubset:  pointer, (out) indicate if the declaration was found
5748  *              in the external subset.
5749  *
5750  * Finds a declaration associated to an element in the document.
5751  *
5752  * returns the pointer to the declaration or NULL if not found.
5753  */
5754 static xmlElementPtr
xmlValidGetElemDecl(xmlValidCtxtPtr ctxt,xmlDocPtr doc,xmlNodePtr elem,int * extsubset)5755 xmlValidGetElemDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5756 	            xmlNodePtr elem, int *extsubset) {
5757     xmlElementPtr elemDecl = NULL;
5758     const xmlChar *prefix = NULL;
5759 
5760     if ((ctxt == NULL) || (doc == NULL) ||
5761         (elem == NULL) || (elem->name == NULL))
5762         return(NULL);
5763     if (extsubset != NULL)
5764 	*extsubset = 0;
5765 
5766     /*
5767      * Fetch the declaration for the qualified name
5768      */
5769     if ((elem->ns != NULL) && (elem->ns->prefix != NULL))
5770 	prefix = elem->ns->prefix;
5771 
5772     if (prefix != NULL) {
5773 	elemDecl = xmlGetDtdQElementDesc(doc->intSubset,
5774 		                         elem->name, prefix);
5775 	if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5776 	    elemDecl = xmlGetDtdQElementDesc(doc->extSubset,
5777 		                             elem->name, prefix);
5778 	    if ((elemDecl != NULL) && (extsubset != NULL))
5779 		*extsubset = 1;
5780 	}
5781     }
5782 
5783     /*
5784      * Fetch the declaration for the non qualified name
5785      * This is "non-strict" validation should be done on the
5786      * full QName but in that case being flexible makes sense.
5787      */
5788     if (elemDecl == NULL) {
5789 	elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
5790 	if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5791 	    elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
5792 	    if ((elemDecl != NULL) && (extsubset != NULL))
5793 		*extsubset = 1;
5794 	}
5795     }
5796     if (elemDecl == NULL) {
5797 	xmlErrValidNode(ctxt, elem,
5798 			XML_DTD_UNKNOWN_ELEM,
5799 	       "No declaration for element %s\n",
5800 	       elem->name, NULL, NULL);
5801     }
5802     return(elemDecl);
5803 }
5804 
5805 #ifdef LIBXML_REGEXP_ENABLED
5806 /**
5807  * xmlValidatePushElement:
5808  * @ctxt:  the validation context
5809  * @doc:  a document instance
5810  * @elem:  an element instance
5811  * @qname:  the qualified name as appearing in the serialization
5812  *
5813  * Push a new element start on the validation stack.
5814  *
5815  * returns 1 if no validation problem was found or 0 otherwise
5816  */
5817 int
xmlValidatePushElement(xmlValidCtxtPtr ctxt,xmlDocPtr doc,xmlNodePtr elem,const xmlChar * qname)5818 xmlValidatePushElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5819                        xmlNodePtr elem, const xmlChar *qname) {
5820     int ret = 1;
5821     xmlElementPtr eDecl;
5822     int extsubset = 0;
5823 
5824     if (ctxt == NULL)
5825         return(0);
5826 /* printf("PushElem %s\n", qname); */
5827     if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5828 	xmlValidStatePtr state = ctxt->vstate;
5829 	xmlElementPtr elemDecl;
5830 
5831 	/*
5832 	 * Check the new element against the content model of the new elem.
5833 	 */
5834 	if (state->elemDecl != NULL) {
5835 	    elemDecl = state->elemDecl;
5836 
5837 	    switch(elemDecl->etype) {
5838 		case XML_ELEMENT_TYPE_UNDEFINED:
5839 		    ret = 0;
5840 		    break;
5841 		case XML_ELEMENT_TYPE_EMPTY:
5842 		    xmlErrValidNode(ctxt, state->node,
5843 				    XML_DTD_NOT_EMPTY,
5844 	       "Element %s was declared EMPTY this one has content\n",
5845 			   state->node->name, NULL, NULL);
5846 		    ret = 0;
5847 		    break;
5848 		case XML_ELEMENT_TYPE_ANY:
5849 		    /* I don't think anything is required then */
5850 		    break;
5851 		case XML_ELEMENT_TYPE_MIXED:
5852 		    /* simple case of declared as #PCDATA */
5853 		    if ((elemDecl->content != NULL) &&
5854 			(elemDecl->content->type ==
5855 			 XML_ELEMENT_CONTENT_PCDATA)) {
5856 			xmlErrValidNode(ctxt, state->node,
5857 					XML_DTD_NOT_PCDATA,
5858 	       "Element %s was declared #PCDATA but contains non text nodes\n",
5859 				state->node->name, NULL, NULL);
5860 			ret = 0;
5861 		    } else {
5862 			ret = xmlValidateCheckMixed(ctxt, elemDecl->content,
5863 				                    qname);
5864 			if (ret != 1) {
5865 			    xmlErrValidNode(ctxt, state->node,
5866 					    XML_DTD_INVALID_CHILD,
5867 	       "Element %s is not declared in %s list of possible children\n",
5868 				    qname, state->node->name, NULL);
5869 			}
5870 		    }
5871 		    break;
5872 		case XML_ELEMENT_TYPE_ELEMENT:
5873 		    /*
5874 		     * TODO:
5875 		     * VC: Standalone Document Declaration
5876 		     *     - element types with element content, if white space
5877 		     *       occurs directly within any instance of those types.
5878 		     */
5879 		    if (state->exec != NULL) {
5880 			ret = xmlRegExecPushString(state->exec, qname, NULL);
5881 			if (ret < 0) {
5882 			    xmlErrValidNode(ctxt, state->node,
5883 					    XML_DTD_CONTENT_MODEL,
5884 	       "Element %s content does not follow the DTD, Misplaced %s\n",
5885 				   state->node->name, qname, NULL);
5886 			    ret = 0;
5887 			} else {
5888 			    ret = 1;
5889 			}
5890 		    }
5891 		    break;
5892 	    }
5893 	}
5894     }
5895     eDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
5896     vstateVPush(ctxt, eDecl, elem);
5897     return(ret);
5898 }
5899 
5900 /**
5901  * xmlValidatePushCData:
5902  * @ctxt:  the validation context
5903  * @data:  some character data read
5904  * @len:  the length of the data
5905  *
5906  * check the CData parsed for validation in the current stack
5907  *
5908  * returns 1 if no validation problem was found or 0 otherwise
5909  */
5910 int
xmlValidatePushCData(xmlValidCtxtPtr ctxt,const xmlChar * data,int len)5911 xmlValidatePushCData(xmlValidCtxtPtr ctxt, const xmlChar *data, int len) {
5912     int ret = 1;
5913 
5914 /* printf("CDATA %s %d\n", data, len); */
5915     if (ctxt == NULL)
5916         return(0);
5917     if (len <= 0)
5918 	return(ret);
5919     if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5920 	xmlValidStatePtr state = ctxt->vstate;
5921 	xmlElementPtr elemDecl;
5922 
5923 	/*
5924 	 * Check the new element against the content model of the new elem.
5925 	 */
5926 	if (state->elemDecl != NULL) {
5927 	    elemDecl = state->elemDecl;
5928 
5929 	    switch(elemDecl->etype) {
5930 		case XML_ELEMENT_TYPE_UNDEFINED:
5931 		    ret = 0;
5932 		    break;
5933 		case XML_ELEMENT_TYPE_EMPTY:
5934 		    xmlErrValidNode(ctxt, state->node,
5935 				    XML_DTD_NOT_EMPTY,
5936 	       "Element %s was declared EMPTY this one has content\n",
5937 			   state->node->name, NULL, NULL);
5938 		    ret = 0;
5939 		    break;
5940 		case XML_ELEMENT_TYPE_ANY:
5941 		    break;
5942 		case XML_ELEMENT_TYPE_MIXED:
5943 		    break;
5944 		case XML_ELEMENT_TYPE_ELEMENT: {
5945                     int i;
5946 
5947                     for (i = 0;i < len;i++) {
5948                         if (!IS_BLANK_CH(data[i])) {
5949                             xmlErrValidNode(ctxt, state->node,
5950                                             XML_DTD_CONTENT_MODEL,
5951        "Element %s content does not follow the DTD, Text not allowed\n",
5952                                    state->node->name, NULL, NULL);
5953                             ret = 0;
5954                             goto done;
5955                         }
5956                     }
5957                     /*
5958                      * TODO:
5959                      * VC: Standalone Document Declaration
5960                      *  element types with element content, if white space
5961                      *  occurs directly within any instance of those types.
5962                      */
5963                     break;
5964                 }
5965 	    }
5966 	}
5967     }
5968 done:
5969     return(ret);
5970 }
5971 
5972 /**
5973  * xmlValidatePopElement:
5974  * @ctxt:  the validation context
5975  * @doc:  a document instance
5976  * @elem:  an element instance
5977  * @qname:  the qualified name as appearing in the serialization
5978  *
5979  * Pop the element end from the validation stack.
5980  *
5981  * returns 1 if no validation problem was found or 0 otherwise
5982  */
5983 int
xmlValidatePopElement(xmlValidCtxtPtr ctxt,xmlDocPtr doc ATTRIBUTE_UNUSED,xmlNodePtr elem ATTRIBUTE_UNUSED,const xmlChar * qname ATTRIBUTE_UNUSED)5984 xmlValidatePopElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc ATTRIBUTE_UNUSED,
5985                       xmlNodePtr elem ATTRIBUTE_UNUSED,
5986 		      const xmlChar *qname ATTRIBUTE_UNUSED) {
5987     int ret = 1;
5988 
5989     if (ctxt == NULL)
5990         return(0);
5991 /* printf("PopElem %s\n", qname); */
5992     if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5993 	xmlValidStatePtr state = ctxt->vstate;
5994 	xmlElementPtr elemDecl;
5995 
5996 	/*
5997 	 * Check the new element against the content model of the new elem.
5998 	 */
5999 	if (state->elemDecl != NULL) {
6000 	    elemDecl = state->elemDecl;
6001 
6002 	    if (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT) {
6003 		if (state->exec != NULL) {
6004 		    ret = xmlRegExecPushString(state->exec, NULL, NULL);
6005 		    if (ret == 0) {
6006 			xmlErrValidNode(ctxt, state->node,
6007 			                XML_DTD_CONTENT_MODEL,
6008 	   "Element %s content does not follow the DTD, Expecting more child\n",
6009 			       state->node->name, NULL,NULL);
6010 		    } else {
6011 			/*
6012 			 * previous validation errors should not generate
6013 			 * a new one here
6014 			 */
6015 			ret = 1;
6016 		    }
6017 		}
6018 	    }
6019 	}
6020 	vstateVPop(ctxt);
6021     }
6022     return(ret);
6023 }
6024 #endif /* LIBXML_REGEXP_ENABLED */
6025 
6026 /**
6027  * xmlValidateOneElement:
6028  * @ctxt:  the validation context
6029  * @doc:  a document instance
6030  * @elem:  an element instance
6031  *
6032  * Try to validate a single element and it's attributes,
6033  * basically it does the following checks as described by the
6034  * XML-1.0 recommendation:
6035  *  - [ VC: Element Valid ]
6036  *  - [ VC: Required Attribute ]
6037  * Then call xmlValidateOneAttribute() for each attribute present.
6038  *
6039  * The ID/IDREF checkings are done separately
6040  *
6041  * returns 1 if valid or 0 otherwise
6042  */
6043 
6044 int
xmlValidateOneElement(xmlValidCtxtPtr ctxt,xmlDocPtr doc,xmlNodePtr elem)6045 xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
6046                       xmlNodePtr elem) {
6047     xmlElementPtr elemDecl = NULL;
6048     xmlElementContentPtr cont;
6049     xmlAttributePtr attr;
6050     xmlNodePtr child;
6051     int ret = 1, tmp;
6052     const xmlChar *name;
6053     int extsubset = 0;
6054 
6055     CHECK_DTD;
6056 
6057     if (elem == NULL) return(0);
6058     switch (elem->type) {
6059         case XML_ATTRIBUTE_NODE:
6060 	    xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
6061 		   "Attribute element not expected\n", NULL, NULL ,NULL);
6062 	    return(0);
6063         case XML_TEXT_NODE:
6064 	    if (elem->children != NULL) {
6065 		xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
6066 		                "Text element has children !\n",
6067 				NULL,NULL,NULL);
6068 		return(0);
6069 	    }
6070 	    if (elem->ns != NULL) {
6071 		xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
6072 		                "Text element has namespace !\n",
6073 				NULL,NULL,NULL);
6074 		return(0);
6075 	    }
6076 	    if (elem->content == NULL) {
6077 		xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
6078 		                "Text element has no content !\n",
6079 				NULL,NULL,NULL);
6080 		return(0);
6081 	    }
6082 	    return(1);
6083         case XML_XINCLUDE_START:
6084         case XML_XINCLUDE_END:
6085             return(1);
6086         case XML_CDATA_SECTION_NODE:
6087         case XML_ENTITY_REF_NODE:
6088         case XML_PI_NODE:
6089         case XML_COMMENT_NODE:
6090 	    return(1);
6091         case XML_ENTITY_NODE:
6092 	    xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
6093 		   "Entity element not expected\n", NULL, NULL ,NULL);
6094 	    return(0);
6095         case XML_NOTATION_NODE:
6096 	    xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
6097 		   "Notation element not expected\n", NULL, NULL ,NULL);
6098 	    return(0);
6099         case XML_DOCUMENT_NODE:
6100         case XML_DOCUMENT_TYPE_NODE:
6101         case XML_DOCUMENT_FRAG_NODE:
6102 	    xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
6103 		   "Document element not expected\n", NULL, NULL ,NULL);
6104 	    return(0);
6105         case XML_HTML_DOCUMENT_NODE:
6106 	    xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
6107 		   "HTML Document not expected\n", NULL, NULL ,NULL);
6108 	    return(0);
6109         case XML_ELEMENT_NODE:
6110 	    break;
6111 	default:
6112 	    xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
6113 		   "unknown element type\n", NULL, NULL ,NULL);
6114 	    return(0);
6115     }
6116 
6117     /*
6118      * Fetch the declaration
6119      */
6120     elemDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
6121     if (elemDecl == NULL)
6122 	return(0);
6123 
6124     /*
6125      * If vstateNr is not zero that means continuous validation is
6126      * activated, do not try to check the content model at that level.
6127      */
6128     if (ctxt->vstateNr == 0) {
6129     /* Check that the element content matches the definition */
6130     switch (elemDecl->etype) {
6131         case XML_ELEMENT_TYPE_UNDEFINED:
6132 	    xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ELEM,
6133 	                    "No declaration for element %s\n",
6134 		   elem->name, NULL, NULL);
6135 	    return(0);
6136         case XML_ELEMENT_TYPE_EMPTY:
6137 	    if (elem->children != NULL) {
6138 		xmlErrValidNode(ctxt, elem, XML_DTD_NOT_EMPTY,
6139 	       "Element %s was declared EMPTY this one has content\n",
6140 	               elem->name, NULL, NULL);
6141 		ret = 0;
6142 	    }
6143 	    break;
6144         case XML_ELEMENT_TYPE_ANY:
6145 	    /* I don't think anything is required then */
6146 	    break;
6147         case XML_ELEMENT_TYPE_MIXED:
6148 
6149 	    /* simple case of declared as #PCDATA */
6150 	    if ((elemDecl->content != NULL) &&
6151 		(elemDecl->content->type == XML_ELEMENT_CONTENT_PCDATA)) {
6152 		ret = xmlValidateOneCdataElement(ctxt, doc, elem);
6153 		if (!ret) {
6154 		    xmlErrValidNode(ctxt, elem, XML_DTD_NOT_PCDATA,
6155 	       "Element %s was declared #PCDATA but contains non text nodes\n",
6156 			   elem->name, NULL, NULL);
6157 		}
6158 		break;
6159 	    }
6160 	    child = elem->children;
6161 	    /* Hum, this start to get messy */
6162 	    while (child != NULL) {
6163 	        if (child->type == XML_ELEMENT_NODE) {
6164 		    name = child->name;
6165 		    if ((child->ns != NULL) && (child->ns->prefix != NULL)) {
6166 			xmlChar fn[50];
6167 			xmlChar *fullname;
6168 
6169 			fullname = xmlBuildQName(child->name, child->ns->prefix,
6170 				                 fn, 50);
6171 			if (fullname == NULL)
6172 			    return(0);
6173 			cont = elemDecl->content;
6174 			while (cont != NULL) {
6175 			    if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
6176 				if (xmlStrEqual(cont->name, fullname))
6177 				    break;
6178 			    } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
6179 			       (cont->c1 != NULL) &&
6180 			       (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
6181 				if (xmlStrEqual(cont->c1->name, fullname))
6182 				    break;
6183 			    } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
6184 				(cont->c1 == NULL) ||
6185 				(cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
6186 				xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT,
6187 					"Internal: MIXED struct corrupted\n",
6188 					NULL);
6189 				break;
6190 			    }
6191 			    cont = cont->c2;
6192 			}
6193 			if ((fullname != fn) && (fullname != child->name))
6194 			    xmlFree(fullname);
6195 			if (cont != NULL)
6196 			    goto child_ok;
6197 		    }
6198 		    cont = elemDecl->content;
6199 		    while (cont != NULL) {
6200 		        if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
6201 			    if (xmlStrEqual(cont->name, name)) break;
6202 			} else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
6203 			   (cont->c1 != NULL) &&
6204 			   (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
6205 			    if (xmlStrEqual(cont->c1->name, name)) break;
6206 			} else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
6207 			    (cont->c1 == NULL) ||
6208 			    (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
6209 			    xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT,
6210 				    "Internal: MIXED struct corrupted\n",
6211 				    NULL);
6212 			    break;
6213 			}
6214 			cont = cont->c2;
6215 		    }
6216 		    if (cont == NULL) {
6217 			xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_CHILD,
6218 	       "Element %s is not declared in %s list of possible children\n",
6219 			       name, elem->name, NULL);
6220 			ret = 0;
6221 		    }
6222 		}
6223 child_ok:
6224 	        child = child->next;
6225 	    }
6226 	    break;
6227         case XML_ELEMENT_TYPE_ELEMENT:
6228 	    if ((doc->standalone == 1) && (extsubset == 1)) {
6229 		/*
6230 		 * VC: Standalone Document Declaration
6231 		 *     - element types with element content, if white space
6232 		 *       occurs directly within any instance of those types.
6233 		 */
6234 		child = elem->children;
6235 		while (child != NULL) {
6236 		    if (child->type == XML_TEXT_NODE) {
6237 			const xmlChar *content = child->content;
6238 
6239 			while (IS_BLANK_CH(*content))
6240 			    content++;
6241 			if (*content == 0) {
6242 			    xmlErrValidNode(ctxt, elem,
6243 			                    XML_DTD_STANDALONE_WHITE_SPACE,
6244 "standalone: %s declared in the external subset contains white spaces nodes\n",
6245 				   elem->name, NULL, NULL);
6246 			    ret = 0;
6247 			    break;
6248 			}
6249 		    }
6250 		    child =child->next;
6251 		}
6252 	    }
6253 	    child = elem->children;
6254 	    cont = elemDecl->content;
6255 	    tmp = xmlValidateElementContent(ctxt, child, elemDecl, 1, elem);
6256 	    if (tmp <= 0)
6257 		ret = tmp;
6258 	    break;
6259     }
6260     } /* not continuous */
6261 
6262     /* [ VC: Required Attribute ] */
6263     attr = elemDecl->attributes;
6264     while (attr != NULL) {
6265 	if (attr->def == XML_ATTRIBUTE_REQUIRED) {
6266 	    int qualified = -1;
6267 
6268 	    if ((attr->prefix == NULL) &&
6269 		(xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
6270 		xmlNsPtr ns;
6271 
6272 		ns = elem->nsDef;
6273 		while (ns != NULL) {
6274 		    if (ns->prefix == NULL)
6275 			goto found;
6276 		    ns = ns->next;
6277 		}
6278 	    } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
6279 		xmlNsPtr ns;
6280 
6281 		ns = elem->nsDef;
6282 		while (ns != NULL) {
6283 		    if (xmlStrEqual(attr->name, ns->prefix))
6284 			goto found;
6285 		    ns = ns->next;
6286 		}
6287 	    } else {
6288 		xmlAttrPtr attrib;
6289 
6290 		attrib = elem->properties;
6291 		while (attrib != NULL) {
6292 		    if (xmlStrEqual(attrib->name, attr->name)) {
6293 			if (attr->prefix != NULL) {
6294 			    xmlNsPtr nameSpace = attrib->ns;
6295 
6296 			    if (nameSpace == NULL)
6297 				nameSpace = elem->ns;
6298 			    /*
6299 			     * qualified names handling is problematic, having a
6300 			     * different prefix should be possible but DTDs don't
6301 			     * allow to define the URI instead of the prefix :-(
6302 			     */
6303 			    if (nameSpace == NULL) {
6304 				if (qualified < 0)
6305 				    qualified = 0;
6306 			    } else if (!xmlStrEqual(nameSpace->prefix,
6307 						    attr->prefix)) {
6308 				if (qualified < 1)
6309 				    qualified = 1;
6310 			    } else
6311 				goto found;
6312 			} else {
6313 			    /*
6314 			     * We should allow applications to define namespaces
6315 			     * for their application even if the DTD doesn't
6316 			     * carry one, otherwise, basically we would always
6317 			     * break.
6318 			     */
6319 			    goto found;
6320 			}
6321 		    }
6322 		    attrib = attrib->next;
6323 		}
6324 	    }
6325 	    if (qualified == -1) {
6326 		if (attr->prefix == NULL) {
6327 		    xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
6328 		       "Element %s does not carry attribute %s\n",
6329 			   elem->name, attr->name, NULL);
6330 		    ret = 0;
6331 	        } else {
6332 		    xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
6333 		       "Element %s does not carry attribute %s:%s\n",
6334 			   elem->name, attr->prefix,attr->name);
6335 		    ret = 0;
6336 		}
6337 	    } else if (qualified == 0) {
6338 		xmlErrValidWarning(ctxt, elem, XML_DTD_NO_PREFIX,
6339 		   "Element %s required attribute %s:%s has no prefix\n",
6340 		       elem->name, attr->prefix, attr->name);
6341 	    } else if (qualified == 1) {
6342 		xmlErrValidWarning(ctxt, elem, XML_DTD_DIFFERENT_PREFIX,
6343 		   "Element %s required attribute %s:%s has different prefix\n",
6344 		       elem->name, attr->prefix, attr->name);
6345 	    }
6346 	} else if (attr->def == XML_ATTRIBUTE_FIXED) {
6347 	    /*
6348 	     * Special tests checking #FIXED namespace declarations
6349 	     * have the right value since this is not done as an
6350 	     * attribute checking
6351 	     */
6352 	    if ((attr->prefix == NULL) &&
6353 		(xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
6354 		xmlNsPtr ns;
6355 
6356 		ns = elem->nsDef;
6357 		while (ns != NULL) {
6358 		    if (ns->prefix == NULL) {
6359 			if (!xmlStrEqual(attr->defaultValue, ns->href)) {
6360 			    xmlErrValidNode(ctxt, elem,
6361 			           XML_DTD_ELEM_DEFAULT_NAMESPACE,
6362    "Element %s namespace name for default namespace does not match the DTD\n",
6363 				   elem->name, NULL, NULL);
6364 			    ret = 0;
6365 			}
6366 			goto found;
6367 		    }
6368 		    ns = ns->next;
6369 		}
6370 	    } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
6371 		xmlNsPtr ns;
6372 
6373 		ns = elem->nsDef;
6374 		while (ns != NULL) {
6375 		    if (xmlStrEqual(attr->name, ns->prefix)) {
6376 			if (!xmlStrEqual(attr->defaultValue, ns->href)) {
6377 			    xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
6378 		   "Element %s namespace name for %s does not match the DTD\n",
6379 				   elem->name, ns->prefix, NULL);
6380 			    ret = 0;
6381 			}
6382 			goto found;
6383 		    }
6384 		    ns = ns->next;
6385 		}
6386 	    }
6387 	}
6388 found:
6389         attr = attr->nexth;
6390     }
6391     return(ret);
6392 }
6393 
6394 /**
6395  * xmlValidateRoot:
6396  * @ctxt:  the validation context
6397  * @doc:  a document instance
6398  *
6399  * Try to validate a the root element
6400  * basically it does the following check as described by the
6401  * XML-1.0 recommendation:
6402  *  - [ VC: Root Element Type ]
6403  * it doesn't try to recurse or apply other check to the element
6404  *
6405  * returns 1 if valid or 0 otherwise
6406  */
6407 
6408 int
xmlValidateRoot(xmlValidCtxtPtr ctxt,xmlDocPtr doc)6409 xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6410     xmlNodePtr root;
6411     int ret;
6412 
6413     if (doc == NULL) return(0);
6414 
6415     root = xmlDocGetRootElement(doc);
6416     if ((root == NULL) || (root->name == NULL)) {
6417 	xmlErrValid(ctxt, XML_DTD_NO_ROOT,
6418 	            "no root element\n", NULL);
6419         return(0);
6420     }
6421 
6422     /*
6423      * When doing post validation against a separate DTD, those may
6424      * no internal subset has been generated
6425      */
6426     if ((doc->intSubset != NULL) &&
6427 	(doc->intSubset->name != NULL)) {
6428 	/*
6429 	 * Check first the document root against the NQName
6430 	 */
6431 	if (!xmlStrEqual(doc->intSubset->name, root->name)) {
6432 	    if ((root->ns != NULL) && (root->ns->prefix != NULL)) {
6433 		xmlChar fn[50];
6434 		xmlChar *fullname;
6435 
6436 		fullname = xmlBuildQName(root->name, root->ns->prefix, fn, 50);
6437 		if (fullname == NULL) {
6438 		    xmlVErrMemory(ctxt, NULL);
6439 		    return(0);
6440 		}
6441 		ret = xmlStrEqual(doc->intSubset->name, fullname);
6442 		if ((fullname != fn) && (fullname != root->name))
6443 		    xmlFree(fullname);
6444 		if (ret == 1)
6445 		    goto name_ok;
6446 	    }
6447 	    if ((xmlStrEqual(doc->intSubset->name, BAD_CAST "HTML")) &&
6448 		(xmlStrEqual(root->name, BAD_CAST "html")))
6449 		goto name_ok;
6450 	    xmlErrValidNode(ctxt, root, XML_DTD_ROOT_NAME,
6451 		   "root and DTD name do not match '%s' and '%s'\n",
6452 		   root->name, doc->intSubset->name, NULL);
6453 	    return(0);
6454 	}
6455     }
6456 name_ok:
6457     return(1);
6458 }
6459 
6460 
6461 /**
6462  * xmlValidateElement:
6463  * @ctxt:  the validation context
6464  * @doc:  a document instance
6465  * @elem:  an element instance
6466  *
6467  * Try to validate the subtree under an element
6468  *
6469  * returns 1 if valid or 0 otherwise
6470  */
6471 
6472 int
xmlValidateElement(xmlValidCtxtPtr ctxt,xmlDocPtr doc,xmlNodePtr elem)6473 xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
6474     xmlNodePtr child;
6475     xmlAttrPtr attr;
6476     xmlNsPtr ns;
6477     const xmlChar *value;
6478     int ret = 1;
6479 
6480     if (elem == NULL) return(0);
6481 
6482     /*
6483      * XInclude elements were added after parsing in the infoset,
6484      * they don't really mean anything validation wise.
6485      */
6486     if ((elem->type == XML_XINCLUDE_START) ||
6487 	(elem->type == XML_XINCLUDE_END) ||
6488 	(elem->type == XML_NAMESPACE_DECL))
6489 	return(1);
6490 
6491     CHECK_DTD;
6492 
6493     /*
6494      * Entities references have to be handled separately
6495      */
6496     if (elem->type == XML_ENTITY_REF_NODE) {
6497 	return(1);
6498     }
6499 
6500     ret &= xmlValidateOneElement(ctxt, doc, elem);
6501     if (elem->type == XML_ELEMENT_NODE) {
6502 	attr = elem->properties;
6503 	while (attr != NULL) {
6504 	    value = xmlNodeListGetString(doc, attr->children, 0);
6505 	    ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
6506 	    if (value != NULL)
6507 		xmlFree((char *)value);
6508 	    attr= attr->next;
6509 	}
6510 	ns = elem->nsDef;
6511 	while (ns != NULL) {
6512 	    if (elem->ns == NULL)
6513 		ret &= xmlValidateOneNamespace(ctxt, doc, elem, NULL,
6514 					       ns, ns->href);
6515 	    else
6516 		ret &= xmlValidateOneNamespace(ctxt, doc, elem,
6517 		                               elem->ns->prefix, ns, ns->href);
6518 	    ns = ns->next;
6519 	}
6520     }
6521     child = elem->children;
6522     while (child != NULL) {
6523         ret &= xmlValidateElement(ctxt, doc, child);
6524         child = child->next;
6525     }
6526 
6527     return(ret);
6528 }
6529 
6530 /**
6531  * xmlValidateRef:
6532  * @ref:   A reference to be validated
6533  * @ctxt:  Validation context
6534  * @name:  Name of ID we are searching for
6535  *
6536  */
6537 static void
xmlValidateRef(xmlRefPtr ref,xmlValidCtxtPtr ctxt,const xmlChar * name)6538 xmlValidateRef(xmlRefPtr ref, xmlValidCtxtPtr ctxt,
6539 	                   const xmlChar *name) {
6540     xmlAttrPtr id;
6541     xmlAttrPtr attr;
6542 
6543     if (ref == NULL)
6544 	return;
6545     if ((ref->attr == NULL) && (ref->name == NULL))
6546 	return;
6547     attr = ref->attr;
6548     if (attr == NULL) {
6549 	xmlChar *dup, *str = NULL, *cur, save;
6550 
6551 	dup = xmlStrdup(name);
6552 	if (dup == NULL) {
6553 	    ctxt->valid = 0;
6554 	    return;
6555 	}
6556 	cur = dup;
6557 	while (*cur != 0) {
6558 	    str = cur;
6559 	    while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
6560 	    save = *cur;
6561 	    *cur = 0;
6562 	    id = xmlGetID(ctxt->doc, str);
6563 	    if (id == NULL) {
6564 		xmlErrValidNodeNr(ctxt, NULL, XML_DTD_UNKNOWN_ID,
6565 	   "attribute %s line %d references an unknown ID \"%s\"\n",
6566 		       ref->name, ref->lineno, str);
6567 		ctxt->valid = 0;
6568 	    }
6569 	    if (save == 0)
6570 		break;
6571 	    *cur = save;
6572 	    while (IS_BLANK_CH(*cur)) cur++;
6573 	}
6574 	xmlFree(dup);
6575     } else if (attr->atype == XML_ATTRIBUTE_IDREF) {
6576 	id = xmlGetID(ctxt->doc, name);
6577 	if (id == NULL) {
6578 	    xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
6579 	   "IDREF attribute %s references an unknown ID \"%s\"\n",
6580 		   attr->name, name, NULL);
6581 	    ctxt->valid = 0;
6582 	}
6583     } else if (attr->atype == XML_ATTRIBUTE_IDREFS) {
6584 	xmlChar *dup, *str = NULL, *cur, save;
6585 
6586 	dup = xmlStrdup(name);
6587 	if (dup == NULL) {
6588 	    xmlVErrMemory(ctxt, "IDREFS split");
6589 	    ctxt->valid = 0;
6590 	    return;
6591 	}
6592 	cur = dup;
6593 	while (*cur != 0) {
6594 	    str = cur;
6595 	    while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
6596 	    save = *cur;
6597 	    *cur = 0;
6598 	    id = xmlGetID(ctxt->doc, str);
6599 	    if (id == NULL) {
6600 		xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
6601 	   "IDREFS attribute %s references an unknown ID \"%s\"\n",
6602 			     attr->name, str, NULL);
6603 		ctxt->valid = 0;
6604 	    }
6605 	    if (save == 0)
6606 		break;
6607 	    *cur = save;
6608 	    while (IS_BLANK_CH(*cur)) cur++;
6609 	}
6610 	xmlFree(dup);
6611     }
6612 }
6613 
6614 /**
6615  * xmlWalkValidateList:
6616  * @data:  Contents of current link
6617  * @user:  Value supplied by the user
6618  *
6619  * Returns 0 to abort the walk or 1 to continue
6620  */
6621 static int
xmlWalkValidateList(const void * data,void * user)6622 xmlWalkValidateList(const void *data, void *user)
6623 {
6624 	xmlValidateMemoPtr memo = (xmlValidateMemoPtr)user;
6625 	xmlValidateRef((xmlRefPtr)data, memo->ctxt, memo->name);
6626 	return 1;
6627 }
6628 
6629 /**
6630  * xmlValidateCheckRefCallback:
6631  * @ref_list:  List of references
6632  * @ctxt:  Validation context
6633  * @name:  Name of ID we are searching for
6634  *
6635  */
6636 static void
xmlValidateCheckRefCallback(void * payload,void * data,const xmlChar * name)6637 xmlValidateCheckRefCallback(void *payload, void *data, const xmlChar *name) {
6638     xmlListPtr ref_list = (xmlListPtr) payload;
6639     xmlValidCtxtPtr ctxt = (xmlValidCtxtPtr) data;
6640     xmlValidateMemo memo;
6641 
6642     if (ref_list == NULL)
6643 	return;
6644     memo.ctxt = ctxt;
6645     memo.name = name;
6646 
6647     xmlListWalk(ref_list, xmlWalkValidateList, &memo);
6648 
6649 }
6650 
6651 /**
6652  * xmlValidateDocumentFinal:
6653  * @ctxt:  the validation context
6654  * @doc:  a document instance
6655  *
6656  * Does the final step for the document validation once all the
6657  * incremental validation steps have been completed
6658  *
6659  * basically it does the following checks described by the XML Rec
6660  *
6661  * Check all the IDREF/IDREFS attributes definition for validity
6662  *
6663  * returns 1 if valid or 0 otherwise
6664  */
6665 
6666 int
xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt,xmlDocPtr doc)6667 xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6668     xmlRefTablePtr table;
6669     unsigned int save;
6670 
6671     if (ctxt == NULL)
6672         return(0);
6673     if (doc == NULL) {
6674         xmlErrValid(ctxt, XML_DTD_NO_DOC,
6675 		"xmlValidateDocumentFinal: doc == NULL\n", NULL);
6676 	return(0);
6677     }
6678 
6679     /* trick to get correct line id report */
6680     save = ctxt->finishDtd;
6681     ctxt->finishDtd = 0;
6682 
6683     /*
6684      * Check all the NOTATION/NOTATIONS attributes
6685      */
6686     /*
6687      * Check all the ENTITY/ENTITIES attributes definition for validity
6688      */
6689     /*
6690      * Check all the IDREF/IDREFS attributes definition for validity
6691      */
6692     table = (xmlRefTablePtr) doc->refs;
6693     ctxt->doc = doc;
6694     ctxt->valid = 1;
6695     xmlHashScan(table, xmlValidateCheckRefCallback, ctxt);
6696 
6697     ctxt->finishDtd = save;
6698     return(ctxt->valid);
6699 }
6700 
6701 /**
6702  * xmlValidateDtd:
6703  * @ctxt:  the validation context
6704  * @doc:  a document instance
6705  * @dtd:  a dtd instance
6706  *
6707  * Try to validate the document against the dtd instance
6708  *
6709  * Basically it does check all the definitions in the DtD.
6710  * Note the the internal subset (if present) is de-coupled
6711  * (i.e. not used), which could give problems if ID or IDREF
6712  * is present.
6713  *
6714  * returns 1 if valid or 0 otherwise
6715  */
6716 
6717 int
xmlValidateDtd(xmlValidCtxtPtr ctxt,xmlDocPtr doc,xmlDtdPtr dtd)6718 xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
6719     int ret;
6720     xmlDtdPtr oldExt, oldInt;
6721     xmlNodePtr root;
6722 
6723     if (dtd == NULL) return(0);
6724     if (doc == NULL) return(0);
6725     oldExt = doc->extSubset;
6726     oldInt = doc->intSubset;
6727     doc->extSubset = dtd;
6728     doc->intSubset = NULL;
6729     ret = xmlValidateRoot(ctxt, doc);
6730     if (ret == 0) {
6731 	doc->extSubset = oldExt;
6732 	doc->intSubset = oldInt;
6733 	return(ret);
6734     }
6735     if (doc->ids != NULL) {
6736           xmlFreeIDTable(doc->ids);
6737           doc->ids = NULL;
6738     }
6739     if (doc->refs != NULL) {
6740           xmlFreeRefTable(doc->refs);
6741           doc->refs = NULL;
6742     }
6743     root = xmlDocGetRootElement(doc);
6744     ret = xmlValidateElement(ctxt, doc, root);
6745     ret &= xmlValidateDocumentFinal(ctxt, doc);
6746     doc->extSubset = oldExt;
6747     doc->intSubset = oldInt;
6748     return(ret);
6749 }
6750 
6751 static void
xmlValidateNotationCallback(void * payload,void * data,const xmlChar * name ATTRIBUTE_UNUSED)6752 xmlValidateNotationCallback(void *payload, void *data,
6753 	                    const xmlChar *name ATTRIBUTE_UNUSED) {
6754     xmlEntityPtr cur = (xmlEntityPtr) payload;
6755     xmlValidCtxtPtr ctxt = (xmlValidCtxtPtr) data;
6756     if (cur == NULL)
6757 	return;
6758     if (cur->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
6759 	xmlChar *notation = cur->content;
6760 
6761 	if (notation != NULL) {
6762 	    int ret;
6763 
6764 	    ret = xmlValidateNotationUse(ctxt, cur->doc, notation);
6765 	    if (ret != 1) {
6766 		ctxt->valid = 0;
6767 	    }
6768 	}
6769     }
6770 }
6771 
6772 static void
xmlValidateAttributeCallback(void * payload,void * data,const xmlChar * name ATTRIBUTE_UNUSED)6773 xmlValidateAttributeCallback(void *payload, void *data,
6774 	                     const xmlChar *name ATTRIBUTE_UNUSED) {
6775     xmlAttributePtr cur = (xmlAttributePtr) payload;
6776     xmlValidCtxtPtr ctxt = (xmlValidCtxtPtr) data;
6777     int ret;
6778     xmlDocPtr doc;
6779     xmlElementPtr elem = NULL;
6780 
6781     if (cur == NULL)
6782 	return;
6783     switch (cur->atype) {
6784 	case XML_ATTRIBUTE_CDATA:
6785 	case XML_ATTRIBUTE_ID:
6786 	case XML_ATTRIBUTE_IDREF	:
6787 	case XML_ATTRIBUTE_IDREFS:
6788 	case XML_ATTRIBUTE_NMTOKEN:
6789 	case XML_ATTRIBUTE_NMTOKENS:
6790 	case XML_ATTRIBUTE_ENUMERATION:
6791 	    break;
6792 	case XML_ATTRIBUTE_ENTITY:
6793 	case XML_ATTRIBUTE_ENTITIES:
6794 	case XML_ATTRIBUTE_NOTATION:
6795 	    if (cur->defaultValue != NULL) {
6796 
6797 		ret = xmlValidateAttributeValue2(ctxt, ctxt->doc, cur->name,
6798 			                         cur->atype, cur->defaultValue);
6799 		if ((ret == 0) && (ctxt->valid == 1))
6800 		    ctxt->valid = 0;
6801 	    }
6802 	    if (cur->tree != NULL) {
6803 		xmlEnumerationPtr tree = cur->tree;
6804 		while (tree != NULL) {
6805 		    ret = xmlValidateAttributeValue2(ctxt, ctxt->doc,
6806 				    cur->name, cur->atype, tree->name);
6807 		    if ((ret == 0) && (ctxt->valid == 1))
6808 			ctxt->valid = 0;
6809 		    tree = tree->next;
6810 		}
6811 	    }
6812     }
6813     if (cur->atype == XML_ATTRIBUTE_NOTATION) {
6814 	doc = cur->doc;
6815 	if (cur->elem == NULL) {
6816 	    xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
6817 		   "xmlValidateAttributeCallback(%s): internal error\n",
6818 		   (const char *) cur->name);
6819 	    return;
6820 	}
6821 
6822 	if (doc != NULL)
6823 	    elem = xmlGetDtdElementDesc(doc->intSubset, cur->elem);
6824 	if ((elem == NULL) && (doc != NULL))
6825 	    elem = xmlGetDtdElementDesc(doc->extSubset, cur->elem);
6826 	if ((elem == NULL) && (cur->parent != NULL) &&
6827 	    (cur->parent->type == XML_DTD_NODE))
6828 	    elem = xmlGetDtdElementDesc((xmlDtdPtr) cur->parent, cur->elem);
6829 	if (elem == NULL) {
6830 	    xmlErrValidNode(ctxt, NULL, XML_DTD_UNKNOWN_ELEM,
6831 		   "attribute %s: could not find decl for element %s\n",
6832 		   cur->name, cur->elem, NULL);
6833 	    return;
6834 	}
6835 	if (elem->etype == XML_ELEMENT_TYPE_EMPTY) {
6836 	    xmlErrValidNode(ctxt, NULL, XML_DTD_EMPTY_NOTATION,
6837 		   "NOTATION attribute %s declared for EMPTY element %s\n",
6838 		   cur->name, cur->elem, NULL);
6839 	    ctxt->valid = 0;
6840 	}
6841     }
6842 }
6843 
6844 /**
6845  * xmlValidateDtdFinal:
6846  * @ctxt:  the validation context
6847  * @doc:  a document instance
6848  *
6849  * Does the final step for the dtds validation once all the
6850  * subsets have been parsed
6851  *
6852  * basically it does the following checks described by the XML Rec
6853  * - check that ENTITY and ENTITIES type attributes default or
6854  *   possible values matches one of the defined entities.
6855  * - check that NOTATION type attributes default or
6856  *   possible values matches one of the defined notations.
6857  *
6858  * returns 1 if valid or 0 if invalid and -1 if not well-formed
6859  */
6860 
6861 int
xmlValidateDtdFinal(xmlValidCtxtPtr ctxt,xmlDocPtr doc)6862 xmlValidateDtdFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6863     xmlDtdPtr dtd;
6864     xmlAttributeTablePtr table;
6865     xmlEntitiesTablePtr entities;
6866 
6867     if ((doc == NULL) || (ctxt == NULL)) return(0);
6868     if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
6869 	return(0);
6870     ctxt->doc = doc;
6871     ctxt->valid = 1;
6872     dtd = doc->intSubset;
6873     if ((dtd != NULL) && (dtd->attributes != NULL)) {
6874 	table = (xmlAttributeTablePtr) dtd->attributes;
6875 	xmlHashScan(table, xmlValidateAttributeCallback, ctxt);
6876     }
6877     if ((dtd != NULL) && (dtd->entities != NULL)) {
6878 	entities = (xmlEntitiesTablePtr) dtd->entities;
6879 	xmlHashScan(entities, xmlValidateNotationCallback, ctxt);
6880     }
6881     dtd = doc->extSubset;
6882     if ((dtd != NULL) && (dtd->attributes != NULL)) {
6883 	table = (xmlAttributeTablePtr) dtd->attributes;
6884 	xmlHashScan(table, xmlValidateAttributeCallback, ctxt);
6885     }
6886     if ((dtd != NULL) && (dtd->entities != NULL)) {
6887 	entities = (xmlEntitiesTablePtr) dtd->entities;
6888 	xmlHashScan(entities, xmlValidateNotationCallback, ctxt);
6889     }
6890     return(ctxt->valid);
6891 }
6892 
6893 /**
6894  * xmlValidateDocument:
6895  * @ctxt:  the validation context
6896  * @doc:  a document instance
6897  *
6898  * Try to validate the document instance
6899  *
6900  * basically it does the all the checks described by the XML Rec
6901  * i.e. validates the internal and external subset (if present)
6902  * and validate the document tree.
6903  *
6904  * returns 1 if valid or 0 otherwise
6905  */
6906 
6907 int
xmlValidateDocument(xmlValidCtxtPtr ctxt,xmlDocPtr doc)6908 xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6909     int ret;
6910     xmlNodePtr root;
6911 
6912     if (doc == NULL)
6913         return(0);
6914     if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
6915         xmlErrValid(ctxt, XML_DTD_NO_DTD,
6916 	            "no DTD found!\n", NULL);
6917 	return(0);
6918     }
6919     if ((doc->intSubset != NULL) && ((doc->intSubset->SystemID != NULL) ||
6920 	(doc->intSubset->ExternalID != NULL)) && (doc->extSubset == NULL)) {
6921 	xmlChar *sysID;
6922 	if (doc->intSubset->SystemID != NULL) {
6923 	    sysID = xmlBuildURI(doc->intSubset->SystemID,
6924 			doc->URL);
6925 	    if (sysID == NULL) {
6926 	        xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
6927 			"Could not build URI for external subset \"%s\"\n",
6928 			(const char *) doc->intSubset->SystemID);
6929 		return 0;
6930 	    }
6931 	} else
6932 	    sysID = NULL;
6933         doc->extSubset = xmlParseDTD(doc->intSubset->ExternalID,
6934 			(const xmlChar *)sysID);
6935 	if (sysID != NULL)
6936 	    xmlFree(sysID);
6937         if (doc->extSubset == NULL) {
6938 	    if (doc->intSubset->SystemID != NULL) {
6939 		xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
6940 		       "Could not load the external subset \"%s\"\n",
6941 		       (const char *) doc->intSubset->SystemID);
6942 	    } else {
6943 		xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
6944 		       "Could not load the external subset \"%s\"\n",
6945 		       (const char *) doc->intSubset->ExternalID);
6946 	    }
6947 	    return(0);
6948 	}
6949     }
6950 
6951     if (doc->ids != NULL) {
6952           xmlFreeIDTable(doc->ids);
6953           doc->ids = NULL;
6954     }
6955     if (doc->refs != NULL) {
6956           xmlFreeRefTable(doc->refs);
6957           doc->refs = NULL;
6958     }
6959     ret = xmlValidateDtdFinal(ctxt, doc);
6960     if (!xmlValidateRoot(ctxt, doc)) return(0);
6961 
6962     root = xmlDocGetRootElement(doc);
6963     ret &= xmlValidateElement(ctxt, doc, root);
6964     ret &= xmlValidateDocumentFinal(ctxt, doc);
6965     return(ret);
6966 }
6967 
6968 /************************************************************************
6969  *									*
6970  *		Routines for dynamic validation editing			*
6971  *									*
6972  ************************************************************************/
6973 
6974 /**
6975  * xmlValidGetPotentialChildren:
6976  * @ctree:  an element content tree
6977  * @names:  an array to store the list of child names
6978  * @len:  a pointer to the number of element in the list
6979  * @max:  the size of the array
6980  *
6981  * Build/extend a list of  potential children allowed by the content tree
6982  *
6983  * returns the number of element in the list, or -1 in case of error.
6984  */
6985 
6986 int
xmlValidGetPotentialChildren(xmlElementContent * ctree,const xmlChar ** names,int * len,int max)6987 xmlValidGetPotentialChildren(xmlElementContent *ctree,
6988                              const xmlChar **names,
6989                              int *len, int max) {
6990     int i;
6991 
6992     if ((ctree == NULL) || (names == NULL) || (len == NULL))
6993         return(-1);
6994     if (*len >= max) return(*len);
6995 
6996     switch (ctree->type) {
6997 	case XML_ELEMENT_CONTENT_PCDATA:
6998 	    for (i = 0; i < *len;i++)
6999 		if (xmlStrEqual(BAD_CAST "#PCDATA", names[i])) return(*len);
7000 	    names[(*len)++] = BAD_CAST "#PCDATA";
7001 	    break;
7002 	case XML_ELEMENT_CONTENT_ELEMENT:
7003 	    for (i = 0; i < *len;i++)
7004 		if (xmlStrEqual(ctree->name, names[i])) return(*len);
7005 	    names[(*len)++] = ctree->name;
7006 	    break;
7007 	case XML_ELEMENT_CONTENT_SEQ:
7008 	    xmlValidGetPotentialChildren(ctree->c1, names, len, max);
7009 	    xmlValidGetPotentialChildren(ctree->c2, names, len, max);
7010 	    break;
7011 	case XML_ELEMENT_CONTENT_OR:
7012 	    xmlValidGetPotentialChildren(ctree->c1, names, len, max);
7013 	    xmlValidGetPotentialChildren(ctree->c2, names, len, max);
7014 	    break;
7015    }
7016 
7017    return(*len);
7018 }
7019 
7020 /*
7021  * Dummy function to suppress messages while we try out valid elements
7022  */
xmlNoValidityErr(void * ctx ATTRIBUTE_UNUSED,const char * msg ATTRIBUTE_UNUSED,...)7023 static void XMLCDECL xmlNoValidityErr(void *ctx ATTRIBUTE_UNUSED,
7024                                 const char *msg ATTRIBUTE_UNUSED, ...) {
7025     return;
7026 }
7027 
7028 /**
7029  * xmlValidGetValidElements:
7030  * @prev:  an element to insert after
7031  * @next:  an element to insert next
7032  * @names:  an array to store the list of child names
7033  * @max:  the size of the array
7034  *
7035  * This function returns the list of authorized children to insert
7036  * within an existing tree while respecting the validity constraints
7037  * forced by the Dtd. The insertion point is defined using @prev and
7038  * @next in the following ways:
7039  *  to insert before 'node': xmlValidGetValidElements(node->prev, node, ...
7040  *  to insert next 'node': xmlValidGetValidElements(node, node->next, ...
7041  *  to replace 'node': xmlValidGetValidElements(node->prev, node->next, ...
7042  *  to prepend a child to 'node': xmlValidGetValidElements(NULL, node->childs,
7043  *  to append a child to 'node': xmlValidGetValidElements(node->last, NULL, ...
7044  *
7045  * pointers to the element names are inserted at the beginning of the array
7046  * and do not need to be freed.
7047  *
7048  * returns the number of element in the list, or -1 in case of error. If
7049  *    the function returns the value @max the caller is invited to grow the
7050  *    receiving array and retry.
7051  */
7052 
7053 int
xmlValidGetValidElements(xmlNode * prev,xmlNode * next,const xmlChar ** names,int max)7054 xmlValidGetValidElements(xmlNode *prev, xmlNode *next, const xmlChar **names,
7055                          int max) {
7056     xmlValidCtxt vctxt;
7057     int nb_valid_elements = 0;
7058     const xmlChar *elements[256]={0};
7059     int nb_elements = 0, i;
7060     const xmlChar *name;
7061 
7062     xmlNode *ref_node;
7063     xmlNode *parent;
7064     xmlNode *test_node;
7065 
7066     xmlNode *prev_next;
7067     xmlNode *next_prev;
7068     xmlNode *parent_childs;
7069     xmlNode *parent_last;
7070 
7071     xmlElement *element_desc;
7072 
7073     if (prev == NULL && next == NULL)
7074         return(-1);
7075 
7076     if (names == NULL) return(-1);
7077     if (max <= 0) return(-1);
7078 
7079     memset(&vctxt, 0, sizeof (xmlValidCtxt));
7080     vctxt.error = xmlNoValidityErr;	/* this suppresses err/warn output */
7081 
7082     nb_valid_elements = 0;
7083     ref_node = prev ? prev : next;
7084     parent = ref_node->parent;
7085 
7086     /*
7087      * Retrieves the parent element declaration
7088      */
7089     element_desc = xmlGetDtdElementDesc(parent->doc->intSubset,
7090                                          parent->name);
7091     if ((element_desc == NULL) && (parent->doc->extSubset != NULL))
7092         element_desc = xmlGetDtdElementDesc(parent->doc->extSubset,
7093                                              parent->name);
7094     if (element_desc == NULL) return(-1);
7095 
7096     /*
7097      * Do a backup of the current tree structure
7098      */
7099     prev_next = prev ? prev->next : NULL;
7100     next_prev = next ? next->prev : NULL;
7101     parent_childs = parent->children;
7102     parent_last = parent->last;
7103 
7104     /*
7105      * Creates a dummy node and insert it into the tree
7106      */
7107     test_node = xmlNewDocNode (ref_node->doc, NULL, BAD_CAST "<!dummy?>", NULL);
7108     if (test_node == NULL)
7109         return(-1);
7110 
7111     test_node->parent = parent;
7112     test_node->prev = prev;
7113     test_node->next = next;
7114     name = test_node->name;
7115 
7116     if (prev) prev->next = test_node;
7117     else parent->children = test_node;
7118 
7119     if (next) next->prev = test_node;
7120     else parent->last = test_node;
7121 
7122     /*
7123      * Insert each potential child node and check if the parent is
7124      * still valid
7125      */
7126     nb_elements = xmlValidGetPotentialChildren(element_desc->content,
7127 		       elements, &nb_elements, 256);
7128 
7129     for (i = 0;i < nb_elements;i++) {
7130 	test_node->name = elements[i];
7131 	if (xmlValidateOneElement(&vctxt, parent->doc, parent)) {
7132 	    int j;
7133 
7134 	    for (j = 0; j < nb_valid_elements;j++)
7135 		if (xmlStrEqual(elements[i], names[j])) break;
7136 	    names[nb_valid_elements++] = elements[i];
7137 	    if (nb_valid_elements >= max) break;
7138 	}
7139     }
7140 
7141     /*
7142      * Restore the tree structure
7143      */
7144     if (prev) prev->next = prev_next;
7145     if (next) next->prev = next_prev;
7146     parent->children = parent_childs;
7147     parent->last = parent_last;
7148 
7149     /*
7150      * Free up the dummy node
7151      */
7152     test_node->name = name;
7153     xmlFreeNode(test_node);
7154 
7155     return(nb_valid_elements);
7156 }
7157 #endif /* LIBXML_VALID_ENABLED */
7158 
7159 #define bottom_valid
7160 #include "elfgcchack.h"
7161