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