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