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