msscript.ocx: Fake success in FreezeEvents.
[wine.git] / libs / xml2 / valid.c
blob06a7f382044a2ac7e325d1bf4fe3e07c2b3b7a38
1 /*
2 * valid.c : part of the code use to do the DTD handling and the validity
3 * checking
5 * See Copyright for the status of this software.
7 * daniel@veillard.com
8 */
10 #define IN_LIBXML
11 #include "libxml.h"
13 #include <string.h>
14 #include <stdlib.h>
16 #include <libxml/xmlmemory.h>
17 #include <libxml/hash.h>
18 #include <libxml/uri.h>
19 #include <libxml/valid.h>
20 #include <libxml/parser.h>
21 #include <libxml/parserInternals.h>
22 #include <libxml/xmlerror.h>
23 #include <libxml/list.h>
24 #include <libxml/globals.h>
26 #include "private/error.h"
27 #include "private/parser.h"
29 static xmlElementPtr
30 xmlGetDtdElementDesc2(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name,
31 int create);
32 /* #define DEBUG_VALID_ALGO */
33 /* #define DEBUG_REGEXP_ALGO */
35 #define TODO \
36 xmlGenericError(xmlGenericErrorContext, \
37 "Unimplemented block at %s:%d\n", \
38 __FILE__, __LINE__);
40 #ifdef LIBXML_VALID_ENABLED
41 static int
42 xmlValidateAttributeValueInternal(xmlDocPtr doc, xmlAttributeType type,
43 const xmlChar *value);
44 #endif
45 /************************************************************************
46 * *
47 * Error handling routines *
48 * *
49 ************************************************************************/
51 /**
52 * xmlVErrMemory:
53 * @ctxt: an XML validation parser context
54 * @extra: extra information
56 * Handle an out of memory error
58 static void
59 xmlVErrMemory(xmlValidCtxtPtr ctxt, const char *extra)
61 xmlGenericErrorFunc channel = NULL;
62 xmlParserCtxtPtr pctxt = NULL;
63 void *data = NULL;
65 if (ctxt != NULL) {
66 channel = ctxt->error;
67 data = ctxt->userData;
68 /* Look up flag to detect if it is part of a parsing
69 context */
70 if (ctxt->flags & XML_VCTXT_USE_PCTXT) {
71 pctxt = ctxt->userData;
74 if (extra)
75 __xmlRaiseError(NULL, channel, data,
76 pctxt, NULL, XML_FROM_VALID, XML_ERR_NO_MEMORY,
77 XML_ERR_FATAL, NULL, 0, extra, NULL, NULL, 0, 0,
78 "Memory allocation failed : %s\n", extra);
79 else
80 __xmlRaiseError(NULL, channel, data,
81 pctxt, NULL, XML_FROM_VALID, XML_ERR_NO_MEMORY,
82 XML_ERR_FATAL, NULL, 0, NULL, NULL, NULL, 0, 0,
83 "Memory allocation failed\n");
86 /**
87 * xmlErrValid:
88 * @ctxt: an XML validation parser context
89 * @error: the error number
90 * @extra: extra information
92 * Handle a validation error
94 static void LIBXML_ATTR_FORMAT(3,0)
95 xmlErrValid(xmlValidCtxtPtr ctxt, xmlParserErrors error,
96 const char *msg, const char *extra)
98 xmlGenericErrorFunc channel = NULL;
99 xmlParserCtxtPtr pctxt = NULL;
100 void *data = NULL;
102 if (ctxt != NULL) {
103 channel = ctxt->error;
104 data = ctxt->userData;
105 /* Look up flag to detect if it is part of a parsing
106 context */
107 if (ctxt->flags & XML_VCTXT_USE_PCTXT) {
108 pctxt = ctxt->userData;
111 if (extra)
112 __xmlRaiseError(NULL, channel, data,
113 pctxt, NULL, XML_FROM_VALID, error,
114 XML_ERR_ERROR, NULL, 0, extra, NULL, NULL, 0, 0,
115 msg, extra);
116 else
117 __xmlRaiseError(NULL, channel, data,
118 pctxt, NULL, XML_FROM_VALID, error,
119 XML_ERR_ERROR, NULL, 0, NULL, NULL, NULL, 0, 0,
120 "%s", msg);
123 #if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
125 * xmlErrValidNode:
126 * @ctxt: an XML validation parser context
127 * @node: the node raising the error
128 * @error: the error number
129 * @str1: extra information
130 * @str2: extra information
131 * @str3: extra information
133 * Handle a validation error, provide contextual information
135 static void LIBXML_ATTR_FORMAT(4,0)
136 xmlErrValidNode(xmlValidCtxtPtr ctxt,
137 xmlNodePtr node, xmlParserErrors error,
138 const char *msg, const xmlChar * str1,
139 const xmlChar * str2, const xmlChar * str3)
141 xmlStructuredErrorFunc schannel = NULL;
142 xmlGenericErrorFunc channel = NULL;
143 xmlParserCtxtPtr pctxt = NULL;
144 void *data = NULL;
146 if (ctxt != NULL) {
147 channel = ctxt->error;
148 data = ctxt->userData;
149 /* Look up flag to detect if it is part of a parsing
150 context */
151 if (ctxt->flags & XML_VCTXT_USE_PCTXT) {
152 pctxt = ctxt->userData;
155 __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
156 XML_ERR_ERROR, NULL, 0,
157 (const char *) str1,
158 (const char *) str2,
159 (const char *) str3, 0, 0, msg, str1, str2, str3);
161 #endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */
163 #ifdef LIBXML_VALID_ENABLED
165 * xmlErrValidNodeNr:
166 * @ctxt: an XML validation parser context
167 * @node: the node raising the error
168 * @error: the error number
169 * @str1: extra information
170 * @int2: extra information
171 * @str3: extra information
173 * Handle a validation error, provide contextual information
175 static void LIBXML_ATTR_FORMAT(4,0)
176 xmlErrValidNodeNr(xmlValidCtxtPtr ctxt,
177 xmlNodePtr node, xmlParserErrors error,
178 const char *msg, const xmlChar * str1,
179 int int2, const xmlChar * str3)
181 xmlStructuredErrorFunc schannel = NULL;
182 xmlGenericErrorFunc channel = NULL;
183 xmlParserCtxtPtr pctxt = NULL;
184 void *data = NULL;
186 if (ctxt != NULL) {
187 channel = ctxt->error;
188 data = ctxt->userData;
189 /* Look up flag to detect if it is part of a parsing
190 context */
191 if (ctxt->flags & XML_VCTXT_USE_PCTXT) {
192 pctxt = ctxt->userData;
195 __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
196 XML_ERR_ERROR, NULL, 0,
197 (const char *) str1,
198 (const char *) str3,
199 NULL, int2, 0, msg, str1, int2, str3);
203 * xmlErrValidWarning:
204 * @ctxt: an XML validation parser context
205 * @node: the node raising the error
206 * @error: the error number
207 * @str1: extra information
208 * @str2: extra information
209 * @str3: extra information
211 * Handle a validation error, provide contextual information
213 static void LIBXML_ATTR_FORMAT(4,0)
214 xmlErrValidWarning(xmlValidCtxtPtr ctxt,
215 xmlNodePtr node, xmlParserErrors error,
216 const char *msg, const xmlChar * str1,
217 const xmlChar * str2, const xmlChar * str3)
219 xmlStructuredErrorFunc schannel = NULL;
220 xmlGenericErrorFunc channel = NULL;
221 xmlParserCtxtPtr pctxt = NULL;
222 void *data = NULL;
224 if (ctxt != NULL) {
225 channel = ctxt->warning;
226 data = ctxt->userData;
227 /* Look up flag to detect if it is part of a parsing
228 context */
229 if (ctxt->flags & XML_VCTXT_USE_PCTXT) {
230 pctxt = ctxt->userData;
233 __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
234 XML_ERR_WARNING, NULL, 0,
235 (const char *) str1,
236 (const char *) str2,
237 (const char *) str3, 0, 0, msg, str1, str2, str3);
242 #ifdef LIBXML_REGEXP_ENABLED
244 * If regexp are enabled we can do continuous validation without the
245 * need of a tree to validate the content model. this is done in each
246 * callbacks.
247 * Each xmlValidState represent the validation state associated to the
248 * set of nodes currently open from the document root to the current element.
252 typedef struct _xmlValidState {
253 xmlElementPtr elemDecl; /* pointer to the content model */
254 xmlNodePtr node; /* pointer to the current node */
255 xmlRegExecCtxtPtr exec; /* regexp runtime */
256 } _xmlValidState;
259 static int
260 vstateVPush(xmlValidCtxtPtr ctxt, xmlElementPtr elemDecl, xmlNodePtr node) {
261 if ((ctxt->vstateMax == 0) || (ctxt->vstateTab == NULL)) {
262 ctxt->vstateMax = 10;
263 ctxt->vstateTab = (xmlValidState *) xmlMalloc(ctxt->vstateMax *
264 sizeof(ctxt->vstateTab[0]));
265 if (ctxt->vstateTab == NULL) {
266 xmlVErrMemory(ctxt, "malloc failed");
267 return(-1);
271 if (ctxt->vstateNr >= ctxt->vstateMax) {
272 xmlValidState *tmp;
274 tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
275 2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
276 if (tmp == NULL) {
277 xmlVErrMemory(ctxt, "realloc failed");
278 return(-1);
280 ctxt->vstateMax *= 2;
281 ctxt->vstateTab = tmp;
283 ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr];
284 ctxt->vstateTab[ctxt->vstateNr].elemDecl = elemDecl;
285 ctxt->vstateTab[ctxt->vstateNr].node = node;
286 if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) {
287 if (elemDecl->contModel == NULL)
288 xmlValidBuildContentModel(ctxt, elemDecl);
289 if (elemDecl->contModel != NULL) {
290 ctxt->vstateTab[ctxt->vstateNr].exec =
291 xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
292 } else {
293 ctxt->vstateTab[ctxt->vstateNr].exec = NULL;
294 xmlErrValidNode(ctxt, (xmlNodePtr) elemDecl,
295 XML_ERR_INTERNAL_ERROR,
296 "Failed to build content model regexp for %s\n",
297 node->name, NULL, NULL);
300 return(ctxt->vstateNr++);
303 static int
304 vstateVPop(xmlValidCtxtPtr ctxt) {
305 xmlElementPtr elemDecl;
307 if (ctxt->vstateNr < 1) return(-1);
308 ctxt->vstateNr--;
309 elemDecl = ctxt->vstateTab[ctxt->vstateNr].elemDecl;
310 ctxt->vstateTab[ctxt->vstateNr].elemDecl = NULL;
311 ctxt->vstateTab[ctxt->vstateNr].node = NULL;
312 if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) {
313 xmlRegFreeExecCtxt(ctxt->vstateTab[ctxt->vstateNr].exec);
315 ctxt->vstateTab[ctxt->vstateNr].exec = NULL;
316 if (ctxt->vstateNr >= 1)
317 ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr - 1];
318 else
319 ctxt->vstate = NULL;
320 return(ctxt->vstateNr);
323 #else /* not LIBXML_REGEXP_ENABLED */
325 * If regexp are not enabled, it uses a home made algorithm less
326 * complex and easier to
327 * debug/maintain than a generic NFA -> DFA state based algo. The
328 * only restriction is on the deepness of the tree limited by the
329 * size of the occurs bitfield
331 * this is the content of a saved state for rollbacks
334 #define ROLLBACK_OR 0
335 #define ROLLBACK_PARENT 1
337 typedef struct _xmlValidState {
338 xmlElementContentPtr cont; /* pointer to the content model subtree */
339 xmlNodePtr node; /* pointer to the current node in the list */
340 long occurs;/* bitfield for multiple occurrences */
341 unsigned char depth; /* current depth in the overall tree */
342 unsigned char state; /* ROLLBACK_XXX */
343 } _xmlValidState;
345 #define MAX_RECURSE 25000
346 #define MAX_DEPTH ((sizeof(_xmlValidState.occurs)) * 8)
347 #define CONT ctxt->vstate->cont
348 #define NODE ctxt->vstate->node
349 #define DEPTH ctxt->vstate->depth
350 #define OCCURS ctxt->vstate->occurs
351 #define STATE ctxt->vstate->state
353 #define OCCURRENCE (ctxt->vstate->occurs & (1 << DEPTH))
354 #define PARENT_OCCURRENCE (ctxt->vstate->occurs & ((1 << DEPTH) - 1))
356 #define SET_OCCURRENCE ctxt->vstate->occurs |= (1 << DEPTH)
357 #define RESET_OCCURRENCE ctxt->vstate->occurs &= ((1 << DEPTH) - 1)
359 static int
360 vstateVPush(xmlValidCtxtPtr ctxt, xmlElementContentPtr cont,
361 xmlNodePtr node, unsigned char depth, long occurs,
362 unsigned char state) {
363 int i = ctxt->vstateNr - 1;
365 if (ctxt->vstateNr > MAX_RECURSE) {
366 return(-1);
368 if (ctxt->vstateTab == NULL) {
369 ctxt->vstateMax = 8;
370 ctxt->vstateTab = (xmlValidState *) xmlMalloc(
371 ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
372 if (ctxt->vstateTab == NULL) {
373 xmlVErrMemory(ctxt, "malloc failed");
374 return(-1);
377 if (ctxt->vstateNr >= ctxt->vstateMax) {
378 xmlValidState *tmp;
380 tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
381 2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
382 if (tmp == NULL) {
383 xmlVErrMemory(ctxt, "malloc failed");
384 return(-1);
386 ctxt->vstateMax *= 2;
387 ctxt->vstateTab = tmp;
388 ctxt->vstate = &ctxt->vstateTab[0];
391 * Don't push on the stack a state already here
393 if ((i >= 0) && (ctxt->vstateTab[i].cont == cont) &&
394 (ctxt->vstateTab[i].node == node) &&
395 (ctxt->vstateTab[i].depth == depth) &&
396 (ctxt->vstateTab[i].occurs == occurs) &&
397 (ctxt->vstateTab[i].state == state))
398 return(ctxt->vstateNr);
399 ctxt->vstateTab[ctxt->vstateNr].cont = cont;
400 ctxt->vstateTab[ctxt->vstateNr].node = node;
401 ctxt->vstateTab[ctxt->vstateNr].depth = depth;
402 ctxt->vstateTab[ctxt->vstateNr].occurs = occurs;
403 ctxt->vstateTab[ctxt->vstateNr].state = state;
404 return(ctxt->vstateNr++);
407 static int
408 vstateVPop(xmlValidCtxtPtr ctxt) {
409 if (ctxt->vstateNr <= 1) return(-1);
410 ctxt->vstateNr--;
411 ctxt->vstate = &ctxt->vstateTab[0];
412 ctxt->vstate->cont = ctxt->vstateTab[ctxt->vstateNr].cont;
413 ctxt->vstate->node = ctxt->vstateTab[ctxt->vstateNr].node;
414 ctxt->vstate->depth = ctxt->vstateTab[ctxt->vstateNr].depth;
415 ctxt->vstate->occurs = ctxt->vstateTab[ctxt->vstateNr].occurs;
416 ctxt->vstate->state = ctxt->vstateTab[ctxt->vstateNr].state;
417 return(ctxt->vstateNr);
420 #endif /* LIBXML_REGEXP_ENABLED */
422 static int
423 nodeVPush(xmlValidCtxtPtr ctxt, xmlNodePtr value)
425 if (ctxt->nodeMax <= 0) {
426 ctxt->nodeMax = 4;
427 ctxt->nodeTab =
428 (xmlNodePtr *) xmlMalloc(ctxt->nodeMax *
429 sizeof(ctxt->nodeTab[0]));
430 if (ctxt->nodeTab == NULL) {
431 xmlVErrMemory(ctxt, "malloc failed");
432 ctxt->nodeMax = 0;
433 return (0);
436 if (ctxt->nodeNr >= ctxt->nodeMax) {
437 xmlNodePtr *tmp;
438 tmp = (xmlNodePtr *) xmlRealloc(ctxt->nodeTab,
439 ctxt->nodeMax * 2 * sizeof(ctxt->nodeTab[0]));
440 if (tmp == NULL) {
441 xmlVErrMemory(ctxt, "realloc failed");
442 return (0);
444 ctxt->nodeMax *= 2;
445 ctxt->nodeTab = tmp;
447 ctxt->nodeTab[ctxt->nodeNr] = value;
448 ctxt->node = value;
449 return (ctxt->nodeNr++);
451 static xmlNodePtr
452 nodeVPop(xmlValidCtxtPtr ctxt)
454 xmlNodePtr ret;
456 if (ctxt->nodeNr <= 0)
457 return (NULL);
458 ctxt->nodeNr--;
459 if (ctxt->nodeNr > 0)
460 ctxt->node = ctxt->nodeTab[ctxt->nodeNr - 1];
461 else
462 ctxt->node = NULL;
463 ret = ctxt->nodeTab[ctxt->nodeNr];
464 ctxt->nodeTab[ctxt->nodeNr] = NULL;
465 return (ret);
468 #ifdef DEBUG_VALID_ALGO
469 static void
470 xmlValidPrintNode(xmlNodePtr cur) {
471 if (cur == NULL) {
472 xmlGenericError(xmlGenericErrorContext, "null");
473 return;
475 switch (cur->type) {
476 case XML_ELEMENT_NODE:
477 xmlGenericError(xmlGenericErrorContext, "%s ", cur->name);
478 break;
479 case XML_TEXT_NODE:
480 xmlGenericError(xmlGenericErrorContext, "text ");
481 break;
482 case XML_CDATA_SECTION_NODE:
483 xmlGenericError(xmlGenericErrorContext, "cdata ");
484 break;
485 case XML_ENTITY_REF_NODE:
486 xmlGenericError(xmlGenericErrorContext, "&%s; ", cur->name);
487 break;
488 case XML_PI_NODE:
489 xmlGenericError(xmlGenericErrorContext, "pi(%s) ", cur->name);
490 break;
491 case XML_COMMENT_NODE:
492 xmlGenericError(xmlGenericErrorContext, "comment ");
493 break;
494 case XML_ATTRIBUTE_NODE:
495 xmlGenericError(xmlGenericErrorContext, "?attr? ");
496 break;
497 case XML_ENTITY_NODE:
498 xmlGenericError(xmlGenericErrorContext, "?ent? ");
499 break;
500 case XML_DOCUMENT_NODE:
501 xmlGenericError(xmlGenericErrorContext, "?doc? ");
502 break;
503 case XML_DOCUMENT_TYPE_NODE:
504 xmlGenericError(xmlGenericErrorContext, "?doctype? ");
505 break;
506 case XML_DOCUMENT_FRAG_NODE:
507 xmlGenericError(xmlGenericErrorContext, "?frag? ");
508 break;
509 case XML_NOTATION_NODE:
510 xmlGenericError(xmlGenericErrorContext, "?nota? ");
511 break;
512 case XML_HTML_DOCUMENT_NODE:
513 xmlGenericError(xmlGenericErrorContext, "?html? ");
514 break;
515 case XML_DTD_NODE:
516 xmlGenericError(xmlGenericErrorContext, "?dtd? ");
517 break;
518 case XML_ELEMENT_DECL:
519 xmlGenericError(xmlGenericErrorContext, "?edecl? ");
520 break;
521 case XML_ATTRIBUTE_DECL:
522 xmlGenericError(xmlGenericErrorContext, "?adecl? ");
523 break;
524 case XML_ENTITY_DECL:
525 xmlGenericError(xmlGenericErrorContext, "?entdecl? ");
526 break;
527 case XML_NAMESPACE_DECL:
528 xmlGenericError(xmlGenericErrorContext, "?nsdecl? ");
529 break;
530 case XML_XINCLUDE_START:
531 xmlGenericError(xmlGenericErrorContext, "incstart ");
532 break;
533 case XML_XINCLUDE_END:
534 xmlGenericError(xmlGenericErrorContext, "incend ");
535 break;
539 static void
540 xmlValidPrintNodeList(xmlNodePtr cur) {
541 if (cur == NULL)
542 xmlGenericError(xmlGenericErrorContext, "null ");
543 while (cur != NULL) {
544 xmlValidPrintNode(cur);
545 cur = cur->next;
549 static void
550 xmlValidDebug(xmlNodePtr cur, xmlElementContentPtr cont) {
551 char expr[5000];
553 expr[0] = 0;
554 xmlGenericError(xmlGenericErrorContext, "valid: ");
555 xmlValidPrintNodeList(cur);
556 xmlGenericError(xmlGenericErrorContext, "against ");
557 xmlSnprintfElementContent(expr, 5000, cont, 1);
558 xmlGenericError(xmlGenericErrorContext, "%s\n", expr);
561 static void
562 xmlValidDebugState(xmlValidStatePtr state) {
563 xmlGenericError(xmlGenericErrorContext, "(");
564 if (state->cont == NULL)
565 xmlGenericError(xmlGenericErrorContext, "null,");
566 else
567 switch (state->cont->type) {
568 case XML_ELEMENT_CONTENT_PCDATA:
569 xmlGenericError(xmlGenericErrorContext, "pcdata,");
570 break;
571 case XML_ELEMENT_CONTENT_ELEMENT:
572 xmlGenericError(xmlGenericErrorContext, "%s,",
573 state->cont->name);
574 break;
575 case XML_ELEMENT_CONTENT_SEQ:
576 xmlGenericError(xmlGenericErrorContext, "seq,");
577 break;
578 case XML_ELEMENT_CONTENT_OR:
579 xmlGenericError(xmlGenericErrorContext, "or,");
580 break;
582 xmlValidPrintNode(state->node);
583 xmlGenericError(xmlGenericErrorContext, ",%d,%X,%d)",
584 state->depth, state->occurs, state->state);
587 static void
588 xmlValidStateDebug(xmlValidCtxtPtr ctxt) {
589 int i, j;
591 xmlGenericError(xmlGenericErrorContext, "state: ");
592 xmlValidDebugState(ctxt->vstate);
593 xmlGenericError(xmlGenericErrorContext, " stack: %d ",
594 ctxt->vstateNr - 1);
595 for (i = 0, j = ctxt->vstateNr - 1;(i < 3) && (j > 0);i++,j--)
596 xmlValidDebugState(&ctxt->vstateTab[j]);
597 xmlGenericError(xmlGenericErrorContext, "\n");
600 /*****
601 #define DEBUG_VALID_STATE(n,c) xmlValidDebug(n,c);
602 *****/
604 #define DEBUG_VALID_STATE(n,c) xmlValidStateDebug(ctxt);
605 #define DEBUG_VALID_MSG(m) \
606 xmlGenericError(xmlGenericErrorContext, "%s\n", m);
608 #else
609 #define DEBUG_VALID_STATE(n,c)
610 #define DEBUG_VALID_MSG(m)
611 #endif
613 /* TODO: use hash table for accesses to elem and attribute definitions */
616 #define CHECK_DTD \
617 if (doc == NULL) return(0); \
618 else if ((doc->intSubset == NULL) && \
619 (doc->extSubset == NULL)) return(0)
621 #ifdef LIBXML_REGEXP_ENABLED
623 /************************************************************************
625 * Content model validation based on the regexps *
627 ************************************************************************/
630 * xmlValidBuildAContentModel:
631 * @content: the content model
632 * @ctxt: the schema parser context
633 * @name: the element name whose content is being built
635 * Generate the automata sequence needed for that type
637 * Returns 1 if successful or 0 in case of error.
639 static int
640 xmlValidBuildAContentModel(xmlElementContentPtr content,
641 xmlValidCtxtPtr ctxt,
642 const xmlChar *name) {
643 if (content == NULL) {
644 xmlErrValidNode(ctxt, NULL, XML_ERR_INTERNAL_ERROR,
645 "Found NULL content in content model of %s\n",
646 name, NULL, NULL);
647 return(0);
649 switch (content->type) {
650 case XML_ELEMENT_CONTENT_PCDATA:
651 xmlErrValidNode(ctxt, NULL, XML_ERR_INTERNAL_ERROR,
652 "Found PCDATA in content model of %s\n",
653 name, NULL, NULL);
654 return(0);
655 break;
656 case XML_ELEMENT_CONTENT_ELEMENT: {
657 xmlAutomataStatePtr oldstate = ctxt->state;
658 xmlChar fn[50];
659 xmlChar *fullname;
661 fullname = xmlBuildQName(content->name, content->prefix, fn, 50);
662 if (fullname == NULL) {
663 xmlVErrMemory(ctxt, "Building content model");
664 return(0);
667 switch (content->ocur) {
668 case XML_ELEMENT_CONTENT_ONCE:
669 ctxt->state = xmlAutomataNewTransition(ctxt->am,
670 ctxt->state, NULL, fullname, NULL);
671 break;
672 case XML_ELEMENT_CONTENT_OPT:
673 ctxt->state = xmlAutomataNewTransition(ctxt->am,
674 ctxt->state, NULL, fullname, NULL);
675 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
676 break;
677 case XML_ELEMENT_CONTENT_PLUS:
678 ctxt->state = xmlAutomataNewTransition(ctxt->am,
679 ctxt->state, NULL, fullname, NULL);
680 xmlAutomataNewTransition(ctxt->am, ctxt->state,
681 ctxt->state, fullname, NULL);
682 break;
683 case XML_ELEMENT_CONTENT_MULT:
684 ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
685 ctxt->state, NULL);
686 xmlAutomataNewTransition(ctxt->am,
687 ctxt->state, ctxt->state, fullname, NULL);
688 break;
690 if ((fullname != fn) && (fullname != content->name))
691 xmlFree(fullname);
692 break;
694 case XML_ELEMENT_CONTENT_SEQ: {
695 xmlAutomataStatePtr oldstate, oldend;
696 xmlElementContentOccur ocur;
699 * Simply iterate over the content
701 oldstate = ctxt->state;
702 ocur = content->ocur;
703 if (ocur != XML_ELEMENT_CONTENT_ONCE) {
704 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
705 oldstate = ctxt->state;
707 do {
708 xmlValidBuildAContentModel(content->c1, ctxt, name);
709 content = content->c2;
710 } while ((content->type == XML_ELEMENT_CONTENT_SEQ) &&
711 (content->ocur == XML_ELEMENT_CONTENT_ONCE));
712 xmlValidBuildAContentModel(content, ctxt, name);
713 oldend = ctxt->state;
714 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL);
715 switch (ocur) {
716 case XML_ELEMENT_CONTENT_ONCE:
717 break;
718 case XML_ELEMENT_CONTENT_OPT:
719 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
720 break;
721 case XML_ELEMENT_CONTENT_MULT:
722 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
723 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
724 break;
725 case XML_ELEMENT_CONTENT_PLUS:
726 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
727 break;
729 break;
731 case XML_ELEMENT_CONTENT_OR: {
732 xmlAutomataStatePtr oldstate, oldend;
733 xmlElementContentOccur ocur;
735 ocur = content->ocur;
736 if ((ocur == XML_ELEMENT_CONTENT_PLUS) ||
737 (ocur == XML_ELEMENT_CONTENT_MULT)) {
738 ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
739 ctxt->state, NULL);
741 oldstate = ctxt->state;
742 oldend = xmlAutomataNewState(ctxt->am);
745 * iterate over the subtypes and remerge the end with an
746 * epsilon transition
748 do {
749 ctxt->state = oldstate;
750 xmlValidBuildAContentModel(content->c1, ctxt, name);
751 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend);
752 content = content->c2;
753 } while ((content->type == XML_ELEMENT_CONTENT_OR) &&
754 (content->ocur == XML_ELEMENT_CONTENT_ONCE));
755 ctxt->state = oldstate;
756 xmlValidBuildAContentModel(content, ctxt, name);
757 xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend);
758 ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL);
759 switch (ocur) {
760 case XML_ELEMENT_CONTENT_ONCE:
761 break;
762 case XML_ELEMENT_CONTENT_OPT:
763 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
764 break;
765 case XML_ELEMENT_CONTENT_MULT:
766 xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
767 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
768 break;
769 case XML_ELEMENT_CONTENT_PLUS:
770 xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
771 break;
773 break;
775 default:
776 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
777 "ContentModel broken for element %s\n",
778 (const char *) name);
779 return(0);
781 return(1);
784 * xmlValidBuildContentModel:
785 * @ctxt: a validation context
786 * @elem: an element declaration node
788 * (Re)Build the automata associated to the content model of this
789 * element
791 * Returns 1 in case of success, 0 in case of error
794 xmlValidBuildContentModel(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
796 if ((ctxt == NULL) || (elem == NULL))
797 return(0);
798 if (elem->type != XML_ELEMENT_DECL)
799 return(0);
800 if (elem->etype != XML_ELEMENT_TYPE_ELEMENT)
801 return(1);
802 /* TODO: should we rebuild in this case ? */
803 if (elem->contModel != NULL) {
804 if (!xmlRegexpIsDeterminist(elem->contModel)) {
805 ctxt->valid = 0;
806 return(0);
808 return(1);
811 ctxt->am = xmlNewAutomata();
812 if (ctxt->am == NULL) {
813 xmlErrValidNode(ctxt, (xmlNodePtr) elem,
814 XML_ERR_INTERNAL_ERROR,
815 "Cannot create automata for element %s\n",
816 elem->name, NULL, NULL);
817 return(0);
819 ctxt->state = xmlAutomataGetInitState(ctxt->am);
820 xmlValidBuildAContentModel(elem->content, ctxt, elem->name);
821 xmlAutomataSetFinalState(ctxt->am, ctxt->state);
822 elem->contModel = xmlAutomataCompile(ctxt->am);
823 if (xmlRegexpIsDeterminist(elem->contModel) != 1) {
824 char expr[5000];
825 expr[0] = 0;
826 xmlSnprintfElementContent(expr, 5000, elem->content, 1);
827 xmlErrValidNode(ctxt, (xmlNodePtr) elem,
828 XML_DTD_CONTENT_NOT_DETERMINIST,
829 "Content model of %s is not deterministic: %s\n",
830 elem->name, BAD_CAST expr, NULL);
831 #ifdef DEBUG_REGEXP_ALGO
832 xmlRegexpPrint(stderr, elem->contModel);
833 #endif
834 ctxt->valid = 0;
835 ctxt->state = NULL;
836 xmlFreeAutomata(ctxt->am);
837 ctxt->am = NULL;
838 return(0);
840 ctxt->state = NULL;
841 xmlFreeAutomata(ctxt->am);
842 ctxt->am = NULL;
843 return(1);
846 #endif /* LIBXML_REGEXP_ENABLED */
848 /****************************************************************
850 * Util functions for data allocation/deallocation *
852 ****************************************************************/
855 * xmlNewValidCtxt:
857 * Allocate a validation context structure.
859 * Returns NULL if not, otherwise the new validation context structure
861 xmlValidCtxtPtr xmlNewValidCtxt(void) {
862 xmlValidCtxtPtr ret;
864 if ((ret = xmlMalloc(sizeof (xmlValidCtxt))) == NULL) {
865 xmlVErrMemory(NULL, "malloc failed");
866 return (NULL);
869 (void) memset(ret, 0, sizeof (xmlValidCtxt));
871 return (ret);
875 * xmlFreeValidCtxt:
876 * @cur: the validation context to free
878 * Free a validation context structure.
880 void
881 xmlFreeValidCtxt(xmlValidCtxtPtr cur) {
882 if (cur == NULL)
883 return;
884 if (cur->vstateTab != NULL)
885 xmlFree(cur->vstateTab);
886 if (cur->nodeTab != NULL)
887 xmlFree(cur->nodeTab);
888 xmlFree(cur);
891 #endif /* LIBXML_VALID_ENABLED */
894 * xmlNewDocElementContent:
895 * @doc: the document
896 * @name: the subelement name or NULL
897 * @type: the type of element content decl
899 * Allocate an element content structure for the document.
901 * Returns NULL if not, otherwise the new element content structure
903 xmlElementContentPtr
904 xmlNewDocElementContent(xmlDocPtr doc, const xmlChar *name,
905 xmlElementContentType type) {
906 xmlElementContentPtr ret;
907 xmlDictPtr dict = NULL;
909 if (doc != NULL)
910 dict = doc->dict;
912 switch(type) {
913 case XML_ELEMENT_CONTENT_ELEMENT:
914 if (name == NULL) {
915 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
916 "xmlNewElementContent : name == NULL !\n",
917 NULL);
919 break;
920 case XML_ELEMENT_CONTENT_PCDATA:
921 case XML_ELEMENT_CONTENT_SEQ:
922 case XML_ELEMENT_CONTENT_OR:
923 if (name != NULL) {
924 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
925 "xmlNewElementContent : name != NULL !\n",
926 NULL);
928 break;
929 default:
930 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
931 "Internal: ELEMENT content corrupted invalid type\n",
932 NULL);
933 return(NULL);
935 ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
936 if (ret == NULL) {
937 xmlVErrMemory(NULL, "malloc failed");
938 return(NULL);
940 memset(ret, 0, sizeof(xmlElementContent));
941 ret->type = type;
942 ret->ocur = XML_ELEMENT_CONTENT_ONCE;
943 if (name != NULL) {
944 int l;
945 const xmlChar *tmp;
947 tmp = xmlSplitQName3(name, &l);
948 if (tmp == NULL) {
949 if (dict == NULL)
950 ret->name = xmlStrdup(name);
951 else
952 ret->name = xmlDictLookup(dict, name, -1);
953 } else {
954 if (dict == NULL) {
955 ret->prefix = xmlStrndup(name, l);
956 ret->name = xmlStrdup(tmp);
957 } else {
958 ret->prefix = xmlDictLookup(dict, name, l);
959 ret->name = xmlDictLookup(dict, tmp, -1);
963 return(ret);
967 * xmlNewElementContent:
968 * @name: the subelement name or NULL
969 * @type: the type of element content decl
971 * Allocate an element content structure.
972 * Deprecated in favor of xmlNewDocElementContent
974 * Returns NULL if not, otherwise the new element content structure
976 xmlElementContentPtr
977 xmlNewElementContent(const xmlChar *name, xmlElementContentType type) {
978 return(xmlNewDocElementContent(NULL, name, type));
982 * xmlCopyDocElementContent:
983 * @doc: the document owning the element declaration
984 * @cur: An element content pointer.
986 * Build a copy of an element content description.
988 * Returns the new xmlElementContentPtr or NULL in case of error.
990 xmlElementContentPtr
991 xmlCopyDocElementContent(xmlDocPtr doc, xmlElementContentPtr cur) {
992 xmlElementContentPtr ret = NULL, prev = NULL, tmp;
993 xmlDictPtr dict = NULL;
995 if (cur == NULL) return(NULL);
997 if (doc != NULL)
998 dict = doc->dict;
1000 ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
1001 if (ret == NULL) {
1002 xmlVErrMemory(NULL, "malloc failed");
1003 return(NULL);
1005 memset(ret, 0, sizeof(xmlElementContent));
1006 ret->type = cur->type;
1007 ret->ocur = cur->ocur;
1008 if (cur->name != NULL) {
1009 if (dict)
1010 ret->name = xmlDictLookup(dict, cur->name, -1);
1011 else
1012 ret->name = xmlStrdup(cur->name);
1015 if (cur->prefix != NULL) {
1016 if (dict)
1017 ret->prefix = xmlDictLookup(dict, cur->prefix, -1);
1018 else
1019 ret->prefix = xmlStrdup(cur->prefix);
1021 if (cur->c1 != NULL)
1022 ret->c1 = xmlCopyDocElementContent(doc, cur->c1);
1023 if (ret->c1 != NULL)
1024 ret->c1->parent = ret;
1025 if (cur->c2 != NULL) {
1026 prev = ret;
1027 cur = cur->c2;
1028 while (cur != NULL) {
1029 tmp = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
1030 if (tmp == NULL) {
1031 xmlVErrMemory(NULL, "malloc failed");
1032 return(ret);
1034 memset(tmp, 0, sizeof(xmlElementContent));
1035 tmp->type = cur->type;
1036 tmp->ocur = cur->ocur;
1037 prev->c2 = tmp;
1038 tmp->parent = prev;
1039 if (cur->name != NULL) {
1040 if (dict)
1041 tmp->name = xmlDictLookup(dict, cur->name, -1);
1042 else
1043 tmp->name = xmlStrdup(cur->name);
1046 if (cur->prefix != NULL) {
1047 if (dict)
1048 tmp->prefix = xmlDictLookup(dict, cur->prefix, -1);
1049 else
1050 tmp->prefix = xmlStrdup(cur->prefix);
1052 if (cur->c1 != NULL)
1053 tmp->c1 = xmlCopyDocElementContent(doc,cur->c1);
1054 if (tmp->c1 != NULL)
1055 tmp->c1->parent = ret;
1056 prev = tmp;
1057 cur = cur->c2;
1060 return(ret);
1064 * xmlCopyElementContent:
1065 * @cur: An element content pointer.
1067 * Build a copy of an element content description.
1068 * Deprecated, use xmlCopyDocElementContent instead
1070 * Returns the new xmlElementContentPtr or NULL in case of error.
1072 xmlElementContentPtr
1073 xmlCopyElementContent(xmlElementContentPtr cur) {
1074 return(xmlCopyDocElementContent(NULL, cur));
1078 * xmlFreeDocElementContent:
1079 * @doc: the document owning the element declaration
1080 * @cur: the element content tree to free
1082 * Free an element content structure. The whole subtree is removed.
1084 void
1085 xmlFreeDocElementContent(xmlDocPtr doc, xmlElementContentPtr cur) {
1086 xmlDictPtr dict = NULL;
1087 size_t depth = 0;
1089 if (cur == NULL)
1090 return;
1091 if (doc != NULL)
1092 dict = doc->dict;
1094 while (1) {
1095 xmlElementContentPtr parent;
1097 while ((cur->c1 != NULL) || (cur->c2 != NULL)) {
1098 cur = (cur->c1 != NULL) ? cur->c1 : cur->c2;
1099 depth += 1;
1102 switch (cur->type) {
1103 case XML_ELEMENT_CONTENT_PCDATA:
1104 case XML_ELEMENT_CONTENT_ELEMENT:
1105 case XML_ELEMENT_CONTENT_SEQ:
1106 case XML_ELEMENT_CONTENT_OR:
1107 break;
1108 default:
1109 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1110 "Internal: ELEMENT content corrupted invalid type\n",
1111 NULL);
1112 return;
1114 if (dict) {
1115 if ((cur->name != NULL) && (!xmlDictOwns(dict, cur->name)))
1116 xmlFree((xmlChar *) cur->name);
1117 if ((cur->prefix != NULL) && (!xmlDictOwns(dict, cur->prefix)))
1118 xmlFree((xmlChar *) cur->prefix);
1119 } else {
1120 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
1121 if (cur->prefix != NULL) xmlFree((xmlChar *) cur->prefix);
1123 parent = cur->parent;
1124 if ((depth == 0) || (parent == NULL)) {
1125 xmlFree(cur);
1126 break;
1128 if (cur == parent->c1)
1129 parent->c1 = NULL;
1130 else
1131 parent->c2 = NULL;
1132 xmlFree(cur);
1134 if (parent->c2 != NULL) {
1135 cur = parent->c2;
1136 } else {
1137 depth -= 1;
1138 cur = parent;
1144 * xmlFreeElementContent:
1145 * @cur: the element content tree to free
1147 * Free an element content structure. The whole subtree is removed.
1148 * Deprecated, use xmlFreeDocElementContent instead
1150 void
1151 xmlFreeElementContent(xmlElementContentPtr cur) {
1152 xmlFreeDocElementContent(NULL, cur);
1155 #ifdef LIBXML_OUTPUT_ENABLED
1157 * xmlDumpElementOccur:
1158 * @buf: An XML buffer
1159 * @cur: An element table
1161 * Dump the occurrence operator of an element.
1163 static void
1164 xmlDumpElementOccur(xmlBufferPtr buf, xmlElementContentPtr cur) {
1165 switch (cur->ocur) {
1166 case XML_ELEMENT_CONTENT_ONCE:
1167 break;
1168 case XML_ELEMENT_CONTENT_OPT:
1169 xmlBufferWriteChar(buf, "?");
1170 break;
1171 case XML_ELEMENT_CONTENT_MULT:
1172 xmlBufferWriteChar(buf, "*");
1173 break;
1174 case XML_ELEMENT_CONTENT_PLUS:
1175 xmlBufferWriteChar(buf, "+");
1176 break;
1181 * xmlDumpElementContent:
1182 * @buf: An XML buffer
1183 * @content: An element table
1185 * This will dump the content of the element table as an XML DTD definition
1187 static void
1188 xmlDumpElementContent(xmlBufferPtr buf, xmlElementContentPtr content) {
1189 xmlElementContentPtr cur;
1191 if (content == NULL) return;
1193 xmlBufferWriteChar(buf, "(");
1194 cur = content;
1196 do {
1197 if (cur == NULL) return;
1199 switch (cur->type) {
1200 case XML_ELEMENT_CONTENT_PCDATA:
1201 xmlBufferWriteChar(buf, "#PCDATA");
1202 break;
1203 case XML_ELEMENT_CONTENT_ELEMENT:
1204 if (cur->prefix != NULL) {
1205 xmlBufferWriteCHAR(buf, cur->prefix);
1206 xmlBufferWriteChar(buf, ":");
1208 xmlBufferWriteCHAR(buf, cur->name);
1209 break;
1210 case XML_ELEMENT_CONTENT_SEQ:
1211 case XML_ELEMENT_CONTENT_OR:
1212 if ((cur != content) &&
1213 (cur->parent != NULL) &&
1214 ((cur->type != cur->parent->type) ||
1215 (cur->ocur != XML_ELEMENT_CONTENT_ONCE)))
1216 xmlBufferWriteChar(buf, "(");
1217 cur = cur->c1;
1218 continue;
1219 default:
1220 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1221 "Internal: ELEMENT cur corrupted invalid type\n",
1222 NULL);
1225 while (cur != content) {
1226 xmlElementContentPtr parent = cur->parent;
1228 if (parent == NULL) return;
1230 if (((cur->type == XML_ELEMENT_CONTENT_OR) ||
1231 (cur->type == XML_ELEMENT_CONTENT_SEQ)) &&
1232 ((cur->type != parent->type) ||
1233 (cur->ocur != XML_ELEMENT_CONTENT_ONCE)))
1234 xmlBufferWriteChar(buf, ")");
1235 xmlDumpElementOccur(buf, cur);
1237 if (cur == parent->c1) {
1238 if (parent->type == XML_ELEMENT_CONTENT_SEQ)
1239 xmlBufferWriteChar(buf, " , ");
1240 else if (parent->type == XML_ELEMENT_CONTENT_OR)
1241 xmlBufferWriteChar(buf, " | ");
1243 cur = parent->c2;
1244 break;
1247 cur = parent;
1249 } while (cur != content);
1251 xmlBufferWriteChar(buf, ")");
1252 xmlDumpElementOccur(buf, content);
1256 * xmlSprintfElementContent:
1257 * @buf: an output buffer
1258 * @content: An element table
1259 * @englob: 1 if one must print the englobing parenthesis, 0 otherwise
1261 * Deprecated, unsafe, use xmlSnprintfElementContent
1263 void
1264 xmlSprintfElementContent(char *buf ATTRIBUTE_UNUSED,
1265 xmlElementContentPtr content ATTRIBUTE_UNUSED,
1266 int englob ATTRIBUTE_UNUSED) {
1268 #endif /* LIBXML_OUTPUT_ENABLED */
1271 * xmlSnprintfElementContent:
1272 * @buf: an output buffer
1273 * @size: the buffer size
1274 * @content: An element table
1275 * @englob: 1 if one must print the englobing parenthesis, 0 otherwise
1277 * This will dump the content of the element content definition
1278 * Intended just for the debug routine
1280 void
1281 xmlSnprintfElementContent(char *buf, int size, xmlElementContentPtr content, int englob) {
1282 int len;
1284 if (content == NULL) return;
1285 len = strlen(buf);
1286 if (size - len < 50) {
1287 if ((size - len > 4) && (buf[len - 1] != '.'))
1288 strcat(buf, " ...");
1289 return;
1291 if (englob) strcat(buf, "(");
1292 switch (content->type) {
1293 case XML_ELEMENT_CONTENT_PCDATA:
1294 strcat(buf, "#PCDATA");
1295 break;
1296 case XML_ELEMENT_CONTENT_ELEMENT: {
1297 int qnameLen = xmlStrlen(content->name);
1299 if (content->prefix != NULL)
1300 qnameLen += xmlStrlen(content->prefix) + 1;
1301 if (size - len < qnameLen + 10) {
1302 strcat(buf, " ...");
1303 return;
1305 if (content->prefix != NULL) {
1306 strcat(buf, (char *) content->prefix);
1307 strcat(buf, ":");
1309 if (content->name != NULL)
1310 strcat(buf, (char *) content->name);
1311 break;
1313 case XML_ELEMENT_CONTENT_SEQ:
1314 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1315 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
1316 xmlSnprintfElementContent(buf, size, content->c1, 1);
1317 else
1318 xmlSnprintfElementContent(buf, size, content->c1, 0);
1319 len = strlen(buf);
1320 if (size - len < 50) {
1321 if ((size - len > 4) && (buf[len - 1] != '.'))
1322 strcat(buf, " ...");
1323 return;
1325 strcat(buf, " , ");
1326 if (((content->c2->type == XML_ELEMENT_CONTENT_OR) ||
1327 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
1328 (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
1329 xmlSnprintfElementContent(buf, size, content->c2, 1);
1330 else
1331 xmlSnprintfElementContent(buf, size, content->c2, 0);
1332 break;
1333 case XML_ELEMENT_CONTENT_OR:
1334 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1335 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
1336 xmlSnprintfElementContent(buf, size, content->c1, 1);
1337 else
1338 xmlSnprintfElementContent(buf, size, content->c1, 0);
1339 len = strlen(buf);
1340 if (size - len < 50) {
1341 if ((size - len > 4) && (buf[len - 1] != '.'))
1342 strcat(buf, " ...");
1343 return;
1345 strcat(buf, " | ");
1346 if (((content->c2->type == XML_ELEMENT_CONTENT_SEQ) ||
1347 (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
1348 (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
1349 xmlSnprintfElementContent(buf, size, content->c2, 1);
1350 else
1351 xmlSnprintfElementContent(buf, size, content->c2, 0);
1352 break;
1354 if (size - strlen(buf) <= 2) return;
1355 if (englob)
1356 strcat(buf, ")");
1357 switch (content->ocur) {
1358 case XML_ELEMENT_CONTENT_ONCE:
1359 break;
1360 case XML_ELEMENT_CONTENT_OPT:
1361 strcat(buf, "?");
1362 break;
1363 case XML_ELEMENT_CONTENT_MULT:
1364 strcat(buf, "*");
1365 break;
1366 case XML_ELEMENT_CONTENT_PLUS:
1367 strcat(buf, "+");
1368 break;
1372 /****************************************************************
1374 * Registration of DTD declarations *
1376 ****************************************************************/
1379 * xmlFreeElement:
1380 * @elem: An element
1382 * Deallocate the memory used by an element definition
1384 static void
1385 xmlFreeElement(xmlElementPtr elem) {
1386 if (elem == NULL) return;
1387 xmlUnlinkNode((xmlNodePtr) elem);
1388 xmlFreeDocElementContent(elem->doc, elem->content);
1389 if (elem->name != NULL)
1390 xmlFree((xmlChar *) elem->name);
1391 if (elem->prefix != NULL)
1392 xmlFree((xmlChar *) elem->prefix);
1393 #ifdef LIBXML_REGEXP_ENABLED
1394 if (elem->contModel != NULL)
1395 xmlRegFreeRegexp(elem->contModel);
1396 #endif
1397 xmlFree(elem);
1402 * xmlAddElementDecl:
1403 * @ctxt: the validation context
1404 * @dtd: pointer to the DTD
1405 * @name: the entity name
1406 * @type: the element type
1407 * @content: the element content tree or NULL
1409 * Register a new element declaration
1411 * Returns NULL if not, otherwise the entity
1413 xmlElementPtr
1414 xmlAddElementDecl(xmlValidCtxtPtr ctxt,
1415 xmlDtdPtr dtd, const xmlChar *name,
1416 xmlElementTypeVal type,
1417 xmlElementContentPtr content) {
1418 xmlElementPtr ret;
1419 xmlElementTablePtr table;
1420 xmlAttributePtr oldAttributes = NULL;
1421 xmlChar *ns, *uqname;
1423 if (dtd == NULL) {
1424 return(NULL);
1426 if (name == NULL) {
1427 return(NULL);
1430 switch (type) {
1431 case XML_ELEMENT_TYPE_EMPTY:
1432 if (content != NULL) {
1433 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1434 "xmlAddElementDecl: content != NULL for EMPTY\n",
1435 NULL);
1436 return(NULL);
1438 break;
1439 case XML_ELEMENT_TYPE_ANY:
1440 if (content != NULL) {
1441 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1442 "xmlAddElementDecl: content != NULL for ANY\n",
1443 NULL);
1444 return(NULL);
1446 break;
1447 case XML_ELEMENT_TYPE_MIXED:
1448 if (content == NULL) {
1449 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1450 "xmlAddElementDecl: content == NULL for MIXED\n",
1451 NULL);
1452 return(NULL);
1454 break;
1455 case XML_ELEMENT_TYPE_ELEMENT:
1456 if (content == NULL) {
1457 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1458 "xmlAddElementDecl: content == NULL for ELEMENT\n",
1459 NULL);
1460 return(NULL);
1462 break;
1463 default:
1464 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1465 "Internal: ELEMENT decl corrupted invalid type\n",
1466 NULL);
1467 return(NULL);
1471 * check if name is a QName
1473 uqname = xmlSplitQName2(name, &ns);
1474 if (uqname != NULL)
1475 name = uqname;
1478 * Create the Element table if needed.
1480 table = (xmlElementTablePtr) dtd->elements;
1481 if (table == NULL) {
1482 xmlDictPtr dict = NULL;
1484 if (dtd->doc != NULL)
1485 dict = dtd->doc->dict;
1486 table = xmlHashCreateDict(0, dict);
1487 dtd->elements = (void *) table;
1489 if (table == NULL) {
1490 xmlVErrMemory(ctxt,
1491 "xmlAddElementDecl: Table creation failed!\n");
1492 if (uqname != NULL)
1493 xmlFree(uqname);
1494 if (ns != NULL)
1495 xmlFree(ns);
1496 return(NULL);
1500 * lookup old attributes inserted on an undefined element in the
1501 * internal subset.
1503 if ((dtd->doc != NULL) && (dtd->doc->intSubset != NULL)) {
1504 ret = xmlHashLookup2(dtd->doc->intSubset->elements, name, ns);
1505 if ((ret != NULL) && (ret->etype == XML_ELEMENT_TYPE_UNDEFINED)) {
1506 oldAttributes = ret->attributes;
1507 ret->attributes = NULL;
1508 xmlHashRemoveEntry2(dtd->doc->intSubset->elements, name, ns, NULL);
1509 xmlFreeElement(ret);
1514 * The element may already be present if one of its attribute
1515 * was registered first
1517 ret = xmlHashLookup2(table, name, ns);
1518 if (ret != NULL) {
1519 if (ret->etype != XML_ELEMENT_TYPE_UNDEFINED) {
1520 #ifdef LIBXML_VALID_ENABLED
1522 * The element is already defined in this DTD.
1524 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED,
1525 "Redefinition of element %s\n",
1526 name, NULL, NULL);
1527 #endif /* LIBXML_VALID_ENABLED */
1528 if (uqname != NULL)
1529 xmlFree(uqname);
1530 if (ns != NULL)
1531 xmlFree(ns);
1532 return(NULL);
1534 if (ns != NULL) {
1535 xmlFree(ns);
1536 ns = NULL;
1538 } else {
1539 ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1540 if (ret == NULL) {
1541 xmlVErrMemory(ctxt, "malloc failed");
1542 if (uqname != NULL)
1543 xmlFree(uqname);
1544 if (ns != NULL)
1545 xmlFree(ns);
1546 return(NULL);
1548 memset(ret, 0, sizeof(xmlElement));
1549 ret->type = XML_ELEMENT_DECL;
1552 * fill the structure.
1554 ret->name = xmlStrdup(name);
1555 if (ret->name == NULL) {
1556 xmlVErrMemory(ctxt, "malloc failed");
1557 if (uqname != NULL)
1558 xmlFree(uqname);
1559 if (ns != NULL)
1560 xmlFree(ns);
1561 xmlFree(ret);
1562 return(NULL);
1564 ret->prefix = ns;
1567 * Validity Check:
1568 * Insertion must not fail
1570 if (xmlHashAddEntry2(table, name, ns, ret)) {
1571 #ifdef LIBXML_VALID_ENABLED
1573 * The element is already defined in this DTD.
1575 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED,
1576 "Redefinition of element %s\n",
1577 name, NULL, NULL);
1578 #endif /* LIBXML_VALID_ENABLED */
1579 xmlFreeElement(ret);
1580 if (uqname != NULL)
1581 xmlFree(uqname);
1582 return(NULL);
1585 * For new element, may have attributes from earlier
1586 * definition in internal subset
1588 ret->attributes = oldAttributes;
1592 * Finish to fill the structure.
1594 ret->etype = type;
1596 * Avoid a stupid copy when called by the parser
1597 * and flag it by setting a special parent value
1598 * so the parser doesn't unallocate it.
1600 if ((ctxt != NULL) && (ctxt->flags & XML_VCTXT_USE_PCTXT)) {
1601 ret->content = content;
1602 if (content != NULL)
1603 content->parent = (xmlElementContentPtr) 1;
1604 } else {
1605 ret->content = xmlCopyDocElementContent(dtd->doc, content);
1609 * Link it to the DTD
1611 ret->parent = dtd;
1612 ret->doc = dtd->doc;
1613 if (dtd->last == NULL) {
1614 dtd->children = dtd->last = (xmlNodePtr) ret;
1615 } else {
1616 dtd->last->next = (xmlNodePtr) ret;
1617 ret->prev = dtd->last;
1618 dtd->last = (xmlNodePtr) ret;
1620 if (uqname != NULL)
1621 xmlFree(uqname);
1622 return(ret);
1625 static void
1626 xmlFreeElementTableEntry(void *elem, const xmlChar *name ATTRIBUTE_UNUSED) {
1627 xmlFreeElement((xmlElementPtr) elem);
1631 * xmlFreeElementTable:
1632 * @table: An element table
1634 * Deallocate the memory used by an element hash table.
1636 void
1637 xmlFreeElementTable(xmlElementTablePtr table) {
1638 xmlHashFree(table, xmlFreeElementTableEntry);
1641 #ifdef LIBXML_TREE_ENABLED
1643 * xmlCopyElement:
1644 * @elem: An element
1646 * Build a copy of an element.
1648 * Returns the new xmlElementPtr or NULL in case of error.
1650 static void *
1651 xmlCopyElement(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) {
1652 xmlElementPtr elem = (xmlElementPtr) payload;
1653 xmlElementPtr cur;
1655 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1656 if (cur == NULL) {
1657 xmlVErrMemory(NULL, "malloc failed");
1658 return(NULL);
1660 memset(cur, 0, sizeof(xmlElement));
1661 cur->type = XML_ELEMENT_DECL;
1662 cur->etype = elem->etype;
1663 if (elem->name != NULL)
1664 cur->name = xmlStrdup(elem->name);
1665 else
1666 cur->name = NULL;
1667 if (elem->prefix != NULL)
1668 cur->prefix = xmlStrdup(elem->prefix);
1669 else
1670 cur->prefix = NULL;
1671 cur->content = xmlCopyElementContent(elem->content);
1672 /* TODO : rebuild the attribute list on the copy */
1673 cur->attributes = NULL;
1674 return(cur);
1678 * xmlCopyElementTable:
1679 * @table: An element table
1681 * Build a copy of an element table.
1683 * Returns the new xmlElementTablePtr or NULL in case of error.
1685 xmlElementTablePtr
1686 xmlCopyElementTable(xmlElementTablePtr table) {
1687 return((xmlElementTablePtr) xmlHashCopy(table, xmlCopyElement));
1689 #endif /* LIBXML_TREE_ENABLED */
1691 #ifdef LIBXML_OUTPUT_ENABLED
1693 * xmlDumpElementDecl:
1694 * @buf: the XML buffer output
1695 * @elem: An element table
1697 * This will dump the content of the element declaration as an XML
1698 * DTD definition
1700 void
1701 xmlDumpElementDecl(xmlBufferPtr buf, xmlElementPtr elem) {
1702 if ((buf == NULL) || (elem == NULL))
1703 return;
1704 switch (elem->etype) {
1705 case XML_ELEMENT_TYPE_EMPTY:
1706 xmlBufferWriteChar(buf, "<!ELEMENT ");
1707 if (elem->prefix != NULL) {
1708 xmlBufferWriteCHAR(buf, elem->prefix);
1709 xmlBufferWriteChar(buf, ":");
1711 xmlBufferWriteCHAR(buf, elem->name);
1712 xmlBufferWriteChar(buf, " EMPTY>\n");
1713 break;
1714 case XML_ELEMENT_TYPE_ANY:
1715 xmlBufferWriteChar(buf, "<!ELEMENT ");
1716 if (elem->prefix != NULL) {
1717 xmlBufferWriteCHAR(buf, elem->prefix);
1718 xmlBufferWriteChar(buf, ":");
1720 xmlBufferWriteCHAR(buf, elem->name);
1721 xmlBufferWriteChar(buf, " ANY>\n");
1722 break;
1723 case XML_ELEMENT_TYPE_MIXED:
1724 xmlBufferWriteChar(buf, "<!ELEMENT ");
1725 if (elem->prefix != NULL) {
1726 xmlBufferWriteCHAR(buf, elem->prefix);
1727 xmlBufferWriteChar(buf, ":");
1729 xmlBufferWriteCHAR(buf, elem->name);
1730 xmlBufferWriteChar(buf, " ");
1731 xmlDumpElementContent(buf, elem->content);
1732 xmlBufferWriteChar(buf, ">\n");
1733 break;
1734 case XML_ELEMENT_TYPE_ELEMENT:
1735 xmlBufferWriteChar(buf, "<!ELEMENT ");
1736 if (elem->prefix != NULL) {
1737 xmlBufferWriteCHAR(buf, elem->prefix);
1738 xmlBufferWriteChar(buf, ":");
1740 xmlBufferWriteCHAR(buf, elem->name);
1741 xmlBufferWriteChar(buf, " ");
1742 xmlDumpElementContent(buf, elem->content);
1743 xmlBufferWriteChar(buf, ">\n");
1744 break;
1745 default:
1746 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1747 "Internal: ELEMENT struct corrupted invalid type\n",
1748 NULL);
1753 * xmlDumpElementDeclScan:
1754 * @elem: An element table
1755 * @buf: the XML buffer output
1757 * This routine is used by the hash scan function. It just reverses
1758 * the arguments.
1760 static void
1761 xmlDumpElementDeclScan(void *elem, void *buf,
1762 const xmlChar *name ATTRIBUTE_UNUSED) {
1763 xmlDumpElementDecl((xmlBufferPtr) buf, (xmlElementPtr) elem);
1767 * xmlDumpElementTable:
1768 * @buf: the XML buffer output
1769 * @table: An element table
1771 * This will dump the content of the element table as an XML DTD definition
1773 void
1774 xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) {
1775 if ((buf == NULL) || (table == NULL))
1776 return;
1777 xmlHashScan(table, xmlDumpElementDeclScan, buf);
1779 #endif /* LIBXML_OUTPUT_ENABLED */
1782 * xmlCreateEnumeration:
1783 * @name: the enumeration name or NULL
1785 * create and initialize an enumeration attribute node.
1787 * Returns the xmlEnumerationPtr just created or NULL in case
1788 * of error.
1790 xmlEnumerationPtr
1791 xmlCreateEnumeration(const xmlChar *name) {
1792 xmlEnumerationPtr ret;
1794 ret = (xmlEnumerationPtr) xmlMalloc(sizeof(xmlEnumeration));
1795 if (ret == NULL) {
1796 xmlVErrMemory(NULL, "malloc failed");
1797 return(NULL);
1799 memset(ret, 0, sizeof(xmlEnumeration));
1801 if (name != NULL)
1802 ret->name = xmlStrdup(name);
1803 return(ret);
1807 * xmlFreeEnumeration:
1808 * @cur: the tree to free.
1810 * free an enumeration attribute node (recursive).
1812 void
1813 xmlFreeEnumeration(xmlEnumerationPtr cur) {
1814 if (cur == NULL) return;
1816 if (cur->next != NULL) xmlFreeEnumeration(cur->next);
1818 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
1819 xmlFree(cur);
1822 #ifdef LIBXML_TREE_ENABLED
1824 * xmlCopyEnumeration:
1825 * @cur: the tree to copy.
1827 * Copy an enumeration attribute node (recursive).
1829 * Returns the xmlEnumerationPtr just created or NULL in case
1830 * of error.
1832 xmlEnumerationPtr
1833 xmlCopyEnumeration(xmlEnumerationPtr cur) {
1834 xmlEnumerationPtr ret;
1836 if (cur == NULL) return(NULL);
1837 ret = xmlCreateEnumeration((xmlChar *) cur->name);
1838 if (ret == NULL) return(NULL);
1840 if (cur->next != NULL) ret->next = xmlCopyEnumeration(cur->next);
1841 else ret->next = NULL;
1843 return(ret);
1845 #endif /* LIBXML_TREE_ENABLED */
1847 #ifdef LIBXML_OUTPUT_ENABLED
1849 * xmlDumpEnumeration:
1850 * @buf: the XML buffer output
1851 * @enum: An enumeration
1853 * This will dump the content of the enumeration
1855 static void
1856 xmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) {
1857 if ((buf == NULL) || (cur == NULL))
1858 return;
1860 xmlBufferWriteCHAR(buf, cur->name);
1861 if (cur->next == NULL)
1862 xmlBufferWriteChar(buf, ")");
1863 else {
1864 xmlBufferWriteChar(buf, " | ");
1865 xmlDumpEnumeration(buf, cur->next);
1868 #endif /* LIBXML_OUTPUT_ENABLED */
1870 #ifdef LIBXML_VALID_ENABLED
1872 * xmlScanIDAttributeDecl:
1873 * @ctxt: the validation context
1874 * @elem: the element name
1875 * @err: whether to raise errors here
1877 * Verify that the element don't have too many ID attributes
1878 * declared.
1880 * Returns the number of ID attributes found.
1882 static int
1883 xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem, int err) {
1884 xmlAttributePtr cur;
1885 int ret = 0;
1887 if (elem == NULL) return(0);
1888 cur = elem->attributes;
1889 while (cur != NULL) {
1890 if (cur->atype == XML_ATTRIBUTE_ID) {
1891 ret ++;
1892 if ((ret > 1) && (err))
1893 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_MULTIPLE_ID,
1894 "Element %s has too many ID attributes defined : %s\n",
1895 elem->name, cur->name, NULL);
1897 cur = cur->nexth;
1899 return(ret);
1901 #endif /* LIBXML_VALID_ENABLED */
1904 * xmlFreeAttribute:
1905 * @elem: An attribute
1907 * Deallocate the memory used by an attribute definition
1909 static void
1910 xmlFreeAttribute(xmlAttributePtr attr) {
1911 xmlDictPtr dict;
1913 if (attr == NULL) return;
1914 if (attr->doc != NULL)
1915 dict = attr->doc->dict;
1916 else
1917 dict = NULL;
1918 xmlUnlinkNode((xmlNodePtr) attr);
1919 if (attr->tree != NULL)
1920 xmlFreeEnumeration(attr->tree);
1921 if (dict) {
1922 if ((attr->elem != NULL) && (!xmlDictOwns(dict, attr->elem)))
1923 xmlFree((xmlChar *) attr->elem);
1924 if ((attr->name != NULL) && (!xmlDictOwns(dict, attr->name)))
1925 xmlFree((xmlChar *) attr->name);
1926 if ((attr->prefix != NULL) && (!xmlDictOwns(dict, attr->prefix)))
1927 xmlFree((xmlChar *) attr->prefix);
1928 if ((attr->defaultValue != NULL) &&
1929 (!xmlDictOwns(dict, attr->defaultValue)))
1930 xmlFree((xmlChar *) attr->defaultValue);
1931 } else {
1932 if (attr->elem != NULL)
1933 xmlFree((xmlChar *) attr->elem);
1934 if (attr->name != NULL)
1935 xmlFree((xmlChar *) attr->name);
1936 if (attr->defaultValue != NULL)
1937 xmlFree((xmlChar *) attr->defaultValue);
1938 if (attr->prefix != NULL)
1939 xmlFree((xmlChar *) attr->prefix);
1941 xmlFree(attr);
1946 * xmlAddAttributeDecl:
1947 * @ctxt: the validation context
1948 * @dtd: pointer to the DTD
1949 * @elem: the element name
1950 * @name: the attribute name
1951 * @ns: the attribute namespace prefix
1952 * @type: the attribute type
1953 * @def: the attribute default type
1954 * @defaultValue: the attribute default value
1955 * @tree: if it's an enumeration, the associated list
1957 * Register a new attribute declaration
1958 * Note that @tree becomes the ownership of the DTD
1960 * Returns NULL if not new, otherwise the attribute decl
1962 xmlAttributePtr
1963 xmlAddAttributeDecl(xmlValidCtxtPtr ctxt,
1964 xmlDtdPtr dtd, const xmlChar *elem,
1965 const xmlChar *name, const xmlChar *ns,
1966 xmlAttributeType type, xmlAttributeDefault def,
1967 const xmlChar *defaultValue, xmlEnumerationPtr tree) {
1968 xmlAttributePtr ret;
1969 xmlAttributeTablePtr table;
1970 xmlElementPtr elemDef;
1971 xmlDictPtr dict = NULL;
1973 if (dtd == NULL) {
1974 xmlFreeEnumeration(tree);
1975 return(NULL);
1977 if (name == NULL) {
1978 xmlFreeEnumeration(tree);
1979 return(NULL);
1981 if (elem == NULL) {
1982 xmlFreeEnumeration(tree);
1983 return(NULL);
1985 if (dtd->doc != NULL)
1986 dict = dtd->doc->dict;
1988 #ifdef LIBXML_VALID_ENABLED
1990 * Check the type and possibly the default value.
1992 switch (type) {
1993 case XML_ATTRIBUTE_CDATA:
1994 break;
1995 case XML_ATTRIBUTE_ID:
1996 break;
1997 case XML_ATTRIBUTE_IDREF:
1998 break;
1999 case XML_ATTRIBUTE_IDREFS:
2000 break;
2001 case XML_ATTRIBUTE_ENTITY:
2002 break;
2003 case XML_ATTRIBUTE_ENTITIES:
2004 break;
2005 case XML_ATTRIBUTE_NMTOKEN:
2006 break;
2007 case XML_ATTRIBUTE_NMTOKENS:
2008 break;
2009 case XML_ATTRIBUTE_ENUMERATION:
2010 break;
2011 case XML_ATTRIBUTE_NOTATION:
2012 break;
2013 default:
2014 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
2015 "Internal: ATTRIBUTE struct corrupted invalid type\n",
2016 NULL);
2017 xmlFreeEnumeration(tree);
2018 return(NULL);
2020 if ((defaultValue != NULL) &&
2021 (!xmlValidateAttributeValueInternal(dtd->doc, type, defaultValue))) {
2022 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_DEFAULT,
2023 "Attribute %s of %s: invalid default value\n",
2024 elem, name, defaultValue);
2025 defaultValue = NULL;
2026 if (ctxt != NULL)
2027 ctxt->valid = 0;
2029 #endif /* LIBXML_VALID_ENABLED */
2032 * Check first that an attribute defined in the external subset wasn't
2033 * already defined in the internal subset
2035 if ((dtd->doc != NULL) && (dtd->doc->extSubset == dtd) &&
2036 (dtd->doc->intSubset != NULL) &&
2037 (dtd->doc->intSubset->attributes != NULL)) {
2038 ret = xmlHashLookup3(dtd->doc->intSubset->attributes, name, ns, elem);
2039 if (ret != NULL) {
2040 xmlFreeEnumeration(tree);
2041 return(NULL);
2046 * Create the Attribute table if needed.
2048 table = (xmlAttributeTablePtr) dtd->attributes;
2049 if (table == NULL) {
2050 table = xmlHashCreateDict(0, dict);
2051 dtd->attributes = (void *) table;
2053 if (table == NULL) {
2054 xmlVErrMemory(ctxt,
2055 "xmlAddAttributeDecl: Table creation failed!\n");
2056 xmlFreeEnumeration(tree);
2057 return(NULL);
2061 ret = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
2062 if (ret == NULL) {
2063 xmlVErrMemory(ctxt, "malloc failed");
2064 xmlFreeEnumeration(tree);
2065 return(NULL);
2067 memset(ret, 0, sizeof(xmlAttribute));
2068 ret->type = XML_ATTRIBUTE_DECL;
2071 * fill the structure.
2073 ret->atype = type;
2075 * doc must be set before possible error causes call
2076 * to xmlFreeAttribute (because it's used to check on
2077 * dict use)
2079 ret->doc = dtd->doc;
2080 if (dict) {
2081 ret->name = xmlDictLookup(dict, name, -1);
2082 ret->prefix = xmlDictLookup(dict, ns, -1);
2083 ret->elem = xmlDictLookup(dict, elem, -1);
2084 } else {
2085 ret->name = xmlStrdup(name);
2086 ret->prefix = xmlStrdup(ns);
2087 ret->elem = xmlStrdup(elem);
2089 ret->def = def;
2090 ret->tree = tree;
2091 if (defaultValue != NULL) {
2092 if (dict)
2093 ret->defaultValue = xmlDictLookup(dict, defaultValue, -1);
2094 else
2095 ret->defaultValue = xmlStrdup(defaultValue);
2099 * Validity Check:
2100 * Search the DTD for previous declarations of the ATTLIST
2102 if (xmlHashAddEntry3(table, ret->name, ret->prefix, ret->elem, ret) < 0) {
2103 #ifdef LIBXML_VALID_ENABLED
2105 * The attribute is already defined in this DTD.
2107 xmlErrValidWarning(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_REDEFINED,
2108 "Attribute %s of element %s: already defined\n",
2109 name, elem, NULL);
2110 #endif /* LIBXML_VALID_ENABLED */
2111 xmlFreeAttribute(ret);
2112 return(NULL);
2116 * Validity Check:
2117 * Multiple ID per element
2119 elemDef = xmlGetDtdElementDesc2(ctxt, dtd, elem, 1);
2120 if (elemDef != NULL) {
2122 #ifdef LIBXML_VALID_ENABLED
2123 if ((type == XML_ATTRIBUTE_ID) &&
2124 (xmlScanIDAttributeDecl(NULL, elemDef, 1) != 0)) {
2125 xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_MULTIPLE_ID,
2126 "Element %s has too may ID attributes defined : %s\n",
2127 elem, name, NULL);
2128 if (ctxt != NULL)
2129 ctxt->valid = 0;
2131 #endif /* LIBXML_VALID_ENABLED */
2134 * Insert namespace default def first they need to be
2135 * processed first.
2137 if ((xmlStrEqual(ret->name, BAD_CAST "xmlns")) ||
2138 ((ret->prefix != NULL &&
2139 (xmlStrEqual(ret->prefix, BAD_CAST "xmlns"))))) {
2140 ret->nexth = elemDef->attributes;
2141 elemDef->attributes = ret;
2142 } else {
2143 xmlAttributePtr tmp = elemDef->attributes;
2145 while ((tmp != NULL) &&
2146 ((xmlStrEqual(tmp->name, BAD_CAST "xmlns")) ||
2147 ((ret->prefix != NULL &&
2148 (xmlStrEqual(ret->prefix, BAD_CAST "xmlns")))))) {
2149 if (tmp->nexth == NULL)
2150 break;
2151 tmp = tmp->nexth;
2153 if (tmp != NULL) {
2154 ret->nexth = tmp->nexth;
2155 tmp->nexth = ret;
2156 } else {
2157 ret->nexth = elemDef->attributes;
2158 elemDef->attributes = ret;
2164 * Link it to the DTD
2166 ret->parent = dtd;
2167 if (dtd->last == NULL) {
2168 dtd->children = dtd->last = (xmlNodePtr) ret;
2169 } else {
2170 dtd->last->next = (xmlNodePtr) ret;
2171 ret->prev = dtd->last;
2172 dtd->last = (xmlNodePtr) ret;
2174 return(ret);
2177 static void
2178 xmlFreeAttributeTableEntry(void *attr, const xmlChar *name ATTRIBUTE_UNUSED) {
2179 xmlFreeAttribute((xmlAttributePtr) attr);
2183 * xmlFreeAttributeTable:
2184 * @table: An attribute table
2186 * Deallocate the memory used by an entities hash table.
2188 void
2189 xmlFreeAttributeTable(xmlAttributeTablePtr table) {
2190 xmlHashFree(table, xmlFreeAttributeTableEntry);
2193 #ifdef LIBXML_TREE_ENABLED
2195 * xmlCopyAttribute:
2196 * @attr: An attribute
2198 * Build a copy of an attribute.
2200 * Returns the new xmlAttributePtr or NULL in case of error.
2202 static void *
2203 xmlCopyAttribute(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) {
2204 xmlAttributePtr attr = (xmlAttributePtr) payload;
2205 xmlAttributePtr cur;
2207 cur = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
2208 if (cur == NULL) {
2209 xmlVErrMemory(NULL, "malloc failed");
2210 return(NULL);
2212 memset(cur, 0, sizeof(xmlAttribute));
2213 cur->type = XML_ATTRIBUTE_DECL;
2214 cur->atype = attr->atype;
2215 cur->def = attr->def;
2216 cur->tree = xmlCopyEnumeration(attr->tree);
2217 if (attr->elem != NULL)
2218 cur->elem = xmlStrdup(attr->elem);
2219 if (attr->name != NULL)
2220 cur->name = xmlStrdup(attr->name);
2221 if (attr->prefix != NULL)
2222 cur->prefix = xmlStrdup(attr->prefix);
2223 if (attr->defaultValue != NULL)
2224 cur->defaultValue = xmlStrdup(attr->defaultValue);
2225 return(cur);
2229 * xmlCopyAttributeTable:
2230 * @table: An attribute table
2232 * Build a copy of an attribute table.
2234 * Returns the new xmlAttributeTablePtr or NULL in case of error.
2236 xmlAttributeTablePtr
2237 xmlCopyAttributeTable(xmlAttributeTablePtr table) {
2238 return((xmlAttributeTablePtr) xmlHashCopy(table, xmlCopyAttribute));
2240 #endif /* LIBXML_TREE_ENABLED */
2242 #ifdef LIBXML_OUTPUT_ENABLED
2244 * xmlDumpAttributeDecl:
2245 * @buf: the XML buffer output
2246 * @attr: An attribute declaration
2248 * This will dump the content of the attribute declaration as an XML
2249 * DTD definition
2251 void
2252 xmlDumpAttributeDecl(xmlBufferPtr buf, xmlAttributePtr attr) {
2253 if ((buf == NULL) || (attr == NULL))
2254 return;
2255 xmlBufferWriteChar(buf, "<!ATTLIST ");
2256 xmlBufferWriteCHAR(buf, attr->elem);
2257 xmlBufferWriteChar(buf, " ");
2258 if (attr->prefix != NULL) {
2259 xmlBufferWriteCHAR(buf, attr->prefix);
2260 xmlBufferWriteChar(buf, ":");
2262 xmlBufferWriteCHAR(buf, attr->name);
2263 switch (attr->atype) {
2264 case XML_ATTRIBUTE_CDATA:
2265 xmlBufferWriteChar(buf, " CDATA");
2266 break;
2267 case XML_ATTRIBUTE_ID:
2268 xmlBufferWriteChar(buf, " ID");
2269 break;
2270 case XML_ATTRIBUTE_IDREF:
2271 xmlBufferWriteChar(buf, " IDREF");
2272 break;
2273 case XML_ATTRIBUTE_IDREFS:
2274 xmlBufferWriteChar(buf, " IDREFS");
2275 break;
2276 case XML_ATTRIBUTE_ENTITY:
2277 xmlBufferWriteChar(buf, " ENTITY");
2278 break;
2279 case XML_ATTRIBUTE_ENTITIES:
2280 xmlBufferWriteChar(buf, " ENTITIES");
2281 break;
2282 case XML_ATTRIBUTE_NMTOKEN:
2283 xmlBufferWriteChar(buf, " NMTOKEN");
2284 break;
2285 case XML_ATTRIBUTE_NMTOKENS:
2286 xmlBufferWriteChar(buf, " NMTOKENS");
2287 break;
2288 case XML_ATTRIBUTE_ENUMERATION:
2289 xmlBufferWriteChar(buf, " (");
2290 xmlDumpEnumeration(buf, attr->tree);
2291 break;
2292 case XML_ATTRIBUTE_NOTATION:
2293 xmlBufferWriteChar(buf, " NOTATION (");
2294 xmlDumpEnumeration(buf, attr->tree);
2295 break;
2296 default:
2297 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2298 "Internal: ATTRIBUTE struct corrupted invalid type\n",
2299 NULL);
2301 switch (attr->def) {
2302 case XML_ATTRIBUTE_NONE:
2303 break;
2304 case XML_ATTRIBUTE_REQUIRED:
2305 xmlBufferWriteChar(buf, " #REQUIRED");
2306 break;
2307 case XML_ATTRIBUTE_IMPLIED:
2308 xmlBufferWriteChar(buf, " #IMPLIED");
2309 break;
2310 case XML_ATTRIBUTE_FIXED:
2311 xmlBufferWriteChar(buf, " #FIXED");
2312 break;
2313 default:
2314 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2315 "Internal: ATTRIBUTE struct corrupted invalid def\n",
2316 NULL);
2318 if (attr->defaultValue != NULL) {
2319 xmlBufferWriteChar(buf, " ");
2320 xmlBufferWriteQuotedString(buf, attr->defaultValue);
2322 xmlBufferWriteChar(buf, ">\n");
2326 * xmlDumpAttributeDeclScan:
2327 * @attr: An attribute declaration
2328 * @buf: the XML buffer output
2330 * This is used with the hash scan function - just reverses arguments
2332 static void
2333 xmlDumpAttributeDeclScan(void *attr, void *buf,
2334 const xmlChar *name ATTRIBUTE_UNUSED) {
2335 xmlDumpAttributeDecl((xmlBufferPtr) buf, (xmlAttributePtr) attr);
2339 * xmlDumpAttributeTable:
2340 * @buf: the XML buffer output
2341 * @table: An attribute table
2343 * This will dump the content of the attribute table as an XML DTD definition
2345 void
2346 xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) {
2347 if ((buf == NULL) || (table == NULL))
2348 return;
2349 xmlHashScan(table, xmlDumpAttributeDeclScan, buf);
2351 #endif /* LIBXML_OUTPUT_ENABLED */
2353 /************************************************************************
2355 * NOTATIONs *
2357 ************************************************************************/
2359 * xmlFreeNotation:
2360 * @not: A notation
2362 * Deallocate the memory used by an notation definition
2364 static void
2365 xmlFreeNotation(xmlNotationPtr nota) {
2366 if (nota == NULL) return;
2367 if (nota->name != NULL)
2368 xmlFree((xmlChar *) nota->name);
2369 if (nota->PublicID != NULL)
2370 xmlFree((xmlChar *) nota->PublicID);
2371 if (nota->SystemID != NULL)
2372 xmlFree((xmlChar *) nota->SystemID);
2373 xmlFree(nota);
2378 * xmlAddNotationDecl:
2379 * @dtd: pointer to the DTD
2380 * @ctxt: the validation context
2381 * @name: the entity name
2382 * @PublicID: the public identifier or NULL
2383 * @SystemID: the system identifier or NULL
2385 * Register a new notation declaration
2387 * Returns NULL if not, otherwise the entity
2389 xmlNotationPtr
2390 xmlAddNotationDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd,
2391 const xmlChar *name,
2392 const xmlChar *PublicID, const xmlChar *SystemID) {
2393 xmlNotationPtr ret;
2394 xmlNotationTablePtr table;
2396 if (dtd == NULL) {
2397 return(NULL);
2399 if (name == NULL) {
2400 return(NULL);
2402 if ((PublicID == NULL) && (SystemID == NULL)) {
2403 return(NULL);
2407 * Create the Notation table if needed.
2409 table = (xmlNotationTablePtr) dtd->notations;
2410 if (table == NULL) {
2411 xmlDictPtr dict = NULL;
2412 if (dtd->doc != NULL)
2413 dict = dtd->doc->dict;
2415 dtd->notations = table = xmlHashCreateDict(0, dict);
2417 if (table == NULL) {
2418 xmlVErrMemory(ctxt,
2419 "xmlAddNotationDecl: Table creation failed!\n");
2420 return(NULL);
2423 ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
2424 if (ret == NULL) {
2425 xmlVErrMemory(ctxt, "malloc failed");
2426 return(NULL);
2428 memset(ret, 0, sizeof(xmlNotation));
2431 * fill the structure.
2433 ret->name = xmlStrdup(name);
2434 if (SystemID != NULL)
2435 ret->SystemID = xmlStrdup(SystemID);
2436 if (PublicID != NULL)
2437 ret->PublicID = xmlStrdup(PublicID);
2440 * Validity Check:
2441 * Check the DTD for previous declarations of the ATTLIST
2443 if (xmlHashAddEntry(table, name, ret)) {
2444 #ifdef LIBXML_VALID_ENABLED
2445 xmlErrValid(NULL, XML_DTD_NOTATION_REDEFINED,
2446 "xmlAddNotationDecl: %s already defined\n",
2447 (const char *) name);
2448 #endif /* LIBXML_VALID_ENABLED */
2449 xmlFreeNotation(ret);
2450 return(NULL);
2452 return(ret);
2455 static void
2456 xmlFreeNotationTableEntry(void *nota, const xmlChar *name ATTRIBUTE_UNUSED) {
2457 xmlFreeNotation((xmlNotationPtr) nota);
2461 * xmlFreeNotationTable:
2462 * @table: An notation table
2464 * Deallocate the memory used by an entities hash table.
2466 void
2467 xmlFreeNotationTable(xmlNotationTablePtr table) {
2468 xmlHashFree(table, xmlFreeNotationTableEntry);
2471 #ifdef LIBXML_TREE_ENABLED
2473 * xmlCopyNotation:
2474 * @nota: A notation
2476 * Build a copy of a notation.
2478 * Returns the new xmlNotationPtr or NULL in case of error.
2480 static void *
2481 xmlCopyNotation(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) {
2482 xmlNotationPtr nota = (xmlNotationPtr) payload;
2483 xmlNotationPtr cur;
2485 cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
2486 if (cur == NULL) {
2487 xmlVErrMemory(NULL, "malloc failed");
2488 return(NULL);
2490 if (nota->name != NULL)
2491 cur->name = xmlStrdup(nota->name);
2492 else
2493 cur->name = NULL;
2494 if (nota->PublicID != NULL)
2495 cur->PublicID = xmlStrdup(nota->PublicID);
2496 else
2497 cur->PublicID = NULL;
2498 if (nota->SystemID != NULL)
2499 cur->SystemID = xmlStrdup(nota->SystemID);
2500 else
2501 cur->SystemID = NULL;
2502 return(cur);
2506 * xmlCopyNotationTable:
2507 * @table: A notation table
2509 * Build a copy of a notation table.
2511 * Returns the new xmlNotationTablePtr or NULL in case of error.
2513 xmlNotationTablePtr
2514 xmlCopyNotationTable(xmlNotationTablePtr table) {
2515 return((xmlNotationTablePtr) xmlHashCopy(table, xmlCopyNotation));
2517 #endif /* LIBXML_TREE_ENABLED */
2519 #ifdef LIBXML_OUTPUT_ENABLED
2521 * xmlDumpNotationDecl:
2522 * @buf: the XML buffer output
2523 * @nota: A notation declaration
2525 * This will dump the content the notation declaration as an XML DTD definition
2527 void
2528 xmlDumpNotationDecl(xmlBufferPtr buf, xmlNotationPtr nota) {
2529 if ((buf == NULL) || (nota == NULL))
2530 return;
2531 xmlBufferWriteChar(buf, "<!NOTATION ");
2532 xmlBufferWriteCHAR(buf, nota->name);
2533 if (nota->PublicID != NULL) {
2534 xmlBufferWriteChar(buf, " PUBLIC ");
2535 xmlBufferWriteQuotedString(buf, nota->PublicID);
2536 if (nota->SystemID != NULL) {
2537 xmlBufferWriteChar(buf, " ");
2538 xmlBufferWriteQuotedString(buf, nota->SystemID);
2540 } else {
2541 xmlBufferWriteChar(buf, " SYSTEM ");
2542 xmlBufferWriteQuotedString(buf, nota->SystemID);
2544 xmlBufferWriteChar(buf, " >\n");
2548 * xmlDumpNotationDeclScan:
2549 * @nota: A notation declaration
2550 * @buf: the XML buffer output
2552 * This is called with the hash scan function, and just reverses args
2554 static void
2555 xmlDumpNotationDeclScan(void *nota, void *buf,
2556 const xmlChar *name ATTRIBUTE_UNUSED) {
2557 xmlDumpNotationDecl((xmlBufferPtr) buf, (xmlNotationPtr) nota);
2561 * xmlDumpNotationTable:
2562 * @buf: the XML buffer output
2563 * @table: A notation table
2565 * This will dump the content of the notation table as an XML DTD definition
2567 void
2568 xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
2569 if ((buf == NULL) || (table == NULL))
2570 return;
2571 xmlHashScan(table, xmlDumpNotationDeclScan, buf);
2573 #endif /* LIBXML_OUTPUT_ENABLED */
2575 /************************************************************************
2577 * IDs *
2579 ************************************************************************/
2581 * DICT_FREE:
2582 * @str: a string
2584 * Free a string if it is not owned by the "dict" dictionary in the
2585 * current scope
2587 #define DICT_FREE(str) \
2588 if ((str) && ((!dict) || \
2589 (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \
2590 xmlFree((char *)(str));
2593 * xmlValidNormalizeString:
2594 * @str: a string
2596 * Normalize a string in-place.
2598 static void
2599 xmlValidNormalizeString(xmlChar *str) {
2600 xmlChar *dst;
2601 const xmlChar *src;
2603 if (str == NULL)
2604 return;
2605 src = str;
2606 dst = str;
2608 while (*src == 0x20) src++;
2609 while (*src != 0) {
2610 if (*src == 0x20) {
2611 while (*src == 0x20) src++;
2612 if (*src != 0)
2613 *dst++ = 0x20;
2614 } else {
2615 *dst++ = *src++;
2618 *dst = 0;
2621 static int
2622 xmlIsStreaming(xmlValidCtxtPtr ctxt) {
2623 xmlParserCtxtPtr pctxt;
2625 if (ctxt == NULL)
2626 return(0);
2627 if ((ctxt->flags & XML_VCTXT_USE_PCTXT) == 0)
2628 return(0);
2629 pctxt = ctxt->userData;
2630 return(pctxt->parseMode == XML_PARSE_READER);
2634 * xmlFreeID:
2635 * @not: A id
2637 * Deallocate the memory used by an id definition
2639 static void
2640 xmlFreeID(xmlIDPtr id) {
2641 xmlDictPtr dict = NULL;
2643 if (id == NULL) return;
2645 if (id->doc != NULL)
2646 dict = id->doc->dict;
2648 if (id->value != NULL)
2649 DICT_FREE(id->value)
2650 if (id->name != NULL)
2651 DICT_FREE(id->name)
2652 xmlFree(id);
2657 * xmlAddID:
2658 * @ctxt: the validation context
2659 * @doc: pointer to the document
2660 * @value: the value name
2661 * @attr: the attribute holding the ID
2663 * Register a new id declaration
2665 * Returns NULL if not, otherwise the new xmlIDPtr
2667 xmlIDPtr
2668 xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
2669 xmlAttrPtr attr) {
2670 xmlIDPtr ret;
2671 xmlIDTablePtr table;
2673 if (doc == NULL) {
2674 return(NULL);
2676 if ((value == NULL) || (value[0] == 0)) {
2677 return(NULL);
2679 if (attr == NULL) {
2680 return(NULL);
2684 * Create the ID table if needed.
2686 table = (xmlIDTablePtr) doc->ids;
2687 if (table == NULL) {
2688 doc->ids = table = xmlHashCreateDict(0, doc->dict);
2690 if (table == NULL) {
2691 xmlVErrMemory(ctxt,
2692 "xmlAddID: Table creation failed!\n");
2693 return(NULL);
2696 ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
2697 if (ret == NULL) {
2698 xmlVErrMemory(ctxt, "malloc failed");
2699 return(NULL);
2703 * fill the structure.
2705 ret->value = xmlStrdup(value);
2706 ret->doc = doc;
2707 if (xmlIsStreaming(ctxt)) {
2709 * Operating in streaming mode, attr is gonna disappear
2711 if (doc->dict != NULL)
2712 ret->name = xmlDictLookup(doc->dict, attr->name, -1);
2713 else
2714 ret->name = xmlStrdup(attr->name);
2715 ret->attr = NULL;
2716 } else {
2717 ret->attr = attr;
2718 ret->name = NULL;
2720 ret->lineno = xmlGetLineNo(attr->parent);
2722 if (xmlHashAddEntry(table, value, ret) < 0) {
2723 #ifdef LIBXML_VALID_ENABLED
2725 * The id is already defined in this DTD.
2727 if (ctxt != NULL) {
2728 xmlErrValidNode(ctxt, attr->parent, XML_DTD_ID_REDEFINED,
2729 "ID %s already defined\n", value, NULL, NULL);
2731 #endif /* LIBXML_VALID_ENABLED */
2732 xmlFreeID(ret);
2733 return(NULL);
2735 if (attr != NULL)
2736 attr->atype = XML_ATTRIBUTE_ID;
2737 return(ret);
2740 static void
2741 xmlFreeIDTableEntry(void *id, const xmlChar *name ATTRIBUTE_UNUSED) {
2742 xmlFreeID((xmlIDPtr) id);
2746 * xmlFreeIDTable:
2747 * @table: An id table
2749 * Deallocate the memory used by an ID hash table.
2751 void
2752 xmlFreeIDTable(xmlIDTablePtr table) {
2753 xmlHashFree(table, xmlFreeIDTableEntry);
2757 * xmlIsID:
2758 * @doc: the document
2759 * @elem: the element carrying the attribute
2760 * @attr: the attribute
2762 * Determine whether an attribute is of type ID. In case we have DTD(s)
2763 * then this is done if DTD loading has been requested. In the case
2764 * of HTML documents parsed with the HTML parser, then ID detection is
2765 * done systematically.
2767 * Returns 0 or 1 depending on the lookup result
2770 xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
2771 if ((attr == NULL) || (attr->name == NULL)) return(0);
2772 if ((attr->ns != NULL) && (attr->ns->prefix != NULL) &&
2773 (!strcmp((char *) attr->name, "id")) &&
2774 (!strcmp((char *) attr->ns->prefix, "xml")))
2775 return(1);
2776 if (doc == NULL) return(0);
2777 if ((doc->intSubset == NULL) && (doc->extSubset == NULL) &&
2778 (doc->type != XML_HTML_DOCUMENT_NODE)) {
2779 return(0);
2780 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
2781 if ((xmlStrEqual(BAD_CAST "id", attr->name)) ||
2782 ((xmlStrEqual(BAD_CAST "name", attr->name)) &&
2783 ((elem == NULL) || (xmlStrEqual(elem->name, BAD_CAST "a")))))
2784 return(1);
2785 return(0);
2786 } else if (elem == NULL) {
2787 return(0);
2788 } else {
2789 xmlAttributePtr attrDecl = NULL;
2791 xmlChar felem[50], fattr[50];
2792 xmlChar *fullelemname, *fullattrname;
2794 fullelemname = (elem->ns != NULL && elem->ns->prefix != NULL) ?
2795 xmlBuildQName(elem->name, elem->ns->prefix, felem, 50) :
2796 (xmlChar *)elem->name;
2798 fullattrname = (attr->ns != NULL && attr->ns->prefix != NULL) ?
2799 xmlBuildQName(attr->name, attr->ns->prefix, fattr, 50) :
2800 (xmlChar *)attr->name;
2802 if (fullelemname != NULL && fullattrname != NULL) {
2803 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullelemname,
2804 fullattrname);
2805 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2806 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullelemname,
2807 fullattrname);
2810 if ((fullattrname != fattr) && (fullattrname != attr->name))
2811 xmlFree(fullattrname);
2812 if ((fullelemname != felem) && (fullelemname != elem->name))
2813 xmlFree(fullelemname);
2815 if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_ID))
2816 return(1);
2818 return(0);
2822 * xmlRemoveID:
2823 * @doc: the document
2824 * @attr: the attribute
2826 * Remove the given attribute from the ID table maintained internally.
2828 * Returns -1 if the lookup failed and 0 otherwise
2831 xmlRemoveID(xmlDocPtr doc, xmlAttrPtr attr) {
2832 xmlIDTablePtr table;
2833 xmlIDPtr id;
2834 xmlChar *ID;
2836 if (doc == NULL) return(-1);
2837 if (attr == NULL) return(-1);
2839 table = (xmlIDTablePtr) doc->ids;
2840 if (table == NULL)
2841 return(-1);
2843 ID = xmlNodeListGetString(doc, attr->children, 1);
2844 if (ID == NULL)
2845 return(-1);
2846 xmlValidNormalizeString(ID);
2848 id = xmlHashLookup(table, ID);
2849 if (id == NULL || id->attr != attr) {
2850 xmlFree(ID);
2851 return(-1);
2854 xmlHashRemoveEntry(table, ID, xmlFreeIDTableEntry);
2855 xmlFree(ID);
2856 attr->atype = 0;
2857 return(0);
2861 * xmlGetID:
2862 * @doc: pointer to the document
2863 * @ID: the ID value
2865 * Search the attribute declaring the given ID
2867 * Returns NULL if not found, otherwise the xmlAttrPtr defining the ID
2869 xmlAttrPtr
2870 xmlGetID(xmlDocPtr doc, const xmlChar *ID) {
2871 xmlIDTablePtr table;
2872 xmlIDPtr id;
2874 if (doc == NULL) {
2875 return(NULL);
2878 if (ID == NULL) {
2879 return(NULL);
2882 table = (xmlIDTablePtr) doc->ids;
2883 if (table == NULL)
2884 return(NULL);
2886 id = xmlHashLookup(table, ID);
2887 if (id == NULL)
2888 return(NULL);
2889 if (id->attr == NULL) {
2891 * We are operating on a stream, return a well known reference
2892 * since the attribute node doesn't exist anymore
2894 return((xmlAttrPtr) doc);
2896 return(id->attr);
2899 /************************************************************************
2901 * Refs *
2903 ************************************************************************/
2904 typedef struct xmlRemoveMemo_t
2906 xmlListPtr l;
2907 xmlAttrPtr ap;
2908 } xmlRemoveMemo;
2910 typedef xmlRemoveMemo *xmlRemoveMemoPtr;
2912 typedef struct xmlValidateMemo_t
2914 xmlValidCtxtPtr ctxt;
2915 const xmlChar *name;
2916 } xmlValidateMemo;
2918 typedef xmlValidateMemo *xmlValidateMemoPtr;
2921 * xmlFreeRef:
2922 * @lk: A list link
2924 * Deallocate the memory used by a ref definition
2926 static void
2927 xmlFreeRef(xmlLinkPtr lk) {
2928 xmlRefPtr ref = (xmlRefPtr)xmlLinkGetData(lk);
2929 if (ref == NULL) return;
2930 if (ref->value != NULL)
2931 xmlFree((xmlChar *)ref->value);
2932 if (ref->name != NULL)
2933 xmlFree((xmlChar *)ref->name);
2934 xmlFree(ref);
2938 * xmlFreeRefTableEntry:
2939 * @list_ref: A list of references.
2941 * Deallocate the memory used by a list of references
2943 static void
2944 xmlFreeRefTableEntry(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) {
2945 xmlListPtr list_ref = (xmlListPtr) payload;
2946 if (list_ref == NULL) return;
2947 xmlListDelete(list_ref);
2951 * xmlWalkRemoveRef:
2952 * @data: Contents of current link
2953 * @user: Value supplied by the user
2955 * Returns 0 to abort the walk or 1 to continue
2957 static int
2958 xmlWalkRemoveRef(const void *data, void *user)
2960 xmlAttrPtr attr0 = ((xmlRefPtr)data)->attr;
2961 xmlAttrPtr attr1 = ((xmlRemoveMemoPtr)user)->ap;
2962 xmlListPtr ref_list = ((xmlRemoveMemoPtr)user)->l;
2964 if (attr0 == attr1) { /* Matched: remove and terminate walk */
2965 xmlListRemoveFirst(ref_list, (void *)data);
2966 return 0;
2968 return 1;
2972 * xmlDummyCompare
2973 * @data0: Value supplied by the user
2974 * @data1: Value supplied by the user
2976 * Do nothing, return 0. Used to create unordered lists.
2978 static int
2979 xmlDummyCompare(const void *data0 ATTRIBUTE_UNUSED,
2980 const void *data1 ATTRIBUTE_UNUSED)
2982 return (0);
2986 * xmlAddRef:
2987 * @ctxt: the validation context
2988 * @doc: pointer to the document
2989 * @value: the value name
2990 * @attr: the attribute holding the Ref
2992 * DEPRECATED, do not use. This function will be removed from the public API.
2994 * Register a new ref declaration
2996 * Returns NULL if not, otherwise the new xmlRefPtr
2998 xmlRefPtr
2999 xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
3000 xmlAttrPtr attr) {
3001 xmlRefPtr ret;
3002 xmlRefTablePtr table;
3003 xmlListPtr ref_list;
3005 if (doc == NULL) {
3006 return(NULL);
3008 if (value == NULL) {
3009 return(NULL);
3011 if (attr == NULL) {
3012 return(NULL);
3016 * Create the Ref table if needed.
3018 table = (xmlRefTablePtr) doc->refs;
3019 if (table == NULL) {
3020 doc->refs = table = xmlHashCreateDict(0, doc->dict);
3022 if (table == NULL) {
3023 xmlVErrMemory(ctxt,
3024 "xmlAddRef: Table creation failed!\n");
3025 return(NULL);
3028 ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
3029 if (ret == NULL) {
3030 xmlVErrMemory(ctxt, "malloc failed");
3031 return(NULL);
3035 * fill the structure.
3037 ret->value = xmlStrdup(value);
3038 if (xmlIsStreaming(ctxt)) {
3040 * Operating in streaming mode, attr is gonna disappear
3042 ret->name = xmlStrdup(attr->name);
3043 ret->attr = NULL;
3044 } else {
3045 ret->name = NULL;
3046 ret->attr = attr;
3048 ret->lineno = xmlGetLineNo(attr->parent);
3050 /* To add a reference :-
3051 * References are maintained as a list of references,
3052 * Lookup the entry, if no entry create new nodelist
3053 * Add the owning node to the NodeList
3054 * Return the ref
3057 if (NULL == (ref_list = xmlHashLookup(table, value))) {
3058 if (NULL == (ref_list = xmlListCreate(xmlFreeRef, xmlDummyCompare))) {
3059 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
3060 "xmlAddRef: Reference list creation failed!\n",
3061 NULL);
3062 goto failed;
3064 if (xmlHashAddEntry(table, value, ref_list) < 0) {
3065 xmlListDelete(ref_list);
3066 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
3067 "xmlAddRef: Reference list insertion failed!\n",
3068 NULL);
3069 goto failed;
3072 if (xmlListAppend(ref_list, ret) != 0) {
3073 xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
3074 "xmlAddRef: Reference list insertion failed!\n",
3075 NULL);
3076 goto failed;
3078 return(ret);
3079 failed:
3080 if (ret != NULL) {
3081 if (ret->value != NULL)
3082 xmlFree((char *)ret->value);
3083 if (ret->name != NULL)
3084 xmlFree((char *)ret->name);
3085 xmlFree(ret);
3087 return(NULL);
3091 * xmlFreeRefTable:
3092 * @table: An ref table
3094 * DEPRECATED, do not use. This function will be removed from the public API.
3096 * Deallocate the memory used by an Ref hash table.
3098 void
3099 xmlFreeRefTable(xmlRefTablePtr table) {
3100 xmlHashFree(table, xmlFreeRefTableEntry);
3104 * xmlIsRef:
3105 * @doc: the document
3106 * @elem: the element carrying the attribute
3107 * @attr: the attribute
3109 * DEPRECATED, do not use. This function will be removed from the public API.
3111 * Determine whether an attribute is of type Ref. In case we have DTD(s)
3112 * then this is simple, otherwise we use an heuristic: name Ref (upper
3113 * or lowercase).
3115 * Returns 0 or 1 depending on the lookup result
3118 xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
3119 if (attr == NULL)
3120 return(0);
3121 if (doc == NULL) {
3122 doc = attr->doc;
3123 if (doc == NULL) return(0);
3126 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
3127 return(0);
3128 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
3129 /* TODO @@@ */
3130 return(0);
3131 } else {
3132 xmlAttributePtr attrDecl;
3134 if (elem == NULL) return(0);
3135 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
3136 if ((attrDecl == NULL) && (doc->extSubset != NULL))
3137 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
3138 elem->name, attr->name);
3140 if ((attrDecl != NULL) &&
3141 (attrDecl->atype == XML_ATTRIBUTE_IDREF ||
3142 attrDecl->atype == XML_ATTRIBUTE_IDREFS))
3143 return(1);
3145 return(0);
3149 * xmlRemoveRef:
3150 * @doc: the document
3151 * @attr: the attribute
3153 * DEPRECATED, do not use. This function will be removed from the public API.
3155 * Remove the given attribute from the Ref table maintained internally.
3157 * Returns -1 if the lookup failed and 0 otherwise
3160 xmlRemoveRef(xmlDocPtr doc, xmlAttrPtr attr) {
3161 xmlListPtr ref_list;
3162 xmlRefTablePtr table;
3163 xmlChar *ID;
3164 xmlRemoveMemo target;
3166 if (doc == NULL) return(-1);
3167 if (attr == NULL) return(-1);
3169 table = (xmlRefTablePtr) doc->refs;
3170 if (table == NULL)
3171 return(-1);
3173 ID = xmlNodeListGetString(doc, attr->children, 1);
3174 if (ID == NULL)
3175 return(-1);
3177 ref_list = xmlHashLookup(table, ID);
3178 if(ref_list == NULL) {
3179 xmlFree(ID);
3180 return (-1);
3183 /* At this point, ref_list refers to a list of references which
3184 * have the same key as the supplied attr. Our list of references
3185 * is ordered by reference address and we don't have that information
3186 * here to use when removing. We'll have to walk the list and
3187 * check for a matching attribute, when we find one stop the walk
3188 * and remove the entry.
3189 * The list is ordered by reference, so that means we don't have the
3190 * key. Passing the list and the reference to the walker means we
3191 * will have enough data to be able to remove the entry.
3193 target.l = ref_list;
3194 target.ap = attr;
3196 /* Remove the supplied attr from our list */
3197 xmlListWalk(ref_list, xmlWalkRemoveRef, &target);
3199 /*If the list is empty then remove the list entry in the hash */
3200 if (xmlListEmpty(ref_list))
3201 xmlHashUpdateEntry(table, ID, NULL, xmlFreeRefTableEntry);
3202 xmlFree(ID);
3203 return(0);
3207 * xmlGetRefs:
3208 * @doc: pointer to the document
3209 * @ID: the ID value
3211 * DEPRECATED, do not use. This function will be removed from the public API.
3213 * Find the set of references for the supplied ID.
3215 * Returns NULL if not found, otherwise node set for the ID.
3217 xmlListPtr
3218 xmlGetRefs(xmlDocPtr doc, const xmlChar *ID) {
3219 xmlRefTablePtr table;
3221 if (doc == NULL) {
3222 return(NULL);
3225 if (ID == NULL) {
3226 return(NULL);
3229 table = (xmlRefTablePtr) doc->refs;
3230 if (table == NULL)
3231 return(NULL);
3233 return (xmlHashLookup(table, ID));
3236 /************************************************************************
3238 * Routines for validity checking *
3240 ************************************************************************/
3243 * xmlGetDtdElementDesc:
3244 * @dtd: a pointer to the DtD to search
3245 * @name: the element name
3247 * Search the DTD for the description of this element
3249 * returns the xmlElementPtr if found or NULL
3252 xmlElementPtr
3253 xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) {
3254 xmlElementTablePtr table;
3255 xmlElementPtr cur;
3256 xmlChar *uqname = NULL, *prefix = NULL;
3258 if ((dtd == NULL) || (name == NULL)) return(NULL);
3259 if (dtd->elements == NULL)
3260 return(NULL);
3261 table = (xmlElementTablePtr) dtd->elements;
3263 uqname = xmlSplitQName2(name, &prefix);
3264 if (uqname != NULL)
3265 name = uqname;
3266 cur = xmlHashLookup2(table, name, prefix);
3267 if (prefix != NULL) xmlFree(prefix);
3268 if (uqname != NULL) xmlFree(uqname);
3269 return(cur);
3272 * xmlGetDtdElementDesc2:
3273 * @dtd: a pointer to the DtD to search
3274 * @name: the element name
3275 * @create: create an empty description if not found
3277 * Search the DTD for the description of this element
3279 * returns the xmlElementPtr if found or NULL
3282 static xmlElementPtr
3283 xmlGetDtdElementDesc2(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name,
3284 int create) {
3285 xmlElementTablePtr table;
3286 xmlElementPtr cur;
3287 xmlChar *uqname = NULL, *prefix = NULL;
3289 if (dtd == NULL) return(NULL);
3290 if (dtd->elements == NULL) {
3291 xmlDictPtr dict = NULL;
3293 if (dtd->doc != NULL)
3294 dict = dtd->doc->dict;
3296 if (!create)
3297 return(NULL);
3299 * Create the Element table if needed.
3301 table = (xmlElementTablePtr) dtd->elements;
3302 if (table == NULL) {
3303 table = xmlHashCreateDict(0, dict);
3304 dtd->elements = (void *) table;
3306 if (table == NULL) {
3307 xmlVErrMemory(ctxt, "element table allocation failed");
3308 return(NULL);
3311 table = (xmlElementTablePtr) dtd->elements;
3313 uqname = xmlSplitQName2(name, &prefix);
3314 if (uqname != NULL)
3315 name = uqname;
3316 cur = xmlHashLookup2(table, name, prefix);
3317 if ((cur == NULL) && (create)) {
3318 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
3319 if (cur == NULL) {
3320 xmlVErrMemory(ctxt, "malloc failed");
3321 goto error;
3323 memset(cur, 0, sizeof(xmlElement));
3324 cur->type = XML_ELEMENT_DECL;
3327 * fill the structure.
3329 cur->name = xmlStrdup(name);
3330 cur->prefix = xmlStrdup(prefix);
3331 cur->etype = XML_ELEMENT_TYPE_UNDEFINED;
3333 if (xmlHashAddEntry2(table, name, prefix, cur) < 0) {
3334 xmlVErrMemory(ctxt, "adding entry failed");
3335 xmlFreeElement(cur);
3336 cur = NULL;
3339 error:
3340 if (prefix != NULL) xmlFree(prefix);
3341 if (uqname != NULL) xmlFree(uqname);
3342 return(cur);
3346 * xmlGetDtdQElementDesc:
3347 * @dtd: a pointer to the DtD to search
3348 * @name: the element name
3349 * @prefix: the element namespace prefix
3351 * Search the DTD for the description of this element
3353 * returns the xmlElementPtr if found or NULL
3356 xmlElementPtr
3357 xmlGetDtdQElementDesc(xmlDtdPtr dtd, const xmlChar *name,
3358 const xmlChar *prefix) {
3359 xmlElementTablePtr table;
3361 if (dtd == NULL) return(NULL);
3362 if (dtd->elements == NULL) return(NULL);
3363 table = (xmlElementTablePtr) dtd->elements;
3365 return(xmlHashLookup2(table, name, prefix));
3369 * xmlGetDtdAttrDesc:
3370 * @dtd: a pointer to the DtD to search
3371 * @elem: the element name
3372 * @name: the attribute name
3374 * Search the DTD for the description of this attribute on
3375 * this element.
3377 * returns the xmlAttributePtr if found or NULL
3380 xmlAttributePtr
3381 xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) {
3382 xmlAttributeTablePtr table;
3383 xmlAttributePtr cur;
3384 xmlChar *uqname = NULL, *prefix = NULL;
3386 if (dtd == NULL) return(NULL);
3387 if (dtd->attributes == NULL) return(NULL);
3389 table = (xmlAttributeTablePtr) dtd->attributes;
3390 if (table == NULL)
3391 return(NULL);
3393 uqname = xmlSplitQName2(name, &prefix);
3395 if (uqname != NULL) {
3396 cur = xmlHashLookup3(table, uqname, prefix, elem);
3397 if (prefix != NULL) xmlFree(prefix);
3398 if (uqname != NULL) xmlFree(uqname);
3399 } else
3400 cur = xmlHashLookup3(table, name, NULL, elem);
3401 return(cur);
3405 * xmlGetDtdQAttrDesc:
3406 * @dtd: a pointer to the DtD to search
3407 * @elem: the element name
3408 * @name: the attribute name
3409 * @prefix: the attribute namespace prefix
3411 * Search the DTD for the description of this qualified attribute on
3412 * this element.
3414 * returns the xmlAttributePtr if found or NULL
3417 xmlAttributePtr
3418 xmlGetDtdQAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name,
3419 const xmlChar *prefix) {
3420 xmlAttributeTablePtr table;
3422 if (dtd == NULL) return(NULL);
3423 if (dtd->attributes == NULL) return(NULL);
3424 table = (xmlAttributeTablePtr) dtd->attributes;
3426 return(xmlHashLookup3(table, name, prefix, elem));
3430 * xmlGetDtdNotationDesc:
3431 * @dtd: a pointer to the DtD to search
3432 * @name: the notation name
3434 * Search the DTD for the description of this notation
3436 * returns the xmlNotationPtr if found or NULL
3439 xmlNotationPtr
3440 xmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) {
3441 xmlNotationTablePtr table;
3443 if (dtd == NULL) return(NULL);
3444 if (dtd->notations == NULL) return(NULL);
3445 table = (xmlNotationTablePtr) dtd->notations;
3447 return(xmlHashLookup(table, name));
3450 #if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
3452 * xmlValidateNotationUse:
3453 * @ctxt: the validation context
3454 * @doc: the document
3455 * @notationName: the notation name to check
3457 * Validate that the given name match a notation declaration.
3458 * - [ VC: Notation Declared ]
3460 * returns 1 if valid or 0 otherwise
3464 xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3465 const xmlChar *notationName) {
3466 xmlNotationPtr notaDecl;
3467 if ((doc == NULL) || (doc->intSubset == NULL) ||
3468 (notationName == NULL)) return(-1);
3470 notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
3471 if ((notaDecl == NULL) && (doc->extSubset != NULL))
3472 notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
3474 if ((notaDecl == NULL) && (ctxt != NULL)) {
3475 xmlErrValidNode(ctxt, (xmlNodePtr) doc, XML_DTD_UNKNOWN_NOTATION,
3476 "NOTATION %s is not declared\n",
3477 notationName, NULL, NULL);
3478 return(0);
3480 return(1);
3482 #endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */
3485 * xmlIsMixedElement:
3486 * @doc: the document
3487 * @name: the element name
3489 * Search in the DtDs whether an element accept Mixed content (or ANY)
3490 * basically if it is supposed to accept text childs
3492 * returns 0 if no, 1 if yes, and -1 if no element description is available
3496 xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) {
3497 xmlElementPtr elemDecl;
3499 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
3501 elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
3502 if ((elemDecl == NULL) && (doc->extSubset != NULL))
3503 elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
3504 if (elemDecl == NULL) return(-1);
3505 switch (elemDecl->etype) {
3506 case XML_ELEMENT_TYPE_UNDEFINED:
3507 return(-1);
3508 case XML_ELEMENT_TYPE_ELEMENT:
3509 return(0);
3510 case XML_ELEMENT_TYPE_EMPTY:
3512 * return 1 for EMPTY since we want VC error to pop up
3513 * on <empty> </empty> for example
3515 case XML_ELEMENT_TYPE_ANY:
3516 case XML_ELEMENT_TYPE_MIXED:
3517 return(1);
3519 return(1);
3522 #ifdef LIBXML_VALID_ENABLED
3524 static int
3525 xmlIsDocNameStartChar(xmlDocPtr doc, int c) {
3526 if ((doc == NULL) || (doc->properties & XML_DOC_OLD10) == 0) {
3528 * Use the new checks of production [4] [4a] amd [5] of the
3529 * Update 5 of XML-1.0
3531 if (((c >= 'a') && (c <= 'z')) ||
3532 ((c >= 'A') && (c <= 'Z')) ||
3533 (c == '_') || (c == ':') ||
3534 ((c >= 0xC0) && (c <= 0xD6)) ||
3535 ((c >= 0xD8) && (c <= 0xF6)) ||
3536 ((c >= 0xF8) && (c <= 0x2FF)) ||
3537 ((c >= 0x370) && (c <= 0x37D)) ||
3538 ((c >= 0x37F) && (c <= 0x1FFF)) ||
3539 ((c >= 0x200C) && (c <= 0x200D)) ||
3540 ((c >= 0x2070) && (c <= 0x218F)) ||
3541 ((c >= 0x2C00) && (c <= 0x2FEF)) ||
3542 ((c >= 0x3001) && (c <= 0xD7FF)) ||
3543 ((c >= 0xF900) && (c <= 0xFDCF)) ||
3544 ((c >= 0xFDF0) && (c <= 0xFFFD)) ||
3545 ((c >= 0x10000) && (c <= 0xEFFFF)))
3546 return(1);
3547 } else {
3548 if (IS_LETTER(c) || (c == '_') || (c == ':'))
3549 return(1);
3551 return(0);
3554 static int
3555 xmlIsDocNameChar(xmlDocPtr doc, int c) {
3556 if ((doc == NULL) || (doc->properties & XML_DOC_OLD10) == 0) {
3558 * Use the new checks of production [4] [4a] amd [5] of the
3559 * Update 5 of XML-1.0
3561 if (((c >= 'a') && (c <= 'z')) ||
3562 ((c >= 'A') && (c <= 'Z')) ||
3563 ((c >= '0') && (c <= '9')) || /* !start */
3564 (c == '_') || (c == ':') ||
3565 (c == '-') || (c == '.') || (c == 0xB7) || /* !start */
3566 ((c >= 0xC0) && (c <= 0xD6)) ||
3567 ((c >= 0xD8) && (c <= 0xF6)) ||
3568 ((c >= 0xF8) && (c <= 0x2FF)) ||
3569 ((c >= 0x300) && (c <= 0x36F)) || /* !start */
3570 ((c >= 0x370) && (c <= 0x37D)) ||
3571 ((c >= 0x37F) && (c <= 0x1FFF)) ||
3572 ((c >= 0x200C) && (c <= 0x200D)) ||
3573 ((c >= 0x203F) && (c <= 0x2040)) || /* !start */
3574 ((c >= 0x2070) && (c <= 0x218F)) ||
3575 ((c >= 0x2C00) && (c <= 0x2FEF)) ||
3576 ((c >= 0x3001) && (c <= 0xD7FF)) ||
3577 ((c >= 0xF900) && (c <= 0xFDCF)) ||
3578 ((c >= 0xFDF0) && (c <= 0xFFFD)) ||
3579 ((c >= 0x10000) && (c <= 0xEFFFF)))
3580 return(1);
3581 } else {
3582 if ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
3583 (c == '.') || (c == '-') ||
3584 (c == '_') || (c == ':') ||
3585 (IS_COMBINING(c)) ||
3586 (IS_EXTENDER(c)))
3587 return(1);
3589 return(0);
3593 * xmlValidateNameValue:
3594 * @doc: pointer to the document or NULL
3595 * @value: an Name value
3597 * Validate that the given value match Name production
3599 * returns 1 if valid or 0 otherwise
3602 static int
3603 xmlValidateNameValueInternal(xmlDocPtr doc, const xmlChar *value) {
3604 const xmlChar *cur;
3605 int val, len;
3607 if (value == NULL) return(0);
3608 cur = value;
3609 val = xmlStringCurrentChar(NULL, cur, &len);
3610 cur += len;
3611 if (!xmlIsDocNameStartChar(doc, val))
3612 return(0);
3614 val = xmlStringCurrentChar(NULL, cur, &len);
3615 cur += len;
3616 while (xmlIsDocNameChar(doc, val)) {
3617 val = xmlStringCurrentChar(NULL, cur, &len);
3618 cur += len;
3621 if (val != 0) return(0);
3623 return(1);
3627 * xmlValidateNameValue:
3628 * @value: an Name value
3630 * Validate that the given value match Name production
3632 * returns 1 if valid or 0 otherwise
3636 xmlValidateNameValue(const xmlChar *value) {
3637 return(xmlValidateNameValueInternal(NULL, value));
3641 * xmlValidateNamesValueInternal:
3642 * @doc: pointer to the document or NULL
3643 * @value: an Names value
3645 * Validate that the given value match Names production
3647 * returns 1 if valid or 0 otherwise
3650 static int
3651 xmlValidateNamesValueInternal(xmlDocPtr doc, const xmlChar *value) {
3652 const xmlChar *cur;
3653 int val, len;
3655 if (value == NULL) return(0);
3656 cur = value;
3657 val = xmlStringCurrentChar(NULL, cur, &len);
3658 cur += len;
3660 if (!xmlIsDocNameStartChar(doc, val))
3661 return(0);
3663 val = xmlStringCurrentChar(NULL, cur, &len);
3664 cur += len;
3665 while (xmlIsDocNameChar(doc, val)) {
3666 val = xmlStringCurrentChar(NULL, cur, &len);
3667 cur += len;
3670 /* Should not test IS_BLANK(val) here -- see erratum E20*/
3671 while (val == 0x20) {
3672 while (val == 0x20) {
3673 val = xmlStringCurrentChar(NULL, cur, &len);
3674 cur += len;
3677 if (!xmlIsDocNameStartChar(doc, val))
3678 return(0);
3680 val = xmlStringCurrentChar(NULL, cur, &len);
3681 cur += len;
3683 while (xmlIsDocNameChar(doc, val)) {
3684 val = xmlStringCurrentChar(NULL, cur, &len);
3685 cur += len;
3689 if (val != 0) return(0);
3691 return(1);
3695 * xmlValidateNamesValue:
3696 * @value: an Names value
3698 * Validate that the given value match Names production
3700 * returns 1 if valid or 0 otherwise
3704 xmlValidateNamesValue(const xmlChar *value) {
3705 return(xmlValidateNamesValueInternal(NULL, value));
3709 * xmlValidateNmtokenValueInternal:
3710 * @doc: pointer to the document or NULL
3711 * @value: an Nmtoken value
3713 * Validate that the given value match Nmtoken production
3715 * [ VC: Name Token ]
3717 * returns 1 if valid or 0 otherwise
3720 static int
3721 xmlValidateNmtokenValueInternal(xmlDocPtr doc, const xmlChar *value) {
3722 const xmlChar *cur;
3723 int val, len;
3725 if (value == NULL) return(0);
3726 cur = value;
3727 val = xmlStringCurrentChar(NULL, cur, &len);
3728 cur += len;
3730 if (!xmlIsDocNameChar(doc, val))
3731 return(0);
3733 val = xmlStringCurrentChar(NULL, cur, &len);
3734 cur += len;
3735 while (xmlIsDocNameChar(doc, val)) {
3736 val = xmlStringCurrentChar(NULL, cur, &len);
3737 cur += len;
3740 if (val != 0) return(0);
3742 return(1);
3746 * xmlValidateNmtokenValue:
3747 * @value: an Nmtoken value
3749 * Validate that the given value match Nmtoken production
3751 * [ VC: Name Token ]
3753 * returns 1 if valid or 0 otherwise
3757 xmlValidateNmtokenValue(const xmlChar *value) {
3758 return(xmlValidateNmtokenValueInternal(NULL, value));
3762 * xmlValidateNmtokensValueInternal:
3763 * @doc: pointer to the document or NULL
3764 * @value: an Nmtokens value
3766 * Validate that the given value match Nmtokens production
3768 * [ VC: Name Token ]
3770 * returns 1 if valid or 0 otherwise
3773 static int
3774 xmlValidateNmtokensValueInternal(xmlDocPtr doc, const xmlChar *value) {
3775 const xmlChar *cur;
3776 int val, len;
3778 if (value == NULL) return(0);
3779 cur = value;
3780 val = xmlStringCurrentChar(NULL, cur, &len);
3781 cur += len;
3783 while (IS_BLANK(val)) {
3784 val = xmlStringCurrentChar(NULL, cur, &len);
3785 cur += len;
3788 if (!xmlIsDocNameChar(doc, val))
3789 return(0);
3791 while (xmlIsDocNameChar(doc, val)) {
3792 val = xmlStringCurrentChar(NULL, cur, &len);
3793 cur += len;
3796 /* Should not test IS_BLANK(val) here -- see erratum E20*/
3797 while (val == 0x20) {
3798 while (val == 0x20) {
3799 val = xmlStringCurrentChar(NULL, cur, &len);
3800 cur += len;
3802 if (val == 0) return(1);
3804 if (!xmlIsDocNameChar(doc, val))
3805 return(0);
3807 val = xmlStringCurrentChar(NULL, cur, &len);
3808 cur += len;
3810 while (xmlIsDocNameChar(doc, val)) {
3811 val = xmlStringCurrentChar(NULL, cur, &len);
3812 cur += len;
3816 if (val != 0) return(0);
3818 return(1);
3822 * xmlValidateNmtokensValue:
3823 * @value: an Nmtokens value
3825 * Validate that the given value match Nmtokens production
3827 * [ VC: Name Token ]
3829 * returns 1 if valid or 0 otherwise
3833 xmlValidateNmtokensValue(const xmlChar *value) {
3834 return(xmlValidateNmtokensValueInternal(NULL, value));
3838 * xmlValidateNotationDecl:
3839 * @ctxt: the validation context
3840 * @doc: a document instance
3841 * @nota: a notation definition
3843 * Try to validate a single notation definition
3844 * basically it does the following checks as described by the
3845 * XML-1.0 recommendation:
3846 * - it seems that no validity constraint exists on notation declarations
3847 * But this function get called anyway ...
3849 * returns 1 if valid or 0 otherwise
3853 xmlValidateNotationDecl(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED, xmlDocPtr doc ATTRIBUTE_UNUSED,
3854 xmlNotationPtr nota ATTRIBUTE_UNUSED) {
3855 int ret = 1;
3857 return(ret);
3861 * xmlValidateAttributeValueInternal:
3862 * @doc: the document
3863 * @type: an attribute type
3864 * @value: an attribute value
3866 * Validate that the given attribute value match the proper production
3868 * returns 1 if valid or 0 otherwise
3871 static int
3872 xmlValidateAttributeValueInternal(xmlDocPtr doc, xmlAttributeType type,
3873 const xmlChar *value) {
3874 switch (type) {
3875 case XML_ATTRIBUTE_ENTITIES:
3876 case XML_ATTRIBUTE_IDREFS:
3877 return(xmlValidateNamesValueInternal(doc, value));
3878 case XML_ATTRIBUTE_ENTITY:
3879 case XML_ATTRIBUTE_IDREF:
3880 case XML_ATTRIBUTE_ID:
3881 case XML_ATTRIBUTE_NOTATION:
3882 return(xmlValidateNameValueInternal(doc, value));
3883 case XML_ATTRIBUTE_NMTOKENS:
3884 case XML_ATTRIBUTE_ENUMERATION:
3885 return(xmlValidateNmtokensValueInternal(doc, value));
3886 case XML_ATTRIBUTE_NMTOKEN:
3887 return(xmlValidateNmtokenValueInternal(doc, value));
3888 case XML_ATTRIBUTE_CDATA:
3889 break;
3891 return(1);
3895 * xmlValidateAttributeValue:
3896 * @type: an attribute type
3897 * @value: an attribute value
3899 * Validate that the given attribute value match the proper production
3901 * [ VC: ID ]
3902 * Values of type ID must match the Name production....
3904 * [ VC: IDREF ]
3905 * Values of type IDREF must match the Name production, and values
3906 * of type IDREFS must match Names ...
3908 * [ VC: Entity Name ]
3909 * Values of type ENTITY must match the Name production, values
3910 * of type ENTITIES must match Names ...
3912 * [ VC: Name Token ]
3913 * Values of type NMTOKEN must match the Nmtoken production; values
3914 * of type NMTOKENS must match Nmtokens.
3916 * returns 1 if valid or 0 otherwise
3919 xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) {
3920 return(xmlValidateAttributeValueInternal(NULL, type, value));
3924 * xmlValidateAttributeValue2:
3925 * @ctxt: the validation context
3926 * @doc: the document
3927 * @name: the attribute name (used for error reporting only)
3928 * @type: the attribute type
3929 * @value: the attribute value
3931 * Validate that the given attribute value match a given type.
3932 * This typically cannot be done before having finished parsing
3933 * the subsets.
3935 * [ VC: IDREF ]
3936 * Values of type IDREF must match one of the declared IDs
3937 * Values of type IDREFS must match a sequence of the declared IDs
3938 * each Name must match the value of an ID attribute on some element
3939 * in the XML document; i.e. IDREF values must match the value of
3940 * some ID attribute
3942 * [ VC: Entity Name ]
3943 * Values of type ENTITY must match one declared entity
3944 * Values of type ENTITIES must match a sequence of declared entities
3946 * [ VC: Notation Attributes ]
3947 * all notation names in the declaration must be declared.
3949 * returns 1 if valid or 0 otherwise
3952 static int
3953 xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3954 const xmlChar *name, xmlAttributeType type, const xmlChar *value) {
3955 int ret = 1;
3956 switch (type) {
3957 case XML_ATTRIBUTE_IDREFS:
3958 case XML_ATTRIBUTE_IDREF:
3959 case XML_ATTRIBUTE_ID:
3960 case XML_ATTRIBUTE_NMTOKENS:
3961 case XML_ATTRIBUTE_ENUMERATION:
3962 case XML_ATTRIBUTE_NMTOKEN:
3963 case XML_ATTRIBUTE_CDATA:
3964 break;
3965 case XML_ATTRIBUTE_ENTITY: {
3966 xmlEntityPtr ent;
3968 ent = xmlGetDocEntity(doc, value);
3969 /* yeah it's a bit messy... */
3970 if ((ent == NULL) && (doc->standalone == 1)) {
3971 doc->standalone = 0;
3972 ent = xmlGetDocEntity(doc, value);
3974 if (ent == NULL) {
3975 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3976 XML_DTD_UNKNOWN_ENTITY,
3977 "ENTITY attribute %s reference an unknown entity \"%s\"\n",
3978 name, value, NULL);
3979 ret = 0;
3980 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
3981 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3982 XML_DTD_ENTITY_TYPE,
3983 "ENTITY attribute %s reference an entity \"%s\" of wrong type\n",
3984 name, value, NULL);
3985 ret = 0;
3987 break;
3989 case XML_ATTRIBUTE_ENTITIES: {
3990 xmlChar *dup, *nam = NULL, *cur, save;
3991 xmlEntityPtr ent;
3993 dup = xmlStrdup(value);
3994 if (dup == NULL)
3995 return(0);
3996 cur = dup;
3997 while (*cur != 0) {
3998 nam = cur;
3999 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
4000 save = *cur;
4001 *cur = 0;
4002 ent = xmlGetDocEntity(doc, nam);
4003 if (ent == NULL) {
4004 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
4005 XML_DTD_UNKNOWN_ENTITY,
4006 "ENTITIES attribute %s reference an unknown entity \"%s\"\n",
4007 name, nam, NULL);
4008 ret = 0;
4009 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
4010 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
4011 XML_DTD_ENTITY_TYPE,
4012 "ENTITIES attribute %s reference an entity \"%s\" of wrong type\n",
4013 name, nam, NULL);
4014 ret = 0;
4016 if (save == 0)
4017 break;
4018 *cur = save;
4019 while (IS_BLANK_CH(*cur)) cur++;
4021 xmlFree(dup);
4022 break;
4024 case XML_ATTRIBUTE_NOTATION: {
4025 xmlNotationPtr nota;
4027 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4028 if ((nota == NULL) && (doc->extSubset != NULL))
4029 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4031 if (nota == NULL) {
4032 xmlErrValidNode(ctxt, (xmlNodePtr) doc,
4033 XML_DTD_UNKNOWN_NOTATION,
4034 "NOTATION attribute %s reference an unknown notation \"%s\"\n",
4035 name, value, NULL);
4036 ret = 0;
4038 break;
4041 return(ret);
4045 * xmlValidCtxtNormalizeAttributeValue:
4046 * @ctxt: the validation context
4047 * @doc: the document
4048 * @elem: the parent
4049 * @name: the attribute name
4050 * @value: the attribute value
4051 * @ctxt: the validation context or NULL
4053 * Does the validation related extra step of the normalization of attribute
4054 * values:
4056 * If the declared value is not CDATA, then the XML processor must further
4057 * process the normalized attribute value by discarding any leading and
4058 * trailing space (#x20) characters, and by replacing sequences of space
4059 * (#x20) characters by single space (#x20) character.
4061 * Also check VC: Standalone Document Declaration in P32, and update
4062 * ctxt->valid accordingly
4064 * returns a new normalized string if normalization is needed, NULL otherwise
4065 * the caller must free the returned value.
4068 xmlChar *
4069 xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4070 xmlNodePtr elem, const xmlChar *name, const xmlChar *value) {
4071 xmlChar *ret;
4072 xmlAttributePtr attrDecl = NULL;
4073 int extsubset = 0;
4075 if (doc == NULL) return(NULL);
4076 if (elem == NULL) return(NULL);
4077 if (name == NULL) return(NULL);
4078 if (value == NULL) return(NULL);
4080 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
4081 xmlChar fn[50];
4082 xmlChar *fullname;
4084 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
4085 if (fullname == NULL)
4086 return(NULL);
4087 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name);
4088 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
4089 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name);
4090 if (attrDecl != NULL)
4091 extsubset = 1;
4093 if ((fullname != fn) && (fullname != elem->name))
4094 xmlFree(fullname);
4096 if ((attrDecl == NULL) && (doc->intSubset != NULL))
4097 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
4098 if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
4099 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
4100 if (attrDecl != NULL)
4101 extsubset = 1;
4104 if (attrDecl == NULL)
4105 return(NULL);
4106 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
4107 return(NULL);
4109 ret = xmlStrdup(value);
4110 if (ret == NULL)
4111 return(NULL);
4112 xmlValidNormalizeString(ret);
4113 if ((doc->standalone) && (extsubset == 1) && (!xmlStrEqual(value, ret))) {
4114 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_STANDALONE,
4115 "standalone: %s on %s value had to be normalized based on external subset declaration\n",
4116 name, elem->name, NULL);
4117 ctxt->valid = 0;
4119 return(ret);
4123 * xmlValidNormalizeAttributeValue:
4124 * @doc: the document
4125 * @elem: the parent
4126 * @name: the attribute name
4127 * @value: the attribute value
4129 * Does the validation related extra step of the normalization of attribute
4130 * values:
4132 * If the declared value is not CDATA, then the XML processor must further
4133 * process the normalized attribute value by discarding any leading and
4134 * trailing space (#x20) characters, and by replacing sequences of space
4135 * (#x20) characters by single space (#x20) character.
4137 * Returns a new normalized string if normalization is needed, NULL otherwise
4138 * the caller must free the returned value.
4141 xmlChar *
4142 xmlValidNormalizeAttributeValue(xmlDocPtr doc, xmlNodePtr elem,
4143 const xmlChar *name, const xmlChar *value) {
4144 xmlChar *ret;
4145 xmlAttributePtr attrDecl = NULL;
4147 if (doc == NULL) return(NULL);
4148 if (elem == NULL) return(NULL);
4149 if (name == NULL) return(NULL);
4150 if (value == NULL) return(NULL);
4152 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
4153 xmlChar fn[50];
4154 xmlChar *fullname;
4156 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
4157 if (fullname == NULL)
4158 return(NULL);
4159 if ((fullname != fn) && (fullname != elem->name))
4160 xmlFree(fullname);
4162 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
4163 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4164 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
4166 if (attrDecl == NULL)
4167 return(NULL);
4168 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
4169 return(NULL);
4171 ret = xmlStrdup(value);
4172 if (ret == NULL)
4173 return(NULL);
4174 xmlValidNormalizeString(ret);
4175 return(ret);
4178 static void
4179 xmlValidateAttributeIdCallback(void *payload, void *data,
4180 const xmlChar *name ATTRIBUTE_UNUSED) {
4181 xmlAttributePtr attr = (xmlAttributePtr) payload;
4182 int *count = (int *) data;
4183 if (attr->atype == XML_ATTRIBUTE_ID) (*count)++;
4187 * xmlValidateAttributeDecl:
4188 * @ctxt: the validation context
4189 * @doc: a document instance
4190 * @attr: an attribute definition
4192 * Try to validate a single attribute definition
4193 * basically it does the following checks as described by the
4194 * XML-1.0 recommendation:
4195 * - [ VC: Attribute Default Legal ]
4196 * - [ VC: Enumeration ]
4197 * - [ VC: ID Attribute Default ]
4199 * The ID/IDREF uniqueness and matching are done separately
4201 * returns 1 if valid or 0 otherwise
4205 xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4206 xmlAttributePtr attr) {
4207 int ret = 1;
4208 int val;
4209 CHECK_DTD;
4210 if(attr == NULL) return(1);
4212 /* Attribute Default Legal */
4213 /* Enumeration */
4214 if (attr->defaultValue != NULL) {
4215 val = xmlValidateAttributeValueInternal(doc, attr->atype,
4216 attr->defaultValue);
4217 if (val == 0) {
4218 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_DEFAULT,
4219 "Syntax of default value for attribute %s of %s is not valid\n",
4220 attr->name, attr->elem, NULL);
4222 ret &= val;
4225 /* ID Attribute Default */
4226 if ((attr->atype == XML_ATTRIBUTE_ID)&&
4227 (attr->def != XML_ATTRIBUTE_IMPLIED) &&
4228 (attr->def != XML_ATTRIBUTE_REQUIRED)) {
4229 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_FIXED,
4230 "ID attribute %s of %s is not valid must be #IMPLIED or #REQUIRED\n",
4231 attr->name, attr->elem, NULL);
4232 ret = 0;
4235 /* One ID per Element Type */
4236 if (attr->atype == XML_ATTRIBUTE_ID) {
4237 int nbId;
4239 /* the trick is that we parse DtD as their own internal subset */
4240 xmlElementPtr elem = xmlGetDtdElementDesc(doc->intSubset,
4241 attr->elem);
4242 if (elem != NULL) {
4243 nbId = xmlScanIDAttributeDecl(NULL, elem, 0);
4244 } else {
4245 xmlAttributeTablePtr table;
4248 * The attribute may be declared in the internal subset and the
4249 * element in the external subset.
4251 nbId = 0;
4252 if (doc->intSubset != NULL) {
4253 table = (xmlAttributeTablePtr) doc->intSubset->attributes;
4254 xmlHashScan3(table, NULL, NULL, attr->elem,
4255 xmlValidateAttributeIdCallback, &nbId);
4258 if (nbId > 1) {
4260 xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
4261 "Element %s has %d ID attribute defined in the internal subset : %s\n",
4262 attr->elem, nbId, attr->name);
4263 } else if (doc->extSubset != NULL) {
4264 int extId = 0;
4265 elem = xmlGetDtdElementDesc(doc->extSubset, attr->elem);
4266 if (elem != NULL) {
4267 extId = xmlScanIDAttributeDecl(NULL, elem, 0);
4269 if (extId > 1) {
4270 xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
4271 "Element %s has %d ID attribute defined in the external subset : %s\n",
4272 attr->elem, extId, attr->name);
4273 } else if (extId + nbId > 1) {
4274 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
4275 "Element %s has ID attributes defined in the internal and external subset : %s\n",
4276 attr->elem, attr->name, NULL);
4281 /* Validity Constraint: Enumeration */
4282 if ((attr->defaultValue != NULL) && (attr->tree != NULL)) {
4283 xmlEnumerationPtr tree = attr->tree;
4284 while (tree != NULL) {
4285 if (xmlStrEqual(tree->name, attr->defaultValue)) break;
4286 tree = tree->next;
4288 if (tree == NULL) {
4289 xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_VALUE,
4290 "Default value \"%s\" for attribute %s of %s is not among the enumerated set\n",
4291 attr->defaultValue, attr->name, attr->elem);
4292 ret = 0;
4296 return(ret);
4300 * xmlValidateElementDecl:
4301 * @ctxt: the validation context
4302 * @doc: a document instance
4303 * @elem: an element definition
4305 * Try to validate a single element definition
4306 * basically it does the following checks as described by the
4307 * XML-1.0 recommendation:
4308 * - [ VC: One ID per Element Type ]
4309 * - [ VC: No Duplicate Types ]
4310 * - [ VC: Unique Element Type Declaration ]
4312 * returns 1 if valid or 0 otherwise
4316 xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4317 xmlElementPtr elem) {
4318 int ret = 1;
4319 xmlElementPtr tst;
4321 CHECK_DTD;
4323 if (elem == NULL) return(1);
4325 #if 0
4326 #ifdef LIBXML_REGEXP_ENABLED
4327 /* Build the regexp associated to the content model */
4328 ret = xmlValidBuildContentModel(ctxt, elem);
4329 #endif
4330 #endif
4332 /* No Duplicate Types */
4333 if (elem->etype == XML_ELEMENT_TYPE_MIXED) {
4334 xmlElementContentPtr cur, next;
4335 const xmlChar *name;
4337 cur = elem->content;
4338 while (cur != NULL) {
4339 if (cur->type != XML_ELEMENT_CONTENT_OR) break;
4340 if (cur->c1 == NULL) break;
4341 if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
4342 name = cur->c1->name;
4343 next = cur->c2;
4344 while (next != NULL) {
4345 if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
4346 if ((xmlStrEqual(next->name, name)) &&
4347 (xmlStrEqual(next->prefix, cur->c1->prefix))) {
4348 if (cur->c1->prefix == NULL) {
4349 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
4350 "Definition of %s has duplicate references of %s\n",
4351 elem->name, name, NULL);
4352 } else {
4353 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
4354 "Definition of %s has duplicate references of %s:%s\n",
4355 elem->name, cur->c1->prefix, name);
4357 ret = 0;
4359 break;
4361 if (next->c1 == NULL) break;
4362 if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
4363 if ((xmlStrEqual(next->c1->name, name)) &&
4364 (xmlStrEqual(next->c1->prefix, cur->c1->prefix))) {
4365 if (cur->c1->prefix == NULL) {
4366 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
4367 "Definition of %s has duplicate references to %s\n",
4368 elem->name, name, NULL);
4369 } else {
4370 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
4371 "Definition of %s has duplicate references to %s:%s\n",
4372 elem->name, cur->c1->prefix, name);
4374 ret = 0;
4376 next = next->c2;
4379 cur = cur->c2;
4383 /* VC: Unique Element Type Declaration */
4384 tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
4385 if ((tst != NULL ) && (tst != elem) &&
4386 ((tst->prefix == elem->prefix) ||
4387 (xmlStrEqual(tst->prefix, elem->prefix))) &&
4388 (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
4389 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
4390 "Redefinition of element %s\n",
4391 elem->name, NULL, NULL);
4392 ret = 0;
4394 tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
4395 if ((tst != NULL ) && (tst != elem) &&
4396 ((tst->prefix == elem->prefix) ||
4397 (xmlStrEqual(tst->prefix, elem->prefix))) &&
4398 (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
4399 xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
4400 "Redefinition of element %s\n",
4401 elem->name, NULL, NULL);
4402 ret = 0;
4404 /* One ID per Element Type
4405 * already done when registering the attribute
4406 if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
4407 ret = 0;
4408 } */
4409 return(ret);
4413 * xmlValidateOneAttribute:
4414 * @ctxt: the validation context
4415 * @doc: a document instance
4416 * @elem: an element instance
4417 * @attr: an attribute instance
4418 * @value: the attribute value (without entities processing)
4420 * Try to validate a single attribute for an element
4421 * basically it does the following checks as described by the
4422 * XML-1.0 recommendation:
4423 * - [ VC: Attribute Value Type ]
4424 * - [ VC: Fixed Attribute Default ]
4425 * - [ VC: Entity Name ]
4426 * - [ VC: Name Token ]
4427 * - [ VC: ID ]
4428 * - [ VC: IDREF ]
4429 * - [ VC: Entity Name ]
4430 * - [ VC: Notation Attributes ]
4432 * The ID/IDREF uniqueness and matching are done separately
4434 * returns 1 if valid or 0 otherwise
4438 xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4439 xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value)
4441 xmlAttributePtr attrDecl = NULL;
4442 int val;
4443 int ret = 1;
4445 CHECK_DTD;
4446 if ((elem == NULL) || (elem->name == NULL)) return(0);
4447 if ((attr == NULL) || (attr->name == NULL)) return(0);
4449 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
4450 xmlChar fn[50];
4451 xmlChar *fullname;
4453 fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
4454 if (fullname == NULL)
4455 return(0);
4456 if (attr->ns != NULL) {
4457 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
4458 attr->name, attr->ns->prefix);
4459 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4460 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
4461 attr->name, attr->ns->prefix);
4462 } else {
4463 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, attr->name);
4464 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4465 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4466 fullname, attr->name);
4468 if ((fullname != fn) && (fullname != elem->name))
4469 xmlFree(fullname);
4471 if (attrDecl == NULL) {
4472 if (attr->ns != NULL) {
4473 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4474 attr->name, attr->ns->prefix);
4475 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4476 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4477 attr->name, attr->ns->prefix);
4478 } else {
4479 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4480 elem->name, attr->name);
4481 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4482 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4483 elem->name, attr->name);
4488 /* Validity Constraint: Attribute Value Type */
4489 if (attrDecl == NULL) {
4490 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
4491 "No declaration for attribute %s of element %s\n",
4492 attr->name, elem->name, NULL);
4493 return(0);
4495 attr->atype = attrDecl->atype;
4497 val = xmlValidateAttributeValueInternal(doc, attrDecl->atype, value);
4498 if (val == 0) {
4499 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
4500 "Syntax of value for attribute %s of %s is not valid\n",
4501 attr->name, elem->name, NULL);
4502 ret = 0;
4505 /* Validity constraint: Fixed Attribute Default */
4506 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4507 if (!xmlStrEqual(value, attrDecl->defaultValue)) {
4508 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
4509 "Value for attribute %s of %s is different from default \"%s\"\n",
4510 attr->name, elem->name, attrDecl->defaultValue);
4511 ret = 0;
4515 /* Validity Constraint: ID uniqueness */
4516 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4517 if (xmlAddID(ctxt, doc, value, attr) == NULL)
4518 ret = 0;
4521 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4522 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4523 if (xmlAddRef(ctxt, doc, value, attr) == NULL)
4524 ret = 0;
4527 /* Validity Constraint: Notation Attributes */
4528 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4529 xmlEnumerationPtr tree = attrDecl->tree;
4530 xmlNotationPtr nota;
4532 /* First check that the given NOTATION was declared */
4533 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4534 if (nota == NULL)
4535 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4537 if (nota == NULL) {
4538 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
4539 "Value \"%s\" for attribute %s of %s is not a declared Notation\n",
4540 value, attr->name, elem->name);
4541 ret = 0;
4544 /* Second, verify that it's among the list */
4545 while (tree != NULL) {
4546 if (xmlStrEqual(tree->name, value)) break;
4547 tree = tree->next;
4549 if (tree == NULL) {
4550 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
4551 "Value \"%s\" for attribute %s of %s is not among the enumerated notations\n",
4552 value, attr->name, elem->name);
4553 ret = 0;
4557 /* Validity Constraint: Enumeration */
4558 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4559 xmlEnumerationPtr tree = attrDecl->tree;
4560 while (tree != NULL) {
4561 if (xmlStrEqual(tree->name, value)) break;
4562 tree = tree->next;
4564 if (tree == NULL) {
4565 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
4566 "Value \"%s\" for attribute %s of %s is not among the enumerated set\n",
4567 value, attr->name, elem->name);
4568 ret = 0;
4572 /* Fixed Attribute Default */
4573 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4574 (!xmlStrEqual(attrDecl->defaultValue, value))) {
4575 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
4576 "Value for attribute %s of %s must be \"%s\"\n",
4577 attr->name, elem->name, attrDecl->defaultValue);
4578 ret = 0;
4581 /* Extra check for the attribute value */
4582 ret &= xmlValidateAttributeValue2(ctxt, doc, attr->name,
4583 attrDecl->atype, value);
4585 return(ret);
4589 * xmlValidateOneNamespace:
4590 * @ctxt: the validation context
4591 * @doc: a document instance
4592 * @elem: an element instance
4593 * @prefix: the namespace prefix
4594 * @ns: an namespace declaration instance
4595 * @value: the attribute value (without entities processing)
4597 * Try to validate a single namespace declaration for an element
4598 * basically it does the following checks as described by the
4599 * XML-1.0 recommendation:
4600 * - [ VC: Attribute Value Type ]
4601 * - [ VC: Fixed Attribute Default ]
4602 * - [ VC: Entity Name ]
4603 * - [ VC: Name Token ]
4604 * - [ VC: ID ]
4605 * - [ VC: IDREF ]
4606 * - [ VC: Entity Name ]
4607 * - [ VC: Notation Attributes ]
4609 * The ID/IDREF uniqueness and matching are done separately
4611 * returns 1 if valid or 0 otherwise
4615 xmlValidateOneNamespace(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4616 xmlNodePtr elem, const xmlChar *prefix, xmlNsPtr ns, const xmlChar *value) {
4617 /* xmlElementPtr elemDecl; */
4618 xmlAttributePtr attrDecl = NULL;
4619 int val;
4620 int ret = 1;
4622 CHECK_DTD;
4623 if ((elem == NULL) || (elem->name == NULL)) return(0);
4624 if ((ns == NULL) || (ns->href == NULL)) return(0);
4626 if (prefix != NULL) {
4627 xmlChar fn[50];
4628 xmlChar *fullname;
4630 fullname = xmlBuildQName(elem->name, prefix, fn, 50);
4631 if (fullname == NULL) {
4632 xmlVErrMemory(ctxt, "Validating namespace");
4633 return(0);
4635 if (ns->prefix != NULL) {
4636 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
4637 ns->prefix, BAD_CAST "xmlns");
4638 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4639 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
4640 ns->prefix, BAD_CAST "xmlns");
4641 } else {
4642 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname,
4643 BAD_CAST "xmlns");
4644 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4645 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname,
4646 BAD_CAST "xmlns");
4648 if ((fullname != fn) && (fullname != elem->name))
4649 xmlFree(fullname);
4651 if (attrDecl == NULL) {
4652 if (ns->prefix != NULL) {
4653 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4654 ns->prefix, BAD_CAST "xmlns");
4655 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4656 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4657 ns->prefix, BAD_CAST "xmlns");
4658 } else {
4659 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4660 elem->name, BAD_CAST "xmlns");
4661 if ((attrDecl == NULL) && (doc->extSubset != NULL))
4662 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4663 elem->name, BAD_CAST "xmlns");
4668 /* Validity Constraint: Attribute Value Type */
4669 if (attrDecl == NULL) {
4670 if (ns->prefix != NULL) {
4671 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
4672 "No declaration for attribute xmlns:%s of element %s\n",
4673 ns->prefix, elem->name, NULL);
4674 } else {
4675 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
4676 "No declaration for attribute xmlns of element %s\n",
4677 elem->name, NULL, NULL);
4679 return(0);
4682 val = xmlValidateAttributeValueInternal(doc, attrDecl->atype, value);
4683 if (val == 0) {
4684 if (ns->prefix != NULL) {
4685 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
4686 "Syntax of value for attribute xmlns:%s of %s is not valid\n",
4687 ns->prefix, elem->name, NULL);
4688 } else {
4689 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
4690 "Syntax of value for attribute xmlns of %s is not valid\n",
4691 elem->name, NULL, NULL);
4693 ret = 0;
4696 /* Validity constraint: Fixed Attribute Default */
4697 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4698 if (!xmlStrEqual(value, attrDecl->defaultValue)) {
4699 if (ns->prefix != NULL) {
4700 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
4701 "Value for attribute xmlns:%s of %s is different from default \"%s\"\n",
4702 ns->prefix, elem->name, attrDecl->defaultValue);
4703 } else {
4704 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
4705 "Value for attribute xmlns of %s is different from default \"%s\"\n",
4706 elem->name, attrDecl->defaultValue, NULL);
4708 ret = 0;
4713 * Casting ns to xmlAttrPtr is wrong. We'd need separate functions
4714 * xmlAddID and xmlAddRef for namespace declarations, but it makes
4715 * no practical sense to use ID types anyway.
4717 #if 0
4718 /* Validity Constraint: ID uniqueness */
4719 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4720 if (xmlAddID(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4721 ret = 0;
4724 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4725 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4726 if (xmlAddRef(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4727 ret = 0;
4729 #endif
4731 /* Validity Constraint: Notation Attributes */
4732 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4733 xmlEnumerationPtr tree = attrDecl->tree;
4734 xmlNotationPtr nota;
4736 /* First check that the given NOTATION was declared */
4737 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4738 if (nota == NULL)
4739 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4741 if (nota == NULL) {
4742 if (ns->prefix != NULL) {
4743 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
4744 "Value \"%s\" for attribute xmlns:%s of %s is not a declared Notation\n",
4745 value, ns->prefix, elem->name);
4746 } else {
4747 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
4748 "Value \"%s\" for attribute xmlns of %s is not a declared Notation\n",
4749 value, elem->name, NULL);
4751 ret = 0;
4754 /* Second, verify that it's among the list */
4755 while (tree != NULL) {
4756 if (xmlStrEqual(tree->name, value)) break;
4757 tree = tree->next;
4759 if (tree == NULL) {
4760 if (ns->prefix != NULL) {
4761 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
4762 "Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated notations\n",
4763 value, ns->prefix, elem->name);
4764 } else {
4765 xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
4766 "Value \"%s\" for attribute xmlns of %s is not among the enumerated notations\n",
4767 value, elem->name, NULL);
4769 ret = 0;
4773 /* Validity Constraint: Enumeration */
4774 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4775 xmlEnumerationPtr tree = attrDecl->tree;
4776 while (tree != NULL) {
4777 if (xmlStrEqual(tree->name, value)) break;
4778 tree = tree->next;
4780 if (tree == NULL) {
4781 if (ns->prefix != NULL) {
4782 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
4783 "Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated set\n",
4784 value, ns->prefix, elem->name);
4785 } else {
4786 xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
4787 "Value \"%s\" for attribute xmlns of %s is not among the enumerated set\n",
4788 value, elem->name, NULL);
4790 ret = 0;
4794 /* Fixed Attribute Default */
4795 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4796 (!xmlStrEqual(attrDecl->defaultValue, value))) {
4797 if (ns->prefix != NULL) {
4798 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
4799 "Value for attribute xmlns:%s of %s must be \"%s\"\n",
4800 ns->prefix, elem->name, attrDecl->defaultValue);
4801 } else {
4802 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
4803 "Value for attribute xmlns of %s must be \"%s\"\n",
4804 elem->name, attrDecl->defaultValue, NULL);
4806 ret = 0;
4809 /* Extra check for the attribute value */
4810 if (ns->prefix != NULL) {
4811 ret &= xmlValidateAttributeValue2(ctxt, doc, ns->prefix,
4812 attrDecl->atype, value);
4813 } else {
4814 ret &= xmlValidateAttributeValue2(ctxt, doc, BAD_CAST "xmlns",
4815 attrDecl->atype, value);
4818 return(ret);
4821 #ifndef LIBXML_REGEXP_ENABLED
4823 * xmlValidateSkipIgnorable:
4824 * @ctxt: the validation context
4825 * @child: the child list
4827 * Skip ignorable elements w.r.t. the validation process
4829 * returns the first element to consider for validation of the content model
4832 static xmlNodePtr
4833 xmlValidateSkipIgnorable(xmlNodePtr child) {
4834 while (child != NULL) {
4835 switch (child->type) {
4836 /* These things are ignored (skipped) during validation. */
4837 case XML_PI_NODE:
4838 case XML_COMMENT_NODE:
4839 case XML_XINCLUDE_START:
4840 case XML_XINCLUDE_END:
4841 child = child->next;
4842 break;
4843 case XML_TEXT_NODE:
4844 if (xmlIsBlankNode(child))
4845 child = child->next;
4846 else
4847 return(child);
4848 break;
4849 /* keep current node */
4850 default:
4851 return(child);
4854 return(child);
4858 * xmlValidateElementType:
4859 * @ctxt: the validation context
4861 * Try to validate the content model of an element internal function
4863 * returns 1 if valid or 0 ,-1 in case of error, -2 if an entity
4864 * reference is found and -3 if the validation succeeded but
4865 * the content model is not determinist.
4868 static int
4869 xmlValidateElementType(xmlValidCtxtPtr ctxt) {
4870 int ret = -1;
4871 int determinist = 1;
4873 NODE = xmlValidateSkipIgnorable(NODE);
4874 if ((NODE == NULL) && (CONT == NULL))
4875 return(1);
4876 if ((NODE == NULL) &&
4877 ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
4878 (CONT->ocur == XML_ELEMENT_CONTENT_OPT))) {
4879 return(1);
4881 if (CONT == NULL) return(-1);
4882 if ((NODE != NULL) && (NODE->type == XML_ENTITY_REF_NODE))
4883 return(-2);
4886 * We arrive here when more states need to be examined
4888 cont:
4891 * We just recovered from a rollback generated by a possible
4892 * epsilon transition, go directly to the analysis phase
4894 if (STATE == ROLLBACK_PARENT) {
4895 DEBUG_VALID_MSG("restored parent branch");
4896 DEBUG_VALID_STATE(NODE, CONT)
4897 ret = 1;
4898 goto analyze;
4901 DEBUG_VALID_STATE(NODE, CONT)
4903 * we may have to save a backup state here. This is the equivalent
4904 * of handling epsilon transition in NFAs.
4906 if ((CONT != NULL) &&
4907 ((CONT->parent == NULL) ||
4908 (CONT->parent == (xmlElementContentPtr) 1) ||
4909 (CONT->parent->type != XML_ELEMENT_CONTENT_OR)) &&
4910 ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
4911 (CONT->ocur == XML_ELEMENT_CONTENT_OPT) ||
4912 ((CONT->ocur == XML_ELEMENT_CONTENT_PLUS) && (OCCURRENCE)))) {
4913 DEBUG_VALID_MSG("saving parent branch");
4914 if (vstateVPush(ctxt, CONT, NODE, DEPTH, OCCURS, ROLLBACK_PARENT) < 0)
4915 return(0);
4920 * Check first if the content matches
4922 switch (CONT->type) {
4923 case XML_ELEMENT_CONTENT_PCDATA:
4924 if (NODE == NULL) {
4925 DEBUG_VALID_MSG("pcdata failed no node");
4926 ret = 0;
4927 break;
4929 if (NODE->type == XML_TEXT_NODE) {
4930 DEBUG_VALID_MSG("pcdata found, skip to next");
4932 * go to next element in the content model
4933 * skipping ignorable elems
4935 do {
4936 NODE = NODE->next;
4937 NODE = xmlValidateSkipIgnorable(NODE);
4938 if ((NODE != NULL) &&
4939 (NODE->type == XML_ENTITY_REF_NODE))
4940 return(-2);
4941 } while ((NODE != NULL) &&
4942 ((NODE->type != XML_ELEMENT_NODE) &&
4943 (NODE->type != XML_TEXT_NODE) &&
4944 (NODE->type != XML_CDATA_SECTION_NODE)));
4945 ret = 1;
4946 break;
4947 } else {
4948 DEBUG_VALID_MSG("pcdata failed");
4949 ret = 0;
4950 break;
4952 break;
4953 case XML_ELEMENT_CONTENT_ELEMENT:
4954 if (NODE == NULL) {
4955 DEBUG_VALID_MSG("element failed no node");
4956 ret = 0;
4957 break;
4959 ret = ((NODE->type == XML_ELEMENT_NODE) &&
4960 (xmlStrEqual(NODE->name, CONT->name)));
4961 if (ret == 1) {
4962 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4963 ret = (CONT->prefix == NULL);
4964 } else if (CONT->prefix == NULL) {
4965 ret = 0;
4966 } else {
4967 ret = xmlStrEqual(NODE->ns->prefix, CONT->prefix);
4970 if (ret == 1) {
4971 DEBUG_VALID_MSG("element found, skip to next");
4973 * go to next element in the content model
4974 * skipping ignorable elems
4976 do {
4977 NODE = NODE->next;
4978 NODE = xmlValidateSkipIgnorable(NODE);
4979 if ((NODE != NULL) &&
4980 (NODE->type == XML_ENTITY_REF_NODE))
4981 return(-2);
4982 } while ((NODE != NULL) &&
4983 ((NODE->type != XML_ELEMENT_NODE) &&
4984 (NODE->type != XML_TEXT_NODE) &&
4985 (NODE->type != XML_CDATA_SECTION_NODE)));
4986 } else {
4987 DEBUG_VALID_MSG("element failed");
4988 ret = 0;
4989 break;
4991 break;
4992 case XML_ELEMENT_CONTENT_OR:
4994 * Small optimization.
4996 if (CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
4997 if ((NODE == NULL) ||
4998 (!xmlStrEqual(NODE->name, CONT->c1->name))) {
4999 DEPTH++;
5000 CONT = CONT->c2;
5001 goto cont;
5003 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
5004 ret = (CONT->c1->prefix == NULL);
5005 } else if (CONT->c1->prefix == NULL) {
5006 ret = 0;
5007 } else {
5008 ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
5010 if (ret == 0) {
5011 DEPTH++;
5012 CONT = CONT->c2;
5013 goto cont;
5018 * save the second branch 'or' branch
5020 DEBUG_VALID_MSG("saving 'or' branch");
5021 if (vstateVPush(ctxt, CONT->c2, NODE, DEPTH + 1,
5022 OCCURS, ROLLBACK_OR) < 0)
5023 return(-1);
5024 DEPTH++;
5025 CONT = CONT->c1;
5026 goto cont;
5027 case XML_ELEMENT_CONTENT_SEQ:
5029 * Small optimization.
5031 if ((CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) &&
5032 ((CONT->c1->ocur == XML_ELEMENT_CONTENT_OPT) ||
5033 (CONT->c1->ocur == XML_ELEMENT_CONTENT_MULT))) {
5034 if ((NODE == NULL) ||
5035 (!xmlStrEqual(NODE->name, CONT->c1->name))) {
5036 DEPTH++;
5037 CONT = CONT->c2;
5038 goto cont;
5040 if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
5041 ret = (CONT->c1->prefix == NULL);
5042 } else if (CONT->c1->prefix == NULL) {
5043 ret = 0;
5044 } else {
5045 ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
5047 if (ret == 0) {
5048 DEPTH++;
5049 CONT = CONT->c2;
5050 goto cont;
5053 DEPTH++;
5054 CONT = CONT->c1;
5055 goto cont;
5059 * At this point handle going up in the tree
5061 if (ret == -1) {
5062 DEBUG_VALID_MSG("error found returning");
5063 return(ret);
5065 analyze:
5066 while (CONT != NULL) {
5068 * First do the analysis depending on the occurrence model at
5069 * this level.
5071 if (ret == 0) {
5072 switch (CONT->ocur) {
5073 xmlNodePtr cur;
5075 case XML_ELEMENT_CONTENT_ONCE:
5076 cur = ctxt->vstate->node;
5077 DEBUG_VALID_MSG("Once branch failed, rollback");
5078 if (vstateVPop(ctxt) < 0 ) {
5079 DEBUG_VALID_MSG("exhaustion, failed");
5080 return(0);
5082 if (cur != ctxt->vstate->node)
5083 determinist = -3;
5084 goto cont;
5085 case XML_ELEMENT_CONTENT_PLUS:
5086 if (OCCURRENCE == 0) {
5087 cur = ctxt->vstate->node;
5088 DEBUG_VALID_MSG("Plus branch failed, rollback");
5089 if (vstateVPop(ctxt) < 0 ) {
5090 DEBUG_VALID_MSG("exhaustion, failed");
5091 return(0);
5093 if (cur != ctxt->vstate->node)
5094 determinist = -3;
5095 goto cont;
5097 DEBUG_VALID_MSG("Plus branch found");
5098 ret = 1;
5099 break;
5100 case XML_ELEMENT_CONTENT_MULT:
5101 #ifdef DEBUG_VALID_ALGO
5102 if (OCCURRENCE == 0) {
5103 DEBUG_VALID_MSG("Mult branch failed");
5104 } else {
5105 DEBUG_VALID_MSG("Mult branch found");
5107 #endif
5108 ret = 1;
5109 break;
5110 case XML_ELEMENT_CONTENT_OPT:
5111 DEBUG_VALID_MSG("Option branch failed");
5112 ret = 1;
5113 break;
5115 } else {
5116 switch (CONT->ocur) {
5117 case XML_ELEMENT_CONTENT_OPT:
5118 DEBUG_VALID_MSG("Option branch succeeded");
5119 ret = 1;
5120 break;
5121 case XML_ELEMENT_CONTENT_ONCE:
5122 DEBUG_VALID_MSG("Once branch succeeded");
5123 ret = 1;
5124 break;
5125 case XML_ELEMENT_CONTENT_PLUS:
5126 if (STATE == ROLLBACK_PARENT) {
5127 DEBUG_VALID_MSG("Plus branch rollback");
5128 ret = 1;
5129 break;
5131 if (NODE == NULL) {
5132 DEBUG_VALID_MSG("Plus branch exhausted");
5133 ret = 1;
5134 break;
5136 DEBUG_VALID_MSG("Plus branch succeeded, continuing");
5137 SET_OCCURRENCE;
5138 goto cont;
5139 case XML_ELEMENT_CONTENT_MULT:
5140 if (STATE == ROLLBACK_PARENT) {
5141 DEBUG_VALID_MSG("Mult branch rollback");
5142 ret = 1;
5143 break;
5145 if (NODE == NULL) {
5146 DEBUG_VALID_MSG("Mult branch exhausted");
5147 ret = 1;
5148 break;
5150 DEBUG_VALID_MSG("Mult branch succeeded, continuing");
5151 /* SET_OCCURRENCE; */
5152 goto cont;
5155 STATE = 0;
5158 * Then act accordingly at the parent level
5160 RESET_OCCURRENCE;
5161 if ((CONT->parent == NULL) ||
5162 (CONT->parent == (xmlElementContentPtr) 1))
5163 break;
5165 switch (CONT->parent->type) {
5166 case XML_ELEMENT_CONTENT_PCDATA:
5167 DEBUG_VALID_MSG("Error: parent pcdata");
5168 return(-1);
5169 case XML_ELEMENT_CONTENT_ELEMENT:
5170 DEBUG_VALID_MSG("Error: parent element");
5171 return(-1);
5172 case XML_ELEMENT_CONTENT_OR:
5173 if (ret == 1) {
5174 DEBUG_VALID_MSG("Or succeeded");
5175 CONT = CONT->parent;
5176 DEPTH--;
5177 } else {
5178 DEBUG_VALID_MSG("Or failed");
5179 CONT = CONT->parent;
5180 DEPTH--;
5182 break;
5183 case XML_ELEMENT_CONTENT_SEQ:
5184 if (ret == 0) {
5185 DEBUG_VALID_MSG("Sequence failed");
5186 CONT = CONT->parent;
5187 DEPTH--;
5188 } else if (CONT == CONT->parent->c1) {
5189 DEBUG_VALID_MSG("Sequence testing 2nd branch");
5190 CONT = CONT->parent->c2;
5191 goto cont;
5192 } else {
5193 DEBUG_VALID_MSG("Sequence succeeded");
5194 CONT = CONT->parent;
5195 DEPTH--;
5199 if (NODE != NULL) {
5200 xmlNodePtr cur;
5202 cur = ctxt->vstate->node;
5203 DEBUG_VALID_MSG("Failed, remaining input, rollback");
5204 if (vstateVPop(ctxt) < 0 ) {
5205 DEBUG_VALID_MSG("exhaustion, failed");
5206 return(0);
5208 if (cur != ctxt->vstate->node)
5209 determinist = -3;
5210 goto cont;
5212 if (ret == 0) {
5213 xmlNodePtr cur;
5215 cur = ctxt->vstate->node;
5216 DEBUG_VALID_MSG("Failure, rollback");
5217 if (vstateVPop(ctxt) < 0 ) {
5218 DEBUG_VALID_MSG("exhaustion, failed");
5219 return(0);
5221 if (cur != ctxt->vstate->node)
5222 determinist = -3;
5223 goto cont;
5225 return(determinist);
5227 #endif
5230 * xmlSnprintfElements:
5231 * @buf: an output buffer
5232 * @size: the size of the buffer
5233 * @content: An element
5234 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
5236 * This will dump the list of elements to the buffer
5237 * Intended just for the debug routine
5239 static void
5240 xmlSnprintfElements(char *buf, int size, xmlNodePtr node, int glob) {
5241 xmlNodePtr cur;
5242 int len;
5244 if (node == NULL) return;
5245 if (glob) strcat(buf, "(");
5246 cur = node;
5247 while (cur != NULL) {
5248 len = strlen(buf);
5249 if (size - len < 50) {
5250 if ((size - len > 4) && (buf[len - 1] != '.'))
5251 strcat(buf, " ...");
5252 return;
5254 switch (cur->type) {
5255 case XML_ELEMENT_NODE:
5256 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5257 if (size - len < xmlStrlen(cur->ns->prefix) + 10) {
5258 if ((size - len > 4) && (buf[len - 1] != '.'))
5259 strcat(buf, " ...");
5260 return;
5262 strcat(buf, (char *) cur->ns->prefix);
5263 strcat(buf, ":");
5265 if (size - len < xmlStrlen(cur->name) + 10) {
5266 if ((size - len > 4) && (buf[len - 1] != '.'))
5267 strcat(buf, " ...");
5268 return;
5270 strcat(buf, (char *) cur->name);
5271 if (cur->next != NULL)
5272 strcat(buf, " ");
5273 break;
5274 case XML_TEXT_NODE:
5275 if (xmlIsBlankNode(cur))
5276 break;
5277 /* Falls through. */
5278 case XML_CDATA_SECTION_NODE:
5279 case XML_ENTITY_REF_NODE:
5280 strcat(buf, "CDATA");
5281 if (cur->next != NULL)
5282 strcat(buf, " ");
5283 break;
5284 case XML_ATTRIBUTE_NODE:
5285 case XML_DOCUMENT_NODE:
5286 case XML_HTML_DOCUMENT_NODE:
5287 case XML_DOCUMENT_TYPE_NODE:
5288 case XML_DOCUMENT_FRAG_NODE:
5289 case XML_NOTATION_NODE:
5290 case XML_NAMESPACE_DECL:
5291 strcat(buf, "???");
5292 if (cur->next != NULL)
5293 strcat(buf, " ");
5294 break;
5295 case XML_ENTITY_NODE:
5296 case XML_PI_NODE:
5297 case XML_DTD_NODE:
5298 case XML_COMMENT_NODE:
5299 case XML_ELEMENT_DECL:
5300 case XML_ATTRIBUTE_DECL:
5301 case XML_ENTITY_DECL:
5302 case XML_XINCLUDE_START:
5303 case XML_XINCLUDE_END:
5304 break;
5306 cur = cur->next;
5308 if (glob) strcat(buf, ")");
5312 * xmlValidateElementContent:
5313 * @ctxt: the validation context
5314 * @child: the child list
5315 * @elemDecl: pointer to the element declaration
5316 * @warn: emit the error message
5317 * @parent: the parent element (for error reporting)
5319 * Try to validate the content model of an element
5321 * returns 1 if valid or 0 if not and -1 in case of error
5324 static int
5325 xmlValidateElementContent(xmlValidCtxtPtr ctxt, xmlNodePtr child,
5326 xmlElementPtr elemDecl, int warn, xmlNodePtr parent) {
5327 int ret = 1;
5328 #ifndef LIBXML_REGEXP_ENABLED
5329 xmlNodePtr repl = NULL, last = NULL, tmp;
5330 #endif
5331 xmlNodePtr cur;
5332 xmlElementContentPtr cont;
5333 const xmlChar *name;
5335 if ((elemDecl == NULL) || (parent == NULL) || (ctxt == NULL))
5336 return(-1);
5337 cont = elemDecl->content;
5338 name = elemDecl->name;
5340 #ifdef LIBXML_REGEXP_ENABLED
5341 /* Build the regexp associated to the content model */
5342 if (elemDecl->contModel == NULL)
5343 ret = xmlValidBuildContentModel(ctxt, elemDecl);
5344 if (elemDecl->contModel == NULL) {
5345 return(-1);
5346 } else {
5347 xmlRegExecCtxtPtr exec;
5349 if (!xmlRegexpIsDeterminist(elemDecl->contModel)) {
5350 return(-1);
5352 ctxt->nodeMax = 0;
5353 ctxt->nodeNr = 0;
5354 ctxt->nodeTab = NULL;
5355 exec = xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
5356 if (exec != NULL) {
5357 cur = child;
5358 while (cur != NULL) {
5359 switch (cur->type) {
5360 case XML_ENTITY_REF_NODE:
5362 * Push the current node to be able to roll back
5363 * and process within the entity
5365 if ((cur->children != NULL) &&
5366 (cur->children->children != NULL)) {
5367 nodeVPush(ctxt, cur);
5368 cur = cur->children->children;
5369 continue;
5371 break;
5372 case XML_TEXT_NODE:
5373 if (xmlIsBlankNode(cur))
5374 break;
5375 ret = 0;
5376 goto fail;
5377 case XML_CDATA_SECTION_NODE:
5378 /* TODO */
5379 ret = 0;
5380 goto fail;
5381 case XML_ELEMENT_NODE:
5382 if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5383 xmlChar fn[50];
5384 xmlChar *fullname;
5386 fullname = xmlBuildQName(cur->name,
5387 cur->ns->prefix, fn, 50);
5388 if (fullname == NULL) {
5389 ret = -1;
5390 goto fail;
5392 ret = xmlRegExecPushString(exec, fullname, NULL);
5393 if ((fullname != fn) && (fullname != cur->name))
5394 xmlFree(fullname);
5395 } else {
5396 ret = xmlRegExecPushString(exec, cur->name, NULL);
5398 break;
5399 default:
5400 break;
5403 * Switch to next element
5405 cur = cur->next;
5406 while (cur == NULL) {
5407 cur = nodeVPop(ctxt);
5408 if (cur == NULL)
5409 break;
5410 cur = cur->next;
5413 ret = xmlRegExecPushString(exec, NULL, NULL);
5414 fail:
5415 xmlRegFreeExecCtxt(exec);
5418 #else /* LIBXML_REGEXP_ENABLED */
5420 * Allocate the stack
5422 ctxt->vstateMax = 8;
5423 ctxt->vstateTab = (xmlValidState *) xmlMalloc(
5424 ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
5425 if (ctxt->vstateTab == NULL) {
5426 xmlVErrMemory(ctxt, "malloc failed");
5427 return(-1);
5430 * The first entry in the stack is reserved to the current state
5432 ctxt->nodeMax = 0;
5433 ctxt->nodeNr = 0;
5434 ctxt->nodeTab = NULL;
5435 ctxt->vstate = &ctxt->vstateTab[0];
5436 ctxt->vstateNr = 1;
5437 CONT = cont;
5438 NODE = child;
5439 DEPTH = 0;
5440 OCCURS = 0;
5441 STATE = 0;
5442 ret = xmlValidateElementType(ctxt);
5443 if ((ret == -3) && (warn)) {
5444 char expr[5000];
5445 expr[0] = 0;
5446 xmlSnprintfElementContent(expr, 5000, elemDecl->content, 1);
5447 xmlErrValidNode(ctxt, (xmlNodePtr) elemDecl,
5448 XML_DTD_CONTENT_NOT_DETERMINIST,
5449 "Content model of %s is not deterministic: %s\n",
5450 name, BAD_CAST expr, NULL);
5451 } else if (ret == -2) {
5453 * An entities reference appeared at this level.
5454 * Build a minimal representation of this node content
5455 * sufficient to run the validation process on it
5457 DEBUG_VALID_MSG("Found an entity reference, linearizing");
5458 cur = child;
5459 while (cur != NULL) {
5460 switch (cur->type) {
5461 case XML_ENTITY_REF_NODE:
5463 * Push the current node to be able to roll back
5464 * and process within the entity
5466 if ((cur->children != NULL) &&
5467 (cur->children->children != NULL)) {
5468 nodeVPush(ctxt, cur);
5469 cur = cur->children->children;
5470 continue;
5472 break;
5473 case XML_TEXT_NODE:
5474 if (xmlIsBlankNode(cur))
5475 break;
5476 /* no break on purpose */
5477 case XML_CDATA_SECTION_NODE:
5478 /* no break on purpose */
5479 case XML_ELEMENT_NODE:
5481 * Allocate a new node and minimally fills in
5482 * what's required
5484 tmp = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
5485 if (tmp == NULL) {
5486 xmlVErrMemory(ctxt, "malloc failed");
5487 xmlFreeNodeList(repl);
5488 ret = -1;
5489 goto done;
5491 tmp->type = cur->type;
5492 tmp->name = cur->name;
5493 tmp->ns = cur->ns;
5494 tmp->next = NULL;
5495 tmp->content = NULL;
5496 if (repl == NULL)
5497 repl = last = tmp;
5498 else {
5499 last->next = tmp;
5500 last = tmp;
5502 if (cur->type == XML_CDATA_SECTION_NODE) {
5504 * E59 spaces in CDATA does not match the
5505 * nonterminal S
5507 tmp->content = xmlStrdup(BAD_CAST "CDATA");
5509 break;
5510 default:
5511 break;
5514 * Switch to next element
5516 cur = cur->next;
5517 while (cur == NULL) {
5518 cur = nodeVPop(ctxt);
5519 if (cur == NULL)
5520 break;
5521 cur = cur->next;
5526 * Relaunch the validation
5528 ctxt->vstate = &ctxt->vstateTab[0];
5529 ctxt->vstateNr = 1;
5530 CONT = cont;
5531 NODE = repl;
5532 DEPTH = 0;
5533 OCCURS = 0;
5534 STATE = 0;
5535 ret = xmlValidateElementType(ctxt);
5537 #endif /* LIBXML_REGEXP_ENABLED */
5538 if ((warn) && ((ret != 1) && (ret != -3))) {
5539 if (ctxt != NULL) {
5540 char expr[5000];
5541 char list[5000];
5543 expr[0] = 0;
5544 xmlSnprintfElementContent(&expr[0], 5000, cont, 1);
5545 list[0] = 0;
5546 #ifndef LIBXML_REGEXP_ENABLED
5547 if (repl != NULL)
5548 xmlSnprintfElements(&list[0], 5000, repl, 1);
5549 else
5550 #endif /* LIBXML_REGEXP_ENABLED */
5551 xmlSnprintfElements(&list[0], 5000, child, 1);
5553 if (name != NULL) {
5554 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5555 "Element %s content does not follow the DTD, expecting %s, got %s\n",
5556 name, BAD_CAST expr, BAD_CAST list);
5557 } else {
5558 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5559 "Element content does not follow the DTD, expecting %s, got %s\n",
5560 BAD_CAST expr, BAD_CAST list, NULL);
5562 } else {
5563 if (name != NULL) {
5564 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5565 "Element %s content does not follow the DTD\n",
5566 name, NULL, NULL);
5567 } else {
5568 xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
5569 "Element content does not follow the DTD\n",
5570 NULL, NULL, NULL);
5573 ret = 0;
5575 if (ret == -3)
5576 ret = 1;
5578 #ifndef LIBXML_REGEXP_ENABLED
5579 done:
5581 * Deallocate the copy if done, and free up the validation stack
5583 while (repl != NULL) {
5584 tmp = repl->next;
5585 xmlFree(repl);
5586 repl = tmp;
5588 ctxt->vstateMax = 0;
5589 if (ctxt->vstateTab != NULL) {
5590 xmlFree(ctxt->vstateTab);
5591 ctxt->vstateTab = NULL;
5593 #endif
5594 ctxt->nodeMax = 0;
5595 ctxt->nodeNr = 0;
5596 if (ctxt->nodeTab != NULL) {
5597 xmlFree(ctxt->nodeTab);
5598 ctxt->nodeTab = NULL;
5600 return(ret);
5605 * xmlValidateCdataElement:
5606 * @ctxt: the validation context
5607 * @doc: a document instance
5608 * @elem: an element instance
5610 * Check that an element follows #CDATA
5612 * returns 1 if valid or 0 otherwise
5614 static int
5615 xmlValidateOneCdataElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5616 xmlNodePtr elem) {
5617 int ret = 1;
5618 xmlNodePtr cur, child;
5620 if ((ctxt == NULL) || (doc == NULL) || (elem == NULL) ||
5621 (elem->type != XML_ELEMENT_NODE))
5622 return(0);
5624 child = elem->children;
5626 cur = child;
5627 while (cur != NULL) {
5628 switch (cur->type) {
5629 case XML_ENTITY_REF_NODE:
5631 * Push the current node to be able to roll back
5632 * and process within the entity
5634 if ((cur->children != NULL) &&
5635 (cur->children->children != NULL)) {
5636 nodeVPush(ctxt, cur);
5637 cur = cur->children->children;
5638 continue;
5640 break;
5641 case XML_COMMENT_NODE:
5642 case XML_PI_NODE:
5643 case XML_TEXT_NODE:
5644 case XML_CDATA_SECTION_NODE:
5645 break;
5646 default:
5647 ret = 0;
5648 goto done;
5651 * Switch to next element
5653 cur = cur->next;
5654 while (cur == NULL) {
5655 cur = nodeVPop(ctxt);
5656 if (cur == NULL)
5657 break;
5658 cur = cur->next;
5661 done:
5662 ctxt->nodeMax = 0;
5663 ctxt->nodeNr = 0;
5664 if (ctxt->nodeTab != NULL) {
5665 xmlFree(ctxt->nodeTab);
5666 ctxt->nodeTab = NULL;
5668 return(ret);
5671 #ifdef LIBXML_REGEXP_ENABLED
5673 * xmlValidateCheckMixed:
5674 * @ctxt: the validation context
5675 * @cont: the mixed content model
5676 * @qname: the qualified name as appearing in the serialization
5678 * Check if the given node is part of the content model.
5680 * Returns 1 if yes, 0 if no, -1 in case of error
5682 static int
5683 xmlValidateCheckMixed(xmlValidCtxtPtr ctxt,
5684 xmlElementContentPtr cont, const xmlChar *qname) {
5685 const xmlChar *name;
5686 int plen;
5687 name = xmlSplitQName3(qname, &plen);
5689 if (name == NULL) {
5690 while (cont != NULL) {
5691 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5692 if ((cont->prefix == NULL) && (xmlStrEqual(cont->name, qname)))
5693 return(1);
5694 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5695 (cont->c1 != NULL) &&
5696 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5697 if ((cont->c1->prefix == NULL) &&
5698 (xmlStrEqual(cont->c1->name, qname)))
5699 return(1);
5700 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5701 (cont->c1 == NULL) ||
5702 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
5703 xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT,
5704 "Internal: MIXED struct corrupted\n",
5705 NULL);
5706 break;
5708 cont = cont->c2;
5710 } else {
5711 while (cont != NULL) {
5712 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
5713 if ((cont->prefix != NULL) &&
5714 (xmlStrncmp(cont->prefix, qname, plen) == 0) &&
5715 (xmlStrEqual(cont->name, name)))
5716 return(1);
5717 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
5718 (cont->c1 != NULL) &&
5719 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
5720 if ((cont->c1->prefix != NULL) &&
5721 (xmlStrncmp(cont->c1->prefix, qname, plen) == 0) &&
5722 (xmlStrEqual(cont->c1->name, name)))
5723 return(1);
5724 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
5725 (cont->c1 == NULL) ||
5726 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
5727 xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT,
5728 "Internal: MIXED struct corrupted\n",
5729 NULL);
5730 break;
5732 cont = cont->c2;
5735 return(0);
5737 #endif /* LIBXML_REGEXP_ENABLED */
5740 * xmlValidGetElemDecl:
5741 * @ctxt: the validation context
5742 * @doc: a document instance
5743 * @elem: an element instance
5744 * @extsubset: pointer, (out) indicate if the declaration was found
5745 * in the external subset.
5747 * Finds a declaration associated to an element in the document.
5749 * returns the pointer to the declaration or NULL if not found.
5751 static xmlElementPtr
5752 xmlValidGetElemDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5753 xmlNodePtr elem, int *extsubset) {
5754 xmlElementPtr elemDecl = NULL;
5755 const xmlChar *prefix = NULL;
5757 if ((ctxt == NULL) || (doc == NULL) ||
5758 (elem == NULL) || (elem->name == NULL))
5759 return(NULL);
5760 if (extsubset != NULL)
5761 *extsubset = 0;
5764 * Fetch the declaration for the qualified name
5766 if ((elem->ns != NULL) && (elem->ns->prefix != NULL))
5767 prefix = elem->ns->prefix;
5769 if (prefix != NULL) {
5770 elemDecl = xmlGetDtdQElementDesc(doc->intSubset,
5771 elem->name, prefix);
5772 if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5773 elemDecl = xmlGetDtdQElementDesc(doc->extSubset,
5774 elem->name, prefix);
5775 if ((elemDecl != NULL) && (extsubset != NULL))
5776 *extsubset = 1;
5781 * Fetch the declaration for the non qualified name
5782 * This is "non-strict" validation should be done on the
5783 * full QName but in that case being flexible makes sense.
5785 if (elemDecl == NULL) {
5786 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
5787 if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
5788 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
5789 if ((elemDecl != NULL) && (extsubset != NULL))
5790 *extsubset = 1;
5793 if (elemDecl == NULL) {
5794 xmlErrValidNode(ctxt, elem,
5795 XML_DTD_UNKNOWN_ELEM,
5796 "No declaration for element %s\n",
5797 elem->name, NULL, NULL);
5799 return(elemDecl);
5802 #ifdef LIBXML_REGEXP_ENABLED
5804 * xmlValidatePushElement:
5805 * @ctxt: the validation context
5806 * @doc: a document instance
5807 * @elem: an element instance
5808 * @qname: the qualified name as appearing in the serialization
5810 * Push a new element start on the validation stack.
5812 * returns 1 if no validation problem was found or 0 otherwise
5815 xmlValidatePushElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
5816 xmlNodePtr elem, const xmlChar *qname) {
5817 int ret = 1;
5818 xmlElementPtr eDecl;
5819 int extsubset = 0;
5821 if (ctxt == NULL)
5822 return(0);
5823 /* printf("PushElem %s\n", qname); */
5824 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5825 xmlValidStatePtr state = ctxt->vstate;
5826 xmlElementPtr elemDecl;
5829 * Check the new element against the content model of the new elem.
5831 if (state->elemDecl != NULL) {
5832 elemDecl = state->elemDecl;
5834 switch(elemDecl->etype) {
5835 case XML_ELEMENT_TYPE_UNDEFINED:
5836 ret = 0;
5837 break;
5838 case XML_ELEMENT_TYPE_EMPTY:
5839 xmlErrValidNode(ctxt, state->node,
5840 XML_DTD_NOT_EMPTY,
5841 "Element %s was declared EMPTY this one has content\n",
5842 state->node->name, NULL, NULL);
5843 ret = 0;
5844 break;
5845 case XML_ELEMENT_TYPE_ANY:
5846 /* I don't think anything is required then */
5847 break;
5848 case XML_ELEMENT_TYPE_MIXED:
5849 /* simple case of declared as #PCDATA */
5850 if ((elemDecl->content != NULL) &&
5851 (elemDecl->content->type ==
5852 XML_ELEMENT_CONTENT_PCDATA)) {
5853 xmlErrValidNode(ctxt, state->node,
5854 XML_DTD_NOT_PCDATA,
5855 "Element %s was declared #PCDATA but contains non text nodes\n",
5856 state->node->name, NULL, NULL);
5857 ret = 0;
5858 } else {
5859 ret = xmlValidateCheckMixed(ctxt, elemDecl->content,
5860 qname);
5861 if (ret != 1) {
5862 xmlErrValidNode(ctxt, state->node,
5863 XML_DTD_INVALID_CHILD,
5864 "Element %s is not declared in %s list of possible children\n",
5865 qname, state->node->name, NULL);
5868 break;
5869 case XML_ELEMENT_TYPE_ELEMENT:
5871 * TODO:
5872 * VC: Standalone Document Declaration
5873 * - element types with element content, if white space
5874 * occurs directly within any instance of those types.
5876 if (state->exec != NULL) {
5877 ret = xmlRegExecPushString(state->exec, qname, NULL);
5878 if (ret < 0) {
5879 xmlErrValidNode(ctxt, state->node,
5880 XML_DTD_CONTENT_MODEL,
5881 "Element %s content does not follow the DTD, Misplaced %s\n",
5882 state->node->name, qname, NULL);
5883 ret = 0;
5884 } else {
5885 ret = 1;
5888 break;
5892 eDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
5893 vstateVPush(ctxt, eDecl, elem);
5894 return(ret);
5898 * xmlValidatePushCData:
5899 * @ctxt: the validation context
5900 * @data: some character data read
5901 * @len: the length of the data
5903 * check the CData parsed for validation in the current stack
5905 * returns 1 if no validation problem was found or 0 otherwise
5908 xmlValidatePushCData(xmlValidCtxtPtr ctxt, const xmlChar *data, int len) {
5909 int ret = 1;
5911 /* printf("CDATA %s %d\n", data, len); */
5912 if (ctxt == NULL)
5913 return(0);
5914 if (len <= 0)
5915 return(ret);
5916 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5917 xmlValidStatePtr state = ctxt->vstate;
5918 xmlElementPtr elemDecl;
5921 * Check the new element against the content model of the new elem.
5923 if (state->elemDecl != NULL) {
5924 elemDecl = state->elemDecl;
5926 switch(elemDecl->etype) {
5927 case XML_ELEMENT_TYPE_UNDEFINED:
5928 ret = 0;
5929 break;
5930 case XML_ELEMENT_TYPE_EMPTY:
5931 xmlErrValidNode(ctxt, state->node,
5932 XML_DTD_NOT_EMPTY,
5933 "Element %s was declared EMPTY this one has content\n",
5934 state->node->name, NULL, NULL);
5935 ret = 0;
5936 break;
5937 case XML_ELEMENT_TYPE_ANY:
5938 break;
5939 case XML_ELEMENT_TYPE_MIXED:
5940 break;
5941 case XML_ELEMENT_TYPE_ELEMENT: {
5942 int i;
5944 for (i = 0;i < len;i++) {
5945 if (!IS_BLANK_CH(data[i])) {
5946 xmlErrValidNode(ctxt, state->node,
5947 XML_DTD_CONTENT_MODEL,
5948 "Element %s content does not follow the DTD, Text not allowed\n",
5949 state->node->name, NULL, NULL);
5950 ret = 0;
5951 goto done;
5955 * TODO:
5956 * VC: Standalone Document Declaration
5957 * element types with element content, if white space
5958 * occurs directly within any instance of those types.
5960 break;
5965 done:
5966 return(ret);
5970 * xmlValidatePopElement:
5971 * @ctxt: the validation context
5972 * @doc: a document instance
5973 * @elem: an element instance
5974 * @qname: the qualified name as appearing in the serialization
5976 * Pop the element end from the validation stack.
5978 * returns 1 if no validation problem was found or 0 otherwise
5981 xmlValidatePopElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc ATTRIBUTE_UNUSED,
5982 xmlNodePtr elem ATTRIBUTE_UNUSED,
5983 const xmlChar *qname ATTRIBUTE_UNUSED) {
5984 int ret = 1;
5986 if (ctxt == NULL)
5987 return(0);
5988 /* printf("PopElem %s\n", qname); */
5989 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
5990 xmlValidStatePtr state = ctxt->vstate;
5991 xmlElementPtr elemDecl;
5994 * Check the new element against the content model of the new elem.
5996 if (state->elemDecl != NULL) {
5997 elemDecl = state->elemDecl;
5999 if (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT) {
6000 if (state->exec != NULL) {
6001 ret = xmlRegExecPushString(state->exec, NULL, NULL);
6002 if (ret <= 0) {
6003 xmlErrValidNode(ctxt, state->node,
6004 XML_DTD_CONTENT_MODEL,
6005 "Element %s content does not follow the DTD, Expecting more children\n",
6006 state->node->name, NULL,NULL);
6007 ret = 0;
6008 } else {
6010 * previous validation errors should not generate
6011 * a new one here
6013 ret = 1;
6018 vstateVPop(ctxt);
6020 return(ret);
6022 #endif /* LIBXML_REGEXP_ENABLED */
6025 * xmlValidateOneElement:
6026 * @ctxt: the validation context
6027 * @doc: a document instance
6028 * @elem: an element instance
6030 * Try to validate a single element and it's attributes,
6031 * basically it does the following checks as described by the
6032 * XML-1.0 recommendation:
6033 * - [ VC: Element Valid ]
6034 * - [ VC: Required Attribute ]
6035 * Then call xmlValidateOneAttribute() for each attribute present.
6037 * The ID/IDREF checkings are done separately
6039 * returns 1 if valid or 0 otherwise
6043 xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
6044 xmlNodePtr elem) {
6045 xmlElementPtr elemDecl = NULL;
6046 xmlElementContentPtr cont;
6047 xmlAttributePtr attr;
6048 xmlNodePtr child;
6049 int ret = 1, tmp;
6050 const xmlChar *name;
6051 int extsubset = 0;
6053 CHECK_DTD;
6055 if (elem == NULL) return(0);
6056 switch (elem->type) {
6057 case XML_ATTRIBUTE_NODE:
6058 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
6059 "Attribute element not expected\n", NULL, NULL ,NULL);
6060 return(0);
6061 case XML_TEXT_NODE:
6062 if (elem->children != NULL) {
6063 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
6064 "Text element has children !\n",
6065 NULL,NULL,NULL);
6066 return(0);
6068 if (elem->ns != NULL) {
6069 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
6070 "Text element has namespace !\n",
6071 NULL,NULL,NULL);
6072 return(0);
6074 if (elem->content == NULL) {
6075 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
6076 "Text element has no content !\n",
6077 NULL,NULL,NULL);
6078 return(0);
6080 return(1);
6081 case XML_XINCLUDE_START:
6082 case XML_XINCLUDE_END:
6083 return(1);
6084 case XML_CDATA_SECTION_NODE:
6085 case XML_ENTITY_REF_NODE:
6086 case XML_PI_NODE:
6087 case XML_COMMENT_NODE:
6088 return(1);
6089 case XML_ENTITY_NODE:
6090 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
6091 "Entity element not expected\n", NULL, NULL ,NULL);
6092 return(0);
6093 case XML_NOTATION_NODE:
6094 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
6095 "Notation element not expected\n", NULL, NULL ,NULL);
6096 return(0);
6097 case XML_DOCUMENT_NODE:
6098 case XML_DOCUMENT_TYPE_NODE:
6099 case XML_DOCUMENT_FRAG_NODE:
6100 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
6101 "Document element not expected\n", NULL, NULL ,NULL);
6102 return(0);
6103 case XML_HTML_DOCUMENT_NODE:
6104 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
6105 "HTML Document not expected\n", NULL, NULL ,NULL);
6106 return(0);
6107 case XML_ELEMENT_NODE:
6108 break;
6109 default:
6110 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
6111 "unknown element type\n", NULL, NULL ,NULL);
6112 return(0);
6116 * Fetch the declaration
6118 elemDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
6119 if (elemDecl == NULL)
6120 return(0);
6123 * If vstateNr is not zero that means continuous validation is
6124 * activated, do not try to check the content model at that level.
6126 if (ctxt->vstateNr == 0) {
6127 /* Check that the element content matches the definition */
6128 switch (elemDecl->etype) {
6129 case XML_ELEMENT_TYPE_UNDEFINED:
6130 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ELEM,
6131 "No declaration for element %s\n",
6132 elem->name, NULL, NULL);
6133 return(0);
6134 case XML_ELEMENT_TYPE_EMPTY:
6135 if (elem->children != NULL) {
6136 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_EMPTY,
6137 "Element %s was declared EMPTY this one has content\n",
6138 elem->name, NULL, NULL);
6139 ret = 0;
6141 break;
6142 case XML_ELEMENT_TYPE_ANY:
6143 /* I don't think anything is required then */
6144 break;
6145 case XML_ELEMENT_TYPE_MIXED:
6147 /* simple case of declared as #PCDATA */
6148 if ((elemDecl->content != NULL) &&
6149 (elemDecl->content->type == XML_ELEMENT_CONTENT_PCDATA)) {
6150 ret = xmlValidateOneCdataElement(ctxt, doc, elem);
6151 if (!ret) {
6152 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_PCDATA,
6153 "Element %s was declared #PCDATA but contains non text nodes\n",
6154 elem->name, NULL, NULL);
6156 break;
6158 child = elem->children;
6159 /* Hum, this start to get messy */
6160 while (child != NULL) {
6161 if (child->type == XML_ELEMENT_NODE) {
6162 name = child->name;
6163 if ((child->ns != NULL) && (child->ns->prefix != NULL)) {
6164 xmlChar fn[50];
6165 xmlChar *fullname;
6167 fullname = xmlBuildQName(child->name, child->ns->prefix,
6168 fn, 50);
6169 if (fullname == NULL)
6170 return(0);
6171 cont = elemDecl->content;
6172 while (cont != NULL) {
6173 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
6174 if (xmlStrEqual(cont->name, fullname))
6175 break;
6176 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
6177 (cont->c1 != NULL) &&
6178 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
6179 if (xmlStrEqual(cont->c1->name, fullname))
6180 break;
6181 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
6182 (cont->c1 == NULL) ||
6183 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
6184 xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT,
6185 "Internal: MIXED struct corrupted\n",
6186 NULL);
6187 break;
6189 cont = cont->c2;
6191 if ((fullname != fn) && (fullname != child->name))
6192 xmlFree(fullname);
6193 if (cont != NULL)
6194 goto child_ok;
6196 cont = elemDecl->content;
6197 while (cont != NULL) {
6198 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
6199 if (xmlStrEqual(cont->name, name)) break;
6200 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
6201 (cont->c1 != NULL) &&
6202 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
6203 if (xmlStrEqual(cont->c1->name, name)) break;
6204 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
6205 (cont->c1 == NULL) ||
6206 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
6207 xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT,
6208 "Internal: MIXED struct corrupted\n",
6209 NULL);
6210 break;
6212 cont = cont->c2;
6214 if (cont == NULL) {
6215 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_CHILD,
6216 "Element %s is not declared in %s list of possible children\n",
6217 name, elem->name, NULL);
6218 ret = 0;
6221 child_ok:
6222 child = child->next;
6224 break;
6225 case XML_ELEMENT_TYPE_ELEMENT:
6226 if ((doc->standalone == 1) && (extsubset == 1)) {
6228 * VC: Standalone Document Declaration
6229 * - element types with element content, if white space
6230 * occurs directly within any instance of those types.
6232 child = elem->children;
6233 while (child != NULL) {
6234 if (child->type == XML_TEXT_NODE) {
6235 const xmlChar *content = child->content;
6237 while (IS_BLANK_CH(*content))
6238 content++;
6239 if (*content == 0) {
6240 xmlErrValidNode(ctxt, elem,
6241 XML_DTD_STANDALONE_WHITE_SPACE,
6242 "standalone: %s declared in the external subset contains white spaces nodes\n",
6243 elem->name, NULL, NULL);
6244 ret = 0;
6245 break;
6248 child =child->next;
6251 child = elem->children;
6252 cont = elemDecl->content;
6253 tmp = xmlValidateElementContent(ctxt, child, elemDecl, 1, elem);
6254 if (tmp <= 0)
6255 ret = tmp;
6256 break;
6258 } /* not continuous */
6260 /* [ VC: Required Attribute ] */
6261 attr = elemDecl->attributes;
6262 while (attr != NULL) {
6263 if (attr->def == XML_ATTRIBUTE_REQUIRED) {
6264 int qualified = -1;
6266 if ((attr->prefix == NULL) &&
6267 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
6268 xmlNsPtr ns;
6270 ns = elem->nsDef;
6271 while (ns != NULL) {
6272 if (ns->prefix == NULL)
6273 goto found;
6274 ns = ns->next;
6276 } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
6277 xmlNsPtr ns;
6279 ns = elem->nsDef;
6280 while (ns != NULL) {
6281 if (xmlStrEqual(attr->name, ns->prefix))
6282 goto found;
6283 ns = ns->next;
6285 } else {
6286 xmlAttrPtr attrib;
6288 attrib = elem->properties;
6289 while (attrib != NULL) {
6290 if (xmlStrEqual(attrib->name, attr->name)) {
6291 if (attr->prefix != NULL) {
6292 xmlNsPtr nameSpace = attrib->ns;
6294 if (nameSpace == NULL)
6295 nameSpace = elem->ns;
6297 * qualified names handling is problematic, having a
6298 * different prefix should be possible but DTDs don't
6299 * allow to define the URI instead of the prefix :-(
6301 if (nameSpace == NULL) {
6302 if (qualified < 0)
6303 qualified = 0;
6304 } else if (!xmlStrEqual(nameSpace->prefix,
6305 attr->prefix)) {
6306 if (qualified < 1)
6307 qualified = 1;
6308 } else
6309 goto found;
6310 } else {
6312 * We should allow applications to define namespaces
6313 * for their application even if the DTD doesn't
6314 * carry one, otherwise, basically we would always
6315 * break.
6317 goto found;
6320 attrib = attrib->next;
6323 if (qualified == -1) {
6324 if (attr->prefix == NULL) {
6325 xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
6326 "Element %s does not carry attribute %s\n",
6327 elem->name, attr->name, NULL);
6328 ret = 0;
6329 } else {
6330 xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
6331 "Element %s does not carry attribute %s:%s\n",
6332 elem->name, attr->prefix,attr->name);
6333 ret = 0;
6335 } else if (qualified == 0) {
6336 xmlErrValidWarning(ctxt, elem, XML_DTD_NO_PREFIX,
6337 "Element %s required attribute %s:%s has no prefix\n",
6338 elem->name, attr->prefix, attr->name);
6339 } else if (qualified == 1) {
6340 xmlErrValidWarning(ctxt, elem, XML_DTD_DIFFERENT_PREFIX,
6341 "Element %s required attribute %s:%s has different prefix\n",
6342 elem->name, attr->prefix, attr->name);
6344 } else if (attr->def == XML_ATTRIBUTE_FIXED) {
6346 * Special tests checking #FIXED namespace declarations
6347 * have the right value since this is not done as an
6348 * attribute checking
6350 if ((attr->prefix == NULL) &&
6351 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
6352 xmlNsPtr ns;
6354 ns = elem->nsDef;
6355 while (ns != NULL) {
6356 if (ns->prefix == NULL) {
6357 if (!xmlStrEqual(attr->defaultValue, ns->href)) {
6358 xmlErrValidNode(ctxt, elem,
6359 XML_DTD_ELEM_DEFAULT_NAMESPACE,
6360 "Element %s namespace name for default namespace does not match the DTD\n",
6361 elem->name, NULL, NULL);
6362 ret = 0;
6364 goto found;
6366 ns = ns->next;
6368 } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
6369 xmlNsPtr ns;
6371 ns = elem->nsDef;
6372 while (ns != NULL) {
6373 if (xmlStrEqual(attr->name, ns->prefix)) {
6374 if (!xmlStrEqual(attr->defaultValue, ns->href)) {
6375 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
6376 "Element %s namespace name for %s does not match the DTD\n",
6377 elem->name, ns->prefix, NULL);
6378 ret = 0;
6380 goto found;
6382 ns = ns->next;
6386 found:
6387 attr = attr->nexth;
6389 return(ret);
6393 * xmlValidateRoot:
6394 * @ctxt: the validation context
6395 * @doc: a document instance
6397 * Try to validate a the root element
6398 * basically it does the following check as described by the
6399 * XML-1.0 recommendation:
6400 * - [ VC: Root Element Type ]
6401 * it doesn't try to recurse or apply other check to the element
6403 * returns 1 if valid or 0 otherwise
6407 xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6408 xmlNodePtr root;
6409 int ret;
6411 if (doc == NULL) return(0);
6413 root = xmlDocGetRootElement(doc);
6414 if ((root == NULL) || (root->name == NULL)) {
6415 xmlErrValid(ctxt, XML_DTD_NO_ROOT,
6416 "no root element\n", NULL);
6417 return(0);
6421 * When doing post validation against a separate DTD, those may
6422 * no internal subset has been generated
6424 if ((doc->intSubset != NULL) &&
6425 (doc->intSubset->name != NULL)) {
6427 * Check first the document root against the NQName
6429 if (!xmlStrEqual(doc->intSubset->name, root->name)) {
6430 if ((root->ns != NULL) && (root->ns->prefix != NULL)) {
6431 xmlChar fn[50];
6432 xmlChar *fullname;
6434 fullname = xmlBuildQName(root->name, root->ns->prefix, fn, 50);
6435 if (fullname == NULL) {
6436 xmlVErrMemory(ctxt, NULL);
6437 return(0);
6439 ret = xmlStrEqual(doc->intSubset->name, fullname);
6440 if ((fullname != fn) && (fullname != root->name))
6441 xmlFree(fullname);
6442 if (ret == 1)
6443 goto name_ok;
6445 if ((xmlStrEqual(doc->intSubset->name, BAD_CAST "HTML")) &&
6446 (xmlStrEqual(root->name, BAD_CAST "html")))
6447 goto name_ok;
6448 xmlErrValidNode(ctxt, root, XML_DTD_ROOT_NAME,
6449 "root and DTD name do not match '%s' and '%s'\n",
6450 root->name, doc->intSubset->name, NULL);
6451 return(0);
6454 name_ok:
6455 return(1);
6460 * xmlValidateElement:
6461 * @ctxt: the validation context
6462 * @doc: a document instance
6463 * @elem: an element instance
6465 * Try to validate the subtree under an element
6467 * returns 1 if valid or 0 otherwise
6471 xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr root) {
6472 xmlNodePtr elem;
6473 xmlAttrPtr attr;
6474 xmlNsPtr ns;
6475 const xmlChar *value;
6476 int ret = 1;
6478 if (root == NULL) return(0);
6480 CHECK_DTD;
6482 elem = root;
6483 while (1) {
6484 ret &= xmlValidateOneElement(ctxt, doc, elem);
6486 if (elem->type == XML_ELEMENT_NODE) {
6487 attr = elem->properties;
6488 while (attr != NULL) {
6489 value = xmlNodeListGetString(doc, attr->children, 0);
6490 ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
6491 if (value != NULL)
6492 xmlFree((char *)value);
6493 attr= attr->next;
6496 ns = elem->nsDef;
6497 while (ns != NULL) {
6498 if (elem->ns == NULL)
6499 ret &= xmlValidateOneNamespace(ctxt, doc, elem, NULL,
6500 ns, ns->href);
6501 else
6502 ret &= xmlValidateOneNamespace(ctxt, doc, elem,
6503 elem->ns->prefix, ns,
6504 ns->href);
6505 ns = ns->next;
6508 if (elem->children != NULL) {
6509 elem = elem->children;
6510 continue;
6514 while (1) {
6515 if (elem == root)
6516 goto done;
6517 if (elem->next != NULL)
6518 break;
6519 elem = elem->parent;
6521 elem = elem->next;
6524 done:
6525 return(ret);
6529 * xmlValidateRef:
6530 * @ref: A reference to be validated
6531 * @ctxt: Validation context
6532 * @name: Name of ID we are searching for
6535 static void
6536 xmlValidateRef(xmlRefPtr ref, xmlValidCtxtPtr ctxt,
6537 const xmlChar *name) {
6538 xmlAttrPtr id;
6539 xmlAttrPtr attr;
6541 if (ref == NULL)
6542 return;
6543 if ((ref->attr == NULL) && (ref->name == NULL))
6544 return;
6545 attr = ref->attr;
6546 if (attr == NULL) {
6547 xmlChar *dup, *str = NULL, *cur, save;
6549 dup = xmlStrdup(name);
6550 if (dup == NULL) {
6551 ctxt->valid = 0;
6552 return;
6554 cur = dup;
6555 while (*cur != 0) {
6556 str = cur;
6557 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
6558 save = *cur;
6559 *cur = 0;
6560 id = xmlGetID(ctxt->doc, str);
6561 if (id == NULL) {
6562 xmlErrValidNodeNr(ctxt, NULL, XML_DTD_UNKNOWN_ID,
6563 "attribute %s line %d references an unknown ID \"%s\"\n",
6564 ref->name, ref->lineno, str);
6565 ctxt->valid = 0;
6567 if (save == 0)
6568 break;
6569 *cur = save;
6570 while (IS_BLANK_CH(*cur)) cur++;
6572 xmlFree(dup);
6573 } else if (attr->atype == XML_ATTRIBUTE_IDREF) {
6574 id = xmlGetID(ctxt->doc, name);
6575 if (id == NULL) {
6576 xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
6577 "IDREF attribute %s references an unknown ID \"%s\"\n",
6578 attr->name, name, NULL);
6579 ctxt->valid = 0;
6581 } else if (attr->atype == XML_ATTRIBUTE_IDREFS) {
6582 xmlChar *dup, *str = NULL, *cur, save;
6584 dup = xmlStrdup(name);
6585 if (dup == NULL) {
6586 xmlVErrMemory(ctxt, "IDREFS split");
6587 ctxt->valid = 0;
6588 return;
6590 cur = dup;
6591 while (*cur != 0) {
6592 str = cur;
6593 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
6594 save = *cur;
6595 *cur = 0;
6596 id = xmlGetID(ctxt->doc, str);
6597 if (id == NULL) {
6598 xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
6599 "IDREFS attribute %s references an unknown ID \"%s\"\n",
6600 attr->name, str, NULL);
6601 ctxt->valid = 0;
6603 if (save == 0)
6604 break;
6605 *cur = save;
6606 while (IS_BLANK_CH(*cur)) cur++;
6608 xmlFree(dup);
6613 * xmlWalkValidateList:
6614 * @data: Contents of current link
6615 * @user: Value supplied by the user
6617 * Returns 0 to abort the walk or 1 to continue
6619 static int
6620 xmlWalkValidateList(const void *data, void *user)
6622 xmlValidateMemoPtr memo = (xmlValidateMemoPtr)user;
6623 xmlValidateRef((xmlRefPtr)data, memo->ctxt, memo->name);
6624 return 1;
6628 * xmlValidateCheckRefCallback:
6629 * @ref_list: List of references
6630 * @ctxt: Validation context
6631 * @name: Name of ID we are searching for
6634 static void
6635 xmlValidateCheckRefCallback(void *payload, void *data, const xmlChar *name) {
6636 xmlListPtr ref_list = (xmlListPtr) payload;
6637 xmlValidCtxtPtr ctxt = (xmlValidCtxtPtr) data;
6638 xmlValidateMemo memo;
6640 if (ref_list == NULL)
6641 return;
6642 memo.ctxt = ctxt;
6643 memo.name = name;
6645 xmlListWalk(ref_list, xmlWalkValidateList, &memo);
6650 * xmlValidateDocumentFinal:
6651 * @ctxt: the validation context
6652 * @doc: a document instance
6654 * Does the final step for the document validation once all the
6655 * incremental validation steps have been completed
6657 * basically it does the following checks described by the XML Rec
6659 * Check all the IDREF/IDREFS attributes definition for validity
6661 * returns 1 if valid or 0 otherwise
6665 xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6666 xmlRefTablePtr table;
6667 unsigned int save;
6669 if (ctxt == NULL)
6670 return(0);
6671 if (doc == NULL) {
6672 xmlErrValid(ctxt, XML_DTD_NO_DOC,
6673 "xmlValidateDocumentFinal: doc == NULL\n", NULL);
6674 return(0);
6677 /* trick to get correct line id report */
6678 save = ctxt->flags;
6679 ctxt->flags &= ~XML_VCTXT_USE_PCTXT;
6682 * Check all the NOTATION/NOTATIONS attributes
6685 * Check all the ENTITY/ENTITIES attributes definition for validity
6688 * Check all the IDREF/IDREFS attributes definition for validity
6690 table = (xmlRefTablePtr) doc->refs;
6691 ctxt->doc = doc;
6692 ctxt->valid = 1;
6693 xmlHashScan(table, xmlValidateCheckRefCallback, ctxt);
6695 ctxt->flags = save;
6696 return(ctxt->valid);
6700 * xmlValidateDtd:
6701 * @ctxt: the validation context
6702 * @doc: a document instance
6703 * @dtd: a dtd instance
6705 * Try to validate the document against the dtd instance
6707 * Basically it does check all the definitions in the DtD.
6708 * Note the the internal subset (if present) is de-coupled
6709 * (i.e. not used), which could give problems if ID or IDREF
6710 * is present.
6712 * returns 1 if valid or 0 otherwise
6716 xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
6717 int ret;
6718 xmlDtdPtr oldExt, oldInt;
6719 xmlNodePtr root;
6721 if (dtd == NULL) return(0);
6722 if (doc == NULL) return(0);
6723 oldExt = doc->extSubset;
6724 oldInt = doc->intSubset;
6725 doc->extSubset = dtd;
6726 doc->intSubset = NULL;
6727 ret = xmlValidateRoot(ctxt, doc);
6728 if (ret == 0) {
6729 doc->extSubset = oldExt;
6730 doc->intSubset = oldInt;
6731 return(ret);
6733 if (doc->ids != NULL) {
6734 xmlFreeIDTable(doc->ids);
6735 doc->ids = NULL;
6737 if (doc->refs != NULL) {
6738 xmlFreeRefTable(doc->refs);
6739 doc->refs = NULL;
6741 root = xmlDocGetRootElement(doc);
6742 ret = xmlValidateElement(ctxt, doc, root);
6743 ret &= xmlValidateDocumentFinal(ctxt, doc);
6744 doc->extSubset = oldExt;
6745 doc->intSubset = oldInt;
6746 return(ret);
6749 static void
6750 xmlValidateNotationCallback(void *payload, void *data,
6751 const xmlChar *name ATTRIBUTE_UNUSED) {
6752 xmlEntityPtr cur = (xmlEntityPtr) payload;
6753 xmlValidCtxtPtr ctxt = (xmlValidCtxtPtr) data;
6754 if (cur == NULL)
6755 return;
6756 if (cur->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
6757 xmlChar *notation = cur->content;
6759 if (notation != NULL) {
6760 int ret;
6762 ret = xmlValidateNotationUse(ctxt, cur->doc, notation);
6763 if (ret != 1) {
6764 ctxt->valid = 0;
6770 static void
6771 xmlValidateAttributeCallback(void *payload, void *data,
6772 const xmlChar *name ATTRIBUTE_UNUSED) {
6773 xmlAttributePtr cur = (xmlAttributePtr) payload;
6774 xmlValidCtxtPtr ctxt = (xmlValidCtxtPtr) data;
6775 int ret;
6776 xmlDocPtr doc;
6777 xmlElementPtr elem = NULL;
6779 if (cur == NULL)
6780 return;
6781 switch (cur->atype) {
6782 case XML_ATTRIBUTE_CDATA:
6783 case XML_ATTRIBUTE_ID:
6784 case XML_ATTRIBUTE_IDREF :
6785 case XML_ATTRIBUTE_IDREFS:
6786 case XML_ATTRIBUTE_NMTOKEN:
6787 case XML_ATTRIBUTE_NMTOKENS:
6788 case XML_ATTRIBUTE_ENUMERATION:
6789 break;
6790 case XML_ATTRIBUTE_ENTITY:
6791 case XML_ATTRIBUTE_ENTITIES:
6792 case XML_ATTRIBUTE_NOTATION:
6793 if (cur->defaultValue != NULL) {
6795 ret = xmlValidateAttributeValue2(ctxt, ctxt->doc, cur->name,
6796 cur->atype, cur->defaultValue);
6797 if ((ret == 0) && (ctxt->valid == 1))
6798 ctxt->valid = 0;
6800 if (cur->tree != NULL) {
6801 xmlEnumerationPtr tree = cur->tree;
6802 while (tree != NULL) {
6803 ret = xmlValidateAttributeValue2(ctxt, ctxt->doc,
6804 cur->name, cur->atype, tree->name);
6805 if ((ret == 0) && (ctxt->valid == 1))
6806 ctxt->valid = 0;
6807 tree = tree->next;
6811 if (cur->atype == XML_ATTRIBUTE_NOTATION) {
6812 doc = cur->doc;
6813 if (cur->elem == NULL) {
6814 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
6815 "xmlValidateAttributeCallback(%s): internal error\n",
6816 (const char *) cur->name);
6817 return;
6820 if (doc != NULL)
6821 elem = xmlGetDtdElementDesc(doc->intSubset, cur->elem);
6822 if ((elem == NULL) && (doc != NULL))
6823 elem = xmlGetDtdElementDesc(doc->extSubset, cur->elem);
6824 if ((elem == NULL) && (cur->parent != NULL) &&
6825 (cur->parent->type == XML_DTD_NODE))
6826 elem = xmlGetDtdElementDesc((xmlDtdPtr) cur->parent, cur->elem);
6827 if (elem == NULL) {
6828 xmlErrValidNode(ctxt, NULL, XML_DTD_UNKNOWN_ELEM,
6829 "attribute %s: could not find decl for element %s\n",
6830 cur->name, cur->elem, NULL);
6831 return;
6833 if (elem->etype == XML_ELEMENT_TYPE_EMPTY) {
6834 xmlErrValidNode(ctxt, NULL, XML_DTD_EMPTY_NOTATION,
6835 "NOTATION attribute %s declared for EMPTY element %s\n",
6836 cur->name, cur->elem, NULL);
6837 ctxt->valid = 0;
6843 * xmlValidateDtdFinal:
6844 * @ctxt: the validation context
6845 * @doc: a document instance
6847 * Does the final step for the dtds validation once all the
6848 * subsets have been parsed
6850 * basically it does the following checks described by the XML Rec
6851 * - check that ENTITY and ENTITIES type attributes default or
6852 * possible values matches one of the defined entities.
6853 * - check that NOTATION type attributes default or
6854 * possible values matches one of the defined notations.
6856 * returns 1 if valid or 0 if invalid and -1 if not well-formed
6860 xmlValidateDtdFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6861 xmlDtdPtr dtd;
6862 xmlAttributeTablePtr table;
6863 xmlEntitiesTablePtr entities;
6865 if ((doc == NULL) || (ctxt == NULL)) return(0);
6866 if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
6867 return(0);
6868 ctxt->doc = doc;
6869 ctxt->valid = 1;
6870 dtd = doc->intSubset;
6871 if ((dtd != NULL) && (dtd->attributes != NULL)) {
6872 table = (xmlAttributeTablePtr) dtd->attributes;
6873 xmlHashScan(table, xmlValidateAttributeCallback, ctxt);
6875 if ((dtd != NULL) && (dtd->entities != NULL)) {
6876 entities = (xmlEntitiesTablePtr) dtd->entities;
6877 xmlHashScan(entities, xmlValidateNotationCallback, ctxt);
6879 dtd = doc->extSubset;
6880 if ((dtd != NULL) && (dtd->attributes != NULL)) {
6881 table = (xmlAttributeTablePtr) dtd->attributes;
6882 xmlHashScan(table, xmlValidateAttributeCallback, ctxt);
6884 if ((dtd != NULL) && (dtd->entities != NULL)) {
6885 entities = (xmlEntitiesTablePtr) dtd->entities;
6886 xmlHashScan(entities, xmlValidateNotationCallback, ctxt);
6888 return(ctxt->valid);
6892 * xmlValidateDocument:
6893 * @ctxt: the validation context
6894 * @doc: a document instance
6896 * Try to validate the document instance
6898 * basically it does the all the checks described by the XML Rec
6899 * i.e. validates the internal and external subset (if present)
6900 * and validate the document tree.
6902 * returns 1 if valid or 0 otherwise
6906 xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
6907 int ret;
6908 xmlNodePtr root;
6910 if (doc == NULL)
6911 return(0);
6912 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
6913 xmlErrValid(ctxt, XML_DTD_NO_DTD,
6914 "no DTD found!\n", NULL);
6915 return(0);
6917 if ((doc->intSubset != NULL) && ((doc->intSubset->SystemID != NULL) ||
6918 (doc->intSubset->ExternalID != NULL)) && (doc->extSubset == NULL)) {
6919 xmlChar *sysID;
6920 if (doc->intSubset->SystemID != NULL) {
6921 sysID = xmlBuildURI(doc->intSubset->SystemID,
6922 doc->URL);
6923 if (sysID == NULL) {
6924 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
6925 "Could not build URI for external subset \"%s\"\n",
6926 (const char *) doc->intSubset->SystemID);
6927 return 0;
6929 } else
6930 sysID = NULL;
6931 doc->extSubset = xmlParseDTD(doc->intSubset->ExternalID,
6932 (const xmlChar *)sysID);
6933 if (sysID != NULL)
6934 xmlFree(sysID);
6935 if (doc->extSubset == NULL) {
6936 if (doc->intSubset->SystemID != NULL) {
6937 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
6938 "Could not load the external subset \"%s\"\n",
6939 (const char *) doc->intSubset->SystemID);
6940 } else {
6941 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
6942 "Could not load the external subset \"%s\"\n",
6943 (const char *) doc->intSubset->ExternalID);
6945 return(0);
6949 if (doc->ids != NULL) {
6950 xmlFreeIDTable(doc->ids);
6951 doc->ids = NULL;
6953 if (doc->refs != NULL) {
6954 xmlFreeRefTable(doc->refs);
6955 doc->refs = NULL;
6957 ret = xmlValidateDtdFinal(ctxt, doc);
6958 if (!xmlValidateRoot(ctxt, doc)) return(0);
6960 root = xmlDocGetRootElement(doc);
6961 ret &= xmlValidateElement(ctxt, doc, root);
6962 ret &= xmlValidateDocumentFinal(ctxt, doc);
6963 return(ret);
6966 /************************************************************************
6968 * Routines for dynamic validation editing *
6970 ************************************************************************/
6973 * xmlValidGetPotentialChildren:
6974 * @ctree: an element content tree
6975 * @names: an array to store the list of child names
6976 * @len: a pointer to the number of element in the list
6977 * @max: the size of the array
6979 * Build/extend a list of potential children allowed by the content tree
6981 * returns the number of element in the list, or -1 in case of error.
6985 xmlValidGetPotentialChildren(xmlElementContent *ctree,
6986 const xmlChar **names,
6987 int *len, int max) {
6988 int i;
6990 if ((ctree == NULL) || (names == NULL) || (len == NULL))
6991 return(-1);
6992 if (*len >= max) return(*len);
6994 switch (ctree->type) {
6995 case XML_ELEMENT_CONTENT_PCDATA:
6996 for (i = 0; i < *len;i++)
6997 if (xmlStrEqual(BAD_CAST "#PCDATA", names[i])) return(*len);
6998 names[(*len)++] = BAD_CAST "#PCDATA";
6999 break;
7000 case XML_ELEMENT_CONTENT_ELEMENT:
7001 for (i = 0; i < *len;i++)
7002 if (xmlStrEqual(ctree->name, names[i])) return(*len);
7003 names[(*len)++] = ctree->name;
7004 break;
7005 case XML_ELEMENT_CONTENT_SEQ:
7006 xmlValidGetPotentialChildren(ctree->c1, names, len, max);
7007 xmlValidGetPotentialChildren(ctree->c2, names, len, max);
7008 break;
7009 case XML_ELEMENT_CONTENT_OR:
7010 xmlValidGetPotentialChildren(ctree->c1, names, len, max);
7011 xmlValidGetPotentialChildren(ctree->c2, names, len, max);
7012 break;
7015 return(*len);
7019 * Dummy function to suppress messages while we try out valid elements
7021 static void XMLCDECL xmlNoValidityErr(void *ctx ATTRIBUTE_UNUSED,
7022 const char *msg ATTRIBUTE_UNUSED, ...) {
7023 return;
7027 * xmlValidGetValidElements:
7028 * @prev: an element to insert after
7029 * @next: an element to insert next
7030 * @names: an array to store the list of child names
7031 * @max: the size of the array
7033 * This function returns the list of authorized children to insert
7034 * within an existing tree while respecting the validity constraints
7035 * forced by the Dtd. The insertion point is defined using @prev and
7036 * @next in the following ways:
7037 * to insert before 'node': xmlValidGetValidElements(node->prev, node, ...
7038 * to insert next 'node': xmlValidGetValidElements(node, node->next, ...
7039 * to replace 'node': xmlValidGetValidElements(node->prev, node->next, ...
7040 * to prepend a child to 'node': xmlValidGetValidElements(NULL, node->childs,
7041 * to append a child to 'node': xmlValidGetValidElements(node->last, NULL, ...
7043 * pointers to the element names are inserted at the beginning of the array
7044 * and do not need to be freed.
7046 * returns the number of element in the list, or -1 in case of error. If
7047 * the function returns the value @max the caller is invited to grow the
7048 * receiving array and retry.
7052 xmlValidGetValidElements(xmlNode *prev, xmlNode *next, const xmlChar **names,
7053 int max) {
7054 xmlValidCtxt vctxt;
7055 int nb_valid_elements = 0;
7056 const xmlChar *elements[256]={0};
7057 int nb_elements = 0, i;
7058 const xmlChar *name;
7060 xmlNode *ref_node;
7061 xmlNode *parent;
7062 xmlNode *test_node;
7064 xmlNode *prev_next;
7065 xmlNode *next_prev;
7066 xmlNode *parent_childs;
7067 xmlNode *parent_last;
7069 xmlElement *element_desc;
7071 if (prev == NULL && next == NULL)
7072 return(-1);
7074 if (names == NULL) return(-1);
7075 if (max <= 0) return(-1);
7077 memset(&vctxt, 0, sizeof (xmlValidCtxt));
7078 vctxt.error = xmlNoValidityErr; /* this suppresses err/warn output */
7080 nb_valid_elements = 0;
7081 ref_node = prev ? prev : next;
7082 parent = ref_node->parent;
7085 * Retrieves the parent element declaration
7087 element_desc = xmlGetDtdElementDesc(parent->doc->intSubset,
7088 parent->name);
7089 if ((element_desc == NULL) && (parent->doc->extSubset != NULL))
7090 element_desc = xmlGetDtdElementDesc(parent->doc->extSubset,
7091 parent->name);
7092 if (element_desc == NULL) return(-1);
7095 * Do a backup of the current tree structure
7097 prev_next = prev ? prev->next : NULL;
7098 next_prev = next ? next->prev : NULL;
7099 parent_childs = parent->children;
7100 parent_last = parent->last;
7103 * Creates a dummy node and insert it into the tree
7105 test_node = xmlNewDocNode (ref_node->doc, NULL, BAD_CAST "<!dummy?>", NULL);
7106 if (test_node == NULL)
7107 return(-1);
7109 test_node->parent = parent;
7110 test_node->prev = prev;
7111 test_node->next = next;
7112 name = test_node->name;
7114 if (prev) prev->next = test_node;
7115 else parent->children = test_node;
7117 if (next) next->prev = test_node;
7118 else parent->last = test_node;
7121 * Insert each potential child node and check if the parent is
7122 * still valid
7124 nb_elements = xmlValidGetPotentialChildren(element_desc->content,
7125 elements, &nb_elements, 256);
7127 for (i = 0;i < nb_elements;i++) {
7128 test_node->name = elements[i];
7129 if (xmlValidateOneElement(&vctxt, parent->doc, parent)) {
7130 int j;
7132 for (j = 0; j < nb_valid_elements;j++)
7133 if (xmlStrEqual(elements[i], names[j])) break;
7134 names[nb_valid_elements++] = elements[i];
7135 if (nb_valid_elements >= max) break;
7140 * Restore the tree structure
7142 if (prev) prev->next = prev_next;
7143 if (next) next->prev = next_prev;
7144 parent->children = parent_childs;
7145 parent->last = parent_last;
7148 * Free up the dummy node
7150 test_node->name = name;
7151 xmlFreeNode(test_node);
7153 return(nb_valid_elements);
7155 #endif /* LIBXML_VALID_ENABLED */