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