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