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