Annotation of XML/valid.c, revision 1.18
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:
10: #include <stdio.h>
11: #include <stdlib.h>
12: #include <string.h>
13: #include "valid.h"
14: #include "parser.h"
1.16 daniel 15: #include "parserInternals.h"
16:
17: #define VERROR \
18: if ((ctxt != NULL) && (ctxt->error != NULL)) ctxt->error
19:
20: #define VWARNING \
21: if ((ctxt != NULL) && (ctxt->warning != NULL)) ctxt->warning
22:
23: #define CHECK_DTD \
24: if (doc == NULL) return(0); \
25: else if (doc->intSubset == NULL) return(0)
1.1 daniel 26:
1.15 daniel 27: xmlElementPtr xmlGetDtdElementDesc(xmlDtdPtr dtd, const CHAR *name);
28: xmlAttributePtr xmlScanAttributeDecl(xmlDtdPtr dtd, const CHAR *elem);
29:
1.1 daniel 30: /****************************************************************
31: * *
32: * Util functions for data allocation/deallocation *
33: * *
34: ****************************************************************/
35:
36: /**
37: * xmlNewElementContent:
38: * @name: the subelement name or NULL
39: * @type: the type of element content decl
40: *
41: * Allocate an element content structure.
42: *
1.6 daniel 43: * Returns NULL if not, othervise the new element content structure
1.1 daniel 44: */
45: xmlElementContentPtr
46: xmlNewElementContent(CHAR *name, int type) {
1.2 daniel 47: xmlElementContentPtr ret;
48:
49: switch(type) {
50: case XML_ELEMENT_CONTENT_ELEMENT:
51: if (name == NULL) {
52: fprintf(stderr, "xmlNewElementContent : name == NULL !\n");
53: }
54: break;
55: case XML_ELEMENT_CONTENT_PCDATA:
56: case XML_ELEMENT_CONTENT_SEQ:
57: case XML_ELEMENT_CONTENT_OR:
58: if (name != NULL) {
59: fprintf(stderr, "xmlNewElementContent : name != NULL !\n");
60: }
61: break;
62: default:
63: fprintf(stderr, "xmlNewElementContent: unknown type %d\n", type);
64: exit(1);
65: }
66: ret = (xmlElementContentPtr) malloc(sizeof(xmlElementContent));
67: if (ret == NULL) {
68: fprintf(stderr, "xmlNewElementContent : out of memory!\n");
69: return(NULL);
70: }
71: ret->type = type;
72: ret->ocur = XML_ELEMENT_CONTENT_ONCE;
73: if (name != NULL)
74: ret->name = xmlStrdup(name);
75: else
76: ret->name = NULL;
1.4 daniel 77: ret->c1 = ret->c2 = NULL;
1.2 daniel 78: return(ret);
79: }
80:
81: /**
82: * xmlCopyElementContent:
83: * @content: An element content pointer.
84: *
85: * Build a copy of an element content description.
86: *
1.6 daniel 87: * Returns the new xmlElementContentPtr or NULL in case of error.
1.2 daniel 88: */
89: xmlElementContentPtr
1.4 daniel 90: xmlCopyElementContent(xmlElementContentPtr cur) {
91: xmlElementContentPtr ret;
92:
93: if (cur == NULL) return(NULL);
94: ret = xmlNewElementContent((CHAR *) cur->name, cur->type);
1.11 daniel 95: if (ret == NULL) {
96: fprintf(stderr, "xmlCopyElementContent : out of memory\n");
97: return(NULL);
98: }
99: ret->ocur = cur->ocur;
100: if (cur->c1 != NULL) ret->c1 = xmlCopyElementContent(cur->c1);
101: if (cur->c2 != NULL) ret->c2 = xmlCopyElementContent(cur->c2);
1.4 daniel 102: return(ret);
1.1 daniel 103: }
104:
105: /**
1.3 daniel 106: * xmlFreeElementContent:
107: * @cur: the element content tree to free
1.1 daniel 108: *
109: * Free an element content structure. This is a recursive call !
110: */
111: void
112: xmlFreeElementContent(xmlElementContentPtr cur) {
1.4 daniel 113: if (cur == NULL) return;
114: if (cur->c1 != NULL) xmlFreeElementContent(cur->c1);
115: if (cur->c2 != NULL) xmlFreeElementContent(cur->c2);
116: if (cur->name != NULL) free((CHAR *) cur->name);
117: memset(cur, -1, sizeof(xmlElementContent));
118: free(cur);
1.1 daniel 119: }
120:
1.3 daniel 121: /**
122: * xmlDumpElementContent:
1.8 daniel 123: * @buf: An XML buffer
1.3 daniel 124: * @content: An element table
125: * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
126: *
127: * This will dump the content of the element table as an XML DTD definition
128: */
129: void
1.8 daniel 130: xmlDumpElementContent(xmlBufferPtr buf, xmlElementContentPtr content, int glob) {
1.3 daniel 131: if (content == NULL) return;
132:
1.8 daniel 133: if (glob) xmlBufferWriteChar(buf, "(");
1.3 daniel 134: switch (content->type) {
135: case XML_ELEMENT_CONTENT_PCDATA:
1.8 daniel 136: xmlBufferWriteChar(buf, "#PCDATA");
1.3 daniel 137: break;
138: case XML_ELEMENT_CONTENT_ELEMENT:
1.8 daniel 139: xmlBufferWriteCHAR(buf, content->name);
1.3 daniel 140: break;
141: case XML_ELEMENT_CONTENT_SEQ:
142: if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
143: (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
1.8 daniel 144: xmlDumpElementContent(buf, content->c1, 1);
1.3 daniel 145: else
1.8 daniel 146: xmlDumpElementContent(buf, content->c1, 0);
147: xmlBufferWriteChar(buf, " , ");
1.3 daniel 148: if (content->c2->type == XML_ELEMENT_CONTENT_OR)
1.8 daniel 149: xmlDumpElementContent(buf, content->c2, 1);
1.3 daniel 150: else
1.8 daniel 151: xmlDumpElementContent(buf, content->c2, 0);
1.3 daniel 152: break;
153: case XML_ELEMENT_CONTENT_OR:
154: if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
155: (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
1.8 daniel 156: xmlDumpElementContent(buf, content->c1, 1);
1.3 daniel 157: else
1.8 daniel 158: xmlDumpElementContent(buf, content->c1, 0);
159: xmlBufferWriteChar(buf, " | ");
1.3 daniel 160: if (content->c2->type == XML_ELEMENT_CONTENT_SEQ)
1.8 daniel 161: xmlDumpElementContent(buf, content->c2, 1);
1.3 daniel 162: else
1.8 daniel 163: xmlDumpElementContent(buf, content->c2, 0);
1.3 daniel 164: break;
165: default:
166: fprintf(stderr, "xmlDumpElementContent: unknown type %d\n",
167: content->type);
168: }
169: if (glob)
1.8 daniel 170: xmlBufferWriteChar(buf, ")");
1.3 daniel 171: switch (content->ocur) {
172: case XML_ELEMENT_CONTENT_ONCE:
173: break;
174: case XML_ELEMENT_CONTENT_OPT:
1.8 daniel 175: xmlBufferWriteChar(buf, "?");
1.3 daniel 176: break;
177: case XML_ELEMENT_CONTENT_MULT:
1.8 daniel 178: xmlBufferWriteChar(buf, "*");
1.3 daniel 179: break;
180: case XML_ELEMENT_CONTENT_PLUS:
1.8 daniel 181: xmlBufferWriteChar(buf, "+");
1.3 daniel 182: break;
183: }
184: }
185:
1.1 daniel 186: /****************************************************************
187: * *
188: * Registration of DTD declarations *
189: * *
190: ****************************************************************/
191:
1.2 daniel 192: /**
193: * xmlCreateElementTable:
194: *
195: * create and initialize an empty element hash table.
196: *
1.6 daniel 197: * Returns the xmlElementTablePtr just created or NULL in case of error.
1.2 daniel 198: */
199: xmlElementTablePtr
200: xmlCreateElementTable(void) {
201: xmlElementTablePtr ret;
202:
203: ret = (xmlElementTablePtr)
204: malloc(sizeof(xmlElementTable));
205: if (ret == NULL) {
1.12 daniel 206: fprintf(stderr, "xmlCreateElementTable : malloc(%ld) failed\n",
207: (long)sizeof(xmlElementTable));
1.2 daniel 208: return(NULL);
209: }
1.4 daniel 210: ret->max_elements = XML_MIN_ELEMENT_TABLE;
1.2 daniel 211: ret->nb_elements = 0;
1.15 daniel 212: ret->table = (xmlElementPtr *)
213: malloc(ret->max_elements * sizeof(xmlElementPtr));
1.2 daniel 214: if (ret == NULL) {
1.12 daniel 215: fprintf(stderr, "xmlCreateElementTable : malloc(%ld) failed\n",
216: ret->max_elements * (long)sizeof(xmlElement));
1.2 daniel 217: free(ret);
218: return(NULL);
219: }
220: return(ret);
221: }
222:
1.1 daniel 223:
224: /**
225: * xmlAddElementDecl:
1.6 daniel 226: * @dtd: pointer to the DTD
1.1 daniel 227: * @name: the entity name
1.6 daniel 228: * @type: the element type
229: * @content: the element content tree or NULL
1.1 daniel 230: *
231: * Register a new element declaration
232: *
1.6 daniel 233: * Returns NULL if not, othervise the entity
1.1 daniel 234: */
235: xmlElementPtr
1.16 daniel 236: xmlAddElementDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const CHAR *name,
237: int type, xmlElementContentPtr content) {
1.2 daniel 238: xmlElementPtr ret, cur;
239: xmlElementTablePtr table;
240: int i;
1.1 daniel 241:
242: if (dtd == NULL) {
243: fprintf(stderr, "xmlAddElementDecl: dtd == NULL\n");
244: return(NULL);
245: }
246: if (name == NULL) {
247: fprintf(stderr, "xmlAddElementDecl: name == NULL\n");
248: return(NULL);
249: }
250: switch (type) {
251: case XML_ELEMENT_TYPE_EMPTY:
252: if (content != NULL) {
253: fprintf(stderr,
254: "xmlAddElementDecl: content != NULL for EMPTY\n");
255: return(NULL);
256: }
257: break;
258: case XML_ELEMENT_TYPE_ANY:
259: if (content != NULL) {
260: fprintf(stderr,
261: "xmlAddElementDecl: content != NULL for ANY\n");
262: return(NULL);
263: }
264: break;
265: case XML_ELEMENT_TYPE_MIXED:
266: if (content == NULL) {
267: fprintf(stderr,
268: "xmlAddElementDecl: content == NULL for MIXED\n");
269: return(NULL);
270: }
271: break;
272: case XML_ELEMENT_TYPE_ELEMENT:
273: if (content == NULL) {
274: fprintf(stderr,
275: "xmlAddElementDecl: content == NULL for ELEMENT\n");
276: return(NULL);
277: }
278: break;
279: default:
280: fprintf(stderr, "xmlAddElementDecl: unknown type %d\n", type);
281: return(NULL);
282: }
283:
284: /*
1.2 daniel 285: * Create the Element table if needed.
286: */
287: table = dtd->elements;
288: if (table == NULL)
289: table = dtd->elements = xmlCreateElementTable();
290: if (table == NULL) {
291: fprintf(stderr, "xmlAddElementDecl: Table creation failed!\n");
292: return(NULL);
293: }
294:
295: /*
1.1 daniel 296: * Validity Check:
297: * Search the DTD for previous declarations of the ELEMENT
298: */
1.2 daniel 299: for (i = 0;i < table->nb_elements;i++) {
1.15 daniel 300: cur = table->table[i];
1.2 daniel 301: if (!xmlStrcmp(cur->name, name)) {
302: /*
303: * The element is already defined in this Dtd.
304: */
1.16 daniel 305: VERROR(ctxt->userData, "Redefinition of element %s\n", name);
1.2 daniel 306: return(NULL);
307: }
308: }
1.1 daniel 309:
310: /*
1.2 daniel 311: * Grow the table, if needed.
1.1 daniel 312: */
1.2 daniel 313: if (table->nb_elements >= table->max_elements) {
314: /*
315: * need more elements.
316: */
317: table->max_elements *= 2;
1.15 daniel 318: table->table = (xmlElementPtr *)
319: realloc(table->table, table->max_elements * sizeof(xmlElementPtr));
1.13 daniel 320: if (table->table == NULL) {
1.2 daniel 321: fprintf(stderr, "xmlAddElementDecl: out of memory\n");
322: return(NULL);
323: }
1.1 daniel 324: }
1.15 daniel 325: ret = (xmlElementPtr) malloc(sizeof(xmlElement));
326: if (ret == NULL) {
327: fprintf(stderr, "xmlAddElementDecl: out of memory\n");
328: return(NULL);
329: }
330: table->table[table->nb_elements] = ret;
1.2 daniel 331:
332: /*
333: * fill the structure.
334: */
1.1 daniel 335: ret->type = type;
336: ret->name = xmlStrdup(name);
1.11 daniel 337: ret->content = xmlCopyElementContent(content);
1.15 daniel 338: ret->attributes = xmlScanAttributeDecl(dtd, name);
1.2 daniel 339: table->nb_elements++;
340:
341: return(ret);
342: }
343:
344: /**
345: * xmlFreeElement:
346: * @elem: An element
347: *
348: * Deallocate the memory used by an element definition
349: */
350: void
351: xmlFreeElement(xmlElementPtr elem) {
352: if (elem == NULL) return;
353: xmlFreeElementContent(elem->content);
354: if (elem->name != NULL)
355: free((CHAR *) elem->name);
356: memset(elem, -1, sizeof(xmlElement));
1.15 daniel 357: free(elem);
1.2 daniel 358: }
1.1 daniel 359:
1.2 daniel 360: /**
361: * xmlFreeElementTable:
362: * @table: An element table
363: *
1.4 daniel 364: * Deallocate the memory used by an element hash table.
1.2 daniel 365: */
366: void
367: xmlFreeElementTable(xmlElementTablePtr table) {
368: int i;
369:
370: if (table == NULL) return;
371:
372: for (i = 0;i < table->nb_elements;i++) {
1.15 daniel 373: xmlFreeElement(table->table[i]);
1.2 daniel 374: }
375: free(table->table);
376: free(table);
377: }
378:
379: /**
380: * xmlCopyElementTable:
381: * @table: An element table
382: *
383: * Build a copy of an element table.
384: *
1.6 daniel 385: * Returns the new xmlElementTablePtr or NULL in case of error.
1.2 daniel 386: */
387: xmlElementTablePtr
388: xmlCopyElementTable(xmlElementTablePtr table) {
389: xmlElementTablePtr ret;
390: xmlElementPtr cur, ent;
391: int i;
1.1 daniel 392:
1.2 daniel 393: ret = (xmlElementTablePtr) malloc(sizeof(xmlElementTable));
394: if (ret == NULL) {
395: fprintf(stderr, "xmlCopyElementTable: out of memory !\n");
396: return(NULL);
397: }
1.15 daniel 398: ret->table = (xmlElementPtr *) malloc(table->max_elements *
399: sizeof(xmlElementPtr));
1.2 daniel 400: if (ret->table == NULL) {
401: fprintf(stderr, "xmlCopyElementTable: out of memory !\n");
402: free(ret);
403: return(NULL);
404: }
405: ret->max_elements = table->max_elements;
406: ret->nb_elements = table->nb_elements;
407: for (i = 0;i < ret->nb_elements;i++) {
1.15 daniel 408: cur = (xmlElementPtr) malloc(sizeof(xmlElement));
409: if (cur == NULL) {
410: fprintf(stderr, "xmlCopyElementTable: out of memory !\n");
411: free(ret);
412: free(ret->table);
413: return(NULL);
414: }
415: ret->table[i] = cur;
416: ent = table->table[i];
1.2 daniel 417: cur->type = ent->type;
418: if (ent->name != NULL)
419: cur->name = xmlStrdup(ent->name);
420: else
421: cur->name = NULL;
422: cur->content = xmlCopyElementContent(ent->content);
1.15 daniel 423: cur->attributes = NULL;
1.2 daniel 424: }
1.1 daniel 425: return(ret);
426: }
427:
1.2 daniel 428: /**
429: * xmlDumpElementTable:
1.9 daniel 430: * @buf: the XML buffer output
1.2 daniel 431: * @table: An element table
432: *
433: * This will dump the content of the element table as an XML DTD definition
434: */
435: void
1.8 daniel 436: xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) {
1.2 daniel 437: int i;
438: xmlElementPtr cur;
439:
440: if (table == NULL) return;
441:
442: for (i = 0;i < table->nb_elements;i++) {
1.15 daniel 443: cur = table->table[i];
1.2 daniel 444: switch (cur->type) {
445: case XML_ELEMENT_TYPE_EMPTY:
1.8 daniel 446: xmlBufferWriteChar(buf, "<!ELEMENT ");
447: xmlBufferWriteCHAR(buf, cur->name);
448: xmlBufferWriteChar(buf, " EMPTY>\n");
1.2 daniel 449: break;
450: case XML_ELEMENT_TYPE_ANY:
1.8 daniel 451: xmlBufferWriteChar(buf, "<!ELEMENT ");
452: xmlBufferWriteCHAR(buf, cur->name);
453: xmlBufferWriteChar(buf, " ANY>\n");
1.2 daniel 454: break;
455: case XML_ELEMENT_TYPE_MIXED:
1.8 daniel 456: xmlBufferWriteChar(buf, "<!ELEMENT ");
457: xmlBufferWriteCHAR(buf, cur->name);
458: xmlBufferWriteChar(buf, " ");
459: xmlDumpElementContent(buf, cur->content, 1);
460: xmlBufferWriteChar(buf, ">\n");
1.2 daniel 461: break;
462: case XML_ELEMENT_TYPE_ELEMENT:
1.8 daniel 463: xmlBufferWriteChar(buf, "<!ELEMENT ");
464: xmlBufferWriteCHAR(buf, cur->name);
465: xmlBufferWriteChar(buf, " ");
466: xmlDumpElementContent(buf, cur->content, 1);
467: xmlBufferWriteChar(buf, ">\n");
1.2 daniel 468: break;
469: default:
470: fprintf(stderr,
471: "xmlDumpElementTable: internal: unknown type %d\n",
472: cur->type);
473: }
1.4 daniel 474: }
475: }
476:
477: /**
478: * xmlCreateEnumeration:
479: * @name: the enumeration name or NULL
480: *
481: * create and initialize an enumeration attribute node.
482: *
1.6 daniel 483: * Returns the xmlEnumerationPtr just created or NULL in case
1.4 daniel 484: * of error.
485: */
486: xmlEnumerationPtr
487: xmlCreateEnumeration(CHAR *name) {
488: xmlEnumerationPtr ret;
489:
490: ret = (xmlEnumerationPtr) malloc(sizeof(xmlEnumeration));
491: if (ret == NULL) {
1.12 daniel 492: fprintf(stderr, "xmlCreateEnumeration : malloc(%ld) failed\n",
493: (long)sizeof(xmlEnumeration));
1.4 daniel 494: return(NULL);
495: }
496:
497: if (name != NULL)
498: ret->name = xmlStrdup(name);
499: else
500: ret->name = NULL;
501: ret->next = NULL;
502: return(ret);
503: }
504:
505: /**
506: * xmlFreeEnumeration:
507: * @cur: the tree to free.
508: *
509: * free an enumeration attribute node (recursive).
510: */
511: void
512: xmlFreeEnumeration(xmlEnumerationPtr cur) {
513: if (cur == NULL) return;
514:
515: if (cur->next != NULL) xmlFreeEnumeration(cur->next);
516:
517: if (cur->name != NULL) free((CHAR *) cur->name);
518: memset(cur, -1, sizeof(xmlEnumeration));
519: free(cur);
520: }
521:
522: /**
523: * xmlCopyEnumeration:
524: * @cur: the tree to copy.
525: *
526: * Copy an enumeration attribute node (recursive).
527: *
1.6 daniel 528: * Returns the xmlEnumerationPtr just created or NULL in case
1.4 daniel 529: * of error.
530: */
531: xmlEnumerationPtr
532: xmlCopyEnumeration(xmlEnumerationPtr cur) {
533: xmlEnumerationPtr ret;
534:
535: if (cur == NULL) return(NULL);
536: ret = xmlCreateEnumeration((CHAR *) cur->name);
537:
538: if (cur->next != NULL) ret->next = xmlCopyEnumeration(cur->next);
539: else ret->next = NULL;
540:
541: return(ret);
542: }
543:
544: /**
1.18 ! daniel 545: * xmlDumpEnumeration:
! 546: * @buf: the XML buffer output
! 547: * @enum: An enumeration
! 548: *
! 549: * This will dump the content of the enumeration
! 550: */
! 551: void
! 552: xmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) {
! 553: if (cur == NULL) return;
! 554:
! 555: xmlBufferWriteCHAR(buf, cur->name);
! 556: if (cur->next == NULL)
! 557: xmlBufferWriteChar(buf, ")");
! 558: else {
! 559: xmlBufferWriteChar(buf, " | ");
! 560: xmlDumpEnumeration(buf, cur->next);
! 561: }
! 562: }
! 563:
! 564: /**
1.4 daniel 565: * xmlCreateAttributeTable:
566: *
567: * create and initialize an empty attribute hash table.
568: *
1.6 daniel 569: * Returns the xmlAttributeTablePtr just created or NULL in case
1.4 daniel 570: * of error.
571: */
572: xmlAttributeTablePtr
573: xmlCreateAttributeTable(void) {
574: xmlAttributeTablePtr ret;
575:
576: ret = (xmlAttributeTablePtr)
577: malloc(sizeof(xmlAttributeTable));
578: if (ret == NULL) {
1.12 daniel 579: fprintf(stderr, "xmlCreateAttributeTable : malloc(%ld) failed\n",
580: (long)sizeof(xmlAttributeTable));
1.4 daniel 581: return(NULL);
582: }
583: ret->max_attributes = XML_MIN_ATTRIBUTE_TABLE;
584: ret->nb_attributes = 0;
1.15 daniel 585: ret->table = (xmlAttributePtr *)
586: malloc(ret->max_attributes * sizeof(xmlAttributePtr));
1.4 daniel 587: if (ret == NULL) {
1.12 daniel 588: fprintf(stderr, "xmlCreateAttributeTable : malloc(%ld) failed\n",
1.15 daniel 589: ret->max_attributes * (long)sizeof(xmlAttributePtr));
1.4 daniel 590: free(ret);
591: return(NULL);
592: }
593: return(ret);
594: }
595:
1.15 daniel 596: /**
597: * xmlScanAttributeDecl:
598: * @dtd: pointer to the DTD
599: * @elem: the element name
600: *
601: * When inserting a new element scan the DtD for existing attributes
602: * for taht element and initialize the Attribute chain
603: *
604: * Returns the pointer to the first attribute decl in the chain,
605: * possibly NULL.
606: */
607: xmlAttributePtr
608: xmlScanAttributeDecl(xmlDtdPtr dtd, const CHAR *elem) {
1.16 daniel 609: xmlAttributePtr ret = NULL;
1.15 daniel 610: xmlAttributeTablePtr table;
611: int i;
612:
613: if (dtd == NULL) {
614: fprintf(stderr, "xmlScanAttributeDecl: dtd == NULL\n");
615: return(NULL);
616: }
617: if (elem == NULL) {
618: fprintf(stderr, "xmlScanAttributeDecl: elem == NULL\n");
619: return(NULL);
620: }
621: table = dtd->attributes;
622: if (table == NULL)
623: return(NULL);
624:
625: for (i = 0;i < table->nb_attributes;i++) {
626: if (!xmlStrcmp(table->table[i]->elem, elem)) {
1.16 daniel 627: table->table[i]->next = ret;
628: ret = table->table[i];
629: }
630: }
631: return(ret);
632: }
633:
634: /**
635: * xmlScanIDAttributeDecl:
636: * @ctxt: the validation context
637: * @elem: the element name
638: *
639: * Veryfy that the element don't have too many ID attributes
640: * declared.
641: *
642: * Returns the number of ID attributes found.
643: */
644: int
645: xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
646: xmlAttributePtr cur;
647: int ret = 0;
648:
649: if (elem == NULL) return(0);
650: cur = elem->attributes;
651: while (cur != NULL) {
652: if (cur->type == XML_ATTRIBUTE_ID) {
653: ret ++;
654: if (ret > 1)
655: VERROR(ctxt->userData,
656: "Element %s has too may ID attributes defined : %s\n",
657: elem->name, cur->name);
1.15 daniel 658: }
1.16 daniel 659: cur = cur->next;
1.15 daniel 660: }
661: return(ret);
662: }
663:
1.4 daniel 664:
665: /**
666: * xmlAddAttributeDecl:
1.16 daniel 667: * @ctxt: the validation context
1.6 daniel 668: * @dtd: pointer to the DTD
669: * @elem: the element name
670: * @name: the attribute name
671: * @type: the attribute type
672: * @def: the attribute default type
673: * @defaultValue: the attribute default value
674: * @tree: if it's an enumeration, the associated list
1.4 daniel 675: *
676: * Register a new attribute declaration
677: *
1.6 daniel 678: * Returns NULL if not, othervise the entity
1.4 daniel 679: */
680: xmlAttributePtr
1.16 daniel 681: xmlAddAttributeDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const CHAR *elem,
682: const CHAR *name, int type, int def,
683: const CHAR *defaultValue, xmlEnumerationPtr tree) {
1.4 daniel 684: xmlAttributePtr ret, cur;
685: xmlAttributeTablePtr table;
1.15 daniel 686: xmlElementPtr elemDef;
1.4 daniel 687: int i;
688:
689: if (dtd == NULL) {
690: fprintf(stderr, "xmlAddAttributeDecl: dtd == NULL\n");
691: return(NULL);
692: }
693: if (name == NULL) {
694: fprintf(stderr, "xmlAddAttributeDecl: name == NULL\n");
695: return(NULL);
696: }
697: if (elem == NULL) {
698: fprintf(stderr, "xmlAddAttributeDecl: elem == NULL\n");
699: return(NULL);
700: }
701: /* TODO: Lacks verifications !!! */
702: switch (type) {
703: case XML_ATTRIBUTE_CDATA:
704: break;
705: case XML_ATTRIBUTE_ID:
706: break;
707: case XML_ATTRIBUTE_IDREF:
708: break;
709: case XML_ATTRIBUTE_IDREFS:
710: break;
711: case XML_ATTRIBUTE_ENTITY:
712: break;
713: case XML_ATTRIBUTE_ENTITIES:
714: break;
715: case XML_ATTRIBUTE_NMTOKEN:
716: break;
717: case XML_ATTRIBUTE_NMTOKENS:
718: break;
719: case XML_ATTRIBUTE_ENUMERATION:
720: break;
721: case XML_ATTRIBUTE_NOTATION:
722: break;
723: default:
724: fprintf(stderr, "xmlAddAttributeDecl: unknown type %d\n", type);
725: return(NULL);
726: }
727:
728: /*
729: * Create the Attribute table if needed.
730: */
731: table = dtd->attributes;
732: if (table == NULL)
733: table = dtd->attributes = xmlCreateAttributeTable();
734: if (table == NULL) {
735: fprintf(stderr, "xmlAddAttributeDecl: Table creation failed!\n");
736: return(NULL);
737: }
738:
739: /*
740: * Validity Check:
741: * Search the DTD for previous declarations of the ATTLIST
742: */
743: for (i = 0;i < table->nb_attributes;i++) {
1.15 daniel 744: cur = table->table[i];
1.4 daniel 745: if ((!xmlStrcmp(cur->name, name)) && (!xmlStrcmp(cur->elem, elem))) {
746: /*
747: * The attribute is already defined in this Dtd.
748: */
749: fprintf(stderr,
750: "xmlAddAttributeDecl: %s already defined\n", name);
751: }
752: }
753:
754: /*
755: * Grow the table, if needed.
756: */
757: if (table->nb_attributes >= table->max_attributes) {
758: /*
759: * need more attributes.
760: */
761: table->max_attributes *= 2;
1.15 daniel 762: table->table = (xmlAttributePtr *)
763: realloc(table->table, table->max_attributes *
764: sizeof(xmlAttributePtr));
1.13 daniel 765: if (table->table == NULL) {
1.4 daniel 766: fprintf(stderr, "xmlAddAttributeDecl: out of memory\n");
767: return(NULL);
768: }
769: }
1.15 daniel 770: ret = (xmlAttributePtr) malloc(sizeof(xmlAttribute));
771: if (ret == NULL) {
772: fprintf(stderr, "xmlAddAttributeDecl: out of memory\n");
773: return(NULL);
774: }
775: table->table[table->nb_attributes] = ret;
1.4 daniel 776:
777: /*
778: * fill the structure.
779: */
780: ret->type = type;
781: ret->name = xmlStrdup(name);
782: ret->elem = xmlStrdup(elem);
783: ret->def = def;
784: ret->tree = tree;
785: if (defaultValue != NULL)
786: ret->defaultValue = xmlStrdup(defaultValue);
787: else
788: ret->defaultValue = NULL;
1.15 daniel 789: elemDef = xmlGetDtdElementDesc(dtd, elem);
790: if (elemDef != NULL) {
1.16 daniel 791: if ((type == XML_ATTRIBUTE_ID) &&
792: (xmlScanIDAttributeDecl(NULL, elemDef) != 0))
793: VERROR(ctxt->userData,
794: "Element %s has too may ID attributes defined : %s\n",
795: elem, name);
1.15 daniel 796: ret->next = elemDef->attributes;
797: elemDef->attributes = ret;
798: }
1.4 daniel 799: table->nb_attributes++;
800:
801: return(ret);
802: }
803:
804: /**
805: * xmlFreeAttribute:
806: * @elem: An attribute
807: *
808: * Deallocate the memory used by an attribute definition
809: */
810: void
811: xmlFreeAttribute(xmlAttributePtr attr) {
812: if (attr == NULL) return;
813: if (attr->tree != NULL)
814: xmlFreeEnumeration(attr->tree);
815: if (attr->elem != NULL)
816: free((CHAR *) attr->elem);
817: if (attr->name != NULL)
818: free((CHAR *) attr->name);
819: if (attr->defaultValue != NULL)
820: free((CHAR *) attr->defaultValue);
821: memset(attr, -1, sizeof(xmlAttribute));
1.15 daniel 822: free(attr);
1.4 daniel 823: }
824:
825: /**
826: * xmlFreeAttributeTable:
827: * @table: An attribute table
828: *
829: * Deallocate the memory used by an entities hash table.
830: */
831: void
832: xmlFreeAttributeTable(xmlAttributeTablePtr table) {
833: int i;
834:
835: if (table == NULL) return;
836:
837: for (i = 0;i < table->nb_attributes;i++) {
1.15 daniel 838: xmlFreeAttribute(table->table[i]);
1.4 daniel 839: }
840: free(table->table);
841: free(table);
842: }
843:
844: /**
845: * xmlCopyAttributeTable:
846: * @table: An attribute table
847: *
848: * Build a copy of an attribute table.
849: *
1.6 daniel 850: * Returns the new xmlAttributeTablePtr or NULL in case of error.
1.4 daniel 851: */
852: xmlAttributeTablePtr
853: xmlCopyAttributeTable(xmlAttributeTablePtr table) {
854: xmlAttributeTablePtr ret;
855: xmlAttributePtr cur, attr;
856: int i;
857:
858: ret = (xmlAttributeTablePtr) malloc(sizeof(xmlAttributeTable));
859: if (ret == NULL) {
860: fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
861: return(NULL);
862: }
1.15 daniel 863: ret->table = (xmlAttributePtr *) malloc(table->max_attributes *
864: sizeof(xmlAttributePtr));
1.4 daniel 865: if (ret->table == NULL) {
866: fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
867: free(ret);
868: return(NULL);
869: }
870: ret->max_attributes = table->max_attributes;
871: ret->nb_attributes = table->nb_attributes;
872: for (i = 0;i < ret->nb_attributes;i++) {
1.15 daniel 873: attr = table->table[i];
874: cur = (xmlAttributePtr) malloc(sizeof(xmlAttribute));
875: if (cur == NULL) {
876: fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
877: free(ret);
878: free(ret->table);
879: return(NULL);
880: }
881: ret->table[i] = cur;
1.4 daniel 882: cur->type = attr->type;
883: cur->def = attr->def;
884: cur->tree = xmlCopyEnumeration(attr->tree);
885: if (attr->elem != NULL)
886: cur->elem = xmlStrdup(attr->elem);
887: else
888: cur->elem = NULL;
889: if (attr->name != NULL)
890: cur->name = xmlStrdup(attr->name);
891: else
892: cur->name = NULL;
893: if (attr->defaultValue != NULL)
894: cur->defaultValue = xmlStrdup(attr->defaultValue);
895: else
896: cur->defaultValue = NULL;
1.15 daniel 897: /* NEED to rebuild the next chain !!!!!! */
1.4 daniel 898: }
899: return(ret);
900: }
901:
902: /**
903: * xmlDumpAttributeTable:
1.9 daniel 904: * @buf: the XML buffer output
1.4 daniel 905: * @table: An attribute table
906: *
907: * This will dump the content of the attribute table as an XML DTD definition
908: */
909: void
1.8 daniel 910: xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) {
1.4 daniel 911: int i;
912: xmlAttributePtr cur;
913:
914: if (table == NULL) return;
915:
916: for (i = 0;i < table->nb_attributes;i++) {
1.15 daniel 917: cur = table->table[i];
1.8 daniel 918: xmlBufferWriteChar(buf, "<!ATTLIST ");
919: xmlBufferWriteCHAR(buf, cur->elem);
920: xmlBufferWriteChar(buf, " ");
921: xmlBufferWriteCHAR(buf, cur->name);
1.4 daniel 922: switch (cur->type) {
923: case XML_ATTRIBUTE_CDATA:
1.8 daniel 924: xmlBufferWriteChar(buf, " CDATA");
1.4 daniel 925: break;
926: case XML_ATTRIBUTE_ID:
1.8 daniel 927: xmlBufferWriteChar(buf, " ID");
1.4 daniel 928: break;
929: case XML_ATTRIBUTE_IDREF:
1.8 daniel 930: xmlBufferWriteChar(buf, " IDREF");
1.4 daniel 931: break;
932: case XML_ATTRIBUTE_IDREFS:
1.8 daniel 933: xmlBufferWriteChar(buf, " IDREFS");
1.4 daniel 934: break;
935: case XML_ATTRIBUTE_ENTITY:
1.8 daniel 936: xmlBufferWriteChar(buf, " ENTITY");
1.4 daniel 937: break;
938: case XML_ATTRIBUTE_ENTITIES:
1.8 daniel 939: xmlBufferWriteChar(buf, " ENTITIES");
1.4 daniel 940: break;
941: case XML_ATTRIBUTE_NMTOKEN:
1.8 daniel 942: xmlBufferWriteChar(buf, " NMTOKEN");
1.4 daniel 943: break;
944: case XML_ATTRIBUTE_NMTOKENS:
1.8 daniel 945: xmlBufferWriteChar(buf, " NMTOKENS");
1.4 daniel 946: break;
947: case XML_ATTRIBUTE_ENUMERATION:
1.18 ! daniel 948: xmlBufferWriteChar(buf, " (");
! 949: xmlDumpEnumeration(buf, cur->tree);
1.4 daniel 950: break;
951: case XML_ATTRIBUTE_NOTATION:
1.18 ! daniel 952: xmlBufferWriteChar(buf, " NOTATION (");
! 953: xmlDumpEnumeration(buf, cur->tree);
1.4 daniel 954: break;
955: default:
956: fprintf(stderr,
957: "xmlDumpAttributeTable: internal: unknown type %d\n",
958: cur->type);
959: }
960: switch (cur->def) {
961: case XML_ATTRIBUTE_NONE:
962: break;
963: case XML_ATTRIBUTE_REQUIRED:
1.8 daniel 964: xmlBufferWriteChar(buf, " #REQUIRED");
1.4 daniel 965: break;
966: case XML_ATTRIBUTE_IMPLIED:
1.8 daniel 967: xmlBufferWriteChar(buf, " #IMPLIED");
1.4 daniel 968: break;
969: case XML_ATTRIBUTE_FIXED:
1.17 daniel 970: xmlBufferWriteChar(buf, " #FIXED");
1.4 daniel 971: break;
972: default:
973: fprintf(stderr,
974: "xmlDumpAttributeTable: internal: unknown default %d\n",
975: cur->def);
976: }
1.17 daniel 977: if (cur->defaultValue != NULL) {
978: xmlBufferWriteChar(buf, " ");
979: xmlBufferWriteQuotedString(buf, cur->defaultValue);
980: }
1.8 daniel 981: xmlBufferWriteChar(buf, ">\n");
1.5 daniel 982: }
983: }
984:
985: /************************************************************************
986: * *
987: * NOTATIONs *
988: * *
989: ************************************************************************/
990: /**
991: * xmlCreateNotationTable:
992: *
993: * create and initialize an empty notation hash table.
994: *
1.6 daniel 995: * Returns the xmlNotationTablePtr just created or NULL in case
1.5 daniel 996: * of error.
997: */
998: xmlNotationTablePtr
999: xmlCreateNotationTable(void) {
1000: xmlNotationTablePtr ret;
1001:
1002: ret = (xmlNotationTablePtr)
1003: malloc(sizeof(xmlNotationTable));
1004: if (ret == NULL) {
1.12 daniel 1005: fprintf(stderr, "xmlCreateNotationTable : malloc(%ld) failed\n",
1006: (long)sizeof(xmlNotationTable));
1.5 daniel 1007: return(NULL);
1008: }
1009: ret->max_notations = XML_MIN_NOTATION_TABLE;
1010: ret->nb_notations = 0;
1.15 daniel 1011: ret->table = (xmlNotationPtr *)
1012: malloc(ret->max_notations * sizeof(xmlNotationPtr));
1.5 daniel 1013: if (ret == NULL) {
1.12 daniel 1014: fprintf(stderr, "xmlCreateNotationTable : malloc(%ld) failed\n",
1015: ret->max_notations * (long)sizeof(xmlNotation));
1.5 daniel 1016: free(ret);
1017: return(NULL);
1018: }
1019: return(ret);
1020: }
1021:
1022:
1023: /**
1024: * xmlAddNotationDecl:
1.6 daniel 1025: * @dtd: pointer to the DTD
1.16 daniel 1026: * @ctxt: the validation context
1.5 daniel 1027: * @name: the entity name
1.6 daniel 1028: * @PublicID: the public identifier or NULL
1029: * @SystemID: the system identifier or NULL
1.5 daniel 1030: *
1031: * Register a new notation declaration
1032: *
1.6 daniel 1033: * Returns NULL if not, othervise the entity
1.5 daniel 1034: */
1035: xmlNotationPtr
1.16 daniel 1036: xmlAddNotationDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const CHAR *name,
1037: const CHAR *PublicID, const CHAR *SystemID) {
1.5 daniel 1038: xmlNotationPtr ret, cur;
1039: xmlNotationTablePtr table;
1040: int i;
1041:
1042: if (dtd == NULL) {
1043: fprintf(stderr, "xmlAddNotationDecl: dtd == NULL\n");
1044: return(NULL);
1045: }
1046: if (name == NULL) {
1047: fprintf(stderr, "xmlAddNotationDecl: name == NULL\n");
1048: return(NULL);
1049: }
1050: if ((PublicID == NULL) && (SystemID == NULL)) {
1051: fprintf(stderr, "xmlAddNotationDecl: no PUBLIC ID nor SYSTEM ID\n");
1052: }
1053:
1054: /*
1055: * Create the Notation table if needed.
1056: */
1057: table = dtd->notations;
1058: if (table == NULL)
1059: table = dtd->notations = xmlCreateNotationTable();
1060: if (table == NULL) {
1061: fprintf(stderr, "xmlAddNotationDecl: Table creation failed!\n");
1062: return(NULL);
1063: }
1064:
1065: /*
1066: * Validity Check:
1067: * Search the DTD for previous declarations of the ATTLIST
1068: */
1069: for (i = 0;i < table->nb_notations;i++) {
1.15 daniel 1070: cur = table->table[i];
1.5 daniel 1071: if (!xmlStrcmp(cur->name, name)) {
1072: /*
1073: * The notation is already defined in this Dtd.
1074: */
1075: fprintf(stderr,
1076: "xmlAddNotationDecl: %s already defined\n", name);
1077: }
1078: }
1079:
1080: /*
1081: * Grow the table, if needed.
1082: */
1083: if (table->nb_notations >= table->max_notations) {
1084: /*
1085: * need more notations.
1086: */
1087: table->max_notations *= 2;
1.15 daniel 1088: table->table = (xmlNotationPtr *)
1089: realloc(table->table, table->max_notations *
1090: sizeof(xmlNotationPtr));
1.13 daniel 1091: if (table->table == NULL) {
1.5 daniel 1092: fprintf(stderr, "xmlAddNotationDecl: out of memory\n");
1093: return(NULL);
1094: }
1095: }
1.15 daniel 1096: ret = (xmlNotationPtr) malloc(sizeof(xmlNotation));
1097: if (ret == NULL) {
1098: fprintf(stderr, "xmlAddNotationDecl: out of memory\n");
1099: return(NULL);
1100: }
1101: table->table[table->nb_notations] = ret;
1.5 daniel 1102:
1103: /*
1104: * fill the structure.
1105: */
1106: ret->name = xmlStrdup(name);
1107: if (SystemID != NULL)
1108: ret->SystemID = xmlStrdup(SystemID);
1109: else
1110: ret->SystemID = NULL;
1111: if (PublicID != NULL)
1112: ret->PublicID = xmlStrdup(PublicID);
1113: else
1114: ret->PublicID = NULL;
1115: table->nb_notations++;
1116:
1117: return(ret);
1118: }
1119:
1120: /**
1121: * xmlFreeNotation:
1122: * @not: A notation
1123: *
1124: * Deallocate the memory used by an notation definition
1125: */
1126: void
1127: xmlFreeNotation(xmlNotationPtr nota) {
1128: if (nota == NULL) return;
1129: if (nota->name != NULL)
1130: free((CHAR *) nota->name);
1131: if (nota->PublicID != NULL)
1132: free((CHAR *) nota->PublicID);
1133: if (nota->SystemID != NULL)
1134: free((CHAR *) nota->SystemID);
1135: memset(nota, -1, sizeof(xmlNotation));
1.15 daniel 1136: free(nota);
1.5 daniel 1137: }
1138:
1139: /**
1140: * xmlFreeNotationTable:
1141: * @table: An notation table
1142: *
1143: * Deallocate the memory used by an entities hash table.
1144: */
1145: void
1146: xmlFreeNotationTable(xmlNotationTablePtr table) {
1147: int i;
1148:
1149: if (table == NULL) return;
1150:
1151: for (i = 0;i < table->nb_notations;i++) {
1.15 daniel 1152: xmlFreeNotation(table->table[i]);
1.5 daniel 1153: }
1154: free(table->table);
1155: free(table);
1156: }
1157:
1158: /**
1159: * xmlCopyNotationTable:
1160: * @table: A notation table
1161: *
1162: * Build a copy of a notation table.
1163: *
1.6 daniel 1164: * Returns the new xmlNotationTablePtr or NULL in case of error.
1.5 daniel 1165: */
1166: xmlNotationTablePtr
1167: xmlCopyNotationTable(xmlNotationTablePtr table) {
1168: xmlNotationTablePtr ret;
1169: xmlNotationPtr cur, nota;
1170: int i;
1171:
1172: ret = (xmlNotationTablePtr) malloc(sizeof(xmlNotationTable));
1173: if (ret == NULL) {
1174: fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
1175: return(NULL);
1176: }
1.15 daniel 1177: ret->table = (xmlNotationPtr *) malloc(table->max_notations *
1178: sizeof(xmlNotationPtr));
1.5 daniel 1179: if (ret->table == NULL) {
1180: fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
1181: free(ret);
1182: return(NULL);
1183: }
1184: ret->max_notations = table->max_notations;
1185: ret->nb_notations = table->nb_notations;
1186: for (i = 0;i < ret->nb_notations;i++) {
1.15 daniel 1187: cur = (xmlNotationPtr) malloc(sizeof(xmlNotation));
1188: if (cur == NULL) {
1189: fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
1190: free(ret);
1191: free(ret->table);
1192: return(NULL);
1193: }
1194: ret->table[i] = cur;
1195: nota = table->table[i];
1.5 daniel 1196: if (nota->name != NULL)
1197: cur->name = xmlStrdup(nota->name);
1198: else
1199: cur->name = NULL;
1200: if (nota->PublicID != NULL)
1201: cur->PublicID = xmlStrdup(nota->PublicID);
1202: else
1203: cur->PublicID = NULL;
1204: if (nota->SystemID != NULL)
1205: cur->SystemID = xmlStrdup(nota->SystemID);
1206: else
1207: cur->SystemID = NULL;
1208: }
1209: return(ret);
1210: }
1211:
1212: /**
1213: * xmlDumpNotationTable:
1.9 daniel 1214: * @buf: the XML buffer output
1.5 daniel 1215: * @table: A notation table
1216: *
1217: * This will dump the content of the notation table as an XML DTD definition
1218: */
1219: void
1.8 daniel 1220: xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
1.5 daniel 1221: int i;
1222: xmlNotationPtr cur;
1223:
1224: if (table == NULL) return;
1225:
1226: for (i = 0;i < table->nb_notations;i++) {
1.15 daniel 1227: cur = table->table[i];
1.8 daniel 1228: xmlBufferWriteChar(buf, "<!NOTATION ");
1229: xmlBufferWriteCHAR(buf, cur->name);
1.5 daniel 1230: if (cur->PublicID != NULL) {
1.10 daniel 1231: xmlBufferWriteChar(buf, " PUBLIC ");
1232: xmlBufferWriteQuotedString(buf, cur->PublicID);
1.5 daniel 1233: if (cur->SystemID != NULL) {
1.8 daniel 1234: xmlBufferWriteChar(buf, " ");
1235: xmlBufferWriteCHAR(buf, cur->SystemID);
1.5 daniel 1236: }
1237: } else {
1.8 daniel 1238: xmlBufferWriteChar(buf, " SYSTEM ");
1239: xmlBufferWriteCHAR(buf, cur->SystemID);
1.5 daniel 1240: }
1.8 daniel 1241: xmlBufferWriteChar(buf, " >\n");
1.2 daniel 1242: }
1243: }
1.14 daniel 1244:
1245: /************************************************************************
1246: * *
1247: * Routines for validity checking *
1248: * *
1249: ************************************************************************/
1250:
1251: /**
1252: * xmlGetDtdElementDesc:
1253: * @dtd: a pointer to the DtD to search
1254: * @name: the element name
1255: *
1256: * Search the Dtd for the description of this element
1257: *
1258: * returns the xmlElementPtr if found or NULL
1259: */
1260:
1261: xmlElementPtr
1262: xmlGetDtdElementDesc(xmlDtdPtr dtd, const CHAR *name) {
1263: xmlElementTablePtr table;
1264: xmlElementPtr cur;
1265: int i;
1266:
1267: if (dtd == NULL) return(NULL);
1268: if (dtd->elements == NULL) return(NULL);
1269: table = dtd->elements;
1270:
1271: for (i = 0;i < table->nb_elements;i++) {
1.15 daniel 1272: cur = table->table[i];
1.14 daniel 1273: if (!xmlStrcmp(cur->name, name))
1274: return(cur);
1275: }
1276: return(NULL);
1277: }
1278:
1279: /**
1280: * xmlGetDtdAttrDesc:
1281: * @dtd: a pointer to the DtD to search
1.15 daniel 1282: * @elem: the element name
1.14 daniel 1283: * @name: the attribute name
1284: *
1.15 daniel 1285: * Search the Dtd for the description of this attribute on
1286: * this element.
1.14 daniel 1287: *
1288: * returns the xmlAttributePtr if found or NULL
1289: */
1290:
1291: xmlAttributePtr
1.15 daniel 1292: xmlGetDtdAttrDesc(xmlDtdPtr dtd, const CHAR *elem, const CHAR *name) {
1.14 daniel 1293: xmlAttributeTablePtr table;
1294: xmlAttributePtr cur;
1295: int i;
1296:
1297: if (dtd == NULL) return(NULL);
1298: if (dtd->attributes == NULL) return(NULL);
1299: table = dtd->attributes;
1300:
1301: for (i = 0;i < table->nb_attributes;i++) {
1.15 daniel 1302: cur = table->table[i];
1303: if ((!xmlStrcmp(cur->name, name)) &&
1304: (!xmlStrcmp(cur->elem, elem)))
1.14 daniel 1305: return(cur);
1306: }
1307: return(NULL);
1308: }
1309:
1310: /**
1311: * xmlGetDtdNotationDesc:
1312: * @dtd: a pointer to the DtD to search
1313: * @name: the notation name
1314: *
1315: * Search the Dtd for the description of this notation
1316: *
1317: * returns the xmlNotationPtr if found or NULL
1318: */
1319:
1320: xmlNotationPtr
1321: xmlGetDtdNotationDesc(xmlDtdPtr dtd, const CHAR *name) {
1322: xmlNotationTablePtr table;
1323: xmlNotationPtr cur;
1324: int i;
1325:
1326: if (dtd == NULL) return(NULL);
1327: if (dtd->notations == NULL) return(NULL);
1328: table = dtd->notations;
1329:
1330: for (i = 0;i < table->nb_notations;i++) {
1.15 daniel 1331: cur = table->table[i];
1.14 daniel 1332: if (!xmlStrcmp(cur->name, name))
1333: return(cur);
1334: }
1335: return(NULL);
1336: }
1337:
1338: /**
1.18 ! daniel 1339: * xmlIsMixedElement
! 1340: * @doc: the document
! 1341: * @name: the element name
! 1342: *
! 1343: * Search in the DtDs whether an element accept Mixed content (or ANY)
! 1344: * basically if it is supposed to accept text childs
! 1345: *
! 1346: * returns 0 if no, 1 if yes, and -1 if no element description is available
! 1347: */
! 1348:
! 1349: int
! 1350: xmlIsMixedElement(xmlDocPtr doc, const CHAR *name) {
! 1351: xmlElementPtr elemDecl;
! 1352:
! 1353: if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
! 1354:
! 1355: elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
! 1356: if ((elemDecl == NULL) && (doc->extSubset != NULL))
! 1357: elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
! 1358: if (elemDecl == NULL) return(-1);
! 1359: switch (elemDecl->type) {
! 1360: case XML_ELEMENT_TYPE_ELEMENT:
! 1361: return(0);
! 1362: case XML_ELEMENT_TYPE_EMPTY:
! 1363: /*
! 1364: * return 1 for EMPTY since we want VC error to pop up
! 1365: * on <empty> </empty> for example
! 1366: */
! 1367: case XML_ELEMENT_TYPE_ANY:
! 1368: case XML_ELEMENT_TYPE_MIXED:
! 1369: return(1);
! 1370: }
! 1371: return(1);
! 1372: }
! 1373:
! 1374: /**
1.16 daniel 1375: * xmlValidateNameValue:
1376: * @value: an Name value
1377: *
1378: * Validate that the given value match Name production
1379: *
1380: * returns 1 if valid or 0 otherwise
1381: */
1382:
1383: int
1384: xmlValidateNameValue(const CHAR *value) {
1385: const CHAR *cur;
1386:
1387: if (value == NULL) return(0);
1388: cur = value;
1389:
1390: if (!IS_LETTER(*cur) && (*cur != '_') &&
1391: (*cur != ':')) {
1392: return(0);
1393: }
1394:
1395: while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
1396: (*cur == '.') || (*cur == '-') ||
1397: (*cur == '_') || (*cur == ':') ||
1398: (IS_COMBINING(*cur)) ||
1399: (IS_EXTENDER(*cur)))
1400: cur++;
1401:
1402: if (*cur != 0) return(0);
1403:
1404: return(1);
1405: }
1406:
1407: /**
1408: * xmlValidateNamesValue:
1409: * @value: an Names value
1410: *
1411: * Validate that the given value match Names production
1412: *
1413: * returns 1 if valid or 0 otherwise
1414: */
1415:
1416: int
1417: xmlValidateNamesValue(const CHAR *value) {
1418: const CHAR *cur;
1419:
1420: if (value == NULL) return(0);
1421: cur = value;
1422:
1423: if (!IS_LETTER(*cur) && (*cur != '_') &&
1424: (*cur != ':')) {
1425: return(0);
1426: }
1427:
1428: while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
1429: (*cur == '.') || (*cur == '-') ||
1430: (*cur == '_') || (*cur == ':') ||
1431: (IS_COMBINING(*cur)) ||
1432: (IS_EXTENDER(*cur)))
1433: cur++;
1434:
1435: while (IS_BLANK(*cur)) {
1436: while (IS_BLANK(*cur)) cur++;
1437:
1438: if (!IS_LETTER(*cur) && (*cur != '_') &&
1439: (*cur != ':')) {
1440: return(0);
1441: }
1442:
1443: while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
1444: (*cur == '.') || (*cur == '-') ||
1445: (*cur == '_') || (*cur == ':') ||
1446: (IS_COMBINING(*cur)) ||
1447: (IS_EXTENDER(*cur)))
1448: cur++;
1449: }
1450:
1451: if (*cur != 0) return(0);
1452:
1453: return(1);
1454: }
1455:
1456: /**
1457: * xmlValidateNmtokenValue:
1458: * @value: an Mntoken value
1459: *
1460: * Validate that the given value match Nmtoken production
1461: *
1462: * [ VC: Name Token ]
1463: *
1464: * returns 1 if valid or 0 otherwise
1465: */
1466:
1467: int
1468: xmlValidateNmtokenValue(const CHAR *value) {
1469: const CHAR *cur;
1470:
1471: if (value == NULL) return(0);
1472: cur = value;
1473:
1474: if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
1475: (*cur != '.') && (*cur != '-') &&
1476: (*cur != '_') && (*cur != ':') &&
1477: (!IS_COMBINING(*cur)) &&
1478: (!IS_EXTENDER(*cur)))
1479: return(0);
1480:
1481: while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
1482: (*cur == '.') || (*cur == '-') ||
1483: (*cur == '_') || (*cur == ':') ||
1484: (IS_COMBINING(*cur)) ||
1485: (IS_EXTENDER(*cur)))
1486: cur++;
1487:
1488: if (*cur != 0) return(0);
1489:
1490: return(1);
1491: return(1);
1492: }
1493:
1494: /**
1495: * xmlValidateNmtokensValue:
1496: * @value: an Mntokens value
1497: *
1498: * Validate that the given value match Nmtokens production
1499: *
1500: * [ VC: Name Token ]
1501: *
1502: * returns 1 if valid or 0 otherwise
1503: */
1504:
1505: int
1506: xmlValidateNmtokensValue(const CHAR *value) {
1507: const CHAR *cur;
1508:
1509: if (value == NULL) return(0);
1510: cur = value;
1511:
1512: if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
1513: (*cur != '.') && (*cur != '-') &&
1514: (*cur != '_') && (*cur != ':') &&
1515: (!IS_COMBINING(*cur)) &&
1516: (!IS_EXTENDER(*cur)))
1517: return(0);
1518:
1519: while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
1520: (*cur == '.') || (*cur == '-') ||
1521: (*cur == '_') || (*cur == ':') ||
1522: (IS_COMBINING(*cur)) ||
1523: (IS_EXTENDER(*cur)))
1524: cur++;
1525:
1526: while (IS_BLANK(*cur)) {
1527: while (IS_BLANK(*cur)) cur++;
1528:
1529: if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
1530: (*cur != '.') && (*cur != '-') &&
1531: (*cur != '_') && (*cur != ':') &&
1532: (!IS_COMBINING(*cur)) &&
1533: (!IS_EXTENDER(*cur)))
1534: return(0);
1535:
1536: while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
1537: (*cur == '.') || (*cur == '-') ||
1538: (*cur == '_') || (*cur == ':') ||
1539: (IS_COMBINING(*cur)) ||
1540: (IS_EXTENDER(*cur)))
1541: cur++;
1542: }
1543:
1544: if (*cur != 0) return(0);
1545:
1546: return(1);
1547: }
1548:
1549: /**
1550: * xmlValidateNotationDecl:
1551: * @doc: a document instance
1552: * @nota: a notation definition
1553: *
1554: * Try to validate a single notation definition
1555: * basically it does the following checks as described by the
1556: * XML-1.0 recommendation:
1.18 ! daniel 1557: * - it seems that no validity constraing exist on notation declarations
! 1558: * But this function get called anyway ...
1.16 daniel 1559: *
1560: * returns 1 if valid or 0 otherwise
1561: */
1562:
1563: int
1564: xmlValidateNotationDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
1565: xmlNotationPtr nota) {
1566: int ret = 1;
1567:
1568: return(ret);
1569: }
1570:
1571: /**
1572: * xmlValidateAttributeValue:
1573: * @type: an attribute type
1574: * @value: an attribute value
1575: *
1576: * Validate that the given attribute value match the proper production
1577: *
1578: * [ VC: ID ]
1579: * Values of type ID must match the Name production....
1580: *
1581: * [ VC: IDREF ]
1582: * Values of type IDREF must match the Name production, and values
1583: * of type IDREFS must match Names ...
1584: *
1585: * [ VC: Entity Name ]
1586: * Values of type ENTITY must match the Name production, values
1587: * of type ENTITIES must match Names ...
1588: *
1589: * [ VC: Name Token ]
1590: * Values of type NMTOKEN must match the Nmtoken production; values
1591: * of type NMTOKENS must match Nmtokens.
1592: *
1593: * returns 1 if valid or 0 otherwise
1594: */
1595:
1596: int
1597: xmlValidateAttributeValue(xmlAttributeType type, const CHAR *value) {
1598: switch (type) {
1599: case XML_ATTRIBUTE_IDREFS:
1600: case XML_ATTRIBUTE_ENTITIES:
1601: return(xmlValidateNamesValue(value));
1602: case XML_ATTRIBUTE_IDREF:
1603: case XML_ATTRIBUTE_ID:
1604: case XML_ATTRIBUTE_ENTITY:
1605: case XML_ATTRIBUTE_NOTATION:
1606: return(xmlValidateNameValue(value));
1607: case XML_ATTRIBUTE_NMTOKENS:
1608: case XML_ATTRIBUTE_ENUMERATION:
1609: return(xmlValidateNmtokensValue(value));
1610: case XML_ATTRIBUTE_NMTOKEN:
1611: return(xmlValidateNmtokenValue(value));
1612: case XML_ATTRIBUTE_CDATA:
1613: break;
1614: }
1615: return(1);
1616: }
1617:
1618: /**
1.14 daniel 1619: * xmlValidateAttributeDecl:
1620: * @doc: a document instance
1621: * @attr: an attribute definition
1622: *
1623: * Try to validate a single attribute definition
1624: * basically it does the following checks as described by the
1625: * XML-1.0 recommendation:
1626: * - [ VC: Attribute Default Legal ]
1627: * - [ VC: Enumeration ]
1628: * - [ VC: ID Attribute Default ]
1629: *
1630: * The ID/IDREF uniqueness and matching are done separately
1631: *
1632: * returns 1 if valid or 0 otherwise
1633: */
1634:
1635: int
1636: xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
1637: xmlAttributePtr attr) {
1.16 daniel 1638: int ret = 1;
1639: int val;
1.14 daniel 1640: CHECK_DTD;
1.16 daniel 1641: if(attr == NULL) return(1);
1642:
1643: /* Attribute Default Legal */
1644: /* Enumeration */
1645: if (attr->defaultValue != NULL) {
1646: val = xmlValidateAttributeValue(attr->type, attr->defaultValue);
1647: if (val == 0) {
1648: VERROR(ctxt->userData,
1649: "Syntax of default value for attribute %s on %s is not valid\n",
1650: attr->name, attr->elem);
1651: }
1652: ret &= val;
1653: }
1654:
1655: /* ID Attribute Default */
1656: if ((attr->type == XML_ATTRIBUTE_ID)&&
1657: (attr->def != XML_ATTRIBUTE_IMPLIED) &&
1658: (attr->def != XML_ATTRIBUTE_REQUIRED)) {
1659: VERROR(ctxt->userData,
1660: "ID attribute %s on %s is not valid must be #IMPLIED or #REQUIRED\n",
1661: attr->name, attr->elem);
1662: ret = 0;
1663: }
1664:
1665: /* max ID per element */
1666: if ((attr->type == XML_ATTRIBUTE_ID) && (doc->extSubset != NULL)) {
1667: int nbId = 0;
1668:
1669: /* the trick is taht we parse DtD as their own internal subset */
1670: xmlElementPtr elem = xmlGetDtdElementDesc(doc->extSubset,
1671: attr->elem);
1672: if (elem != NULL) {
1673: nbId = xmlScanIDAttributeDecl(NULL, elem);
1674: }
1675: if (nbId >= 1)
1676: VERROR(ctxt->userData,
1677: "Element %s has ID attribute defined in the external subset : %s\n",
1678: attr->elem, attr->name);
1679: }
1.14 daniel 1680:
1.16 daniel 1681: return(ret);
1.14 daniel 1682: }
1683:
1684: /**
1685: * xmlValidateElementDecl:
1686: * @ctxt: the validation context
1687: * @doc: a document instance
1688: * @elem: an element definition
1689: *
1690: * Try to validate a single element definition
1691: * basically it does the following checks as described by the
1692: * XML-1.0 recommendation:
1693: * - [ VC: One ID per Element Type ]
1694: * - [ VC: No Duplicate Types ]
1695: * - [ VC: Unique Element Type Declaration ]
1696: *
1697: * returns 1 if valid or 0 otherwise
1698: */
1699:
1700: int
1.16 daniel 1701: xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
1702: xmlElementPtr elem) {
1703: int ret = 1;
1704: xmlElementPtr tst;
1705:
1.14 daniel 1706: CHECK_DTD;
1.16 daniel 1707:
1708: if (elem == NULL) return(1);
1.14 daniel 1709:
1.16 daniel 1710: /* No Duplicate Types */
1711: if (elem->type == XML_ELEMENT_TYPE_MIXED) {
1712: xmlElementContentPtr cur, next;
1713: const CHAR *name;
1714:
1715: cur = elem->content;
1716: while (cur != NULL) {
1717: if (cur->type != XML_ELEMENT_CONTENT_OR) break;
1718: if (cur->c1 == NULL) break;
1719: if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
1720: name = cur->c1->name;
1721: next = cur->c2;
1722: while (next != NULL) {
1723: if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
1724: if (!xmlStrcmp(next->name, name)) {
1725: VERROR(ctxt->userData,
1726: "Definition of %s has duplicate references of %s\n",
1727: elem->name, name);
1728: ret = 0;
1729: }
1730: break;
1731: }
1732: if (next->c1 == NULL) break;
1733: if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
1734: if (!xmlStrcmp(next->c1->name, name)) {
1735: VERROR(ctxt->userData,
1736: "Definition of %s has duplicate references of %s\n",
1737: elem->name, name);
1738: ret = 0;
1739: }
1740: next = next->c2;
1741: }
1742: }
1743: cur = cur->c2;
1744: }
1745: }
1746:
1747: /* VC: Unique Element Type Declaration */
1748: tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
1749: if ((tst != NULL ) && (tst != elem)) {
1750: VERROR(ctxt->userData, "Redefinition of element %s\n",
1751: elem->name);
1752: ret = 0;
1753: }
1754: tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
1755: if ((tst != NULL ) && (tst != elem)) {
1756: VERROR(ctxt->userData, "Redefinition of element %s\n",
1757: elem->name);
1758: ret = 0;
1759: }
1760:
1761: /* One ID per Element Type */
1762: if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
1763: ret = 0;
1764: }
1765: return(ret);
1.14 daniel 1766: }
1767:
1768: /**
1769: * xmlValidateOneAttribute:
1770: * @ctxt: the validation context
1771: * @doc: a document instance
1772: * @elem: an element instance
1773: * @attr: an attribute instance
1774: *
1775: * Try to validate a single attribute for an element
1776: * basically it * does the following checks as described by the
1777: * XML-1.0 recommendation:
1.18 ! daniel 1778: * - [ VC: Attribute Value Type ]
! 1779: * - [ VC: Fixed Attribute Default ]
1.14 daniel 1780: * - [ VC: Entity Name ]
1781: * - [ VC: Name Token ]
1782: * - [ VC: ID ]
1783: * - [ VC: IDREF ]
1784: * - [ VC: Entity Name ]
1.16 daniel 1785: * - [ VC: Notation Attributes ]
1.14 daniel 1786: *
1787: * The ID/IDREF uniqueness and matching are done separately
1788: *
1789: * returns 1 if valid or 0 otherwise
1790: */
1791:
1792: int
1.16 daniel 1793: xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
1.18 ! daniel 1794: xmlNodePtr elem, xmlAttrPtr attr, const CHAR *value) {
! 1795: xmlElementPtr elemDecl;
! 1796: xmlAttributePtr attrDecl;
! 1797: int val;
! 1798: int ret = 1;
! 1799:
1.14 daniel 1800: CHECK_DTD;
1.18 ! daniel 1801: if ((elem == NULL) || (elem->name == NULL)) return(0);
! 1802: if ((attr == NULL) || (attr->name == NULL)) return(0);
! 1803:
! 1804: attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
! 1805: if ((attrDecl == NULL) && (doc->extSubset != NULL))
! 1806: attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, attr->name);
! 1807:
1.14 daniel 1808:
1.18 ! daniel 1809: /* Validity Constraint: Attribute Value Type */
! 1810: if (attrDecl == NULL) {
! 1811: VERROR(ctxt->userData,
! 1812: "No declaration for attribute %s on element %s\n",
! 1813: attr->name, elem->name);
! 1814: return(0);
! 1815: }
! 1816: val = xmlValidateAttributeValue(attrDecl->type, value);
! 1817: if (val == 0) {
! 1818: VERROR(ctxt->userData,
! 1819: "Syntax of value for attribute %s on %s is not valid\n",
! 1820: attr->name, elem->name);
! 1821: ret = 0;
! 1822: }
! 1823:
! 1824: /* Validity Constraint: Notation Attributes */
! 1825: if (attrDecl->type == XML_ATTRIBUTE_NOTATION) {
! 1826: xmlEnumerationPtr tree = attrDecl->tree;
! 1827: xmlNotationPtr nota;
! 1828:
! 1829: /* First check that the given NOTATION was declared */
! 1830: nota = xmlGetDtdNotationDesc(doc->intSubset, value);
! 1831: if (nota == NULL)
! 1832: nota = xmlGetDtdNotationDesc(doc->extSubset, value);
! 1833:
! 1834: if (nota == NULL) {
! 1835: VERROR(ctxt->userData,
! 1836: "Value \"%s\" for attribute %s on %s is not a declared Notation\n",
! 1837: value, attr->name, elem->name);
! 1838: ret = 0;
! 1839: }
! 1840:
! 1841: /* Second, verify that it's among the list */
! 1842: while (tree != NULL) {
! 1843: if (!xmlStrcmp(tree->name, value)) break;
! 1844: tree = tree->next;
! 1845: }
! 1846: if (tree == NULL) {
! 1847: VERROR(ctxt->userData,
! 1848: "Value \"%s\" for attribute %s on %s is among the enumerated notations\n",
! 1849: value, attr->name, elem->name);
! 1850: ret = 0;
! 1851: }
! 1852: }
! 1853:
! 1854: /* Validity Constraint: Enumeration */
! 1855: if (attrDecl->type == XML_ATTRIBUTE_ENUMERATION) {
! 1856: xmlEnumerationPtr tree = attrDecl->tree;
! 1857: while (tree != NULL) {
! 1858: if (!xmlStrcmp(tree->name, value)) break;
! 1859: tree = tree->next;
! 1860: }
! 1861: if (tree == NULL) {
! 1862: VERROR(ctxt->userData,
! 1863: "Value \"%s\" for attribute %s on %s is among the enumerated set\n",
! 1864: value, attr->name, elem->name);
! 1865: ret = 0;
! 1866: }
! 1867: }
! 1868:
! 1869: /* Fixed Attribute Default */
! 1870: if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
! 1871: (xmlStrcmp(attrDecl->defaultValue, value))) {
! 1872: VERROR(ctxt->userData,
! 1873: "Value for attribute %s on %s must be \"%s\"\n",
! 1874: attr->name, elem->name, attrDecl->defaultValue);
! 1875: ret = 0;
! 1876: }
! 1877:
! 1878: elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
! 1879: if ((elemDecl == NULL) && (doc->extSubset != NULL))
! 1880: elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
! 1881: if (elemDecl == NULL) {
! 1882: /* the error has or will be reported soon in xmlValidateOneElement */
! 1883: return(0);
! 1884: }
! 1885: return(ret);
! 1886: }
! 1887:
! 1888: int xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
! 1889: xmlElementContentPtr cont);
! 1890:
! 1891: /**
! 1892: * xmlValidateElementTypeExpr:
! 1893: * @ctxt: the validation context
! 1894: * @child: pointer to the child list
! 1895: * @cont: pointer to the content declaration
! 1896: *
! 1897: * Try to validate the content of an element of type element
! 1898: * but don't handle the occurence factor
! 1899: *
! 1900: * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
! 1901: * also update child value in-situ.
! 1902: */
! 1903:
! 1904: int
! 1905: xmlValidateElementTypeExpr(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
! 1906: xmlElementContentPtr cont) {
! 1907: xmlNodePtr cur;
! 1908: int ret = 1;
! 1909:
! 1910: if (cont == NULL) return(-1);
! 1911: if (*child == NULL) return(0);
! 1912: while (*child != NULL) {
! 1913: if ((*child)->type == XML_PI_NODE) {
! 1914: *child = (*child)->next;
! 1915: continue;
! 1916: }
! 1917: if ((*child)->type == XML_COMMENT_NODE) {
! 1918: *child = (*child)->next;
! 1919: continue;
! 1920: }
! 1921: else if ((*child)->type != XML_ELEMENT_NODE) {
! 1922: return(-1);
! 1923: }
! 1924: break;
! 1925: }
! 1926: if (*child == NULL) return(0);
! 1927: switch (cont->type) {
! 1928: case XML_ELEMENT_CONTENT_PCDATA:
! 1929: /* Internal error !!! */
! 1930: fprintf(stderr, "Internal: MIXED struct bad\n");
! 1931: return(-1);
! 1932: case XML_ELEMENT_CONTENT_ELEMENT:
! 1933: ret = (!xmlStrcmp((*child)->name, cont->name));
! 1934: if (ret == 1)
! 1935: *child = (*child)->next;
! 1936: return(ret);
! 1937: case XML_ELEMENT_CONTENT_OR:
! 1938: cur = *child;
! 1939: ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
! 1940: if (ret == -1) return(-1);
! 1941: if (ret == 1) {
! 1942: return(1);
! 1943: }
! 1944: /* rollback and retry the other path */
! 1945: *child = cur;
! 1946: ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
! 1947: if (ret == -1) return(-1);
! 1948: if (ret == 0) {
! 1949: *child = cur;
! 1950: return(0);
! 1951: }
! 1952: return(1);
! 1953: case XML_ELEMENT_CONTENT_SEQ:
! 1954: cur = *child;
! 1955: ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
! 1956: if (ret == -1) return(-1);
! 1957: if (ret == 0) {
! 1958: *child = cur;
! 1959: return(0);
! 1960: }
! 1961: ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
! 1962: if (ret == -1) return(-1);
! 1963: if (ret == 0) {
! 1964: *child = cur;
! 1965: return(0);
! 1966: }
! 1967: return(1);
! 1968: }
! 1969: return(ret);
! 1970: }
! 1971:
! 1972: /**
! 1973: * xmlValidateElementTypeElement:
! 1974: * @ctxt: the validation context
! 1975: * @child: pointer to the child list
! 1976: * @cont: pointer to the content declaration
! 1977: *
! 1978: * Try to validate the content of an element of type element
! 1979: * yeah, Yet Another Regexp Implementation, and recursive
! 1980: *
! 1981: * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
! 1982: * also update child and content values in-situ.
! 1983: */
! 1984:
! 1985: int
! 1986: xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
! 1987: xmlElementContentPtr cont) {
! 1988: xmlNodePtr cur;
! 1989: int ret = 1;
! 1990:
! 1991: if (cont == NULL) return(-1);
! 1992: while (*child != NULL) {
! 1993: if ((*child)->type == XML_PI_NODE) {
! 1994: *child = (*child)->next;
! 1995: continue;
! 1996: }
! 1997: if ((*child)->type == XML_COMMENT_NODE) {
! 1998: *child = (*child)->next;
! 1999: continue;
! 2000: }
! 2001: else if ((*child)->type != XML_ELEMENT_NODE) {
! 2002: return(-1);
! 2003: }
! 2004: break;
! 2005: }
! 2006: if (*child == NULL) {
! 2007: if ((cont->ocur == XML_ELEMENT_CONTENT_OPT) ||
! 2008: (cont->ocur == XML_ELEMENT_CONTENT_MULT))
! 2009: return(1);
! 2010: return(0);
! 2011: }
! 2012: cur = *child;
! 2013: ret = xmlValidateElementTypeExpr(ctxt, child, cont);
! 2014: if (ret == -1) return(-1);
! 2015: switch (cont->ocur) {
! 2016: case XML_ELEMENT_CONTENT_ONCE:
! 2017: if (ret == 1) {
! 2018: return(1);
! 2019: }
! 2020: *child = cur;
! 2021: return(0);
! 2022: case XML_ELEMENT_CONTENT_OPT:
! 2023: if (ret == 0) {
! 2024: *child = cur;
! 2025: return(1);
! 2026: }
! 2027: return(1);
! 2028: case XML_ELEMENT_CONTENT_MULT:
! 2029: if (ret == 0) {
! 2030: *child = cur;
! 2031: return(1);
! 2032: }
! 2033: /* no break on purpose */
! 2034: case XML_ELEMENT_CONTENT_PLUS:
! 2035: if (ret == 0) {
! 2036: *child = cur;
! 2037: return(0);
! 2038: }
! 2039: do {
! 2040: cur = *child;
! 2041: ret = xmlValidateElementTypeExpr(ctxt, child, cont);
! 2042: } while (ret == 1);
! 2043: if (ret == -1) return(-1);
! 2044: *child = cur;
! 2045: return(1);
! 2046: }
! 2047: return(ret);
1.14 daniel 2048: }
2049:
2050: /**
2051: * xmlValidateOneElement:
2052: * @ctxt: the validation context
2053: * @doc: a document instance
2054: * @elem: an element instance
2055: *
2056: * Try to validate a single element and it's attributes,
2057: * basically it does the following checks as described by the
2058: * XML-1.0 recommendation:
2059: * - [ VC: Element Valid ]
2060: * - [ VC: Required Attribute ]
2061: * Then call xmlValidateOneAttribute() for each attribute present.
2062: *
2063: * The ID/IDREF checkings are done separately
2064: *
2065: * returns 1 if valid or 0 otherwise
2066: */
2067:
2068: int
1.16 daniel 2069: xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
1.18 ! daniel 2070: xmlNodePtr elem) {
! 2071: xmlElementPtr elemDecl;
! 2072: xmlElementContentPtr cont;
! 2073: xmlNodePtr child;
! 2074: int ret = 1;
! 2075: const CHAR *name;
! 2076:
1.14 daniel 2077: CHECK_DTD;
2078:
1.18 ! daniel 2079: if ((elem == NULL) || (elem->name == NULL)) return(0);
! 2080:
! 2081: elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
! 2082: if ((elemDecl == NULL) && (doc->extSubset != NULL))
! 2083: elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
! 2084: if (elemDecl == NULL) {
! 2085: VERROR(ctxt->userData, "No declaration for element %s\n",
! 2086: elem->name);
! 2087: return(0);
! 2088: }
! 2089:
! 2090: /* Check taht the element content matches the definition */
! 2091: switch (elemDecl->type) {
! 2092: case XML_ELEMENT_TYPE_EMPTY:
! 2093: if (elem->childs != NULL) {
! 2094: VERROR(ctxt->userData,
! 2095: "Element %s was declared EMPTY this one has content\n",
! 2096: elem->name);
! 2097: ret = 0;
! 2098: }
! 2099: break;
! 2100: case XML_ELEMENT_TYPE_ANY:
! 2101: /* I don't think anything is required then */
! 2102: break;
! 2103: case XML_ELEMENT_TYPE_MIXED:
! 2104: /* Hum, this start to get messy */
! 2105: child = elem->childs;
! 2106: while (child != NULL) {
! 2107: if (child->type == XML_ELEMENT_NODE) {
! 2108: name = child->name;
! 2109: cont = elemDecl->content;
! 2110: while (cont != NULL) {
! 2111: if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
! 2112: if (!xmlStrcmp(cont->name, name)) break;
! 2113: } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
! 2114: (cont->c1 != NULL) &&
! 2115: (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
! 2116: if (!xmlStrcmp(cont->c1->name, name)) break;
! 2117: } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
! 2118: (cont->c1 == NULL) ||
! 2119: (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
! 2120: /* Internal error !!! */
! 2121: fprintf(stderr, "Internal: MIXED struct bad\n");
! 2122: break;
! 2123: }
! 2124: cont = cont->c2;
! 2125: }
! 2126: if (cont == NULL) {
! 2127: VERROR(ctxt->userData,
! 2128: "Element %s is not declared in %s list of possible childs\n",
! 2129: name, elem->name);
! 2130: ret = 0;
! 2131: }
! 2132: }
! 2133: child = child->next;
! 2134: }
! 2135: break;
! 2136: case XML_ELEMENT_TYPE_ELEMENT:
! 2137: child = elem->childs;
! 2138: cont = elemDecl->content;
! 2139: ret = xmlValidateElementTypeElement(ctxt, &child, cont);
! 2140: if (ret == 0) {
! 2141: VERROR(ctxt->userData,
! 2142: "Element %s content doesn't follow the Dtd\n", elem->name);
! 2143: ret = 0;
! 2144: } else if (child != NULL) {
! 2145: VERROR(ctxt->userData,
! 2146: "Element %s content doesn't follow the Dtd, extra elements\n",
! 2147: elem->name);
! 2148: ret = 0;
! 2149: }
! 2150: break;
! 2151: }
! 2152:
! 2153: return(ret);
1.14 daniel 2154: }
2155:
2156: /**
2157: * xmlValidateRoot:
2158: * @ctxt: the validation context
2159: * @doc: a document instance
2160: *
2161: * Try to validate a the root element
2162: * basically it does the following check as described by the
2163: * XML-1.0 recommendation:
2164: * - [ VC: Root Element Type ]
2165: * it doesn't try to recurse or apply other check to the element
2166: *
2167: * returns 1 if valid or 0 otherwise
2168: */
2169:
2170: int
2171: xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
2172: if (doc == NULL) return(0);
2173:
2174: if ((doc->intSubset == NULL) ||
2175: (doc->intSubset->name == NULL)) {
2176: VERROR(ctxt->userData, "Not valid: no DtD found\n");
2177: return(0);
2178: }
2179: if ((doc->root == NULL) || (doc->root->name == NULL)) {
2180: VERROR(ctxt->userData, "Not valid: no root element\n");
2181: return(0);
2182: }
2183: if (xmlStrcmp(doc->intSubset->name, doc->root->name)) {
2184: VERROR(ctxt->userData,
2185: "Not valid: root and DtD name do not match %s and %s\n",
2186: doc->root->name, doc->intSubset->name);
2187: return(0);
2188: }
2189: return(1);
2190: }
2191:
2192:
2193: /**
2194: * xmlValidateElement:
2195: * @ctxt: the validation context
2196: * @doc: a document instance
2197: * @elem: an element instance
2198: *
2199: * Try to validate the subtree under an element
2200: *
2201: * returns 1 if valid or 0 otherwise
2202: */
2203:
2204: int
1.18 ! daniel 2205: xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
1.14 daniel 2206: CHECK_DTD;
2207:
2208: return(1);
2209: }
2210:
2211: /**
2212: * xmlValidateDtd:
2213: * @ctxt: the validation context
2214: * @doc: a document instance
2215: * @dtd: a dtd instance
2216: *
2217: * Try to validate the dtd instance
2218: *
2219: * basically it does check all the definitions in the DtD.
2220: *
2221: * returns 1 if valid or 0 otherwise
2222: */
2223:
2224: int
2225: xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
2226: return(1);
2227: }
2228:
2229: /**
2230: * xmlValidateDocument:
2231: * @ctxt: the validation context
2232: * @doc: a document instance
2233: *
2234: * Try to validate the document instance
2235: *
2236: * basically it does the all the checks described by the
2237: * i.e. validates the internal and external subset (if present)
2238: * and validate the document tree.
2239: *
2240: * returns 1 if valid or 0 otherwise
2241: */
2242:
2243: int
2244: xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
2245: if (!xmlValidateRoot(ctxt, doc)) return(0);
2246:
2247: return(1);
2248: }
2249:
Webmaster