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