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