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