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