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