blob: 1b7e6f65c13e38550fd19b216ad72a5e0c478f2f [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
2 * valid.c : part of the code use to do the DTD handling and the validity
3 * checking
4 *
5 * See Copyright for the status of this software.
6 *
7 * Daniel.Veillard@w3.org
8 */
9
10#ifdef WIN32
11#include "win32config.h"
12#else
13#include "config.h"
14#endif
15
16#include <stdio.h>
17#include <string.h>
18
19#ifdef HAVE_STDLIB_H
20#include <stdlib.h>
21#endif
22
23#include <libxml/xmlmemory.h>
24#include <libxml/hash.h>
25#include <libxml/valid.h>
26#include <libxml/parser.h>
27#include <libxml/parserInternals.h>
28#include <libxml/xmlerror.h>
29#include <libxml/list.h>
30
31/*
32 * Generic function for accessing stacks in the Validity Context
33 */
34
35#define PUSH_AND_POP(scope, type, name) \
36scope int name##VPush(xmlValidCtxtPtr ctxt, type value) { \
37 if (ctxt->name##Nr >= ctxt->name##Max) { \
38 ctxt->name##Max *= 2; \
39 ctxt->name##Tab = (type *) xmlRealloc(ctxt->name##Tab, \
40 ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \
41 if (ctxt->name##Tab == NULL) { \
42 xmlGenericError(xmlGenericErrorContext, \
43 "realloc failed !\n"); \
44 return(0); \
45 } \
46 } \
47 ctxt->name##Tab[ctxt->name##Nr] = value; \
48 ctxt->name = value; \
49 return(ctxt->name##Nr++); \
50} \
51scope type name##VPop(xmlValidCtxtPtr ctxt) { \
52 type ret; \
53 if (ctxt->name##Nr <= 0) return(0); \
54 ctxt->name##Nr--; \
55 if (ctxt->name##Nr > 0) \
56 ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \
57 else \
58 ctxt->name = NULL; \
59 ret = ctxt->name##Tab[ctxt->name##Nr]; \
60 ctxt->name##Tab[ctxt->name##Nr] = 0; \
61 return(ret); \
62} \
63
64PUSH_AND_POP(static, xmlNodePtr, node)
65
66/* #define DEBUG_VALID_ALGO */
67
68#ifdef DEBUG_VALID_ALGO
69void xmlValidPrintNodeList(xmlNodePtr cur) {
70 if (cur == NULL)
71 xmlGenericError(xmlGenericErrorContext, "null ");
72 while (cur != NULL) {
73 switch (cur->type) {
74 case XML_ELEMENT_NODE:
75 xmlGenericError(xmlGenericErrorContext, "%s ", cur->name);
76 break;
77 case XML_TEXT_NODE:
78 xmlGenericError(xmlGenericErrorContext, "text ");
79 break;
80 case XML_CDATA_SECTION_NODE:
81 xmlGenericError(xmlGenericErrorContext, "cdata ");
82 break;
83 case XML_ENTITY_REF_NODE:
84 xmlGenericError(xmlGenericErrorContext, "&%s; ", cur->name);
85 break;
86 case XML_PI_NODE:
87 xmlGenericError(xmlGenericErrorContext, "pi(%s) ", cur->name);
88 break;
89 case XML_COMMENT_NODE:
90 xmlGenericError(xmlGenericErrorContext, "comment ");
91 break;
92 case XML_ATTRIBUTE_NODE:
93 xmlGenericError(xmlGenericErrorContext, "?attr? ");
94 break;
95 case XML_ENTITY_NODE:
96 xmlGenericError(xmlGenericErrorContext, "?ent? ");
97 break;
98 case XML_DOCUMENT_NODE:
99 xmlGenericError(xmlGenericErrorContext, "?doc? ");
100 break;
101 case XML_DOCUMENT_TYPE_NODE:
102 xmlGenericError(xmlGenericErrorContext, "?doctype? ");
103 break;
104 case XML_DOCUMENT_FRAG_NODE:
105 xmlGenericError(xmlGenericErrorContext, "?frag? ");
106 break;
107 case XML_NOTATION_NODE:
108 xmlGenericError(xmlGenericErrorContext, "?nota? ");
109 break;
110 case XML_HTML_DOCUMENT_NODE:
111 xmlGenericError(xmlGenericErrorContext, "?html? ");
112 break;
113 case XML_DTD_NODE:
114 xmlGenericError(xmlGenericErrorContext, "?dtd? ");
115 break;
116 case XML_ELEMENT_DECL:
117 xmlGenericError(xmlGenericErrorContext, "?edecl? ");
118 break;
119 case XML_ATTRIBUTE_DECL:
120 xmlGenericError(xmlGenericErrorContext, "?adecl? ");
121 break;
122 case XML_ENTITY_DECL:
123 xmlGenericError(xmlGenericErrorContext, "?entdecl? ");
124 break;
125 }
126 cur = cur->next;
127 }
128}
129
130void xmlValidDebug(xmlNodePtr cur, xmlElementContentPtr cont) {
131 char expr[1000];
132
133 expr[0] = 0;
134 xmlGenericError(xmlGenericErrorContext, "valid: ");
135 xmlValidPrintNodeList(cur);
136 xmlGenericError(xmlGenericErrorContext, "against ");
137 xmlSprintfElementContent(expr, cont, 0);
138 xmlGenericError(xmlGenericErrorContext, "%s\n", expr);
139}
140
141#define DEBUG_VALID_STATE(n,c) xmlValidDebug(n,c);
142#else
143#define DEBUG_VALID_STATE(n,c)
144#endif
145
146/* TODO: use hash table for accesses to elem and attribute dedinitions */
147
148#define VERROR \
149 if ((ctxt != NULL) && (ctxt->error != NULL)) ctxt->error
150
151#define VWARNING \
152 if ((ctxt != NULL) && (ctxt->warning != NULL)) ctxt->warning
153
154#define CHECK_DTD \
155 if (doc == NULL) return(0); \
156 else if ((doc->intSubset == NULL) && \
157 (doc->extSubset == NULL)) return(0)
158
159xmlElementPtr xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name);
160xmlAttributePtr xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem);
161
162/************************************************************************
163 * *
164 * QName handling helper *
165 * *
166 ************************************************************************/
167
168/**
169 * xmlSplitQName2:
170 * @name: an XML parser context
171 * @prefix: a xmlChar **
172 *
173 * parse an XML qualified name string
174 *
175 * [NS 5] QName ::= (Prefix ':')? LocalPart
176 *
177 * [NS 6] Prefix ::= NCName
178 *
179 * [NS 7] LocalPart ::= NCName
180 *
181 * Returns NULL if not a QName, otherwise the local part, and prefix
182 * is updated to get the Prefix if any.
183 */
184
185xmlChar *
186xmlSplitQName2(const xmlChar *name, xmlChar **prefix) {
187 int len = 0;
188 xmlChar *ret = NULL;
189
190 *prefix = NULL;
191
192 /* xml: prefix is not really a namespace */
193 if ((name[0] == 'x') && (name[1] == 'm') &&
194 (name[2] == 'l') && (name[3] == ':'))
195 return(NULL);
196
197 /* nasty but valid */
198 if (name[0] == ':')
199 return(NULL);
200
201 /*
202 * we are not trying to validate but just to cut, and yes it will
203 * work even if this is as set of UTF-8 encoded chars
204 */
205 while ((name[len] != 0) && (name[len] != ':'))
206 len++;
207
208 if (name[len] == 0)
209 return(NULL);
210
211 *prefix = xmlStrndup(name, len);
212 ret = xmlStrdup(&name[len + 1]);
213
214 return(ret);
215}
216
217/****************************************************************
218 * *
219 * Util functions for data allocation/deallocation *
220 * *
221 ****************************************************************/
222
223/**
224 * xmlNewElementContent:
225 * @name: the subelement name or NULL
226 * @type: the type of element content decl
227 *
228 * Allocate an element content structure.
229 *
230 * Returns NULL if not, othervise the new element content structure
231 */
232xmlElementContentPtr
233xmlNewElementContent(xmlChar *name, xmlElementContentType type) {
234 xmlElementContentPtr ret;
235
236 switch(type) {
237 case XML_ELEMENT_CONTENT_ELEMENT:
238 if (name == NULL) {
239 xmlGenericError(xmlGenericErrorContext,
240 "xmlNewElementContent : name == NULL !\n");
241 }
242 break;
243 case XML_ELEMENT_CONTENT_PCDATA:
244 case XML_ELEMENT_CONTENT_SEQ:
245 case XML_ELEMENT_CONTENT_OR:
246 if (name != NULL) {
247 xmlGenericError(xmlGenericErrorContext,
248 "xmlNewElementContent : name != NULL !\n");
249 }
250 break;
251 default:
252 xmlGenericError(xmlGenericErrorContext,
253 "xmlNewElementContent: unknown type %d\n", type);
254 return(NULL);
255 }
256 ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
257 if (ret == NULL) {
258 xmlGenericError(xmlGenericErrorContext,
259 "xmlNewElementContent : out of memory!\n");
260 return(NULL);
261 }
262 ret->type = type;
263 ret->ocur = XML_ELEMENT_CONTENT_ONCE;
264 if (name != NULL)
265 ret->name = xmlStrdup(name);
266 else
267 ret->name = NULL;
268 ret->c1 = ret->c2 = NULL;
269 return(ret);
270}
271
272/**
273 * xmlCopyElementContent:
274 * @content: An element content pointer.
275 *
276 * Build a copy of an element content description.
277 *
278 * Returns the new xmlElementContentPtr or NULL in case of error.
279 */
280xmlElementContentPtr
281xmlCopyElementContent(xmlElementContentPtr cur) {
282 xmlElementContentPtr ret;
283
284 if (cur == NULL) return(NULL);
285 ret = xmlNewElementContent((xmlChar *) cur->name, cur->type);
286 if (ret == NULL) {
287 xmlGenericError(xmlGenericErrorContext,
288 "xmlCopyElementContent : out of memory\n");
289 return(NULL);
290 }
291 ret->ocur = cur->ocur;
292 if (cur->c1 != NULL) ret->c1 = xmlCopyElementContent(cur->c1);
293 if (cur->c2 != NULL) ret->c2 = xmlCopyElementContent(cur->c2);
294 return(ret);
295}
296
297/**
298 * xmlFreeElementContent:
299 * @cur: the element content tree to free
300 *
301 * Free an element content structure. This is a recursive call !
302 */
303void
304xmlFreeElementContent(xmlElementContentPtr cur) {
305 if (cur == NULL) return;
306 switch (cur->type) {
307 case XML_ELEMENT_CONTENT_PCDATA:
308 case XML_ELEMENT_CONTENT_ELEMENT:
309 case XML_ELEMENT_CONTENT_SEQ:
310 case XML_ELEMENT_CONTENT_OR:
311 break;
312 default:
313 xmlGenericError(xmlGenericErrorContext,
314 "xmlFreeElementContent : type %d\n", cur->type);
315 return;
316 }
317 if (cur->c1 != NULL) xmlFreeElementContent(cur->c1);
318 if (cur->c2 != NULL) xmlFreeElementContent(cur->c2);
319 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
320 memset(cur, -1, sizeof(xmlElementContent));
321 xmlFree(cur);
322}
323
324/**
325 * xmlDumpElementContent:
326 * @buf: An XML buffer
327 * @content: An element table
328 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
329 *
330 * This will dump the content of the element table as an XML DTD definition
331 */
332void
333xmlDumpElementContent(xmlBufferPtr buf, xmlElementContentPtr content, int glob) {
334 if (content == NULL) return;
335
336 if (glob) xmlBufferWriteChar(buf, "(");
337 switch (content->type) {
338 case XML_ELEMENT_CONTENT_PCDATA:
339 xmlBufferWriteChar(buf, "#PCDATA");
340 break;
341 case XML_ELEMENT_CONTENT_ELEMENT:
342 xmlBufferWriteCHAR(buf, content->name);
343 break;
344 case XML_ELEMENT_CONTENT_SEQ:
345 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
346 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
347 xmlDumpElementContent(buf, content->c1, 1);
348 else
349 xmlDumpElementContent(buf, content->c1, 0);
350 xmlBufferWriteChar(buf, " , ");
351 if (content->c2->type == XML_ELEMENT_CONTENT_OR)
352 xmlDumpElementContent(buf, content->c2, 1);
353 else
354 xmlDumpElementContent(buf, content->c2, 0);
355 break;
356 case XML_ELEMENT_CONTENT_OR:
357 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
358 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
359 xmlDumpElementContent(buf, content->c1, 1);
360 else
361 xmlDumpElementContent(buf, content->c1, 0);
362 xmlBufferWriteChar(buf, " | ");
363 if (content->c2->type == XML_ELEMENT_CONTENT_SEQ)
364 xmlDumpElementContent(buf, content->c2, 1);
365 else
366 xmlDumpElementContent(buf, content->c2, 0);
367 break;
368 default:
369 xmlGenericError(xmlGenericErrorContext,
370 "xmlDumpElementContent: unknown type %d\n",
371 content->type);
372 }
373 if (glob)
374 xmlBufferWriteChar(buf, ")");
375 switch (content->ocur) {
376 case XML_ELEMENT_CONTENT_ONCE:
377 break;
378 case XML_ELEMENT_CONTENT_OPT:
379 xmlBufferWriteChar(buf, "?");
380 break;
381 case XML_ELEMENT_CONTENT_MULT:
382 xmlBufferWriteChar(buf, "*");
383 break;
384 case XML_ELEMENT_CONTENT_PLUS:
385 xmlBufferWriteChar(buf, "+");
386 break;
387 }
388}
389
390/**
391 * xmlSprintfElementContent:
392 * @buf: an output buffer
393 * @content: An element table
394 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
395 *
396 * This will dump the content of the element content definition
397 * Intended just for the debug routine
398 */
399void
400xmlSprintfElementContent(char *buf, xmlElementContentPtr content, int glob) {
401 if (content == NULL) return;
402 if (glob) strcat(buf, "(");
403 switch (content->type) {
404 case XML_ELEMENT_CONTENT_PCDATA:
405 strcat(buf, "#PCDATA");
406 break;
407 case XML_ELEMENT_CONTENT_ELEMENT:
408 strcat(buf, (char *) content->name);
409 break;
410 case XML_ELEMENT_CONTENT_SEQ:
411 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
412 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
413 xmlSprintfElementContent(buf, content->c1, 1);
414 else
415 xmlSprintfElementContent(buf, content->c1, 0);
416 strcat(buf, " , ");
417 if (content->c2->type == XML_ELEMENT_CONTENT_OR)
418 xmlSprintfElementContent(buf, content->c2, 1);
419 else
420 xmlSprintfElementContent(buf, content->c2, 0);
421 break;
422 case XML_ELEMENT_CONTENT_OR:
423 if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
424 (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
425 xmlSprintfElementContent(buf, content->c1, 1);
426 else
427 xmlSprintfElementContent(buf, content->c1, 0);
428 strcat(buf, " | ");
429 if (content->c2->type == XML_ELEMENT_CONTENT_SEQ)
430 xmlSprintfElementContent(buf, content->c2, 1);
431 else
432 xmlSprintfElementContent(buf, content->c2, 0);
433 break;
434 }
435 if (glob)
436 strcat(buf, ")");
437 switch (content->ocur) {
438 case XML_ELEMENT_CONTENT_ONCE:
439 break;
440 case XML_ELEMENT_CONTENT_OPT:
441 strcat(buf, "?");
442 break;
443 case XML_ELEMENT_CONTENT_MULT:
444 strcat(buf, "*");
445 break;
446 case XML_ELEMENT_CONTENT_PLUS:
447 strcat(buf, "+");
448 break;
449 }
450}
451
452/****************************************************************
453 * *
454 * Registration of DTD declarations *
455 * *
456 ****************************************************************/
457
458/**
459 * xmlCreateElementTable:
460 *
461 * create and initialize an empty element hash table.
462 *
463 * Returns the xmlElementTablePtr just created or NULL in case of error.
464 */
465xmlElementTablePtr
466xmlCreateElementTable(void) {
467 return(xmlHashCreate(0));
468}
469
470/**
471 * xmlFreeElement:
472 * @elem: An element
473 *
474 * Deallocate the memory used by an element definition
475 */
476void
477xmlFreeElement(xmlElementPtr elem) {
478 if (elem == NULL) return;
479 xmlUnlinkNode((xmlNodePtr) elem);
480 xmlFreeElementContent(elem->content);
481 if (elem->name != NULL)
482 xmlFree((xmlChar *) elem->name);
483 if (elem->prefix != NULL)
484 xmlFree((xmlChar *) elem->prefix);
485 memset(elem, -1, sizeof(xmlElement));
486 xmlFree(elem);
487}
488
489
490/**
491 * xmlAddElementDecl:
492 * @ctxt: the validation context
493 * @dtd: pointer to the DTD
494 * @name: the entity name
495 * @type: the element type
496 * @content: the element content tree or NULL
497 *
498 * Register a new element declaration
499 *
500 * Returns NULL if not, othervise the entity
501 */
502xmlElementPtr
503xmlAddElementDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name,
504 xmlElementTypeVal type,
505 xmlElementContentPtr content) {
506 xmlElementPtr ret;
507 xmlElementTablePtr table;
508 xmlChar *ns, *uqname;
509
510 if (dtd == NULL) {
511 xmlGenericError(xmlGenericErrorContext,
512 "xmlAddElementDecl: dtd == NULL\n");
513 return(NULL);
514 }
515 if (name == NULL) {
516 xmlGenericError(xmlGenericErrorContext,
517 "xmlAddElementDecl: name == NULL\n");
518 return(NULL);
519 }
520 switch (type) {
521 case XML_ELEMENT_TYPE_EMPTY:
522 if (content != NULL) {
523 xmlGenericError(xmlGenericErrorContext,
524 "xmlAddElementDecl: content != NULL for EMPTY\n");
525 return(NULL);
526 }
527 break;
528 case XML_ELEMENT_TYPE_ANY:
529 if (content != NULL) {
530 xmlGenericError(xmlGenericErrorContext,
531 "xmlAddElementDecl: content != NULL for ANY\n");
532 return(NULL);
533 }
534 break;
535 case XML_ELEMENT_TYPE_MIXED:
536 if (content == NULL) {
537 xmlGenericError(xmlGenericErrorContext,
538 "xmlAddElementDecl: content == NULL for MIXED\n");
539 return(NULL);
540 }
541 break;
542 case XML_ELEMENT_TYPE_ELEMENT:
543 if (content == NULL) {
544 xmlGenericError(xmlGenericErrorContext,
545 "xmlAddElementDecl: content == NULL for ELEMENT\n");
546 return(NULL);
547 }
548 break;
549 default:
550 xmlGenericError(xmlGenericErrorContext,
551 "xmlAddElementDecl: unknown type %d\n", type);
552 return(NULL);
553 }
554
555 /*
556 * check if name is a QName
557 */
558 uqname = xmlSplitQName2(name, &ns);
559 if (uqname != NULL)
560 name = uqname;
561
562 /*
563 * Create the Element table if needed.
564 */
565 table = (xmlElementTablePtr) dtd->elements;
566 if (table == NULL) {
567 table = xmlCreateElementTable();
568 dtd->elements = (void *) table;
569 }
570 if (table == NULL) {
571 xmlGenericError(xmlGenericErrorContext,
572 "xmlAddElementDecl: Table creation failed!\n");
573 return(NULL);
574 }
575
576 ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
577 if (ret == NULL) {
578 xmlGenericError(xmlGenericErrorContext,
579 "xmlAddElementDecl: out of memory\n");
580 return(NULL);
581 }
582 memset(ret, 0, sizeof(xmlElement));
583 ret->type = XML_ELEMENT_DECL;
584
585 /*
586 * fill the structure.
587 */
588 ret->etype = type;
589 ret->name = xmlStrdup(name);
590 ret->prefix = ns;
591 ret->content = xmlCopyElementContent(content);
592 ret->attributes = xmlScanAttributeDecl(dtd, name);
593
594 /*
595 * Validity Check:
596 * Insertion must not fail
597 */
598 if (xmlHashAddEntry2(table, name, ns, ret)) {
599 /*
600 * The element is already defined in this Dtd.
601 */
602 VERROR(ctxt->userData, "Redefinition of element %s\n", name);
603 xmlFreeElement(ret);
604 if (uqname != NULL)
605 xmlFree(uqname);
606 return(NULL);
607 }
608
609 /*
610 * Link it to the Dtd
611 */
612 ret->parent = dtd;
613 ret->doc = dtd->doc;
614 if (dtd->last == NULL) {
615 dtd->children = dtd->last = (xmlNodePtr) ret;
616 } else {
617 dtd->last->next = (xmlNodePtr) ret;
618 ret->prev = dtd->last;
619 dtd->last = (xmlNodePtr) ret;
620 }
621 if (uqname != NULL)
622 xmlFree(uqname);
623 return(ret);
624}
625
626/**
627 * xmlFreeElementTable:
628 * @table: An element table
629 *
630 * Deallocate the memory used by an element hash table.
631 */
632void
633xmlFreeElementTable(xmlElementTablePtr table) {
634 xmlHashFree(table, (xmlHashDeallocator) xmlFreeElement);
635}
636
637/**
638 * xmlCopyElement:
639 * @elem: An element
640 *
641 * Build a copy of an element.
642 *
643 * Returns the new xmlElementPtr or NULL in case of error.
644 */
645xmlElementPtr
646xmlCopyElement(xmlElementPtr elem) {
647 xmlElementPtr cur;
648
649 cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
650 if (cur == NULL) {
651 xmlGenericError(xmlGenericErrorContext,
652 "xmlCopyElement: out of memory !\n");
653 return(NULL);
654 }
655 memset(cur, 0, sizeof(xmlElement));
656 cur->type = XML_ELEMENT_DECL;
657 cur->etype = elem->etype;
658 if (elem->name != NULL)
659 cur->name = xmlStrdup(elem->name);
660 else
661 cur->name = NULL;
662 if (elem->prefix != NULL)
663 cur->prefix = xmlStrdup(elem->prefix);
664 else
665 cur->prefix = NULL;
666 cur->content = xmlCopyElementContent(elem->content);
667 /* TODO : rebuild the attribute list on the copy */
668 cur->attributes = NULL;
669 return(cur);
670}
671
672/**
673 * xmlCopyElementTable:
674 * @table: An element table
675 *
676 * Build a copy of an element table.
677 *
678 * Returns the new xmlElementTablePtr or NULL in case of error.
679 */
680xmlElementTablePtr
681xmlCopyElementTable(xmlElementTablePtr table) {
682 return((xmlElementTablePtr) xmlHashCopy(table,
683 (xmlHashCopier) xmlCopyElement));
684}
685
686/**
687 * xmlDumpElementDecl:
688 * @buf: the XML buffer output
689 * @elem: An element table
690 *
691 * This will dump the content of the element declaration as an XML
692 * DTD definition
693 */
694void
695xmlDumpElementDecl(xmlBufferPtr buf, xmlElementPtr elem) {
696 switch (elem->etype) {
697 case XML_ELEMENT_TYPE_EMPTY:
698 xmlBufferWriteChar(buf, "<!ELEMENT ");
699 xmlBufferWriteCHAR(buf, elem->name);
700 xmlBufferWriteChar(buf, " EMPTY>\n");
701 break;
702 case XML_ELEMENT_TYPE_ANY:
703 xmlBufferWriteChar(buf, "<!ELEMENT ");
704 xmlBufferWriteCHAR(buf, elem->name);
705 xmlBufferWriteChar(buf, " ANY>\n");
706 break;
707 case XML_ELEMENT_TYPE_MIXED:
708 xmlBufferWriteChar(buf, "<!ELEMENT ");
709 xmlBufferWriteCHAR(buf, elem->name);
710 xmlBufferWriteChar(buf, " ");
711 xmlDumpElementContent(buf, elem->content, 1);
712 xmlBufferWriteChar(buf, ">\n");
713 break;
714 case XML_ELEMENT_TYPE_ELEMENT:
715 xmlBufferWriteChar(buf, "<!ELEMENT ");
716 xmlBufferWriteCHAR(buf, elem->name);
717 xmlBufferWriteChar(buf, " ");
718 xmlDumpElementContent(buf, elem->content, 1);
719 xmlBufferWriteChar(buf, ">\n");
720 break;
721 default:
722 xmlGenericError(xmlGenericErrorContext,
723 "xmlDumpElementDecl: internal: unknown type %d\n",
724 elem->etype);
725 }
726}
727
728/**
729 * xmlDumpElementTable:
730 * @buf: the XML buffer output
731 * @table: An element table
732 *
733 * This will dump the content of the element table as an XML DTD definition
734 */
735void
736xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) {
737 xmlHashScan(table, (xmlHashScanner) xmlDumpElementDecl, buf);
738}
739
740/**
741 * xmlCreateEnumeration:
742 * @name: the enumeration name or NULL
743 *
744 * create and initialize an enumeration attribute node.
745 *
746 * Returns the xmlEnumerationPtr just created or NULL in case
747 * of error.
748 */
749xmlEnumerationPtr
750xmlCreateEnumeration(xmlChar *name) {
751 xmlEnumerationPtr ret;
752
753 ret = (xmlEnumerationPtr) xmlMalloc(sizeof(xmlEnumeration));
754 if (ret == NULL) {
755 xmlGenericError(xmlGenericErrorContext,
756 "xmlCreateEnumeration : xmlMalloc(%ld) failed\n",
757 (long)sizeof(xmlEnumeration));
758 return(NULL);
759 }
760 memset(ret, 0, sizeof(xmlEnumeration));
761
762 if (name != NULL)
763 ret->name = xmlStrdup(name);
764 return(ret);
765}
766
767/**
768 * xmlFreeEnumeration:
769 * @cur: the tree to free.
770 *
771 * free an enumeration attribute node (recursive).
772 */
773void
774xmlFreeEnumeration(xmlEnumerationPtr cur) {
775 if (cur == NULL) return;
776
777 if (cur->next != NULL) xmlFreeEnumeration(cur->next);
778
779 if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
780 memset(cur, -1, sizeof(xmlEnumeration));
781 xmlFree(cur);
782}
783
784/**
785 * xmlCopyEnumeration:
786 * @cur: the tree to copy.
787 *
788 * Copy an enumeration attribute node (recursive).
789 *
790 * Returns the xmlEnumerationPtr just created or NULL in case
791 * of error.
792 */
793xmlEnumerationPtr
794xmlCopyEnumeration(xmlEnumerationPtr cur) {
795 xmlEnumerationPtr ret;
796
797 if (cur == NULL) return(NULL);
798 ret = xmlCreateEnumeration((xmlChar *) cur->name);
799
800 if (cur->next != NULL) ret->next = xmlCopyEnumeration(cur->next);
801 else ret->next = NULL;
802
803 return(ret);
804}
805
806/**
807 * xmlDumpEnumeration:
808 * @buf: the XML buffer output
809 * @enum: An enumeration
810 *
811 * This will dump the content of the enumeration
812 */
813void
814xmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) {
815 if (cur == NULL) return;
816
817 xmlBufferWriteCHAR(buf, cur->name);
818 if (cur->next == NULL)
819 xmlBufferWriteChar(buf, ")");
820 else {
821 xmlBufferWriteChar(buf, " | ");
822 xmlDumpEnumeration(buf, cur->next);
823 }
824}
825
826/**
827 * xmlCreateAttributeTable:
828 *
829 * create and initialize an empty attribute hash table.
830 *
831 * Returns the xmlAttributeTablePtr just created or NULL in case
832 * of error.
833 */
834xmlAttributeTablePtr
835xmlCreateAttributeTable(void) {
836 return(xmlHashCreate(0));
837}
838
839/**
840 * xmlScanAttributeDeclCallback:
841 * @attr: the attribute decl
842 * @list: the list to update
843 *
844 * Callback called by xmlScanAttributeDecl when a new attribute
845 * has to be entered in the list.
846 */
847void
848xmlScanAttributeDeclCallback(xmlAttributePtr attr, xmlAttributePtr *list,
849 const xmlChar* name) {
850 attr->nexth = *list;
851 *list = attr;
852}
853
854/**
855 * xmlScanAttributeDecl:
856 * @dtd: pointer to the DTD
857 * @elem: the element name
858 *
859 * When inserting a new element scan the DtD for existing attributes
860 * for taht element and initialize the Attribute chain
861 *
862 * Returns the pointer to the first attribute decl in the chain,
863 * possibly NULL.
864 */
865xmlAttributePtr
866xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem) {
867 xmlAttributePtr ret = NULL;
868 xmlAttributeTablePtr table;
869
870 if (dtd == NULL) {
871 xmlGenericError(xmlGenericErrorContext,
872 "xmlScanAttributeDecl: dtd == NULL\n");
873 return(NULL);
874 }
875 if (elem == NULL) {
876 xmlGenericError(xmlGenericErrorContext,
877 "xmlScanAttributeDecl: elem == NULL\n");
878 return(NULL);
879 }
880 table = (xmlAttributeTablePtr) dtd->attributes;
881 if (table == NULL)
882 return(NULL);
883
884 /* WRONG !!! */
885 xmlHashScan3(table, NULL, NULL, elem,
886 (xmlHashScanner) xmlScanAttributeDeclCallback, &ret);
887 return(ret);
888}
889
890/**
891 * xmlScanIDAttributeDecl:
892 * @ctxt: the validation context
893 * @elem: the element name
894 *
895 * Verify that the element don't have too many ID attributes
896 * declared.
897 *
898 * Returns the number of ID attributes found.
899 */
900int
901xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
902 xmlAttributePtr cur;
903 int ret = 0;
904
905 if (elem == NULL) return(0);
906 cur = elem->attributes;
907 while (cur != NULL) {
908 if (cur->atype == XML_ATTRIBUTE_ID) {
909 ret ++;
910 if (ret > 1)
911 VERROR(ctxt->userData,
912 "Element %s has too may ID attributes defined : %s\n",
913 elem->name, cur->name);
914 }
915 cur = cur->nexth;
916 }
917 return(ret);
918}
919
920/**
921 * xmlFreeAttribute:
922 * @elem: An attribute
923 *
924 * Deallocate the memory used by an attribute definition
925 */
926void
927xmlFreeAttribute(xmlAttributePtr attr) {
928 if (attr == NULL) return;
929 xmlUnlinkNode((xmlNodePtr) attr);
930 if (attr->tree != NULL)
931 xmlFreeEnumeration(attr->tree);
932 if (attr->elem != NULL)
933 xmlFree((xmlChar *) attr->elem);
934 if (attr->name != NULL)
935 xmlFree((xmlChar *) attr->name);
936 if (attr->defaultValue != NULL)
937 xmlFree((xmlChar *) attr->defaultValue);
938 if (attr->prefix != NULL)
939 xmlFree((xmlChar *) attr->prefix);
940 memset(attr, -1, sizeof(xmlAttribute));
941 xmlFree(attr);
942}
943
944
945/**
946 * xmlAddAttributeDecl:
947 * @ctxt: the validation context
948 * @dtd: pointer to the DTD
949 * @elem: the element name
950 * @name: the attribute name
951 * @ns: the attribute namespace prefix
952 * @type: the attribute type
953 * @def: the attribute default type
954 * @defaultValue: the attribute default value
955 * @tree: if it's an enumeration, the associated list
956 *
957 * Register a new attribute declaration
958 * Note that @tree becomes the ownership of the DTD
959 *
960 * Returns NULL if not new, othervise the attribute decl
961 */
962xmlAttributePtr
963xmlAddAttributeDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *elem,
964 const xmlChar *name, const xmlChar *ns,
965 xmlAttributeType type, xmlAttributeDefault def,
966 const xmlChar *defaultValue, xmlEnumerationPtr tree) {
967 xmlAttributePtr ret;
968 xmlAttributeTablePtr table;
969 xmlElementPtr elemDef;
970
971 if (dtd == NULL) {
972 xmlGenericError(xmlGenericErrorContext,
973 "xmlAddAttributeDecl: dtd == NULL\n");
974 xmlFreeEnumeration(tree);
975 return(NULL);
976 }
977 if (name == NULL) {
978 xmlGenericError(xmlGenericErrorContext,
979 "xmlAddAttributeDecl: name == NULL\n");
980 xmlFreeEnumeration(tree);
981 return(NULL);
982 }
983 if (elem == NULL) {
984 xmlGenericError(xmlGenericErrorContext,
985 "xmlAddAttributeDecl: elem == NULL\n");
986 xmlFreeEnumeration(tree);
987 return(NULL);
988 }
989 /*
990 * Check the type and possibly the default value.
991 */
992 switch (type) {
993 case XML_ATTRIBUTE_CDATA:
994 break;
995 case XML_ATTRIBUTE_ID:
996 break;
997 case XML_ATTRIBUTE_IDREF:
998 break;
999 case XML_ATTRIBUTE_IDREFS:
1000 break;
1001 case XML_ATTRIBUTE_ENTITY:
1002 break;
1003 case XML_ATTRIBUTE_ENTITIES:
1004 break;
1005 case XML_ATTRIBUTE_NMTOKEN:
1006 break;
1007 case XML_ATTRIBUTE_NMTOKENS:
1008 break;
1009 case XML_ATTRIBUTE_ENUMERATION:
1010 break;
1011 case XML_ATTRIBUTE_NOTATION:
1012 break;
1013 default:
1014 xmlGenericError(xmlGenericErrorContext,
1015 "xmlAddAttributeDecl: unknown type %d\n", type);
1016 xmlFreeEnumeration(tree);
1017 return(NULL);
1018 }
1019 if ((defaultValue != NULL) &&
1020 (!xmlValidateAttributeValue(type, defaultValue))) {
1021 VERROR(ctxt->userData, "Attribute %s on %s: invalid default value\n",
1022 elem, name, defaultValue);
1023 defaultValue = NULL;
1024 }
1025
1026 /*
1027 * Create the Attribute table if needed.
1028 */
1029 table = (xmlAttributeTablePtr) dtd->attributes;
1030 if (table == NULL) {
1031 table = xmlCreateAttributeTable();
1032 dtd->attributes = (void *) table;
1033 }
1034 if (table == NULL) {
1035 xmlGenericError(xmlGenericErrorContext,
1036 "xmlAddAttributeDecl: Table creation failed!\n");
1037 return(NULL);
1038 }
1039
1040
1041 ret = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
1042 if (ret == NULL) {
1043 xmlGenericError(xmlGenericErrorContext,
1044 "xmlAddAttributeDecl: out of memory\n");
1045 return(NULL);
1046 }
1047 memset(ret, 0, sizeof(xmlAttribute));
1048 ret->type = XML_ATTRIBUTE_DECL;
1049
1050 /*
1051 * fill the structure.
1052 */
1053 ret->atype = type;
1054 ret->name = xmlStrdup(name);
1055 ret->prefix = xmlStrdup(ns);
1056 ret->elem = xmlStrdup(elem);
1057 ret->def = def;
1058 ret->tree = tree;
1059 if (defaultValue != NULL)
1060 ret->defaultValue = xmlStrdup(defaultValue);
1061
1062 /*
1063 * Validity Check:
1064 * Search the DTD for previous declarations of the ATTLIST
1065 */
1066 if (xmlHashAddEntry3(table, name, ns, elem, ret) < 0) {
1067 /*
1068 * The attribute is already defined in this Dtd.
1069 */
1070 VWARNING(ctxt->userData,
1071 "Attribute %s on %s: already defined\n",
1072 name, elem);
1073 xmlFreeAttribute(ret);
1074 return(NULL);
1075 }
1076
1077 /*
1078 * Validity Check:
1079 * Multiple ID per element
1080 */
1081 elemDef = xmlGetDtdElementDesc(dtd, elem);
1082 if (elemDef != NULL) {
1083 if ((type == XML_ATTRIBUTE_ID) &&
1084 (xmlScanIDAttributeDecl(NULL, elemDef) != 0))
1085 VERROR(ctxt->userData,
1086 "Element %s has too may ID attributes defined : %s\n",
1087 elem, name);
1088 ret->nexth = elemDef->attributes;
1089 elemDef->attributes = ret;
1090 }
1091
1092 /*
1093 * Link it to the Dtd
1094 */
1095 ret->parent = dtd;
1096 ret->doc = dtd->doc;
1097 if (dtd->last == NULL) {
1098 dtd->children = dtd->last = (xmlNodePtr) ret;
1099 } else {
1100 dtd->last->next = (xmlNodePtr) ret;
1101 ret->prev = dtd->last;
1102 dtd->last = (xmlNodePtr) ret;
1103 }
1104 return(ret);
1105}
1106
1107/**
1108 * xmlFreeAttributeTable:
1109 * @table: An attribute table
1110 *
1111 * Deallocate the memory used by an entities hash table.
1112 */
1113void
1114xmlFreeAttributeTable(xmlAttributeTablePtr table) {
1115 xmlHashFree(table, (xmlHashDeallocator) xmlFreeAttribute);
1116}
1117
1118/**
1119 * xmlCopyAttribute:
1120 * @attr: An attribute
1121 *
1122 * Build a copy of an attribute.
1123 *
1124 * Returns the new xmlAttributePtr or NULL in case of error.
1125 */
1126xmlAttributePtr
1127xmlCopyAttribute(xmlAttributePtr attr) {
1128 xmlAttributePtr cur;
1129
1130 cur = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
1131 if (cur == NULL) {
1132 xmlGenericError(xmlGenericErrorContext,
1133 "xmlCopyAttribute: out of memory !\n");
1134 return(NULL);
1135 }
1136 memset(cur, 0, sizeof(xmlAttribute));
1137 cur->atype = attr->atype;
1138 cur->def = attr->def;
1139 cur->tree = xmlCopyEnumeration(attr->tree);
1140 if (attr->elem != NULL)
1141 cur->elem = xmlStrdup(attr->elem);
1142 if (attr->name != NULL)
1143 cur->name = xmlStrdup(attr->name);
1144 if (attr->defaultValue != NULL)
1145 cur->defaultValue = xmlStrdup(attr->defaultValue);
1146 return(cur);
1147}
1148
1149/**
1150 * xmlCopyAttributeTable:
1151 * @table: An attribute table
1152 *
1153 * Build a copy of an attribute table.
1154 *
1155 * Returns the new xmlAttributeTablePtr or NULL in case of error.
1156 */
1157xmlAttributeTablePtr
1158xmlCopyAttributeTable(xmlAttributeTablePtr table) {
1159 return((xmlAttributeTablePtr) xmlHashCopy(table,
1160 (xmlHashCopier) xmlCopyAttribute));
1161}
1162
1163/**
1164 * xmlDumpAttributeDecl:
1165 * @buf: the XML buffer output
1166 * @attr: An attribute declaration
1167 *
1168 * This will dump the content of the attribute declaration as an XML
1169 * DTD definition
1170 */
1171void
1172xmlDumpAttributeDecl(xmlBufferPtr buf, xmlAttributePtr attr) {
1173 xmlBufferWriteChar(buf, "<!ATTLIST ");
1174 xmlBufferWriteCHAR(buf, attr->elem);
1175 xmlBufferWriteChar(buf, " ");
1176 if (attr->prefix != NULL) {
1177 xmlBufferWriteCHAR(buf, attr->prefix);
1178 xmlBufferWriteChar(buf, ":");
1179 }
1180 xmlBufferWriteCHAR(buf, attr->name);
1181 switch (attr->atype) {
1182 case XML_ATTRIBUTE_CDATA:
1183 xmlBufferWriteChar(buf, " CDATA");
1184 break;
1185 case XML_ATTRIBUTE_ID:
1186 xmlBufferWriteChar(buf, " ID");
1187 break;
1188 case XML_ATTRIBUTE_IDREF:
1189 xmlBufferWriteChar(buf, " IDREF");
1190 break;
1191 case XML_ATTRIBUTE_IDREFS:
1192 xmlBufferWriteChar(buf, " IDREFS");
1193 break;
1194 case XML_ATTRIBUTE_ENTITY:
1195 xmlBufferWriteChar(buf, " ENTITY");
1196 break;
1197 case XML_ATTRIBUTE_ENTITIES:
1198 xmlBufferWriteChar(buf, " ENTITIES");
1199 break;
1200 case XML_ATTRIBUTE_NMTOKEN:
1201 xmlBufferWriteChar(buf, " NMTOKEN");
1202 break;
1203 case XML_ATTRIBUTE_NMTOKENS:
1204 xmlBufferWriteChar(buf, " NMTOKENS");
1205 break;
1206 case XML_ATTRIBUTE_ENUMERATION:
1207 xmlBufferWriteChar(buf, " (");
1208 xmlDumpEnumeration(buf, attr->tree);
1209 break;
1210 case XML_ATTRIBUTE_NOTATION:
1211 xmlBufferWriteChar(buf, " NOTATION (");
1212 xmlDumpEnumeration(buf, attr->tree);
1213 break;
1214 default:
1215 xmlGenericError(xmlGenericErrorContext,
1216 "xmlDumpAttributeTable: internal: unknown type %d\n",
1217 attr->atype);
1218 }
1219 switch (attr->def) {
1220 case XML_ATTRIBUTE_NONE:
1221 break;
1222 case XML_ATTRIBUTE_REQUIRED:
1223 xmlBufferWriteChar(buf, " #REQUIRED");
1224 break;
1225 case XML_ATTRIBUTE_IMPLIED:
1226 xmlBufferWriteChar(buf, " #IMPLIED");
1227 break;
1228 case XML_ATTRIBUTE_FIXED:
1229 xmlBufferWriteChar(buf, " #FIXED");
1230 break;
1231 default:
1232 xmlGenericError(xmlGenericErrorContext,
1233 "xmlDumpAttributeTable: internal: unknown default %d\n",
1234 attr->def);
1235 }
1236 if (attr->defaultValue != NULL) {
1237 xmlBufferWriteChar(buf, " ");
1238 xmlBufferWriteQuotedString(buf, attr->defaultValue);
1239 }
1240 xmlBufferWriteChar(buf, ">\n");
1241}
1242
1243/**
1244 * xmlDumpAttributeTable:
1245 * @buf: the XML buffer output
1246 * @table: An attribute table
1247 *
1248 * This will dump the content of the attribute table as an XML DTD definition
1249 */
1250void
1251xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) {
1252 xmlHashScan(table, (xmlHashScanner) xmlDumpAttributeDecl, buf);
1253}
1254
1255/************************************************************************
1256 * *
1257 * NOTATIONs *
1258 * *
1259 ************************************************************************/
1260/**
1261 * xmlCreateNotationTable:
1262 *
1263 * create and initialize an empty notation hash table.
1264 *
1265 * Returns the xmlNotationTablePtr just created or NULL in case
1266 * of error.
1267 */
1268xmlNotationTablePtr
1269xmlCreateNotationTable(void) {
1270 return(xmlHashCreate(0));
1271}
1272
1273/**
1274 * xmlFreeNotation:
1275 * @not: A notation
1276 *
1277 * Deallocate the memory used by an notation definition
1278 */
1279void
1280xmlFreeNotation(xmlNotationPtr nota) {
1281 if (nota == NULL) return;
1282 if (nota->name != NULL)
1283 xmlFree((xmlChar *) nota->name);
1284 if (nota->PublicID != NULL)
1285 xmlFree((xmlChar *) nota->PublicID);
1286 if (nota->SystemID != NULL)
1287 xmlFree((xmlChar *) nota->SystemID);
1288 memset(nota, -1, sizeof(xmlNotation));
1289 xmlFree(nota);
1290}
1291
1292
1293/**
1294 * xmlAddNotationDecl:
1295 * @dtd: pointer to the DTD
1296 * @ctxt: the validation context
1297 * @name: the entity name
1298 * @PublicID: the public identifier or NULL
1299 * @SystemID: the system identifier or NULL
1300 *
1301 * Register a new notation declaration
1302 *
1303 * Returns NULL if not, othervise the entity
1304 */
1305xmlNotationPtr
1306xmlAddNotationDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name,
1307 const xmlChar *PublicID, const xmlChar *SystemID) {
1308 xmlNotationPtr ret;
1309 xmlNotationTablePtr table;
1310
1311 if (dtd == NULL) {
1312 xmlGenericError(xmlGenericErrorContext,
1313 "xmlAddNotationDecl: dtd == NULL\n");
1314 return(NULL);
1315 }
1316 if (name == NULL) {
1317 xmlGenericError(xmlGenericErrorContext,
1318 "xmlAddNotationDecl: name == NULL\n");
1319 return(NULL);
1320 }
1321 if ((PublicID == NULL) && (SystemID == NULL)) {
1322 xmlGenericError(xmlGenericErrorContext,
1323 "xmlAddNotationDecl: no PUBLIC ID nor SYSTEM ID\n");
1324 }
1325
1326 /*
1327 * Create the Notation table if needed.
1328 */
1329 table = (xmlNotationTablePtr) dtd->notations;
1330 if (table == NULL)
1331 dtd->notations = table = xmlCreateNotationTable();
1332 if (table == NULL) {
1333 xmlGenericError(xmlGenericErrorContext,
1334 "xmlAddNotationDecl: Table creation failed!\n");
1335 return(NULL);
1336 }
1337
1338 ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
1339 if (ret == NULL) {
1340 xmlGenericError(xmlGenericErrorContext,
1341 "xmlAddNotationDecl: out of memory\n");
1342 return(NULL);
1343 }
1344 memset(ret, 0, sizeof(xmlNotation));
1345
1346 /*
1347 * fill the structure.
1348 */
1349 ret->name = xmlStrdup(name);
1350 if (SystemID != NULL)
1351 ret->SystemID = xmlStrdup(SystemID);
1352 if (PublicID != NULL)
1353 ret->PublicID = xmlStrdup(PublicID);
1354
1355 /*
1356 * Validity Check:
1357 * Check the DTD for previous declarations of the ATTLIST
1358 */
1359 if (xmlHashAddEntry(table, name, ret)) {
1360 xmlGenericError(xmlGenericErrorContext,
1361 "xmlAddNotationDecl: %s already defined\n", name);
1362 xmlFreeNotation(ret);
1363 return(NULL);
1364 }
1365 return(ret);
1366}
1367
1368/**
1369 * xmlFreeNotationTable:
1370 * @table: An notation table
1371 *
1372 * Deallocate the memory used by an entities hash table.
1373 */
1374void
1375xmlFreeNotationTable(xmlNotationTablePtr table) {
1376 xmlHashFree(table, (xmlHashDeallocator) xmlFreeNotation);
1377}
1378
1379/**
1380 * xmlCopyNotation:
1381 * @nota: A notation
1382 *
1383 * Build a copy of a notation.
1384 *
1385 * Returns the new xmlNotationPtr or NULL in case of error.
1386 */
1387xmlNotationPtr
1388xmlCopyNotation(xmlNotationPtr nota) {
1389 xmlNotationPtr cur;
1390
1391 cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
1392 if (cur == NULL) {
1393 xmlGenericError(xmlGenericErrorContext,
1394 "xmlCopyNotation: out of memory !\n");
1395 return(NULL);
1396 }
1397 if (nota->name != NULL)
1398 cur->name = xmlStrdup(nota->name);
1399 else
1400 cur->name = NULL;
1401 if (nota->PublicID != NULL)
1402 cur->PublicID = xmlStrdup(nota->PublicID);
1403 else
1404 cur->PublicID = NULL;
1405 if (nota->SystemID != NULL)
1406 cur->SystemID = xmlStrdup(nota->SystemID);
1407 else
1408 cur->SystemID = NULL;
1409 return(cur);
1410}
1411
1412/**
1413 * xmlCopyNotationTable:
1414 * @table: A notation table
1415 *
1416 * Build a copy of a notation table.
1417 *
1418 * Returns the new xmlNotationTablePtr or NULL in case of error.
1419 */
1420xmlNotationTablePtr
1421xmlCopyNotationTable(xmlNotationTablePtr table) {
1422 return((xmlNotationTablePtr) xmlHashCopy(table,
1423 (xmlHashCopier) xmlCopyNotation));
1424}
1425
1426/**
1427 * xmlDumpNotationDecl:
1428 * @buf: the XML buffer output
1429 * @nota: A notation declaration
1430 *
1431 * This will dump the content the notation declaration as an XML DTD definition
1432 */
1433void
1434xmlDumpNotationDecl(xmlBufferPtr buf, xmlNotationPtr nota) {
1435 xmlBufferWriteChar(buf, "<!NOTATION ");
1436 xmlBufferWriteCHAR(buf, nota->name);
1437 if (nota->PublicID != NULL) {
1438 xmlBufferWriteChar(buf, " PUBLIC ");
1439 xmlBufferWriteQuotedString(buf, nota->PublicID);
1440 if (nota->SystemID != NULL) {
1441 xmlBufferWriteChar(buf, " ");
1442 xmlBufferWriteCHAR(buf, nota->SystemID);
1443 }
1444 } else {
1445 xmlBufferWriteChar(buf, " SYSTEM ");
1446 xmlBufferWriteCHAR(buf, nota->SystemID);
1447 }
1448 xmlBufferWriteChar(buf, " >\n");
1449}
1450
1451/**
1452 * xmlDumpNotationTable:
1453 * @buf: the XML buffer output
1454 * @table: A notation table
1455 *
1456 * This will dump the content of the notation table as an XML DTD definition
1457 */
1458void
1459xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
1460 xmlHashScan(table, (xmlHashScanner) xmlDumpNotationDecl, buf);
1461}
1462
1463/************************************************************************
1464 * *
1465 * IDs *
1466 * *
1467 ************************************************************************/
1468/**
1469 * xmlCreateIDTable:
1470 *
1471 * create and initialize an empty id hash table.
1472 *
1473 * Returns the xmlIDTablePtr just created or NULL in case
1474 * of error.
1475 */
1476xmlIDTablePtr
1477xmlCreateIDTable(void) {
1478 return(xmlHashCreate(0));
1479}
1480
1481/**
1482 * xmlFreeID:
1483 * @not: A id
1484 *
1485 * Deallocate the memory used by an id definition
1486 */
1487void
1488xmlFreeID(xmlIDPtr id) {
1489 if (id == NULL) return;
1490 if (id->value != NULL)
1491 xmlFree((xmlChar *) id->value);
1492 memset(id, -1, sizeof(xmlID));
1493 xmlFree(id);
1494}
1495
1496/**
1497 * xmlAddID:
1498 * @ctxt: the validation context
1499 * @doc: pointer to the document
1500 * @value: the value name
1501 * @attr: the attribute holding the ID
1502 *
1503 * Register a new id declaration
1504 *
1505 * Returns NULL if not, othervise the new xmlIDPtr
1506 */
1507xmlIDPtr
1508xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
1509 xmlAttrPtr attr) {
1510 xmlIDPtr ret;
1511 xmlIDTablePtr table;
1512
1513 if (doc == NULL) {
1514 xmlGenericError(xmlGenericErrorContext,
1515 "xmlAddIDDecl: doc == NULL\n");
1516 return(NULL);
1517 }
1518 if (value == NULL) {
1519 xmlGenericError(xmlGenericErrorContext,
1520 "xmlAddIDDecl: value == NULL\n");
1521 return(NULL);
1522 }
1523 if (attr == NULL) {
1524 xmlGenericError(xmlGenericErrorContext,
1525 "xmlAddIDDecl: attr == NULL\n");
1526 return(NULL);
1527 }
1528
1529 /*
1530 * Create the ID table if needed.
1531 */
1532 table = (xmlIDTablePtr) doc->ids;
1533 if (table == NULL)
1534 doc->ids = table = xmlCreateIDTable();
1535 if (table == NULL) {
1536 xmlGenericError(xmlGenericErrorContext,
1537 "xmlAddID: Table creation failed!\n");
1538 return(NULL);
1539 }
1540
1541 ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
1542 if (ret == NULL) {
1543 xmlGenericError(xmlGenericErrorContext,
1544 "xmlAddID: out of memory\n");
1545 return(NULL);
1546 }
1547
1548 /*
1549 * fill the structure.
1550 */
1551 ret->value = xmlStrdup(value);
1552 ret->attr = attr;
1553
1554 if (xmlHashAddEntry(table, value, ret) < 0) {
1555 /*
1556 * The id is already defined in this Dtd.
1557 */
1558 VERROR(ctxt->userData, "ID %s already defined\n", value);
1559 xmlFreeID(ret);
1560 return(NULL);
1561 }
1562 return(ret);
1563}
1564
1565/**
1566 * xmlFreeIDTable:
1567 * @table: An id table
1568 *
1569 * Deallocate the memory used by an ID hash table.
1570 */
1571void
1572xmlFreeIDTable(xmlIDTablePtr table) {
1573 xmlHashFree(table, (xmlHashDeallocator) xmlFreeID);
1574}
1575
1576/**
1577 * xmlIsID:
1578 * @doc: the document
1579 * @elem: the element carrying the attribute
1580 * @attr: the attribute
1581 *
1582 * Determine whether an attribute is of type ID. In case we have Dtd(s)
1583 * then this is simple, otherwise we use an heuristic: name ID (upper
1584 * or lowercase).
1585 *
1586 * Returns 0 or 1 depending on the lookup result
1587 */
1588int
1589xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
1590 if (doc == NULL) return(0);
1591 if (attr == NULL) return(0);
1592 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
1593 return(0);
1594 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
1595 if ((xmlStrEqual(BAD_CAST "id", attr->name)) ||
1596 (xmlStrEqual(BAD_CAST "name", attr->name)))
1597 return(1);
1598 return(0);
1599 } else {
1600 xmlAttributePtr attrDecl;
1601
1602 if (elem == NULL) return(0);
1603 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
1604 if ((attrDecl == NULL) && (doc->extSubset != NULL))
1605 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
1606 attr->name);
1607
1608 if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_ID))
1609 return(1);
1610 }
1611 return(0);
1612}
1613
1614/**
1615 * xmlRemoveID
1616 * @doc: the document
1617 * @attr: the attribute
1618 *
1619 * Remove the given attribute from the ID table maintained internally.
1620 *
1621 * Returns -1 if the lookup failed and 0 otherwise
1622 */
1623int
1624xmlRemoveID(xmlDocPtr doc, xmlAttrPtr attr) {
1625 xmlAttrPtr cur;
1626 xmlIDTablePtr table;
1627 xmlChar *ID;
1628
1629 if (doc == NULL) return(-1);
1630 if (attr == NULL) return(-1);
1631 table = (xmlIDTablePtr) doc->ids;
1632 if (table == NULL)
1633 return(-1);
1634
1635 if (attr == NULL)
1636 return(-1);
1637 ID = xmlNodeListGetString(doc, attr->children, 1);
1638 if (ID == NULL)
1639 return(-1);
1640 cur = xmlHashLookup(table, ID);
1641 if (cur != attr) {
1642 xmlFree(ID);
1643 return(-1);
1644 }
1645 xmlHashUpdateEntry(table, ID, NULL, (xmlHashDeallocator) xmlFreeID);
1646 xmlFree(ID);
1647 return(0);
1648}
1649
1650/**
1651 * xmlGetID:
1652 * @doc: pointer to the document
1653 * @ID: the ID value
1654 *
1655 * Search the attribute declaring the given ID
1656 *
1657 * Returns NULL if not found, otherwise the xmlAttrPtr defining the ID
1658 */
1659xmlAttrPtr
1660xmlGetID(xmlDocPtr doc, const xmlChar *ID) {
1661 xmlIDTablePtr table;
1662 xmlIDPtr id;
1663
1664 if (doc == NULL) {
1665 xmlGenericError(xmlGenericErrorContext, "xmlGetID: doc == NULL\n");
1666 return(NULL);
1667 }
1668
1669 if (ID == NULL) {
1670 xmlGenericError(xmlGenericErrorContext, "xmlGetID: ID == NULL\n");
1671 return(NULL);
1672 }
1673
1674 table = (xmlIDTablePtr) doc->ids;
1675 if (table == NULL)
1676 return(NULL);
1677
1678 id = xmlHashLookup(table, ID);
1679 if (id == NULL)
1680 return(NULL);
1681 return(id->attr);
1682}
1683
1684/************************************************************************
1685 * *
1686 * Refs *
1687 * *
1688 ************************************************************************/
1689typedef struct xmlRemove_t
1690{
1691 xmlListPtr l;
1692 xmlAttrPtr ap;
1693} xmlRemove;
1694
1695/**
1696 * xmlCreateRefTable:
1697 *
1698 * create and initialize an empty ref hash table.
1699 *
1700 * Returns the xmlRefTablePtr just created or NULL in case
1701 * of error.
1702 */
1703xmlRefTablePtr
1704xmlCreateRefTable(void) {
1705 return(xmlHashCreate(0));
1706}
1707
1708/**
1709 * xmlFreeRef:
1710 * @lk: A list link
1711 *
1712 * Deallocate the memory used by a ref definition
1713 */
1714static void
1715xmlFreeRef(xmlLinkPtr lk) {
1716 xmlRefPtr ref = (xmlRefPtr)xmlLinkGetData(lk);
1717 if (ref == NULL) return;
1718 if (ref->value != NULL)
1719 xmlFree((xmlChar *)ref->value);
1720 memset(ref, -1, sizeof(xmlRef));
1721 xmlFree(ref);
1722}
1723
1724/**
1725 * xmlFreeRefList:
1726 * @list_ref: A list of references.
1727 *
1728 * Deallocate the memory used by a list of references
1729 */
1730static void
1731xmlFreeRefList(xmlListPtr list_ref) {
1732 if (list_ref == NULL) return;
1733 xmlListDelete(list_ref);
1734}
1735
1736/**
1737 * xmlWalkRemoveRef:
1738 * @data: Contents of current link
1739 * @user: Value supplied by the user
1740 *
1741 * Return 0 to abort the walk or 1 to continue
1742 */
1743static int
1744xmlWalkRemoveRef(const void *data, const void *user)
1745{
1746 xmlAttrPtr attr0 = ((xmlRefPtr)data)->attr;
1747 xmlAttrPtr attr1 = ((xmlRemove *)user)->ap;
1748 xmlListPtr ref_list = ((xmlRemove *)user)->l;
1749
1750 if (attr0 == attr1) { /* Matched: remove and terminate walk */
1751 xmlListRemoveFirst(ref_list, (void *)data);
1752 return 0;
1753 }
1754 return 1;
1755}
1756
1757/**
1758 * xmlAddRef:
1759 * @ctxt: the validation context
1760 * @doc: pointer to the document
1761 * @value: the value name
1762 * @attr: the attribute holding the Ref
1763 *
1764 * Register a new ref declaration
1765 *
1766 * Returns NULL if not, othervise the new xmlRefPtr
1767 */
1768xmlRefPtr
1769xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
1770 xmlAttrPtr attr) {
1771 xmlRefPtr ret;
1772 xmlRefTablePtr table;
1773 xmlListPtr ref_list;
1774
1775 if (doc == NULL) {
1776 xmlGenericError(xmlGenericErrorContext,
1777 "xmlAddRefDecl: doc == NULL\n");
1778 return(NULL);
1779 }
1780 if (value == NULL) {
1781 xmlGenericError(xmlGenericErrorContext,
1782 "xmlAddRefDecl: value == NULL\n");
1783 return(NULL);
1784 }
1785 if (attr == NULL) {
1786 xmlGenericError(xmlGenericErrorContext,
1787 "xmlAddRefDecl: attr == NULL\n");
1788 return(NULL);
1789 }
1790
1791 /*
1792 * Create the Ref table if needed.
1793 */
1794 table = (xmlRefTablePtr) doc->refs;
1795 if (table == NULL)
1796 doc->refs = table = xmlCreateRefTable();
1797 if (table == NULL) {
1798 xmlGenericError(xmlGenericErrorContext,
1799 "xmlAddRef: Table creation failed!\n");
1800 return(NULL);
1801 }
1802
1803 ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
1804 if (ret == NULL) {
1805 xmlGenericError(xmlGenericErrorContext,
1806 "xmlAddRef: out of memory\n");
1807 return(NULL);
1808 }
1809
1810 /*
1811 * fill the structure.
1812 */
1813 ret->value = xmlStrdup(value);
1814 ret->attr = attr;
1815
1816 /* To add a reference :-
1817 * References are maintained as a list of references,
1818 * Lookup the entry, if no entry create new nodelist
1819 * Add the owning node to the NodeList
1820 * Return the ref
1821 */
1822
1823 if(NULL == (ref_list = xmlHashLookup(table, value))) {
1824 if(NULL == (ref_list = xmlListCreate(xmlFreeRef, NULL))) {
1825 xmlGenericError(xmlGenericErrorContext,
1826 "xmlAddRef: Reference list creation failed!\n");
1827 return(NULL);
1828 }
1829 if (xmlHashAddEntry(table, value, ref_list) < 0) {
1830 xmlListDelete(ref_list);
1831 xmlGenericError(xmlGenericErrorContext,
1832 "xmlAddRef: Reference list insertion failed!\n");
1833 return(NULL);
1834 }
1835 }
1836 xmlListInsert(ref_list, ret);
1837 return(ret);
1838}
1839
1840/**
1841 * xmlFreeRefTable:
1842 * @table: An ref table
1843 *
1844 * Deallocate the memory used by an Ref hash table.
1845 */
1846void
1847xmlFreeRefTable(xmlRefTablePtr table) {
1848 xmlHashFree(table, (xmlHashDeallocator) xmlFreeRefList);
1849}
1850
1851/**
1852 * xmlIsRef:
1853 * @doc: the document
1854 * @elem: the element carrying the attribute
1855 * @attr: the attribute
1856 *
1857 * Determine whether an attribute is of type Ref. In case we have Dtd(s)
1858 * then this is simple, otherwise we use an heuristic: name Ref (upper
1859 * or lowercase).
1860 *
1861 * Returns 0 or 1 depending on the lookup result
1862 */
1863int
1864xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
1865 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
1866 return(0);
1867 } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
1868 /* TODO @@@ */
1869 return(0);
1870 } else {
1871 xmlAttributePtr attrDecl;
1872
1873 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
1874 if ((attrDecl == NULL) && (doc->extSubset != NULL))
1875 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
1876 attr->name);
1877
1878 if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_IDREF))
1879 return(1);
1880 }
1881 return(0);
1882}
1883
1884/**
1885 * xmlRemoveRef
1886 * @doc: the document
1887 * @attr: the attribute
1888 *
1889 * Remove the given attribute from the Ref table maintained internally.
1890 *
1891 * Returns -1 if the lookup failed and 0 otherwise
1892 */
1893int
1894xmlRemoveRef(xmlDocPtr doc, xmlAttrPtr attr) {
1895 xmlListPtr ref_list;
1896 xmlRefTablePtr table;
1897 xmlChar *ID;
1898 xmlRemove target;
1899
1900 if (doc == NULL) return(-1);
1901 if (attr == NULL) return(-1);
1902 table = (xmlRefTablePtr) doc->refs;
1903 if (table == NULL)
1904 return(-1);
1905
1906 if (attr == NULL)
1907 return(-1);
1908 ID = xmlNodeListGetString(doc, attr->children, 1);
1909 if (ID == NULL)
1910 return(-1);
1911 ref_list = xmlHashLookup(table, ID);
1912
1913 if(ref_list == NULL) {
1914 xmlFree(ID);
1915 return (-1);
1916 }
1917 /* At this point, ref_list refers to a list of references which
1918 * have the same key as the supplied attr. Our list of references
1919 * is ordered by reference address and we don't have that information
1920 * here to use when removing. We'll have to walk the list and
1921 * check for a matching attribute, when we find one stop the walk
1922 * and remove the entry.
1923 * The list is ordered by reference, so that means we don't have the
1924 * key. Passing the list and the reference to the walker means we
1925 * will have enough data to be able to remove the entry.
1926 */
1927 target.l = ref_list;
1928 target.ap = attr;
1929
1930 /* Remove the supplied attr from our list */
1931 xmlListWalk(ref_list, xmlWalkRemoveRef, &target);
1932
1933 /*If the list is empty then remove the list entry in the hash */
1934 if (xmlListEmpty(ref_list))
1935 xmlHashUpdateEntry(table, ID, NULL, (xmlHashDeallocator)
1936 xmlFreeRefList);
1937 xmlFree(ID);
1938 return(0);
1939}
1940
1941/**
1942 * xmlGetRefs:
1943 * @doc: pointer to the document
1944 * @ID: the ID value
1945 *
1946 * Find the set of references for the supplied ID.
1947 *
1948 * Returns NULL if not found, otherwise node set for the ID.
1949 */
1950xmlListPtr
1951xmlGetRefs(xmlDocPtr doc, const xmlChar *ID) {
1952 xmlRefTablePtr table;
1953
1954 if (doc == NULL) {
1955 xmlGenericError(xmlGenericErrorContext, "xmlGetRef: doc == NULL\n");
1956 return(NULL);
1957 }
1958
1959 if (ID == NULL) {
1960 xmlGenericError(xmlGenericErrorContext, "xmlGetRef: ID == NULL\n");
1961 return(NULL);
1962 }
1963
1964 table = (xmlRefTablePtr) doc->refs;
1965 if (table == NULL)
1966 return(NULL);
1967
1968 return (xmlHashLookup(table, ID));
1969}
1970
1971/************************************************************************
1972 * *
1973 * Routines for validity checking *
1974 * *
1975 ************************************************************************/
1976
1977/**
1978 * xmlGetDtdElementDesc:
1979 * @dtd: a pointer to the DtD to search
1980 * @name: the element name
1981 *
1982 * Search the Dtd for the description of this element
1983 *
1984 * returns the xmlElementPtr if found or NULL
1985 */
1986
1987xmlElementPtr
1988xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) {
1989 xmlElementTablePtr table;
1990 xmlElementPtr cur;
1991 xmlChar *uqname = NULL, *prefix = NULL;
1992
1993 if (dtd == NULL) return(NULL);
1994 if (dtd->elements == NULL) return(NULL);
1995 table = (xmlElementTablePtr) dtd->elements;
1996
1997 uqname = xmlSplitQName2(name, &prefix);
1998 if (uqname != NULL) {
1999 cur = xmlHashLookup2(table, uqname, prefix);
2000 if (prefix != NULL) xmlFree(prefix);
2001 if (uqname != NULL) xmlFree(uqname);
2002 } else
2003 cur = xmlHashLookup2(table, name, NULL);
2004 return(cur);
2005}
2006
2007/**
2008 * xmlGetDtdQElementDesc:
2009 * @dtd: a pointer to the DtD to search
2010 * @name: the element name
2011 * @prefix: the element namespace prefix
2012 *
2013 * Search the Dtd for the description of this element
2014 *
2015 * returns the xmlElementPtr if found or NULL
2016 */
2017
2018xmlElementPtr
2019xmlGetDtdQElementDesc(xmlDtdPtr dtd, const xmlChar *name,
2020 const xmlChar *prefix) {
2021 xmlElementTablePtr table;
2022
2023 if (dtd == NULL) return(NULL);
2024 if (dtd->elements == NULL) return(NULL);
2025 table = (xmlElementTablePtr) dtd->elements;
2026
2027 return(xmlHashLookup2(table, name, prefix));
2028}
2029
2030/**
2031 * xmlGetDtdAttrDesc:
2032 * @dtd: a pointer to the DtD to search
2033 * @elem: the element name
2034 * @name: the attribute name
2035 *
2036 * Search the Dtd for the description of this attribute on
2037 * this element.
2038 *
2039 * returns the xmlAttributePtr if found or NULL
2040 */
2041
2042xmlAttributePtr
2043xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) {
2044 xmlAttributeTablePtr table;
2045 xmlAttributePtr cur;
2046 xmlChar *uqname = NULL, *prefix = NULL;
2047
2048 if (dtd == NULL) return(NULL);
2049 if (dtd->attributes == NULL) return(NULL);
2050
2051 table = (xmlAttributeTablePtr) dtd->attributes;
2052 if (table == NULL)
2053 return(NULL);
2054
2055 uqname = xmlSplitQName2(name, &prefix);
2056
2057 if (uqname != NULL) {
2058 cur = xmlHashLookup3(table, uqname, prefix, elem);
2059 if (prefix != NULL) xmlFree(prefix);
2060 if (uqname != NULL) xmlFree(uqname);
2061 } else
2062 cur = xmlHashLookup3(table, name, NULL, elem);
2063 return(cur);
2064}
2065
2066/**
2067 * xmlGetDtdQAttrDesc:
2068 * @dtd: a pointer to the DtD to search
2069 * @elem: the element name
2070 * @name: the attribute name
2071 * @prefix: the attribute namespace prefix
2072 *
2073 * Search the Dtd for the description of this qualified attribute on
2074 * this element.
2075 *
2076 * returns the xmlAttributePtr if found or NULL
2077 */
2078
2079xmlAttributePtr
2080xmlGetDtdQAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name,
2081 const xmlChar *prefix) {
2082 xmlAttributeTablePtr table;
2083
2084 if (dtd == NULL) return(NULL);
2085 if (dtd->attributes == NULL) return(NULL);
2086 table = (xmlAttributeTablePtr) dtd->attributes;
2087
2088 return(xmlHashLookup3(table, name, prefix, elem));
2089}
2090
2091/**
2092 * xmlGetDtdNotationDesc:
2093 * @dtd: a pointer to the DtD to search
2094 * @name: the notation name
2095 *
2096 * Search the Dtd for the description of this notation
2097 *
2098 * returns the xmlNotationPtr if found or NULL
2099 */
2100
2101xmlNotationPtr
2102xmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) {
2103 xmlNotationTablePtr table;
2104
2105 if (dtd == NULL) return(NULL);
2106 if (dtd->notations == NULL) return(NULL);
2107 table = (xmlNotationTablePtr) dtd->notations;
2108
2109 return(xmlHashLookup(table, name));
2110}
2111
2112/**
2113 * xmlValidateNotationUse:
2114 * @ctxt: the validation context
2115 * @doc: the document
2116 * @notationName: the notation name to check
2117 *
2118 * Validate that the given mame match a notation declaration.
2119 * - [ VC: Notation Declared ]
2120 *
2121 * returns 1 if valid or 0 otherwise
2122 */
2123
2124int
2125xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2126 const xmlChar *notationName) {
2127 xmlNotationPtr notaDecl;
2128 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
2129
2130 notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
2131 if ((notaDecl == NULL) && (doc->extSubset != NULL))
2132 notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
2133
2134 if (notaDecl == NULL) {
2135 VERROR(ctxt->userData, "NOTATION %s is not declared\n",
2136 notationName);
2137 return(0);
2138 }
2139 return(1);
2140}
2141
2142/**
2143 * xmlIsMixedElement
2144 * @doc: the document
2145 * @name: the element name
2146 *
2147 * Search in the DtDs whether an element accept Mixed content (or ANY)
2148 * basically if it is supposed to accept text childs
2149 *
2150 * returns 0 if no, 1 if yes, and -1 if no element description is available
2151 */
2152
2153int
2154xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) {
2155 xmlElementPtr elemDecl;
2156
2157 if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
2158
2159 elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
2160 if ((elemDecl == NULL) && (doc->extSubset != NULL))
2161 elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
2162 if (elemDecl == NULL) return(-1);
2163 switch (elemDecl->etype) {
2164 case XML_ELEMENT_TYPE_ELEMENT:
2165 return(0);
2166 case XML_ELEMENT_TYPE_EMPTY:
2167 /*
2168 * return 1 for EMPTY since we want VC error to pop up
2169 * on <empty> </empty> for example
2170 */
2171 case XML_ELEMENT_TYPE_ANY:
2172 case XML_ELEMENT_TYPE_MIXED:
2173 return(1);
2174 }
2175 return(1);
2176}
2177
2178/**
2179 * xmlValidateNameValue:
2180 * @value: an Name value
2181 *
2182 * Validate that the given value match Name production
2183 *
2184 * returns 1 if valid or 0 otherwise
2185 */
2186
2187int
2188xmlValidateNameValue(const xmlChar *value) {
2189 const xmlChar *cur;
2190
2191 if (value == NULL) return(0);
2192 cur = value;
2193
2194 if (!IS_LETTER(*cur) && (*cur != '_') &&
2195 (*cur != ':')) {
2196 return(0);
2197 }
2198
2199 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2200 (*cur == '.') || (*cur == '-') ||
2201 (*cur == '_') || (*cur == ':') ||
2202 (IS_COMBINING(*cur)) ||
2203 (IS_EXTENDER(*cur)))
2204 cur++;
2205
2206 if (*cur != 0) return(0);
2207
2208 return(1);
2209}
2210
2211/**
2212 * xmlValidateNamesValue:
2213 * @value: an Names value
2214 *
2215 * Validate that the given value match Names production
2216 *
2217 * returns 1 if valid or 0 otherwise
2218 */
2219
2220int
2221xmlValidateNamesValue(const xmlChar *value) {
2222 const xmlChar *cur;
2223
2224 if (value == NULL) return(0);
2225 cur = value;
2226
2227 if (!IS_LETTER(*cur) && (*cur != '_') &&
2228 (*cur != ':')) {
2229 return(0);
2230 }
2231
2232 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2233 (*cur == '.') || (*cur == '-') ||
2234 (*cur == '_') || (*cur == ':') ||
2235 (IS_COMBINING(*cur)) ||
2236 (IS_EXTENDER(*cur)))
2237 cur++;
2238
2239 while (IS_BLANK(*cur)) {
2240 while (IS_BLANK(*cur)) cur++;
2241
2242 if (!IS_LETTER(*cur) && (*cur != '_') &&
2243 (*cur != ':')) {
2244 return(0);
2245 }
2246
2247 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2248 (*cur == '.') || (*cur == '-') ||
2249 (*cur == '_') || (*cur == ':') ||
2250 (IS_COMBINING(*cur)) ||
2251 (IS_EXTENDER(*cur)))
2252 cur++;
2253 }
2254
2255 if (*cur != 0) return(0);
2256
2257 return(1);
2258}
2259
2260/**
2261 * xmlValidateNmtokenValue:
2262 * @value: an Mntoken value
2263 *
2264 * Validate that the given value match Nmtoken production
2265 *
2266 * [ VC: Name Token ]
2267 *
2268 * returns 1 if valid or 0 otherwise
2269 */
2270
2271int
2272xmlValidateNmtokenValue(const xmlChar *value) {
2273 const xmlChar *cur;
2274
2275 if (value == NULL) return(0);
2276 cur = value;
2277
2278 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
2279 (*cur != '.') && (*cur != '-') &&
2280 (*cur != '_') && (*cur != ':') &&
2281 (!IS_COMBINING(*cur)) &&
2282 (!IS_EXTENDER(*cur)))
2283 return(0);
2284
2285 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2286 (*cur == '.') || (*cur == '-') ||
2287 (*cur == '_') || (*cur == ':') ||
2288 (IS_COMBINING(*cur)) ||
2289 (IS_EXTENDER(*cur)))
2290 cur++;
2291
2292 if (*cur != 0) return(0);
2293
2294 return(1);
2295}
2296
2297/**
2298 * xmlValidateNmtokensValue:
2299 * @value: an Mntokens value
2300 *
2301 * Validate that the given value match Nmtokens production
2302 *
2303 * [ VC: Name Token ]
2304 *
2305 * returns 1 if valid or 0 otherwise
2306 */
2307
2308int
2309xmlValidateNmtokensValue(const xmlChar *value) {
2310 const xmlChar *cur;
2311
2312 if (value == NULL) return(0);
2313 cur = value;
2314
2315 while (IS_BLANK(*cur)) cur++;
2316 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
2317 (*cur != '.') && (*cur != '-') &&
2318 (*cur != '_') && (*cur != ':') &&
2319 (!IS_COMBINING(*cur)) &&
2320 (!IS_EXTENDER(*cur)))
2321 return(0);
2322
2323 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2324 (*cur == '.') || (*cur == '-') ||
2325 (*cur == '_') || (*cur == ':') ||
2326 (IS_COMBINING(*cur)) ||
2327 (IS_EXTENDER(*cur)))
2328 cur++;
2329
2330 while (IS_BLANK(*cur)) {
2331 while (IS_BLANK(*cur)) cur++;
2332 if (*cur == 0) return(1);
2333
2334 if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
2335 (*cur != '.') && (*cur != '-') &&
2336 (*cur != '_') && (*cur != ':') &&
2337 (!IS_COMBINING(*cur)) &&
2338 (!IS_EXTENDER(*cur)))
2339 return(0);
2340
2341 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2342 (*cur == '.') || (*cur == '-') ||
2343 (*cur == '_') || (*cur == ':') ||
2344 (IS_COMBINING(*cur)) ||
2345 (IS_EXTENDER(*cur)))
2346 cur++;
2347 }
2348
2349 if (*cur != 0) return(0);
2350
2351 return(1);
2352}
2353
2354/**
2355 * xmlValidateNotationDecl:
2356 * @ctxt: the validation context
2357 * @doc: a document instance
2358 * @nota: a notation definition
2359 *
2360 * Try to validate a single notation definition
2361 * basically it does the following checks as described by the
2362 * XML-1.0 recommendation:
2363 * - it seems that no validity constraing exist on notation declarations
2364 * But this function get called anyway ...
2365 *
2366 * returns 1 if valid or 0 otherwise
2367 */
2368
2369int
2370xmlValidateNotationDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2371 xmlNotationPtr nota) {
2372 int ret = 1;
2373
2374 return(ret);
2375}
2376
2377/**
2378 * xmlValidateAttributeValue:
2379 * @type: an attribute type
2380 * @value: an attribute value
2381 *
2382 * Validate that the given attribute value match the proper production
2383 *
2384 * [ VC: ID ]
2385 * Values of type ID must match the Name production....
2386 *
2387 * [ VC: IDREF ]
2388 * Values of type IDREF must match the Name production, and values
2389 * of type IDREFS must match Names ...
2390 *
2391 * [ VC: Entity Name ]
2392 * Values of type ENTITY must match the Name production, values
2393 * of type ENTITIES must match Names ...
2394 *
2395 * [ VC: Name Token ]
2396 * Values of type NMTOKEN must match the Nmtoken production; values
2397 * of type NMTOKENS must match Nmtokens.
2398 *
2399 * returns 1 if valid or 0 otherwise
2400 */
2401
2402int
2403xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) {
2404 switch (type) {
2405 case XML_ATTRIBUTE_ENTITIES:
2406 case XML_ATTRIBUTE_IDREFS:
2407 return(xmlValidateNamesValue(value));
2408 case XML_ATTRIBUTE_ENTITY:
2409 case XML_ATTRIBUTE_IDREF:
2410 case XML_ATTRIBUTE_ID:
2411 case XML_ATTRIBUTE_NOTATION:
2412 return(xmlValidateNameValue(value));
2413 case XML_ATTRIBUTE_NMTOKENS:
2414 case XML_ATTRIBUTE_ENUMERATION:
2415 return(xmlValidateNmtokensValue(value));
2416 case XML_ATTRIBUTE_NMTOKEN:
2417 return(xmlValidateNmtokenValue(value));
2418 case XML_ATTRIBUTE_CDATA:
2419 break;
2420 }
2421 return(1);
2422}
2423
2424/**
2425 * xmlValidateAttributeValue2:
2426 * @ctxt: the validation context
2427 * @doc: the document
2428 * @name: the attribute name (used for error reporting only)
2429 * @type: the attribute type
2430 * @value: the attribute value
2431 *
2432 * Validate that the given attribute value match a given type.
2433 * This typically cannot be done before having finished parsing
2434 * the subsets.
2435 *
2436 * [ VC: IDREF ]
2437 * Values of type IDREF must match one of the declared IDs
2438 * Values of type IDREFS must match a sequence of the declared IDs
2439 * each Name must match the value of an ID attribute on some element
2440 * in the XML document; i.e. IDREF values must match the value of
2441 * some ID attribute
2442 *
2443 * [ VC: Entity Name ]
2444 * Values of type ENTITY must match one declared entity
2445 * Values of type ENTITIES must match a sequence of declared entities
2446 *
2447 * [ VC: Notation Attributes ]
2448 * all notation names in the declaration must be declared.
2449 *
2450 * returns 1 if valid or 0 otherwise
2451 */
2452
2453int
2454xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2455 const xmlChar *name, xmlAttributeType type, const xmlChar *value) {
2456 int ret = 1;
2457 switch (type) {
2458 case XML_ATTRIBUTE_IDREFS:
2459 case XML_ATTRIBUTE_IDREF:
2460 case XML_ATTRIBUTE_ID:
2461 case XML_ATTRIBUTE_NMTOKENS:
2462 case XML_ATTRIBUTE_ENUMERATION:
2463 case XML_ATTRIBUTE_NMTOKEN:
2464 case XML_ATTRIBUTE_CDATA:
2465 break;
2466 case XML_ATTRIBUTE_ENTITY: {
2467 xmlEntityPtr ent;
2468
2469 ent = xmlGetDocEntity(doc, value);
2470 if (ent == NULL) {
2471 VERROR(ctxt->userData,
2472 "ENTITY attribute %s reference an unknown entity \"%s\"\n",
2473 name, value);
2474 ret = 0;
2475 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
2476 VERROR(ctxt->userData,
2477 "ENTITY attribute %s reference an entity \"%s\" of wrong type\n",
2478 name, value);
2479 ret = 0;
2480 }
2481 break;
2482 }
2483 case XML_ATTRIBUTE_ENTITIES: {
2484 xmlChar *dup, *nam = NULL, *cur, save;
2485 xmlEntityPtr ent;
2486
2487 dup = xmlStrdup(value);
2488 if (dup == NULL)
2489 return(0);
2490 cur = dup;
2491 while (*cur != 0) {
2492 nam = cur;
2493 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
2494 save = *cur;
2495 *cur = 0;
2496 ent = xmlGetDocEntity(doc, nam);
2497 if (ent == NULL) {
2498 VERROR(ctxt->userData,
2499 "ENTITIES attribute %s reference an unknown entity \"%s\"\n",
2500 name, nam);
2501 ret = 0;
2502 } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
2503 VERROR(ctxt->userData,
2504 "ENTITIES attribute %s reference an entity \"%s\" of wrong type\n",
2505 name, nam);
2506 ret = 0;
2507 }
2508 if (save == 0)
2509 break;
2510 *cur = save;
2511 while (IS_BLANK(*cur)) cur++;
2512 }
2513 xmlFree(dup);
2514 break;
2515 }
2516 case XML_ATTRIBUTE_NOTATION: {
2517 xmlNotationPtr nota;
2518
2519 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
2520 if ((nota == NULL) && (doc->extSubset != NULL))
2521 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
2522
2523 if (nota == NULL) {
2524 VERROR(ctxt->userData,
2525 "NOTATION attribute %s reference an unknown notation \"%s\"\n",
2526 name, value);
2527 ret = 0;
2528 }
2529 break;
2530 }
2531 }
2532 return(ret);
2533}
2534
2535/**
2536 * xmlValidNormalizeAttributeValue:
2537 * @doc: the document
2538 * @elem: the parent
2539 * @name: the attribute name
2540 * @value: the attribute value
2541 *
2542 * Does the validation related extra step of the normalization of attribute
2543 * values:
2544 *
2545 * If the declared value is not CDATA, then the XML processor must further
2546 * process the normalized attribute value by discarding any leading and
2547 * trailing space (#x20) characters, and by replacing sequences of space
2548 * (#x20) characters by single space (#x20) character.
2549 *
2550 * returns a new normalized string if normalization is needed, NULL otherwise
2551 * the caller must free the returned value.
2552 */
2553
2554xmlChar *
2555xmlValidNormalizeAttributeValue(xmlDocPtr doc, xmlNodePtr elem,
2556 const xmlChar *name, const xmlChar *value) {
2557 xmlChar *ret, *dst;
2558 const xmlChar *src;
2559 xmlAttributePtr attrDecl = NULL;
2560
2561 if (doc == NULL) return(NULL);
2562 if (elem == NULL) return(NULL);
2563 if (name == NULL) return(NULL);
2564 if (value == NULL) return(NULL);
2565
2566 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
2567 xmlChar qname[500];
2568#ifdef HAVE_SNPRINTF
2569 snprintf((char *) qname, sizeof(qname), "%s:%s",
2570 elem->ns->prefix, elem->name);
2571#else
2572 sprintf((char *) qname, "%s:%s", elem->ns->prefix, elem->name);
2573#endif
2574 qname[sizeof(qname) - 1] = 0;
2575 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, qname, name);
2576 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2577 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, qname, name);
2578 }
2579 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
2580 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2581 attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
2582
2583 if (attrDecl == NULL)
2584 return(NULL);
2585 if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
2586 return(NULL);
2587
2588 ret = xmlStrdup(value);
2589 if (ret == NULL)
2590 return(NULL);
2591 src = value;
2592 dst = ret;
2593 while (*src == 0x20) src++;
2594 while (*src != 0) {
2595 if (*src == 0x20) {
2596 while (*src == 0x20) src++;
2597 if (*src != 0)
2598 *dst++ = 0x20;
2599 } else {
2600 *dst++ = *src++;
2601 }
2602 }
2603 *dst = 0;
2604 return(ret);
2605}
2606
2607void
2608xmlValidateAttributeIdCallback(xmlAttributePtr attr, int *count,
2609 const xmlChar* name) {
2610 if (attr->atype == XML_ATTRIBUTE_ID) (*count)++;
2611}
2612
2613/**
2614 * xmlValidateAttributeDecl:
2615 * @ctxt: the validation context
2616 * @doc: a document instance
2617 * @attr: an attribute definition
2618 *
2619 * Try to validate a single attribute definition
2620 * basically it does the following checks as described by the
2621 * XML-1.0 recommendation:
2622 * - [ VC: Attribute Default Legal ]
2623 * - [ VC: Enumeration ]
2624 * - [ VC: ID Attribute Default ]
2625 *
2626 * The ID/IDREF uniqueness and matching are done separately
2627 *
2628 * returns 1 if valid or 0 otherwise
2629 */
2630
2631int
2632xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2633 xmlAttributePtr attr) {
2634 int ret = 1;
2635 int val;
2636 CHECK_DTD;
2637 if(attr == NULL) return(1);
2638
2639 /* Attribute Default Legal */
2640 /* Enumeration */
2641 if (attr->defaultValue != NULL) {
2642 val = xmlValidateAttributeValue(attr->atype, attr->defaultValue);
2643 if (val == 0) {
2644 VERROR(ctxt->userData,
2645 "Syntax of default value for attribute %s on %s is not valid\n",
2646 attr->name, attr->elem);
2647 }
2648 ret &= val;
2649 }
2650
2651 /* ID Attribute Default */
2652 if ((attr->atype == XML_ATTRIBUTE_ID)&&
2653 (attr->def != XML_ATTRIBUTE_IMPLIED) &&
2654 (attr->def != XML_ATTRIBUTE_REQUIRED)) {
2655 VERROR(ctxt->userData,
2656 "ID attribute %s on %s is not valid must be #IMPLIED or #REQUIRED\n",
2657 attr->name, attr->elem);
2658 ret = 0;
2659 }
2660
2661 /* One ID per Element Type */
2662 if (attr->atype == XML_ATTRIBUTE_ID) {
2663 int nbId;
2664
2665 /* the trick is taht we parse DtD as their own internal subset */
2666 xmlElementPtr elem = xmlGetDtdElementDesc(doc->intSubset,
2667 attr->elem);
2668 if (elem != NULL) {
2669 nbId = xmlScanIDAttributeDecl(NULL, elem);
2670 } else {
2671 xmlAttributeTablePtr table;
2672
2673 /*
2674 * The attribute may be declared in the internal subset and the
2675 * element in the external subset.
2676 */
2677 nbId = 0;
2678 table = (xmlAttributeTablePtr) doc->intSubset->attributes;
2679 xmlHashScan3(table, NULL, NULL, attr->elem, (xmlHashScanner)
2680 xmlValidateAttributeIdCallback, &nbId);
2681 }
2682 if (nbId > 1) {
2683 VERROR(ctxt->userData,
2684 "Element %s has %d ID attribute defined in the internal subset : %s\n",
2685 attr->elem, nbId, attr->name);
2686 } else if (doc->extSubset != NULL) {
2687 int extId = 0;
2688 elem = xmlGetDtdElementDesc(doc->extSubset, attr->elem);
2689 if (elem != NULL) {
2690 extId = xmlScanIDAttributeDecl(NULL, elem);
2691 }
2692 if (extId > 1) {
2693 VERROR(ctxt->userData,
2694 "Element %s has %d ID attribute defined in the external subset : %s\n",
2695 attr->elem, extId, attr->name);
2696 } else if (extId + nbId > 1) {
2697 VERROR(ctxt->userData,
2698"Element %s has ID attributes defined in the internal and external subset : %s\n",
2699 attr->elem, attr->name);
2700 }
2701 }
2702 }
2703
2704 /* Validity Constraint: Enumeration */
2705 if ((attr->defaultValue != NULL) && (attr->tree != NULL)) {
2706 xmlEnumerationPtr tree = attr->tree;
2707 while (tree != NULL) {
2708 if (xmlStrEqual(tree->name, attr->defaultValue)) break;
2709 tree = tree->next;
2710 }
2711 if (tree == NULL) {
2712 VERROR(ctxt->userData,
2713"Default value \"%s\" for attribute %s on %s is not among the enumerated set\n",
2714 attr->defaultValue, attr->name, attr->elem);
2715 ret = 0;
2716 }
2717 }
2718
2719 return(ret);
2720}
2721
2722/**
2723 * xmlValidateElementDecl:
2724 * @ctxt: the validation context
2725 * @doc: a document instance
2726 * @elem: an element definition
2727 *
2728 * Try to validate a single element definition
2729 * basically it does the following checks as described by the
2730 * XML-1.0 recommendation:
2731 * - [ VC: One ID per Element Type ]
2732 * - [ VC: No Duplicate Types ]
2733 * - [ VC: Unique Element Type Declaration ]
2734 *
2735 * returns 1 if valid or 0 otherwise
2736 */
2737
2738int
2739xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2740 xmlElementPtr elem) {
2741 int ret = 1;
2742 xmlElementPtr tst;
2743
2744 CHECK_DTD;
2745
2746 if (elem == NULL) return(1);
2747
2748 /* No Duplicate Types */
2749 if (elem->etype == XML_ELEMENT_TYPE_MIXED) {
2750 xmlElementContentPtr cur, next;
2751 const xmlChar *name;
2752
2753 cur = elem->content;
2754 while (cur != NULL) {
2755 if (cur->type != XML_ELEMENT_CONTENT_OR) break;
2756 if (cur->c1 == NULL) break;
2757 if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
2758 name = cur->c1->name;
2759 next = cur->c2;
2760 while (next != NULL) {
2761 if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
2762 if (xmlStrEqual(next->name, name)) {
2763 VERROR(ctxt->userData,
2764 "Definition of %s has duplicate references of %s\n",
2765 elem->name, name);
2766 ret = 0;
2767 }
2768 break;
2769 }
2770 if (next->c1 == NULL) break;
2771 if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
2772 if (xmlStrEqual(next->c1->name, name)) {
2773 VERROR(ctxt->userData,
2774 "Definition of %s has duplicate references of %s\n",
2775 elem->name, name);
2776 ret = 0;
2777 }
2778 next = next->c2;
2779 }
2780 }
2781 cur = cur->c2;
2782 }
2783 }
2784
2785 /* VC: Unique Element Type Declaration */
2786 tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
2787 if ((tst != NULL ) && (tst != elem)) {
2788 VERROR(ctxt->userData, "Redefinition of element %s\n",
2789 elem->name);
2790 ret = 0;
2791 }
2792 tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
2793 if ((tst != NULL ) && (tst != elem)) {
2794 VERROR(ctxt->userData, "Redefinition of element %s\n",
2795 elem->name);
2796 ret = 0;
2797 }
2798
2799 /* One ID per Element Type */
2800 if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
2801 ret = 0;
2802 }
2803 return(ret);
2804}
2805
2806/**
2807 * xmlValidateOneAttribute:
2808 * @ctxt: the validation context
2809 * @doc: a document instance
2810 * @elem: an element instance
2811 * @attr: an attribute instance
2812 * @value: the attribute value (without entities processing)
2813 *
2814 * Try to validate a single attribute for an element
2815 * basically it does the following checks as described by the
2816 * XML-1.0 recommendation:
2817 * - [ VC: Attribute Value Type ]
2818 * - [ VC: Fixed Attribute Default ]
2819 * - [ VC: Entity Name ]
2820 * - [ VC: Name Token ]
2821 * - [ VC: ID ]
2822 * - [ VC: IDREF ]
2823 * - [ VC: Entity Name ]
2824 * - [ VC: Notation Attributes ]
2825 *
2826 * The ID/IDREF uniqueness and matching are done separately
2827 *
2828 * returns 1 if valid or 0 otherwise
2829 */
2830
2831int
2832xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2833 xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value) {
2834 /* xmlElementPtr elemDecl; */
2835 xmlAttributePtr attrDecl = NULL;
2836 int val;
2837 int ret = 1;
2838
2839 CHECK_DTD;
2840 if ((elem == NULL) || (elem->name == NULL)) return(0);
2841 if ((attr == NULL) || (attr->name == NULL)) return(0);
2842
2843 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
2844 xmlChar qname[500];
2845#ifdef HAVE_SNPRINTF
2846 snprintf((char *) qname, sizeof(qname), "%s:%s",
2847 elem->ns->prefix, elem->name);
2848#else
2849 sprintf((char *) qname, "%s:%s", elem->ns->prefix, elem->name);
2850#endif
2851 qname[sizeof(qname) - 1] = 0;
2852 if (attr->ns != NULL) {
2853 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, qname,
2854 attr->name, attr->ns->prefix);
2855 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2856 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, qname,
2857 attr->name, attr->ns->prefix);
2858 } else {
2859 attrDecl = xmlGetDtdAttrDesc(doc->intSubset, qname, attr->name);
2860 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2861 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
2862 qname, attr->name);
2863 }
2864 }
2865 if (attrDecl == NULL) {
2866 if (attr->ns != NULL) {
2867 attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
2868 attr->name, attr->ns->prefix);
2869 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2870 attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
2871 attr->name, attr->ns->prefix);
2872 } else {
2873 attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
2874 elem->name, attr->name);
2875 if ((attrDecl == NULL) && (doc->extSubset != NULL))
2876 attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
2877 elem->name, attr->name);
2878 }
2879 }
2880
2881
2882 /* Validity Constraint: Attribute Value Type */
2883 if (attrDecl == NULL) {
2884 VERROR(ctxt->userData,
2885 "No declaration for attribute %s on element %s\n",
2886 attr->name, elem->name);
2887 return(0);
2888 }
2889 attr->atype = attrDecl->atype;
2890
2891 val = xmlValidateAttributeValue(attrDecl->atype, value);
2892 if (val == 0) {
2893 VERROR(ctxt->userData,
2894 "Syntax of value for attribute %s on %s is not valid\n",
2895 attr->name, elem->name);
2896 ret = 0;
2897 }
2898
2899 /* Validity constraint: Fixed Attribute Default */
2900 if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
2901 if (!xmlStrEqual(value, attrDecl->defaultValue)) {
2902 VERROR(ctxt->userData,
2903 "Value for attribute %s on %s is differnt from default \"%s\"\n",
2904 attr->name, elem->name, attrDecl->defaultValue);
2905 ret = 0;
2906 }
2907 }
2908
2909 /* Validity Constraint: ID uniqueness */
2910 if (attrDecl->atype == XML_ATTRIBUTE_ID) {
2911 if (xmlAddID(ctxt, doc, value, attr) == NULL)
2912 ret = 0;
2913 }
2914
2915 if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
2916 (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
2917 if (xmlAddRef(ctxt, doc, value, attr) == NULL)
2918 ret = 0;
2919 }
2920
2921 /* Validity Constraint: Notation Attributes */
2922 if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
2923 xmlEnumerationPtr tree = attrDecl->tree;
2924 xmlNotationPtr nota;
2925
2926 /* First check that the given NOTATION was declared */
2927 nota = xmlGetDtdNotationDesc(doc->intSubset, value);
2928 if (nota == NULL)
2929 nota = xmlGetDtdNotationDesc(doc->extSubset, value);
2930
2931 if (nota == NULL) {
2932 VERROR(ctxt->userData,
2933 "Value \"%s\" for attribute %s on %s is not a declared Notation\n",
2934 value, attr->name, elem->name);
2935 ret = 0;
2936 }
2937
2938 /* Second, verify that it's among the list */
2939 while (tree != NULL) {
2940 if (xmlStrEqual(tree->name, value)) break;
2941 tree = tree->next;
2942 }
2943 if (tree == NULL) {
2944 VERROR(ctxt->userData,
2945"Value \"%s\" for attribute %s on %s is not among the enumerated notations\n",
2946 value, attr->name, elem->name);
2947 ret = 0;
2948 }
2949 }
2950
2951 /* Validity Constraint: Enumeration */
2952 if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
2953 xmlEnumerationPtr tree = attrDecl->tree;
2954 while (tree != NULL) {
2955 if (xmlStrEqual(tree->name, value)) break;
2956 tree = tree->next;
2957 }
2958 if (tree == NULL) {
2959 VERROR(ctxt->userData,
2960 "Value \"%s\" for attribute %s on %s is not among the enumerated set\n",
2961 value, attr->name, elem->name);
2962 ret = 0;
2963 }
2964 }
2965
2966 /* Fixed Attribute Default */
2967 if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
2968 (!xmlStrEqual(attrDecl->defaultValue, value))) {
2969 VERROR(ctxt->userData,
2970 "Value for attribute %s on %s must be \"%s\"\n",
2971 attr->name, elem->name, attrDecl->defaultValue);
2972 ret = 0;
2973 }
2974
2975 /* Extra check for the attribute value */
2976 ret &= xmlValidateAttributeValue2(ctxt, doc, attr->name,
2977 attrDecl->atype, value);
2978
2979 return(ret);
2980}
2981
2982/* Find the next XML_ELEMENT_NODE, subject to the content constraints.
2983 * Return -1 if we found something unexpected, or 1 otherwise.
2984 */
2985
2986static int
2987xmlValidateFindNextElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
2988 xmlElementContentPtr cont)
2989{
2990 while (*child && (*child)->type != XML_ELEMENT_NODE) {
2991 switch ((*child)->type) {
2992 /*
2993 * If there is an entity declared and it's not empty
2994 * Push the current node on the stack and process with the
2995 * entity content.
2996 */
2997 case XML_ENTITY_REF_NODE:
2998 if (((*child)->children != NULL) &&
2999 ((*child)->children->children != NULL)) {
3000 nodeVPush(ctxt, *child);
3001 *child = (*child)->children->children;
3002 continue;
3003 }
3004 break;
3005
3006 /* These things are ignored (skipped) during validation. */
3007 case XML_PI_NODE:
3008 case XML_COMMENT_NODE:
3009 case XML_XINCLUDE_START:
3010 case XML_XINCLUDE_END:
3011 break;
3012
3013 case XML_TEXT_NODE:
3014 if (xmlIsBlankNode(*child)
3015 && (cont->type == XML_ELEMENT_CONTENT_ELEMENT
3016 || cont->type == XML_ELEMENT_CONTENT_SEQ
3017 || cont->type == XML_ELEMENT_CONTENT_OR))
3018 break;
3019 return -1;
3020
3021 default:
3022 return -1;
3023 }
3024 *child = (*child)->next;
3025 }
3026
3027 return 1;
3028}
3029
3030int xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
3031 xmlElementContentPtr cont);
3032
3033/**
3034 * xmlValidateElementTypeExpr:
3035 * @ctxt: the validation context
3036 * @child: pointer to the child list
3037 * @cont: pointer to the content declaration
3038 *
3039 * Try to validate the content of an element of type element
3040 * but don't handle the occurence factor
3041 *
3042 * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
3043 * also update child value in-situ.
3044 */
3045
3046int
3047xmlValidateElementTypeExpr(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
3048 xmlElementContentPtr cont) {
3049 xmlNodePtr cur;
3050 int ret = 1;
3051
3052 if (cont == NULL) return(-1);
3053 DEBUG_VALID_STATE(*child, cont)
3054 ret = xmlValidateFindNextElement(ctxt, child, cont);
3055 if (ret < 0)
3056 return(-1);
3057 DEBUG_VALID_STATE(*child, cont)
3058 switch (cont->type) {
3059 case XML_ELEMENT_CONTENT_PCDATA:
3060 if (*child == NULL) return(0);
3061 if ((*child)->type == XML_TEXT_NODE) return(1);
3062 return(0);
3063 case XML_ELEMENT_CONTENT_ELEMENT:
3064 if (*child == NULL) return(0);
3065 ret = (xmlStrEqual((*child)->name, cont->name));
3066 if (ret == 1) {
3067 while ((*child)->next == NULL) {
3068 if (((*child)->parent != NULL) &&
3069 ((*child)->parent->type == XML_ENTITY_DECL)) {
3070 *child = nodeVPop(ctxt);
3071 } else
3072 break;
3073 }
3074 *child = (*child)->next;
3075 }
3076 return(ret);
3077 case XML_ELEMENT_CONTENT_OR:
3078 cur = *child;
3079 ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
3080 if (ret == -1) return(-1);
3081 if (ret == 1) {
3082 return(1);
3083 }
3084 /* rollback and retry the other path */
3085 *child = cur;
3086 ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
3087 if (ret == -1) return(-1);
3088 if (ret == 0) {
3089 *child = cur;
3090 return(0);
3091 }
3092 return(1);
3093 case XML_ELEMENT_CONTENT_SEQ:
3094 cur = *child;
3095 ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
3096 if (ret == -1) return(-1);
3097 if (ret == 0) {
3098 *child = cur;
3099 return(0);
3100 }
3101 ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
3102 if (ret == -1) return(-1);
3103 if (ret == 0) {
3104 *child = cur;
3105 return(0);
3106 }
3107 return(1);
3108 }
3109 return(ret);
3110}
3111
3112/**
3113 * xmlValidateElementTypeElement:
3114 * @ctxt: the validation context
3115 * @child: pointer to the child list
3116 * @cont: pointer to the content declaration
3117 *
3118 * Try to validate the content of an element of type element
3119 * yeah, Yet Another Regexp Implementation, and recursive
3120 *
3121 * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
3122 * also update child and content values in-situ.
3123 */
3124
3125int
3126xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
3127 xmlElementContentPtr cont) {
3128 xmlNodePtr cur;
3129 int ret;
3130
3131 if (cont == NULL) return(-1);
3132
3133 DEBUG_VALID_STATE(*child, cont)
3134 ret = xmlValidateFindNextElement(ctxt, child, cont);
3135 if (ret < 0)
3136 return(-1);
3137 DEBUG_VALID_STATE(*child, cont)
3138 cur = *child;
3139 ret = xmlValidateElementTypeExpr(ctxt, child, cont);
3140 if (ret == -1) return(-1);
3141 switch (cont->ocur) {
3142 case XML_ELEMENT_CONTENT_ONCE:
3143 if (ret == 1) {
3144 /* skip ignorable elems */
3145 while ((*child != NULL) &&
3146 ((*child)->type == XML_PI_NODE
3147 || (*child)->type == XML_COMMENT_NODE
3148 || (*child)->type == XML_XINCLUDE_START
3149 || (*child)->type == XML_XINCLUDE_END)) {
3150 while ((*child)->next == NULL) {
3151 if (((*child)->parent != NULL) &&
3152 ((*child)->parent->type == XML_ENTITY_REF_NODE)) {
3153 *child = (*child)->parent;
3154 } else
3155 break;
3156 }
3157 *child = (*child)->next;
3158 }
3159 return(1);
3160 }
3161 *child = cur;
3162 return(0);
3163 case XML_ELEMENT_CONTENT_OPT:
3164 if (ret == 0) {
3165 *child = cur;
3166 return(1);
3167 }
3168 break;
3169 case XML_ELEMENT_CONTENT_MULT:
3170 if (ret == 0) {
3171 *child = cur;
3172 break;
3173 }
3174 /* no break on purpose */
3175 case XML_ELEMENT_CONTENT_PLUS:
3176 if (ret == 0) {
3177 *child = cur;
3178 return(0);
3179 }
3180 if (ret == -1) return(-1);
3181 cur = *child;
3182 do {
3183 if (*child == NULL)
3184 break; /* while */
3185 if ((*child)->type == XML_TEXT_NODE
3186 && xmlIsBlankNode(*child)) {
3187 *child = (*child)->next;
3188 continue;
3189 }
3190 ret = xmlValidateElementTypeExpr(ctxt, child, cont);
3191 if (ret == 1)
3192 cur = *child;
3193 } while (ret == 1);
3194 if (ret == -1) return(-1);
3195 *child = cur;
3196 break;
3197 }
3198
3199 return xmlValidateFindNextElement(ctxt, child, cont);
3200}
3201
3202/**
3203 * xmlSprintfElementChilds:
3204 * @buf: an output buffer
3205 * @content: An element
3206 * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
3207 *
3208 * This will dump the list of childs to the buffer
3209 * Intended just for the debug routine
3210 */
3211void
3212xmlSprintfElementChilds(char *buf, xmlNodePtr node, int glob) {
3213 xmlNodePtr cur;
3214
3215 if (node == NULL) return;
3216 if (glob) strcat(buf, "(");
3217 cur = node->children;
3218 while (cur != NULL) {
3219 switch (cur->type) {
3220 case XML_ELEMENT_NODE:
3221 strcat(buf, (char *) cur->name);
3222 if (cur->next != NULL)
3223 strcat(buf, " ");
3224 break;
3225 case XML_TEXT_NODE:
3226 if (xmlIsBlankNode(cur))
3227 break;
3228 case XML_CDATA_SECTION_NODE:
3229 case XML_ENTITY_REF_NODE:
3230 strcat(buf, "CDATA");
3231 if (cur->next != NULL)
3232 strcat(buf, " ");
3233 break;
3234 case XML_ATTRIBUTE_NODE:
3235 case XML_DOCUMENT_NODE:
3236#ifdef LIBXML_SGML_ENABLED
3237 case XML_SGML_DOCUMENT_NODE:
3238#endif
3239 case XML_HTML_DOCUMENT_NODE:
3240 case XML_DOCUMENT_TYPE_NODE:
3241 case XML_DOCUMENT_FRAG_NODE:
3242 case XML_NOTATION_NODE:
3243 case XML_NAMESPACE_DECL:
3244 strcat(buf, "???");
3245 if (cur->next != NULL)
3246 strcat(buf, " ");
3247 break;
3248 case XML_ENTITY_NODE:
3249 case XML_PI_NODE:
3250 case XML_DTD_NODE:
3251 case XML_COMMENT_NODE:
3252 case XML_ELEMENT_DECL:
3253 case XML_ATTRIBUTE_DECL:
3254 case XML_ENTITY_DECL:
3255 case XML_XINCLUDE_START:
3256 case XML_XINCLUDE_END:
3257 break;
3258 }
3259 cur = cur->next;
3260 }
3261 if (glob) strcat(buf, ")");
3262}
3263
3264
3265/**
3266 * xmlValidateOneElement:
3267 * @ctxt: the validation context
3268 * @doc: a document instance
3269 * @elem: an element instance
3270 *
3271 * Try to validate a single element and it's attributes,
3272 * basically it does the following checks as described by the
3273 * XML-1.0 recommendation:
3274 * - [ VC: Element Valid ]
3275 * - [ VC: Required Attribute ]
3276 * Then call xmlValidateOneAttribute() for each attribute present.
3277 *
3278 * The ID/IDREF checkings are done separately
3279 *
3280 * returns 1 if valid or 0 otherwise
3281 */
3282
3283int
3284xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3285 xmlNodePtr elem) {
3286 xmlElementPtr elemDecl = NULL;
3287 xmlElementContentPtr cont;
3288 xmlAttributePtr attr;
3289 xmlNodePtr child;
3290 int ret = 1;
3291 const xmlChar *name;
3292
3293 CHECK_DTD;
3294
3295 if (elem == NULL) return(0);
3296 if (elem->type == XML_TEXT_NODE) {
3297 }
3298 switch (elem->type) {
3299 case XML_ATTRIBUTE_NODE:
3300 VERROR(ctxt->userData,
3301 "Attribute element not expected here\n");
3302 return(0);
3303 case XML_TEXT_NODE:
3304 if (elem->children != NULL) {
3305 VERROR(ctxt->userData, "Text element has childs !\n");
3306 return(0);
3307 }
3308 if (elem->properties != NULL) {
3309 VERROR(ctxt->userData, "Text element has attributes !\n");
3310 return(0);
3311 }
3312 if (elem->ns != NULL) {
3313 VERROR(ctxt->userData, "Text element has namespace !\n");
3314 return(0);
3315 }
3316 if (elem->nsDef != NULL) {
3317 VERROR(ctxt->userData,
3318 "Text element carries namespace definitions !\n");
3319 return(0);
3320 }
3321 if (elem->content == NULL) {
3322 VERROR(ctxt->userData,
3323 "Text element has no content !\n");
3324 return(0);
3325 }
3326 return(1);
3327 case XML_XINCLUDE_START:
3328 case XML_XINCLUDE_END:
3329 return(1);
3330 case XML_CDATA_SECTION_NODE:
3331 case XML_ENTITY_REF_NODE:
3332 case XML_PI_NODE:
3333 case XML_COMMENT_NODE:
3334 return(1);
3335 case XML_ENTITY_NODE:
3336 VERROR(ctxt->userData,
3337 "Entity element not expected here\n");
3338 return(0);
3339 case XML_NOTATION_NODE:
3340 VERROR(ctxt->userData,
3341 "Notation element not expected here\n");
3342 return(0);
3343 case XML_DOCUMENT_NODE:
3344 case XML_DOCUMENT_TYPE_NODE:
3345 case XML_DOCUMENT_FRAG_NODE:
3346 VERROR(ctxt->userData,
3347 "Document element not expected here\n");
3348 return(0);
3349 case XML_HTML_DOCUMENT_NODE:
3350 VERROR(ctxt->userData,
3351 "\n");
3352 return(0);
3353 case XML_ELEMENT_NODE:
3354 break;
3355 default:
3356 VERROR(ctxt->userData,
3357 "unknown element type %d\n", elem->type);
3358 return(0);
3359 }
3360 if (elem->name == NULL) return(0);
3361
3362 /*
3363 * Fetch the declaration for the qualified name
3364 */
3365 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
3366 elemDecl = xmlGetDtdQElementDesc(doc->intSubset,
3367 elem->name, elem->ns->prefix);
3368 if ((elemDecl == NULL) && (doc->extSubset != NULL))
3369 elemDecl = xmlGetDtdQElementDesc(doc->extSubset,
3370 elem->name, elem->ns->prefix);
3371 }
3372
3373 /*
3374 * Fetch the declaration for the non qualified name
3375 */
3376 if (elemDecl == NULL) {
3377 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
3378 if ((elemDecl == NULL) && (doc->extSubset != NULL))
3379 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
3380 }
3381 if (elemDecl == NULL) {
3382 VERROR(ctxt->userData, "No declaration for element %s\n",
3383 elem->name);
3384 return(0);
3385 }
3386
3387 /* Check taht the element content matches the definition */
3388 switch (elemDecl->etype) {
3389 case XML_ELEMENT_TYPE_EMPTY:
3390 if (elem->children != NULL) {
3391 VERROR(ctxt->userData,
3392 "Element %s was declared EMPTY this one has content\n",
3393 elem->name);
3394 ret = 0;
3395 }
3396 break;
3397 case XML_ELEMENT_TYPE_ANY:
3398 /* I don't think anything is required then */
3399 break;
3400 case XML_ELEMENT_TYPE_MIXED:
3401 /* Hum, this start to get messy */
3402 child = elem->children;
3403 while (child != NULL) {
3404 if (child->type == XML_ELEMENT_NODE) {
3405 name = child->name;
3406 if ((child->ns != NULL) && (child->ns->prefix != NULL)) {
3407 xmlChar qname[500];
3408#ifdef HAVE_SNPRINTF
3409 snprintf((char *) qname, sizeof(qname), "%s:%s",
3410 child->ns->prefix, child->name);
3411#else
3412 sprintf((char *) qname, "%s:%s",
3413 child->ns->prefix, child->name);
3414#endif
3415 qname[sizeof(qname) - 1] = 0;
3416 cont = elemDecl->content;
3417 while (cont != NULL) {
3418 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
3419 if (xmlStrEqual(cont->name, qname)) break;
3420 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
3421 (cont->c1 != NULL) &&
3422 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
3423 if (xmlStrEqual(cont->c1->name, qname)) break;
3424 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
3425 (cont->c1 == NULL) ||
3426 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
3427 /* Internal error !!! */
3428 xmlGenericError(xmlGenericErrorContext,
3429 "Internal: MIXED struct bad\n");
3430 break;
3431 }
3432 cont = cont->c2;
3433 }
3434 if (cont != NULL)
3435 goto child_ok;
3436 }
3437 cont = elemDecl->content;
3438 while (cont != NULL) {
3439 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
3440 if (xmlStrEqual(cont->name, name)) break;
3441 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
3442 (cont->c1 != NULL) &&
3443 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
3444 if (xmlStrEqual(cont->c1->name, name)) break;
3445 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
3446 (cont->c1 == NULL) ||
3447 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
3448 /* Internal error !!! */
3449 xmlGenericError(xmlGenericErrorContext,
3450 "Internal: MIXED struct bad\n");
3451 break;
3452 }
3453 cont = cont->c2;
3454 }
3455 if (cont == NULL) {
3456 VERROR(ctxt->userData,
3457 "Element %s is not declared in %s list of possible childs\n",
3458 name, elem->name);
3459 ret = 0;
3460 }
3461 }
3462child_ok:
3463 child = child->next;
3464 }
3465 break;
3466 case XML_ELEMENT_TYPE_ELEMENT:
3467 child = elem->children;
3468 cont = elemDecl->content;
3469 ret = xmlValidateElementTypeElement(ctxt, &child, cont);
3470 while ((child != NULL) && (child->type == XML_TEXT_NODE) &&
3471 (xmlIsBlankNode(child))) {
3472 child = child->next;
3473 continue;
3474 }
3475 if ((ret == 0) || (child != NULL)) {
3476 char expr[1000];
3477 char list[2000];
3478
3479 expr[0] = 0;
3480 xmlSprintfElementContent(expr, cont, 1);
3481 list[0] = 0;
3482 xmlSprintfElementChilds(list, elem, 1);
3483
3484 VERROR(ctxt->userData,
3485 "Element %s content doesn't follow the Dtd\nExpecting %s, got %s\n",
3486 elem->name, expr, list);
3487 ret = 0;
3488 }
3489 break;
3490 }
3491
3492 /* [ VC: Required Attribute ] */
3493 attr = elemDecl->attributes;
3494 while (attr != NULL) {
3495 if (attr->def == XML_ATTRIBUTE_REQUIRED) {
3496 xmlAttrPtr attrib;
3497 int qualified = -1;
3498
3499 attrib = elem->properties;
3500 while (attrib != NULL) {
3501 if (xmlStrEqual(attrib->name, attr->name)) {
3502 if (attr->prefix != NULL) {
3503 xmlNsPtr nameSpace = attrib->ns;
3504
3505 if (nameSpace == NULL)
3506 nameSpace = elem->ns;
3507 /*
3508 * qualified names handling is problematic, having a
3509 * different prefix should be possible but DTDs don't
3510 * allow to define the URI instead of the prefix :-(
3511 */
3512 if (nameSpace == NULL) {
3513 if (qualified < 0)
3514 qualified = 0;
3515 } else if (!xmlStrEqual(nameSpace->prefix, attr->prefix)) {
3516 if (qualified < 1)
3517 qualified = 1;
3518 } else
3519 goto found;
3520 } else {
3521 /*
3522 * We should allow applications to define namespaces
3523 * for their application even if the DTD doesn't
3524 * carry one, otherwise, basically we would always
3525 * break.
3526 */
3527 goto found;
3528 }
3529 }
3530 attrib = attrib->next;
3531 }
3532 if (qualified == -1) {
3533 if (attr->prefix == NULL) {
3534 VERROR(ctxt->userData,
3535 "Element %s doesn't carry attribute %s\n",
3536 elem->name, attr->name);
3537 ret = 0;
3538 } else {
3539 VERROR(ctxt->userData,
3540 "Element %s doesn't carry attribute %s:%s\n",
3541 elem->name, attr->prefix,attr->name);
3542 ret = 0;
3543 }
3544 } else if (qualified == 0) {
3545 VWARNING(ctxt->userData,
3546 "Element %s required attribute %s:%s has no prefix\n",
3547 elem->name, attr->prefix,attr->name);
3548 } else if (qualified == 1) {
3549 VWARNING(ctxt->userData,
3550 "Element %s required attribute %s:%s has different prefix\n",
3551 elem->name, attr->prefix,attr->name);
3552 }
3553 }
3554found:
3555 attr = attr->nexth;
3556 }
3557 return(ret);
3558}
3559
3560/**
3561 * xmlValidateRoot:
3562 * @ctxt: the validation context
3563 * @doc: a document instance
3564 *
3565 * Try to validate a the root element
3566 * basically it does the following check as described by the
3567 * XML-1.0 recommendation:
3568 * - [ VC: Root Element Type ]
3569 * it doesn't try to recurse or apply other check to the element
3570 *
3571 * returns 1 if valid or 0 otherwise
3572 */
3573
3574int
3575xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
3576 xmlNodePtr root;
3577 if (doc == NULL) return(0);
3578
3579 root = xmlDocGetRootElement(doc);
3580 if ((root == NULL) || (root->name == NULL)) {
3581 VERROR(ctxt->userData, "Not valid: no root element\n");
3582 return(0);
3583 }
3584
3585 /*
3586 * When doing post validation against a separate DTD, those may
3587 * no internal subset has been generated
3588 */
3589 if ((doc->intSubset != NULL) &&
3590 (doc->intSubset->name != NULL)) {
3591 /*
3592 * Check first the document root against the NQName
3593 */
3594 if (!xmlStrEqual(doc->intSubset->name, root->name)) {
3595 if ((root->ns != NULL) && (root->ns->prefix != NULL)) {
3596 xmlChar qname[500];
3597#ifdef HAVE_SNPRINTF
3598 snprintf((char *) qname, sizeof(qname), "%s:%s",
3599 root->ns->prefix, root->name);
3600#else
3601 sprintf((char *) qname, "%s:%s", root->ns->prefix, root->name);
3602#endif
3603 qname[sizeof(qname) - 1] = 0;
3604 if (xmlStrEqual(doc->intSubset->name, qname))
3605 goto name_ok;
3606 }
3607 if ((xmlStrEqual(doc->intSubset->name, BAD_CAST "HTML")) &&
3608 (xmlStrEqual(root->name, BAD_CAST "html")))
3609 goto name_ok;
3610 VERROR(ctxt->userData,
3611 "Not valid: root and DtD name do not match '%s' and '%s'\n",
3612 root->name, doc->intSubset->name);
3613 return(0);
3614
3615 }
3616 }
3617name_ok:
3618 return(1);
3619}
3620
3621
3622/**
3623 * xmlValidateElement:
3624 * @ctxt: the validation context
3625 * @doc: a document instance
3626 * @elem: an element instance
3627 *
3628 * Try to validate the subtree under an element
3629 *
3630 * returns 1 if valid or 0 otherwise
3631 */
3632
3633int
3634xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
3635 xmlNodePtr child;
3636 xmlAttrPtr attr;
3637 xmlChar *value;
3638 int ret = 1;
3639
3640 if (elem == NULL) return(0);
3641
3642 /*
3643 * XInclude elements were added after parsing in the infoset,
3644 * they don't really mean anything validation wise.
3645 */
3646 if ((elem->type == XML_XINCLUDE_START) ||
3647 (elem->type == XML_XINCLUDE_END))
3648 return(1);
3649
3650 CHECK_DTD;
3651
3652 ret &= xmlValidateOneElement(ctxt, doc, elem);
3653 attr = elem->properties;
3654 while(attr != NULL) {
3655 value = xmlNodeListGetString(doc, attr->children, 0);
3656 ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
3657 if (value != NULL)
3658 xmlFree(value);
3659 attr= attr->next;
3660 }
3661 child = elem->children;
3662 while (child != NULL) {
3663 ret &= xmlValidateElement(ctxt, doc, child);
3664 child = child->next;
3665 }
3666
3667 return(ret);
3668}
3669
3670
3671void
3672xmlValidateCheckRefCallback(xmlRefPtr ref, xmlValidCtxtPtr ctxt,
3673 const xmlChar *name) {
3674 xmlAttrPtr id;
3675 xmlAttrPtr attr;
3676
3677 if (ref == NULL)
3678 return;
3679 attr = ref->attr;
3680 if (attr == NULL)
3681 return;
3682 if (attr->atype == XML_ATTRIBUTE_IDREF) {
3683 id = xmlGetID(ctxt->doc, name);
3684 if (id == NULL) {
3685 VERROR(ctxt->userData,
3686 "IDREF attribute %s reference an unknown ID \"%s\"\n",
3687 attr->name, name);
3688 ctxt->valid = 0;
3689 }
3690 } else if (attr->atype == XML_ATTRIBUTE_IDREFS) {
3691 xmlChar *dup, *str = NULL, *cur, save;
3692
3693 dup = xmlStrdup(name);
3694 if (dup == NULL) {
3695 ctxt->valid = 0;
3696 return;
3697 }
3698 cur = dup;
3699 while (*cur != 0) {
3700 str = cur;
3701 while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
3702 save = *cur;
3703 *cur = 0;
3704 id = xmlGetID(ctxt->doc, str);
3705 if (id == NULL) {
3706 VERROR(ctxt->userData,
3707 "IDREFS attribute %s reference an unknown ID \"%s\"\n",
3708 attr->name, str);
3709 ctxt->valid = 0;
3710 }
3711 if (save == 0)
3712 break;
3713 *cur = save;
3714 while (IS_BLANK(*cur)) cur++;
3715 }
3716 xmlFree(dup);
3717 }
3718}
3719
3720/**
3721 * xmlValidateDocumentFinal:
3722 * @ctxt: the validation context
3723 * @doc: a document instance
3724 *
3725 * Does the final step for the document validation once all the
3726 * incremental validation steps have been completed
3727 *
3728 * basically it does the following checks described by the XML Rec
3729 *
3730 *
3731 * returns 1 if valid or 0 otherwise
3732 */
3733
3734int
3735xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
3736 xmlRefTablePtr table;
3737
3738 if (doc == NULL) {
3739 xmlGenericError(xmlGenericErrorContext,
3740 "xmlValidateDocumentFinal: doc == NULL\n");
3741 return(0);
3742 }
3743
3744 /*
3745 * Check all the NOTATION/NOTATIONS attributes
3746 */
3747 /*
3748 * Check all the ENTITY/ENTITIES attributes definition for validity
3749 */
3750 /*
3751 * Check all the IDREF/IDREFS attributes definition for validity
3752 */
3753 table = (xmlRefTablePtr) doc->refs;
3754 ctxt->doc = doc;
3755 ctxt->valid = 1;
3756 xmlHashScan(table, (xmlHashScanner) xmlValidateCheckRefCallback, ctxt);
3757 return(ctxt->valid);
3758}
3759
3760/**
3761 * xmlValidateDtd:
3762 * @ctxt: the validation context
3763 * @doc: a document instance
3764 * @dtd: a dtd instance
3765 *
3766 * Try to validate the document against the dtd instance
3767 *
3768 * basically it does check all the definitions in the DtD.
3769 *
3770 * returns 1 if valid or 0 otherwise
3771 */
3772
3773int
3774xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
3775 int ret;
3776 xmlDtdPtr oldExt;
3777 xmlNodePtr root;
3778
3779 if (dtd == NULL) return(0);
3780 if (doc == NULL) return(0);
3781 oldExt = doc->extSubset;
3782 doc->extSubset = dtd;
3783 ret = xmlValidateRoot(ctxt, doc);
3784 if (ret == 0) {
3785 doc->extSubset = oldExt;
3786 return(ret);
3787 }
3788 if (doc->ids != NULL) {
3789 xmlFreeIDTable(doc->ids);
3790 doc->ids = NULL;
3791 }
3792 if (doc->refs != NULL) {
3793 xmlFreeRefTable(doc->refs);
3794 doc->refs = NULL;
3795 }
3796 root = xmlDocGetRootElement(doc);
3797 ret = xmlValidateElement(ctxt, doc, root);
3798 ret &= xmlValidateDocumentFinal(ctxt, doc);
3799 doc->extSubset = oldExt;
3800 return(ret);
3801}
3802
3803void
3804xmlValidateAttributeCallback(xmlAttributePtr cur, xmlValidCtxtPtr ctxt,
3805 const xmlChar *name) {
3806 if (cur == NULL)
3807 return;
3808 switch (cur->atype) {
3809 case XML_ATTRIBUTE_CDATA:
3810 case XML_ATTRIBUTE_ID:
3811 case XML_ATTRIBUTE_IDREF :
3812 case XML_ATTRIBUTE_IDREFS:
3813 case XML_ATTRIBUTE_NMTOKEN:
3814 case XML_ATTRIBUTE_NMTOKENS:
3815 case XML_ATTRIBUTE_ENUMERATION:
3816 break;
3817 case XML_ATTRIBUTE_ENTITY:
3818 case XML_ATTRIBUTE_ENTITIES:
3819 case XML_ATTRIBUTE_NOTATION:
3820 if (cur->defaultValue != NULL) {
3821 ctxt->valid &= xmlValidateAttributeValue2(ctxt, ctxt->doc,
3822 cur->name, cur->atype, cur->defaultValue);
3823 }
3824 if (cur->tree != NULL) {
3825 xmlEnumerationPtr tree = cur->tree;
3826 while (tree != NULL) {
3827 ctxt->valid &= xmlValidateAttributeValue2(ctxt, ctxt->doc,
3828 cur->name, cur->atype, tree->name);
3829 tree = tree->next;
3830 }
3831 }
3832 }
3833}
3834
3835/**
3836 * xmlValidateDtdFinal:
3837 * @ctxt: the validation context
3838 * @doc: a document instance
3839 *
3840 * Does the final step for the dtds validation once all the
3841 * subsets have been parsed
3842 *
3843 * basically it does the following checks described by the XML Rec
3844 * - check that ENTITY and ENTITIES type attributes default or
3845 * possible values matches one of the defined entities.
3846 * - check that NOTATION type attributes default or
3847 * possible values matches one of the defined notations.
3848 *
3849 * returns 1 if valid or 0 otherwise
3850 */
3851
3852int
3853xmlValidateDtdFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
3854 int ret = 1;
3855 xmlDtdPtr dtd;
3856 xmlAttributeTablePtr table;
3857
3858 if (doc == NULL) return(0);
3859 if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
3860 return(0);
3861 ctxt->doc = doc;
3862 ctxt->valid = ret;
3863 dtd = doc->intSubset;
3864 if ((dtd != NULL) && (dtd->attributes != NULL)) {
3865 table = (xmlAttributeTablePtr) dtd->attributes;
3866 xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt);
3867 }
3868 dtd = doc->extSubset;
3869 if ((dtd != NULL) && (dtd->attributes != NULL)) {
3870 table = (xmlAttributeTablePtr) dtd->attributes;
3871 xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt);
3872 }
3873 return(ctxt->valid);
3874}
3875
3876/**
3877 * xmlValidateDocument:
3878 * @ctxt: the validation context
3879 * @doc: a document instance
3880 *
3881 * Try to validate the document instance
3882 *
3883 * basically it does the all the checks described by the XML Rec
3884 * i.e. validates the internal and external subset (if present)
3885 * and validate the document tree.
3886 *
3887 * returns 1 if valid or 0 otherwise
3888 */
3889
3890int
3891xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
3892 int ret;
3893 xmlNodePtr root;
3894
3895 if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
3896 return(0);
3897 if ((doc->intSubset != NULL) && ((doc->intSubset->SystemID != NULL) ||
3898 (doc->intSubset->ExternalID != NULL)) && (doc->extSubset == NULL)) {
3899 doc->extSubset = xmlParseDTD(doc->intSubset->ExternalID,
3900 doc->intSubset->SystemID);
3901 if (doc->extSubset == NULL) {
3902 if (doc->intSubset->SystemID != NULL) {
3903 VERROR(ctxt->userData,
3904 "Could not load the external subset \"%s\"\n",
3905 doc->intSubset->SystemID);
3906 } else {
3907 VERROR(ctxt->userData,
3908 "Could not load the external subset \"%s\"\n",
3909 doc->intSubset->ExternalID);
3910 }
3911 return(0);
3912 }
3913 }
3914
3915 if (doc->ids != NULL) {
3916 xmlFreeIDTable(doc->ids);
3917 doc->ids = NULL;
3918 }
3919 if (doc->refs != NULL) {
3920 xmlFreeRefTable(doc->refs);
3921 doc->refs = NULL;
3922 }
3923 ret = xmlValidateDtdFinal(ctxt, doc);
3924 if (!xmlValidateRoot(ctxt, doc)) return(0);
3925
3926 root = xmlDocGetRootElement(doc);
3927 ret &= xmlValidateElement(ctxt, doc, root);
3928 ret &= xmlValidateDocumentFinal(ctxt, doc);
3929 return(ret);
3930}
3931
3932
3933/************************************************************************
3934 * *
3935 * Routines for dynamic validation editing *
3936 * *
3937 ************************************************************************/
3938
3939/**
3940 * xmlValidGetPotentialChildren:
3941 * @ctree: an element content tree
3942 * @list: an array to store the list of child names
3943 * @len: a pointer to the number of element in the list
3944 * @max: the size of the array
3945 *
3946 * Build/extend a list of potential children allowed by the content tree
3947 *
3948 * returns the number of element in the list, or -1 in case of error.
3949 */
3950
3951int
3952xmlValidGetPotentialChildren(xmlElementContent *ctree, const xmlChar **list,
3953 int *len, int max) {
3954 int i;
3955
3956 if ((ctree == NULL) || (list == NULL) || (len == NULL))
3957 return(-1);
3958 if (*len >= max) return(*len);
3959
3960 switch (ctree->type) {
3961 case XML_ELEMENT_CONTENT_PCDATA:
3962 for (i = 0; i < *len;i++)
3963 if (xmlStrEqual(BAD_CAST "#PCDATA", list[i])) return(*len);
3964 list[(*len)++] = BAD_CAST "#PCDATA";
3965 break;
3966 case XML_ELEMENT_CONTENT_ELEMENT:
3967 for (i = 0; i < *len;i++)
3968 if (xmlStrEqual(ctree->name, list[i])) return(*len);
3969 list[(*len)++] = ctree->name;
3970 break;
3971 case XML_ELEMENT_CONTENT_SEQ:
3972 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
3973 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
3974 break;
3975 case XML_ELEMENT_CONTENT_OR:
3976 xmlValidGetPotentialChildren(ctree->c1, list, len, max);
3977 xmlValidGetPotentialChildren(ctree->c2, list, len, max);
3978 break;
3979 }
3980
3981 return(*len);
3982}
3983
3984/**
3985 * xmlValidGetValidElements:
3986 * @prev: an element to insert after
3987 * @next: an element to insert next
3988 * @list: an array to store the list of child names
3989 * @max: the size of the array
3990 *
3991 * This function returns the list of authorized children to insert
3992 * within an existing tree while respecting the validity constraints
3993 * forced by the Dtd. The insertion point is defined using @prev and
3994 * @next in the following ways:
3995 * to insert before 'node': xmlValidGetValidElements(node->prev, node, ...
3996 * to insert next 'node': xmlValidGetValidElements(node, node->next, ...
3997 * to replace 'node': xmlValidGetValidElements(node->prev, node->next, ...
3998 * to prepend a child to 'node': xmlValidGetValidElements(NULL, node->childs,
3999 * to append a child to 'node': xmlValidGetValidElements(node->last, NULL, ...
4000 *
4001 * pointers to the element names are inserted at the beginning of the array
4002 * and do not need to be freed.
4003 *
4004 * returns the number of element in the list, or -1 in case of error. If
4005 * the function returns the value @max the caller is invited to grow the
4006 * receiving array and retry.
4007 */
4008
4009int
4010xmlValidGetValidElements(xmlNode *prev, xmlNode *next, const xmlChar **list,
4011 int max) {
4012 int nb_valid_elements = 0;
4013 const xmlChar *elements[256];
4014 int nb_elements = 0, i;
4015
4016 xmlNode *ref_node;
4017 xmlNode *parent;
4018 xmlNode *test_node;
4019
4020 xmlNode *prev_next;
4021 xmlNode *next_prev;
4022 xmlNode *parent_childs;
4023 xmlNode *parent_last;
4024
4025 xmlElement *element_desc;
4026
4027 if (prev == NULL && next == NULL)
4028 return(-1);
4029
4030 if (list == NULL) return(-1);
4031 if (max <= 0) return(-1);
4032
4033 nb_valid_elements = 0;
4034 ref_node = prev ? prev : next;
4035 parent = ref_node->parent;
4036
4037 /*
4038 * Retrieves the parent element declaration
4039 */
4040 element_desc = xmlGetDtdElementDesc(parent->doc->intSubset,
4041 parent->name);
4042 if ((element_desc == NULL) && (parent->doc->extSubset != NULL))
4043 element_desc = xmlGetDtdElementDesc(parent->doc->extSubset,
4044 parent->name);
4045 if (element_desc == NULL) return(-1);
4046
4047 /*
4048 * Do a backup of the current tree structure
4049 */
4050 prev_next = prev ? prev->next : NULL;
4051 next_prev = next ? next->prev : NULL;
4052 parent_childs = parent->children;
4053 parent_last = parent->last;
4054
4055 /*
4056 * Creates a dummy node and insert it into the tree
4057 */
4058 test_node = xmlNewNode (NULL, BAD_CAST "<!dummy?>");
4059 test_node->doc = ref_node->doc;
4060 test_node->parent = parent;
4061 test_node->prev = prev;
4062 test_node->next = next;
4063
4064 if (prev) prev->next = test_node;
4065 else parent->children = test_node;
4066
4067 if (next) next->prev = test_node;
4068 else parent->last = test_node;
4069
4070 /*
4071 * Insert each potential child node and check if the parent is
4072 * still valid
4073 */
4074 nb_elements = xmlValidGetPotentialChildren(element_desc->content,
4075 elements, &nb_elements, 256);
4076
4077 for (i = 0;i < nb_elements;i++) {
4078 test_node->name = elements[i];
4079 if (xmlValidateOneElement(NULL, parent->doc, parent)) {
4080 int j;
4081
4082 for (j = 0; j < nb_valid_elements;j++)
4083 if (xmlStrEqual(elements[i], list[j])) break;
4084 list[nb_valid_elements++] = elements[i];
4085 if (nb_valid_elements >= max) break;
4086 }
4087 }
4088
4089 /*
4090 * Restore the tree structure
4091 */
4092 if (prev) prev->next = prev_next;
4093 if (next) next->prev = next_prev;
4094 parent->children = parent_childs;
4095 parent->last = parent_last;
4096
4097 return(nb_valid_elements);
4098}