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