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