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