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