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