Annotation of XML/valid.c, revision 1.30
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
11: #define HAVE_FCNTL_H
12: #include <io.h>
13: #else
1.30 ! daniel 14: #include "config.h"
1.29 daniel 15: #endif
16:
1.1 daniel 17: #include <stdio.h>
1.29 daniel 18: #include <string.h>
19:
20: #ifdef HAVE_STDLIB_H
1.1 daniel 21: #include <stdlib.h>
1.29 daniel 22: #endif
23:
1.26 daniel 24: #include "xmlmemory.h"
1.1 daniel 25: #include "valid.h"
26: #include "parser.h"
1.16 daniel 27: #include "parserInternals.h"
28:
29: #define VERROR \
30: if ((ctxt != NULL) && (ctxt->error != NULL)) ctxt->error
31:
32: #define VWARNING \
33: if ((ctxt != NULL) && (ctxt->warning != NULL)) ctxt->warning
34:
35: #define CHECK_DTD \
36: if (doc == NULL) return(0); \
37: else if (doc->intSubset == NULL) return(0)
1.1 daniel 38:
1.15 daniel 39: xmlElementPtr xmlGetDtdElementDesc(xmlDtdPtr dtd, const CHAR *name);
40: xmlAttributePtr xmlScanAttributeDecl(xmlDtdPtr dtd, const CHAR *elem);
41:
1.1 daniel 42: /****************************************************************
43: * *
44: * Util functions for data allocation/deallocation *
45: * *
46: ****************************************************************/
47:
48: /**
49: * xmlNewElementContent:
50: * @name: the subelement name or NULL
51: * @type: the type of element content decl
52: *
53: * Allocate an element content structure.
54: *
1.6 daniel 55: * Returns NULL if not, othervise the new element content structure
1.1 daniel 56: */
57: xmlElementContentPtr
1.25 daniel 58: xmlNewElementContent(CHAR *name, xmlElementContentType type) {
1.2 daniel 59: xmlElementContentPtr ret;
60:
61: switch(type) {
62: case XML_ELEMENT_CONTENT_ELEMENT:
63: if (name == NULL) {
64: fprintf(stderr, "xmlNewElementContent : name == NULL !\n");
65: }
66: break;
67: case XML_ELEMENT_CONTENT_PCDATA:
68: case XML_ELEMENT_CONTENT_SEQ:
69: case XML_ELEMENT_CONTENT_OR:
70: if (name != NULL) {
71: fprintf(stderr, "xmlNewElementContent : name != NULL !\n");
72: }
73: break;
74: default:
75: fprintf(stderr, "xmlNewElementContent: unknown type %d\n", type);
76: exit(1);
77: }
1.26 daniel 78: ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
1.2 daniel 79: if (ret == NULL) {
80: fprintf(stderr, "xmlNewElementContent : out of memory!\n");
81: return(NULL);
82: }
83: ret->type = type;
84: ret->ocur = XML_ELEMENT_CONTENT_ONCE;
85: if (name != NULL)
86: ret->name = xmlStrdup(name);
87: else
88: ret->name = NULL;
1.4 daniel 89: ret->c1 = ret->c2 = NULL;
1.2 daniel 90: return(ret);
91: }
92:
93: /**
94: * xmlCopyElementContent:
95: * @content: An element content pointer.
96: *
97: * Build a copy of an element content description.
98: *
1.6 daniel 99: * Returns the new xmlElementContentPtr or NULL in case of error.
1.2 daniel 100: */
101: xmlElementContentPtr
1.4 daniel 102: xmlCopyElementContent(xmlElementContentPtr cur) {
103: xmlElementContentPtr ret;
104:
105: if (cur == NULL) return(NULL);
106: ret = xmlNewElementContent((CHAR *) cur->name, cur->type);
1.11 daniel 107: if (ret == NULL) {
108: fprintf(stderr, "xmlCopyElementContent : out of memory\n");
109: return(NULL);
110: }
111: ret->ocur = cur->ocur;
112: if (cur->c1 != NULL) ret->c1 = xmlCopyElementContent(cur->c1);
113: if (cur->c2 != NULL) ret->c2 = xmlCopyElementContent(cur->c2);
1.4 daniel 114: return(ret);
1.1 daniel 115: }
116:
117: /**
1.3 daniel 118: * xmlFreeElementContent:
119: * @cur: the element content tree to free
1.1 daniel 120: *
121: * Free an element content structure. This is a recursive call !
122: */
123: void
124: xmlFreeElementContent(xmlElementContentPtr cur) {
1.4 daniel 125: if (cur == NULL) return;
126: if (cur->c1 != NULL) xmlFreeElementContent(cur->c1);
127: if (cur->c2 != NULL) xmlFreeElementContent(cur->c2);
1.26 daniel 128: if (cur->name != NULL) xmlFree((CHAR *) cur->name);
1.4 daniel 129: memset(cur, -1, sizeof(xmlElementContent));
1.26 daniel 130: xmlFree(cur);
1.1 daniel 131: }
132:
1.3 daniel 133: /**
134: * xmlDumpElementContent:
1.8 daniel 135: * @buf: An XML buffer
1.3 daniel 136: * @content: An element table
137: * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
138: *
139: * This will dump the content of the element table as an XML DTD definition
140: */
141: void
1.8 daniel 142: xmlDumpElementContent(xmlBufferPtr buf, xmlElementContentPtr content, int glob) {
1.3 daniel 143: if (content == NULL) return;
144:
1.8 daniel 145: if (glob) xmlBufferWriteChar(buf, "(");
1.3 daniel 146: switch (content->type) {
147: case XML_ELEMENT_CONTENT_PCDATA:
1.8 daniel 148: xmlBufferWriteChar(buf, "#PCDATA");
1.3 daniel 149: break;
150: case XML_ELEMENT_CONTENT_ELEMENT:
1.8 daniel 151: xmlBufferWriteCHAR(buf, content->name);
1.3 daniel 152: break;
153: case XML_ELEMENT_CONTENT_SEQ:
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_OR)
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: case XML_ELEMENT_CONTENT_OR:
166: if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
167: (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
1.8 daniel 168: xmlDumpElementContent(buf, content->c1, 1);
1.3 daniel 169: else
1.8 daniel 170: xmlDumpElementContent(buf, content->c1, 0);
171: xmlBufferWriteChar(buf, " | ");
1.3 daniel 172: if (content->c2->type == XML_ELEMENT_CONTENT_SEQ)
1.8 daniel 173: xmlDumpElementContent(buf, content->c2, 1);
1.3 daniel 174: else
1.8 daniel 175: xmlDumpElementContent(buf, content->c2, 0);
1.3 daniel 176: break;
177: default:
178: fprintf(stderr, "xmlDumpElementContent: unknown type %d\n",
179: content->type);
180: }
181: if (glob)
1.8 daniel 182: xmlBufferWriteChar(buf, ")");
1.3 daniel 183: switch (content->ocur) {
184: case XML_ELEMENT_CONTENT_ONCE:
185: break;
186: case XML_ELEMENT_CONTENT_OPT:
1.8 daniel 187: xmlBufferWriteChar(buf, "?");
1.3 daniel 188: break;
189: case XML_ELEMENT_CONTENT_MULT:
1.8 daniel 190: xmlBufferWriteChar(buf, "*");
1.3 daniel 191: break;
192: case XML_ELEMENT_CONTENT_PLUS:
1.8 daniel 193: xmlBufferWriteChar(buf, "+");
1.3 daniel 194: break;
195: }
196: }
197:
1.19 daniel 198: /**
199: * xmlSprintfElementContent:
200: * @buf: an output buffer
201: * @content: An element table
202: * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
203: *
204: * This will dump the content of the element content definition
205: * Intended just for the debug routine
206: */
207: void
208: xmlSprintfElementContent(char *buf, xmlElementContentPtr content, int glob) {
209: if (content == NULL) return;
210: if (glob) strcat(buf, "(");
211: switch (content->type) {
212: case XML_ELEMENT_CONTENT_PCDATA:
213: strcat(buf, "#PCDATA");
214: break;
215: case XML_ELEMENT_CONTENT_ELEMENT:
1.23 daniel 216: strcat(buf, (char *) content->name);
1.19 daniel 217: break;
218: case XML_ELEMENT_CONTENT_SEQ:
219: if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
220: (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
221: xmlSprintfElementContent(buf, content->c1, 1);
222: else
223: xmlSprintfElementContent(buf, content->c1, 0);
224: strcat(buf, " , ");
225: if (content->c2->type == XML_ELEMENT_CONTENT_OR)
226: xmlSprintfElementContent(buf, content->c2, 1);
227: else
228: xmlSprintfElementContent(buf, content->c2, 0);
229: break;
230: case XML_ELEMENT_CONTENT_OR:
231: if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
232: (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
233: xmlSprintfElementContent(buf, content->c1, 1);
234: else
235: xmlSprintfElementContent(buf, content->c1, 0);
236: strcat(buf, " | ");
237: if (content->c2->type == XML_ELEMENT_CONTENT_SEQ)
238: xmlSprintfElementContent(buf, content->c2, 1);
239: else
240: xmlSprintfElementContent(buf, content->c2, 0);
241: break;
242: }
243: if (glob)
244: strcat(buf, ")");
245: switch (content->ocur) {
246: case XML_ELEMENT_CONTENT_ONCE:
247: break;
248: case XML_ELEMENT_CONTENT_OPT:
249: strcat(buf, "?");
250: break;
251: case XML_ELEMENT_CONTENT_MULT:
252: strcat(buf, "*");
253: break;
254: case XML_ELEMENT_CONTENT_PLUS:
255: strcat(buf, "+");
256: break;
257: }
258: }
259:
1.1 daniel 260: /****************************************************************
261: * *
262: * Registration of DTD declarations *
263: * *
264: ****************************************************************/
265:
1.2 daniel 266: /**
267: * xmlCreateElementTable:
268: *
269: * create and initialize an empty element hash table.
270: *
1.6 daniel 271: * Returns the xmlElementTablePtr just created or NULL in case of error.
1.2 daniel 272: */
273: xmlElementTablePtr
274: xmlCreateElementTable(void) {
275: xmlElementTablePtr ret;
276:
277: ret = (xmlElementTablePtr)
1.26 daniel 278: xmlMalloc(sizeof(xmlElementTable));
1.2 daniel 279: if (ret == NULL) {
1.26 daniel 280: fprintf(stderr, "xmlCreateElementTable : xmlMalloc(%ld) failed\n",
1.12 daniel 281: (long)sizeof(xmlElementTable));
1.2 daniel 282: return(NULL);
283: }
1.4 daniel 284: ret->max_elements = XML_MIN_ELEMENT_TABLE;
1.2 daniel 285: ret->nb_elements = 0;
1.15 daniel 286: ret->table = (xmlElementPtr *)
1.26 daniel 287: xmlMalloc(ret->max_elements * sizeof(xmlElementPtr));
1.2 daniel 288: if (ret == NULL) {
1.26 daniel 289: fprintf(stderr, "xmlCreateElementTable : xmlMalloc(%ld) failed\n",
1.12 daniel 290: ret->max_elements * (long)sizeof(xmlElement));
1.26 daniel 291: xmlFree(ret);
1.2 daniel 292: return(NULL);
293: }
294: return(ret);
295: }
296:
1.1 daniel 297:
298: /**
299: * xmlAddElementDecl:
1.6 daniel 300: * @dtd: pointer to the DTD
1.1 daniel 301: * @name: the entity name
1.6 daniel 302: * @type: the element type
303: * @content: the element content tree or NULL
1.1 daniel 304: *
305: * Register a new element declaration
306: *
1.6 daniel 307: * Returns NULL if not, othervise the entity
1.1 daniel 308: */
309: xmlElementPtr
1.16 daniel 310: xmlAddElementDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const CHAR *name,
1.25 daniel 311: xmlElementContentType type, xmlElementContentPtr content) {
1.2 daniel 312: xmlElementPtr ret, cur;
313: xmlElementTablePtr table;
314: int i;
1.1 daniel 315:
316: if (dtd == NULL) {
317: fprintf(stderr, "xmlAddElementDecl: dtd == NULL\n");
318: return(NULL);
319: }
320: if (name == NULL) {
321: fprintf(stderr, "xmlAddElementDecl: name == NULL\n");
322: return(NULL);
323: }
324: switch (type) {
325: case XML_ELEMENT_TYPE_EMPTY:
326: if (content != NULL) {
327: fprintf(stderr,
328: "xmlAddElementDecl: content != NULL for EMPTY\n");
329: return(NULL);
330: }
331: break;
332: case XML_ELEMENT_TYPE_ANY:
333: if (content != NULL) {
334: fprintf(stderr,
335: "xmlAddElementDecl: content != NULL for ANY\n");
336: return(NULL);
337: }
338: break;
339: case XML_ELEMENT_TYPE_MIXED:
340: if (content == NULL) {
341: fprintf(stderr,
342: "xmlAddElementDecl: content == NULL for MIXED\n");
343: return(NULL);
344: }
345: break;
346: case XML_ELEMENT_TYPE_ELEMENT:
347: if (content == NULL) {
348: fprintf(stderr,
349: "xmlAddElementDecl: content == NULL for ELEMENT\n");
350: return(NULL);
351: }
352: break;
353: default:
354: fprintf(stderr, "xmlAddElementDecl: unknown type %d\n", type);
355: return(NULL);
356: }
357:
358: /*
1.2 daniel 359: * Create the Element table if needed.
360: */
361: table = dtd->elements;
362: if (table == NULL)
363: table = dtd->elements = xmlCreateElementTable();
364: if (table == NULL) {
365: fprintf(stderr, "xmlAddElementDecl: Table creation failed!\n");
366: return(NULL);
367: }
368:
369: /*
1.1 daniel 370: * Validity Check:
371: * Search the DTD for previous declarations of the ELEMENT
372: */
1.2 daniel 373: for (i = 0;i < table->nb_elements;i++) {
1.15 daniel 374: cur = table->table[i];
1.2 daniel 375: if (!xmlStrcmp(cur->name, name)) {
376: /*
377: * The element is already defined in this Dtd.
378: */
1.16 daniel 379: VERROR(ctxt->userData, "Redefinition of element %s\n", name);
1.2 daniel 380: return(NULL);
381: }
382: }
1.1 daniel 383:
384: /*
1.2 daniel 385: * Grow the table, if needed.
1.1 daniel 386: */
1.2 daniel 387: if (table->nb_elements >= table->max_elements) {
388: /*
389: * need more elements.
390: */
391: table->max_elements *= 2;
1.15 daniel 392: table->table = (xmlElementPtr *)
1.26 daniel 393: xmlRealloc(table->table, table->max_elements * sizeof(xmlElementPtr));
1.13 daniel 394: if (table->table == NULL) {
1.2 daniel 395: fprintf(stderr, "xmlAddElementDecl: out of memory\n");
396: return(NULL);
397: }
1.1 daniel 398: }
1.26 daniel 399: ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1.15 daniel 400: if (ret == NULL) {
401: fprintf(stderr, "xmlAddElementDecl: out of memory\n");
402: return(NULL);
403: }
404: table->table[table->nb_elements] = ret;
1.2 daniel 405:
406: /*
407: * fill the structure.
408: */
1.1 daniel 409: ret->type = type;
410: ret->name = xmlStrdup(name);
1.11 daniel 411: ret->content = xmlCopyElementContent(content);
1.15 daniel 412: ret->attributes = xmlScanAttributeDecl(dtd, name);
1.2 daniel 413: table->nb_elements++;
414:
415: return(ret);
416: }
417:
418: /**
419: * xmlFreeElement:
420: * @elem: An element
421: *
422: * Deallocate the memory used by an element definition
423: */
424: void
425: xmlFreeElement(xmlElementPtr elem) {
426: if (elem == NULL) return;
427: xmlFreeElementContent(elem->content);
428: if (elem->name != NULL)
1.26 daniel 429: xmlFree((CHAR *) elem->name);
1.2 daniel 430: memset(elem, -1, sizeof(xmlElement));
1.26 daniel 431: xmlFree(elem);
1.2 daniel 432: }
1.1 daniel 433:
1.2 daniel 434: /**
435: * xmlFreeElementTable:
436: * @table: An element table
437: *
1.4 daniel 438: * Deallocate the memory used by an element hash table.
1.2 daniel 439: */
440: void
441: xmlFreeElementTable(xmlElementTablePtr table) {
442: int i;
443:
444: if (table == NULL) return;
445:
446: for (i = 0;i < table->nb_elements;i++) {
1.15 daniel 447: xmlFreeElement(table->table[i]);
1.2 daniel 448: }
1.26 daniel 449: xmlFree(table->table);
450: xmlFree(table);
1.2 daniel 451: }
452:
453: /**
454: * xmlCopyElementTable:
455: * @table: An element table
456: *
457: * Build a copy of an element table.
458: *
1.6 daniel 459: * Returns the new xmlElementTablePtr or NULL in case of error.
1.2 daniel 460: */
461: xmlElementTablePtr
462: xmlCopyElementTable(xmlElementTablePtr table) {
463: xmlElementTablePtr ret;
464: xmlElementPtr cur, ent;
465: int i;
1.1 daniel 466:
1.26 daniel 467: ret = (xmlElementTablePtr) xmlMalloc(sizeof(xmlElementTable));
1.2 daniel 468: if (ret == NULL) {
469: fprintf(stderr, "xmlCopyElementTable: out of memory !\n");
470: return(NULL);
471: }
1.26 daniel 472: ret->table = (xmlElementPtr *) xmlMalloc(table->max_elements *
1.15 daniel 473: sizeof(xmlElementPtr));
1.2 daniel 474: if (ret->table == NULL) {
475: fprintf(stderr, "xmlCopyElementTable: out of memory !\n");
1.26 daniel 476: xmlFree(ret);
1.2 daniel 477: return(NULL);
478: }
479: ret->max_elements = table->max_elements;
480: ret->nb_elements = table->nb_elements;
481: for (i = 0;i < ret->nb_elements;i++) {
1.26 daniel 482: cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1.15 daniel 483: if (cur == NULL) {
484: fprintf(stderr, "xmlCopyElementTable: out of memory !\n");
1.26 daniel 485: xmlFree(ret);
486: xmlFree(ret->table);
1.15 daniel 487: return(NULL);
488: }
489: ret->table[i] = cur;
490: ent = table->table[i];
1.2 daniel 491: cur->type = ent->type;
492: if (ent->name != NULL)
493: cur->name = xmlStrdup(ent->name);
494: else
495: cur->name = NULL;
496: cur->content = xmlCopyElementContent(ent->content);
1.15 daniel 497: cur->attributes = NULL;
1.2 daniel 498: }
1.1 daniel 499: return(ret);
500: }
501:
1.2 daniel 502: /**
503: * xmlDumpElementTable:
1.9 daniel 504: * @buf: the XML buffer output
1.2 daniel 505: * @table: An element table
506: *
507: * This will dump the content of the element table as an XML DTD definition
508: */
509: void
1.8 daniel 510: xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) {
1.2 daniel 511: int i;
512: xmlElementPtr cur;
513:
514: if (table == NULL) return;
515:
516: for (i = 0;i < table->nb_elements;i++) {
1.15 daniel 517: cur = table->table[i];
1.2 daniel 518: switch (cur->type) {
519: case XML_ELEMENT_TYPE_EMPTY:
1.8 daniel 520: xmlBufferWriteChar(buf, "<!ELEMENT ");
521: xmlBufferWriteCHAR(buf, cur->name);
522: xmlBufferWriteChar(buf, " EMPTY>\n");
1.2 daniel 523: break;
524: case XML_ELEMENT_TYPE_ANY:
1.8 daniel 525: xmlBufferWriteChar(buf, "<!ELEMENT ");
526: xmlBufferWriteCHAR(buf, cur->name);
527: xmlBufferWriteChar(buf, " ANY>\n");
1.2 daniel 528: break;
529: case XML_ELEMENT_TYPE_MIXED:
1.8 daniel 530: xmlBufferWriteChar(buf, "<!ELEMENT ");
531: xmlBufferWriteCHAR(buf, cur->name);
532: xmlBufferWriteChar(buf, " ");
533: xmlDumpElementContent(buf, cur->content, 1);
534: xmlBufferWriteChar(buf, ">\n");
1.2 daniel 535: break;
536: case XML_ELEMENT_TYPE_ELEMENT:
1.8 daniel 537: xmlBufferWriteChar(buf, "<!ELEMENT ");
538: xmlBufferWriteCHAR(buf, cur->name);
539: xmlBufferWriteChar(buf, " ");
540: xmlDumpElementContent(buf, cur->content, 1);
541: xmlBufferWriteChar(buf, ">\n");
1.2 daniel 542: break;
543: default:
544: fprintf(stderr,
545: "xmlDumpElementTable: internal: unknown type %d\n",
546: cur->type);
547: }
1.4 daniel 548: }
549: }
550:
551: /**
552: * xmlCreateEnumeration:
553: * @name: the enumeration name or NULL
554: *
555: * create and initialize an enumeration attribute node.
556: *
1.6 daniel 557: * Returns the xmlEnumerationPtr just created or NULL in case
1.4 daniel 558: * of error.
559: */
560: xmlEnumerationPtr
561: xmlCreateEnumeration(CHAR *name) {
562: xmlEnumerationPtr ret;
563:
1.26 daniel 564: ret = (xmlEnumerationPtr) xmlMalloc(sizeof(xmlEnumeration));
1.4 daniel 565: if (ret == NULL) {
1.26 daniel 566: fprintf(stderr, "xmlCreateEnumeration : xmlMalloc(%ld) failed\n",
1.12 daniel 567: (long)sizeof(xmlEnumeration));
1.4 daniel 568: return(NULL);
569: }
570:
571: if (name != NULL)
572: ret->name = xmlStrdup(name);
573: else
574: ret->name = NULL;
575: ret->next = NULL;
576: return(ret);
577: }
578:
579: /**
580: * xmlFreeEnumeration:
581: * @cur: the tree to free.
582: *
583: * free an enumeration attribute node (recursive).
584: */
585: void
586: xmlFreeEnumeration(xmlEnumerationPtr cur) {
587: if (cur == NULL) return;
588:
589: if (cur->next != NULL) xmlFreeEnumeration(cur->next);
590:
1.26 daniel 591: if (cur->name != NULL) xmlFree((CHAR *) cur->name);
1.4 daniel 592: memset(cur, -1, sizeof(xmlEnumeration));
1.26 daniel 593: xmlFree(cur);
1.4 daniel 594: }
595:
596: /**
597: * xmlCopyEnumeration:
598: * @cur: the tree to copy.
599: *
600: * Copy an enumeration attribute node (recursive).
601: *
1.6 daniel 602: * Returns the xmlEnumerationPtr just created or NULL in case
1.4 daniel 603: * of error.
604: */
605: xmlEnumerationPtr
606: xmlCopyEnumeration(xmlEnumerationPtr cur) {
607: xmlEnumerationPtr ret;
608:
609: if (cur == NULL) return(NULL);
610: ret = xmlCreateEnumeration((CHAR *) cur->name);
611:
612: if (cur->next != NULL) ret->next = xmlCopyEnumeration(cur->next);
613: else ret->next = NULL;
614:
615: return(ret);
616: }
617:
618: /**
1.18 daniel 619: * xmlDumpEnumeration:
620: * @buf: the XML buffer output
621: * @enum: An enumeration
622: *
623: * This will dump the content of the enumeration
624: */
625: void
626: xmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) {
627: if (cur == NULL) return;
628:
629: xmlBufferWriteCHAR(buf, cur->name);
630: if (cur->next == NULL)
631: xmlBufferWriteChar(buf, ")");
632: else {
633: xmlBufferWriteChar(buf, " | ");
634: xmlDumpEnumeration(buf, cur->next);
635: }
636: }
637:
638: /**
1.4 daniel 639: * xmlCreateAttributeTable:
640: *
641: * create and initialize an empty attribute hash table.
642: *
1.6 daniel 643: * Returns the xmlAttributeTablePtr just created or NULL in case
1.4 daniel 644: * of error.
645: */
646: xmlAttributeTablePtr
647: xmlCreateAttributeTable(void) {
648: xmlAttributeTablePtr ret;
649:
650: ret = (xmlAttributeTablePtr)
1.26 daniel 651: xmlMalloc(sizeof(xmlAttributeTable));
1.4 daniel 652: if (ret == NULL) {
1.26 daniel 653: fprintf(stderr, "xmlCreateAttributeTable : xmlMalloc(%ld) failed\n",
1.12 daniel 654: (long)sizeof(xmlAttributeTable));
1.4 daniel 655: return(NULL);
656: }
657: ret->max_attributes = XML_MIN_ATTRIBUTE_TABLE;
658: ret->nb_attributes = 0;
1.15 daniel 659: ret->table = (xmlAttributePtr *)
1.26 daniel 660: xmlMalloc(ret->max_attributes * sizeof(xmlAttributePtr));
1.4 daniel 661: if (ret == NULL) {
1.26 daniel 662: fprintf(stderr, "xmlCreateAttributeTable : xmlMalloc(%ld) failed\n",
1.15 daniel 663: ret->max_attributes * (long)sizeof(xmlAttributePtr));
1.26 daniel 664: xmlFree(ret);
1.4 daniel 665: return(NULL);
666: }
667: return(ret);
668: }
669:
1.15 daniel 670: /**
671: * xmlScanAttributeDecl:
672: * @dtd: pointer to the DTD
673: * @elem: the element name
674: *
675: * When inserting a new element scan the DtD for existing attributes
676: * for taht element and initialize the Attribute chain
677: *
678: * Returns the pointer to the first attribute decl in the chain,
679: * possibly NULL.
680: */
681: xmlAttributePtr
682: xmlScanAttributeDecl(xmlDtdPtr dtd, const CHAR *elem) {
1.16 daniel 683: xmlAttributePtr ret = NULL;
1.15 daniel 684: xmlAttributeTablePtr table;
685: int i;
686:
687: if (dtd == NULL) {
688: fprintf(stderr, "xmlScanAttributeDecl: dtd == NULL\n");
689: return(NULL);
690: }
691: if (elem == NULL) {
692: fprintf(stderr, "xmlScanAttributeDecl: elem == NULL\n");
693: return(NULL);
694: }
695: table = dtd->attributes;
696: if (table == NULL)
697: return(NULL);
698:
699: for (i = 0;i < table->nb_attributes;i++) {
700: if (!xmlStrcmp(table->table[i]->elem, elem)) {
1.16 daniel 701: table->table[i]->next = ret;
702: ret = table->table[i];
703: }
704: }
705: return(ret);
706: }
707:
708: /**
709: * xmlScanIDAttributeDecl:
710: * @ctxt: the validation context
711: * @elem: the element name
712: *
713: * Veryfy that the element don't have too many ID attributes
714: * declared.
715: *
716: * Returns the number of ID attributes found.
717: */
718: int
719: xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
720: xmlAttributePtr cur;
721: int ret = 0;
722:
723: if (elem == NULL) return(0);
724: cur = elem->attributes;
725: while (cur != NULL) {
726: if (cur->type == XML_ATTRIBUTE_ID) {
727: ret ++;
728: if (ret > 1)
729: VERROR(ctxt->userData,
730: "Element %s has too may ID attributes defined : %s\n",
731: elem->name, cur->name);
1.15 daniel 732: }
1.16 daniel 733: cur = cur->next;
1.15 daniel 734: }
735: return(ret);
736: }
737:
1.4 daniel 738:
739: /**
740: * xmlAddAttributeDecl:
1.16 daniel 741: * @ctxt: the validation context
1.6 daniel 742: * @dtd: pointer to the DTD
743: * @elem: the element name
744: * @name: the attribute name
745: * @type: the attribute type
746: * @def: the attribute default type
747: * @defaultValue: the attribute default value
748: * @tree: if it's an enumeration, the associated list
1.4 daniel 749: *
750: * Register a new attribute declaration
751: *
1.6 daniel 752: * Returns NULL if not, othervise the entity
1.4 daniel 753: */
754: xmlAttributePtr
1.16 daniel 755: xmlAddAttributeDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const CHAR *elem,
1.25 daniel 756: const CHAR *name, xmlAttributeType type,
757: xmlAttributeDefault def, const CHAR *defaultValue,
758: xmlEnumerationPtr tree) {
1.4 daniel 759: xmlAttributePtr ret, cur;
760: xmlAttributeTablePtr table;
1.15 daniel 761: xmlElementPtr elemDef;
1.4 daniel 762: int i;
763:
764: if (dtd == NULL) {
765: fprintf(stderr, "xmlAddAttributeDecl: dtd == NULL\n");
766: return(NULL);
767: }
768: if (name == NULL) {
769: fprintf(stderr, "xmlAddAttributeDecl: name == NULL\n");
770: return(NULL);
771: }
772: if (elem == NULL) {
773: fprintf(stderr, "xmlAddAttributeDecl: elem == NULL\n");
774: return(NULL);
775: }
1.23 daniel 776: /*
777: * Check the type and possibly the default value.
778: */
1.4 daniel 779: switch (type) {
780: case XML_ATTRIBUTE_CDATA:
781: break;
782: case XML_ATTRIBUTE_ID:
783: break;
784: case XML_ATTRIBUTE_IDREF:
785: break;
786: case XML_ATTRIBUTE_IDREFS:
787: break;
788: case XML_ATTRIBUTE_ENTITY:
789: break;
790: case XML_ATTRIBUTE_ENTITIES:
791: break;
792: case XML_ATTRIBUTE_NMTOKEN:
793: break;
794: case XML_ATTRIBUTE_NMTOKENS:
795: break;
796: case XML_ATTRIBUTE_ENUMERATION:
797: break;
798: case XML_ATTRIBUTE_NOTATION:
799: break;
800: default:
801: fprintf(stderr, "xmlAddAttributeDecl: unknown type %d\n", type);
802: return(NULL);
803: }
1.23 daniel 804: if ((defaultValue != NULL) &&
805: (!xmlValidateAttributeValue(type, defaultValue))) {
806: VERROR(ctxt->userData, "Attribute %s on %s: invalid default value\n",
807: elem, name, defaultValue);
808: defaultValue = NULL;
809: }
1.4 daniel 810:
811: /*
812: * Create the Attribute table if needed.
813: */
814: table = dtd->attributes;
815: if (table == NULL)
816: table = dtd->attributes = xmlCreateAttributeTable();
817: if (table == NULL) {
818: fprintf(stderr, "xmlAddAttributeDecl: Table creation failed!\n");
819: return(NULL);
820: }
821:
822: /*
823: * Validity Check:
824: * Search the DTD for previous declarations of the ATTLIST
825: */
826: for (i = 0;i < table->nb_attributes;i++) {
1.15 daniel 827: cur = table->table[i];
1.4 daniel 828: if ((!xmlStrcmp(cur->name, name)) && (!xmlStrcmp(cur->elem, elem))) {
829: /*
830: * The attribute is already defined in this Dtd.
831: */
1.23 daniel 832: VERROR(ctxt->userData, "Attribute %s on %s: already defined\n",
833: elem, name);
1.4 daniel 834: }
835: }
836:
837: /*
838: * Grow the table, if needed.
839: */
840: if (table->nb_attributes >= table->max_attributes) {
841: /*
842: * need more attributes.
843: */
844: table->max_attributes *= 2;
1.15 daniel 845: table->table = (xmlAttributePtr *)
1.26 daniel 846: xmlRealloc(table->table, table->max_attributes *
1.15 daniel 847: sizeof(xmlAttributePtr));
1.13 daniel 848: if (table->table == NULL) {
1.4 daniel 849: fprintf(stderr, "xmlAddAttributeDecl: out of memory\n");
850: return(NULL);
851: }
852: }
1.26 daniel 853: ret = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
1.15 daniel 854: if (ret == NULL) {
855: fprintf(stderr, "xmlAddAttributeDecl: out of memory\n");
856: return(NULL);
857: }
858: table->table[table->nb_attributes] = ret;
1.4 daniel 859:
860: /*
861: * fill the structure.
862: */
863: ret->type = type;
864: ret->name = xmlStrdup(name);
865: ret->elem = xmlStrdup(elem);
866: ret->def = def;
867: ret->tree = tree;
868: if (defaultValue != NULL)
869: ret->defaultValue = xmlStrdup(defaultValue);
870: else
871: ret->defaultValue = NULL;
1.15 daniel 872: elemDef = xmlGetDtdElementDesc(dtd, elem);
873: if (elemDef != NULL) {
1.16 daniel 874: if ((type == XML_ATTRIBUTE_ID) &&
875: (xmlScanIDAttributeDecl(NULL, elemDef) != 0))
876: VERROR(ctxt->userData,
877: "Element %s has too may ID attributes defined : %s\n",
878: elem, name);
1.15 daniel 879: ret->next = elemDef->attributes;
880: elemDef->attributes = ret;
881: }
1.4 daniel 882: table->nb_attributes++;
883:
884: return(ret);
885: }
886:
887: /**
888: * xmlFreeAttribute:
889: * @elem: An attribute
890: *
891: * Deallocate the memory used by an attribute definition
892: */
893: void
894: xmlFreeAttribute(xmlAttributePtr attr) {
895: if (attr == NULL) return;
896: if (attr->tree != NULL)
897: xmlFreeEnumeration(attr->tree);
898: if (attr->elem != NULL)
1.26 daniel 899: xmlFree((CHAR *) attr->elem);
1.4 daniel 900: if (attr->name != NULL)
1.26 daniel 901: xmlFree((CHAR *) attr->name);
1.4 daniel 902: if (attr->defaultValue != NULL)
1.26 daniel 903: xmlFree((CHAR *) attr->defaultValue);
1.4 daniel 904: memset(attr, -1, sizeof(xmlAttribute));
1.26 daniel 905: xmlFree(attr);
1.4 daniel 906: }
907:
908: /**
909: * xmlFreeAttributeTable:
910: * @table: An attribute table
911: *
912: * Deallocate the memory used by an entities hash table.
913: */
914: void
915: xmlFreeAttributeTable(xmlAttributeTablePtr table) {
916: int i;
917:
918: if (table == NULL) return;
919:
920: for (i = 0;i < table->nb_attributes;i++) {
1.15 daniel 921: xmlFreeAttribute(table->table[i]);
1.4 daniel 922: }
1.26 daniel 923: xmlFree(table->table);
924: xmlFree(table);
1.4 daniel 925: }
926:
927: /**
928: * xmlCopyAttributeTable:
929: * @table: An attribute table
930: *
931: * Build a copy of an attribute table.
932: *
1.6 daniel 933: * Returns the new xmlAttributeTablePtr or NULL in case of error.
1.4 daniel 934: */
935: xmlAttributeTablePtr
936: xmlCopyAttributeTable(xmlAttributeTablePtr table) {
937: xmlAttributeTablePtr ret;
938: xmlAttributePtr cur, attr;
939: int i;
940:
1.26 daniel 941: ret = (xmlAttributeTablePtr) xmlMalloc(sizeof(xmlAttributeTable));
1.4 daniel 942: if (ret == NULL) {
943: fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
944: return(NULL);
945: }
1.26 daniel 946: ret->table = (xmlAttributePtr *) xmlMalloc(table->max_attributes *
1.15 daniel 947: sizeof(xmlAttributePtr));
1.4 daniel 948: if (ret->table == NULL) {
949: fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
1.26 daniel 950: xmlFree(ret);
1.4 daniel 951: return(NULL);
952: }
953: ret->max_attributes = table->max_attributes;
954: ret->nb_attributes = table->nb_attributes;
955: for (i = 0;i < ret->nb_attributes;i++) {
1.15 daniel 956: attr = table->table[i];
1.26 daniel 957: cur = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
1.15 daniel 958: if (cur == NULL) {
959: fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
1.26 daniel 960: xmlFree(ret);
961: xmlFree(ret->table);
1.15 daniel 962: return(NULL);
963: }
964: ret->table[i] = cur;
1.4 daniel 965: cur->type = attr->type;
966: cur->def = attr->def;
967: cur->tree = xmlCopyEnumeration(attr->tree);
968: if (attr->elem != NULL)
969: cur->elem = xmlStrdup(attr->elem);
970: else
971: cur->elem = NULL;
972: if (attr->name != NULL)
973: cur->name = xmlStrdup(attr->name);
974: else
975: cur->name = NULL;
976: if (attr->defaultValue != NULL)
977: cur->defaultValue = xmlStrdup(attr->defaultValue);
978: else
979: cur->defaultValue = NULL;
1.15 daniel 980: /* NEED to rebuild the next chain !!!!!! */
1.4 daniel 981: }
982: return(ret);
983: }
984:
985: /**
986: * xmlDumpAttributeTable:
1.9 daniel 987: * @buf: the XML buffer output
1.4 daniel 988: * @table: An attribute table
989: *
990: * This will dump the content of the attribute table as an XML DTD definition
991: */
992: void
1.8 daniel 993: xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) {
1.4 daniel 994: int i;
995: xmlAttributePtr cur;
996:
997: if (table == NULL) return;
998:
999: for (i = 0;i < table->nb_attributes;i++) {
1.15 daniel 1000: cur = table->table[i];
1.8 daniel 1001: xmlBufferWriteChar(buf, "<!ATTLIST ");
1002: xmlBufferWriteCHAR(buf, cur->elem);
1003: xmlBufferWriteChar(buf, " ");
1004: xmlBufferWriteCHAR(buf, cur->name);
1.4 daniel 1005: switch (cur->type) {
1006: case XML_ATTRIBUTE_CDATA:
1.8 daniel 1007: xmlBufferWriteChar(buf, " CDATA");
1.4 daniel 1008: break;
1009: case XML_ATTRIBUTE_ID:
1.8 daniel 1010: xmlBufferWriteChar(buf, " ID");
1.4 daniel 1011: break;
1012: case XML_ATTRIBUTE_IDREF:
1.8 daniel 1013: xmlBufferWriteChar(buf, " IDREF");
1.4 daniel 1014: break;
1015: case XML_ATTRIBUTE_IDREFS:
1.8 daniel 1016: xmlBufferWriteChar(buf, " IDREFS");
1.4 daniel 1017: break;
1018: case XML_ATTRIBUTE_ENTITY:
1.8 daniel 1019: xmlBufferWriteChar(buf, " ENTITY");
1.4 daniel 1020: break;
1021: case XML_ATTRIBUTE_ENTITIES:
1.8 daniel 1022: xmlBufferWriteChar(buf, " ENTITIES");
1.4 daniel 1023: break;
1024: case XML_ATTRIBUTE_NMTOKEN:
1.8 daniel 1025: xmlBufferWriteChar(buf, " NMTOKEN");
1.4 daniel 1026: break;
1027: case XML_ATTRIBUTE_NMTOKENS:
1.8 daniel 1028: xmlBufferWriteChar(buf, " NMTOKENS");
1.4 daniel 1029: break;
1030: case XML_ATTRIBUTE_ENUMERATION:
1.18 daniel 1031: xmlBufferWriteChar(buf, " (");
1032: xmlDumpEnumeration(buf, cur->tree);
1.4 daniel 1033: break;
1034: case XML_ATTRIBUTE_NOTATION:
1.18 daniel 1035: xmlBufferWriteChar(buf, " NOTATION (");
1036: xmlDumpEnumeration(buf, cur->tree);
1.4 daniel 1037: break;
1038: default:
1039: fprintf(stderr,
1040: "xmlDumpAttributeTable: internal: unknown type %d\n",
1041: cur->type);
1042: }
1043: switch (cur->def) {
1044: case XML_ATTRIBUTE_NONE:
1045: break;
1046: case XML_ATTRIBUTE_REQUIRED:
1.8 daniel 1047: xmlBufferWriteChar(buf, " #REQUIRED");
1.4 daniel 1048: break;
1049: case XML_ATTRIBUTE_IMPLIED:
1.8 daniel 1050: xmlBufferWriteChar(buf, " #IMPLIED");
1.4 daniel 1051: break;
1052: case XML_ATTRIBUTE_FIXED:
1.17 daniel 1053: xmlBufferWriteChar(buf, " #FIXED");
1.4 daniel 1054: break;
1055: default:
1056: fprintf(stderr,
1057: "xmlDumpAttributeTable: internal: unknown default %d\n",
1058: cur->def);
1059: }
1.17 daniel 1060: if (cur->defaultValue != NULL) {
1061: xmlBufferWriteChar(buf, " ");
1062: xmlBufferWriteQuotedString(buf, cur->defaultValue);
1063: }
1.8 daniel 1064: xmlBufferWriteChar(buf, ">\n");
1.5 daniel 1065: }
1066: }
1067:
1068: /************************************************************************
1069: * *
1070: * NOTATIONs *
1071: * *
1072: ************************************************************************/
1073: /**
1074: * xmlCreateNotationTable:
1075: *
1076: * create and initialize an empty notation hash table.
1077: *
1.6 daniel 1078: * Returns the xmlNotationTablePtr just created or NULL in case
1.5 daniel 1079: * of error.
1080: */
1081: xmlNotationTablePtr
1082: xmlCreateNotationTable(void) {
1083: xmlNotationTablePtr ret;
1084:
1085: ret = (xmlNotationTablePtr)
1.26 daniel 1086: xmlMalloc(sizeof(xmlNotationTable));
1.5 daniel 1087: if (ret == NULL) {
1.26 daniel 1088: fprintf(stderr, "xmlCreateNotationTable : xmlMalloc(%ld) failed\n",
1.12 daniel 1089: (long)sizeof(xmlNotationTable));
1.5 daniel 1090: return(NULL);
1091: }
1092: ret->max_notations = XML_MIN_NOTATION_TABLE;
1093: ret->nb_notations = 0;
1.15 daniel 1094: ret->table = (xmlNotationPtr *)
1.26 daniel 1095: xmlMalloc(ret->max_notations * sizeof(xmlNotationPtr));
1.5 daniel 1096: if (ret == NULL) {
1.26 daniel 1097: fprintf(stderr, "xmlCreateNotationTable : xmlMalloc(%ld) failed\n",
1.12 daniel 1098: ret->max_notations * (long)sizeof(xmlNotation));
1.26 daniel 1099: xmlFree(ret);
1.5 daniel 1100: return(NULL);
1101: }
1102: return(ret);
1103: }
1104:
1105:
1106: /**
1107: * xmlAddNotationDecl:
1.6 daniel 1108: * @dtd: pointer to the DTD
1.16 daniel 1109: * @ctxt: the validation context
1.5 daniel 1110: * @name: the entity name
1.6 daniel 1111: * @PublicID: the public identifier or NULL
1112: * @SystemID: the system identifier or NULL
1.5 daniel 1113: *
1114: * Register a new notation declaration
1115: *
1.6 daniel 1116: * Returns NULL if not, othervise the entity
1.5 daniel 1117: */
1118: xmlNotationPtr
1.16 daniel 1119: xmlAddNotationDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const CHAR *name,
1120: const CHAR *PublicID, const CHAR *SystemID) {
1.5 daniel 1121: xmlNotationPtr ret, cur;
1122: xmlNotationTablePtr table;
1123: int i;
1124:
1125: if (dtd == NULL) {
1126: fprintf(stderr, "xmlAddNotationDecl: dtd == NULL\n");
1127: return(NULL);
1128: }
1129: if (name == NULL) {
1130: fprintf(stderr, "xmlAddNotationDecl: name == NULL\n");
1131: return(NULL);
1132: }
1133: if ((PublicID == NULL) && (SystemID == NULL)) {
1134: fprintf(stderr, "xmlAddNotationDecl: no PUBLIC ID nor SYSTEM ID\n");
1135: }
1136:
1137: /*
1138: * Create the Notation table if needed.
1139: */
1140: table = dtd->notations;
1141: if (table == NULL)
1142: table = dtd->notations = xmlCreateNotationTable();
1143: if (table == NULL) {
1144: fprintf(stderr, "xmlAddNotationDecl: Table creation failed!\n");
1145: return(NULL);
1146: }
1147:
1148: /*
1149: * Validity Check:
1150: * Search the DTD for previous declarations of the ATTLIST
1151: */
1152: for (i = 0;i < table->nb_notations;i++) {
1.15 daniel 1153: cur = table->table[i];
1.5 daniel 1154: if (!xmlStrcmp(cur->name, name)) {
1155: /*
1156: * The notation is already defined in this Dtd.
1157: */
1158: fprintf(stderr,
1159: "xmlAddNotationDecl: %s already defined\n", name);
1160: }
1161: }
1162:
1163: /*
1164: * Grow the table, if needed.
1165: */
1166: if (table->nb_notations >= table->max_notations) {
1167: /*
1168: * need more notations.
1169: */
1170: table->max_notations *= 2;
1.15 daniel 1171: table->table = (xmlNotationPtr *)
1.26 daniel 1172: xmlRealloc(table->table, table->max_notations *
1.15 daniel 1173: sizeof(xmlNotationPtr));
1.13 daniel 1174: if (table->table == NULL) {
1.5 daniel 1175: fprintf(stderr, "xmlAddNotationDecl: out of memory\n");
1176: return(NULL);
1177: }
1178: }
1.26 daniel 1179: ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
1.15 daniel 1180: if (ret == NULL) {
1181: fprintf(stderr, "xmlAddNotationDecl: out of memory\n");
1182: return(NULL);
1183: }
1184: table->table[table->nb_notations] = ret;
1.5 daniel 1185:
1186: /*
1187: * fill the structure.
1188: */
1189: ret->name = xmlStrdup(name);
1190: if (SystemID != NULL)
1191: ret->SystemID = xmlStrdup(SystemID);
1192: else
1193: ret->SystemID = NULL;
1194: if (PublicID != NULL)
1195: ret->PublicID = xmlStrdup(PublicID);
1196: else
1197: ret->PublicID = NULL;
1198: table->nb_notations++;
1199:
1200: return(ret);
1201: }
1202:
1203: /**
1204: * xmlFreeNotation:
1205: * @not: A notation
1206: *
1207: * Deallocate the memory used by an notation definition
1208: */
1209: void
1210: xmlFreeNotation(xmlNotationPtr nota) {
1211: if (nota == NULL) return;
1212: if (nota->name != NULL)
1.26 daniel 1213: xmlFree((CHAR *) nota->name);
1.5 daniel 1214: if (nota->PublicID != NULL)
1.26 daniel 1215: xmlFree((CHAR *) nota->PublicID);
1.5 daniel 1216: if (nota->SystemID != NULL)
1.26 daniel 1217: xmlFree((CHAR *) nota->SystemID);
1.5 daniel 1218: memset(nota, -1, sizeof(xmlNotation));
1.26 daniel 1219: xmlFree(nota);
1.5 daniel 1220: }
1221:
1222: /**
1223: * xmlFreeNotationTable:
1224: * @table: An notation table
1225: *
1226: * Deallocate the memory used by an entities hash table.
1227: */
1228: void
1229: xmlFreeNotationTable(xmlNotationTablePtr table) {
1230: int i;
1231:
1232: if (table == NULL) return;
1233:
1234: for (i = 0;i < table->nb_notations;i++) {
1.15 daniel 1235: xmlFreeNotation(table->table[i]);
1.5 daniel 1236: }
1.26 daniel 1237: xmlFree(table->table);
1238: xmlFree(table);
1.5 daniel 1239: }
1240:
1241: /**
1242: * xmlCopyNotationTable:
1243: * @table: A notation table
1244: *
1245: * Build a copy of a notation table.
1246: *
1.6 daniel 1247: * Returns the new xmlNotationTablePtr or NULL in case of error.
1.5 daniel 1248: */
1249: xmlNotationTablePtr
1250: xmlCopyNotationTable(xmlNotationTablePtr table) {
1251: xmlNotationTablePtr ret;
1252: xmlNotationPtr cur, nota;
1253: int i;
1254:
1.26 daniel 1255: ret = (xmlNotationTablePtr) xmlMalloc(sizeof(xmlNotationTable));
1.5 daniel 1256: if (ret == NULL) {
1257: fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
1258: return(NULL);
1259: }
1.26 daniel 1260: ret->table = (xmlNotationPtr *) xmlMalloc(table->max_notations *
1.15 daniel 1261: sizeof(xmlNotationPtr));
1.5 daniel 1262: if (ret->table == NULL) {
1263: fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
1.26 daniel 1264: xmlFree(ret);
1.5 daniel 1265: return(NULL);
1266: }
1267: ret->max_notations = table->max_notations;
1268: ret->nb_notations = table->nb_notations;
1269: for (i = 0;i < ret->nb_notations;i++) {
1.26 daniel 1270: cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
1.15 daniel 1271: if (cur == NULL) {
1272: fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
1.26 daniel 1273: xmlFree(ret);
1274: xmlFree(ret->table);
1.15 daniel 1275: return(NULL);
1276: }
1277: ret->table[i] = cur;
1278: nota = table->table[i];
1.5 daniel 1279: if (nota->name != NULL)
1280: cur->name = xmlStrdup(nota->name);
1281: else
1282: cur->name = NULL;
1283: if (nota->PublicID != NULL)
1284: cur->PublicID = xmlStrdup(nota->PublicID);
1285: else
1286: cur->PublicID = NULL;
1287: if (nota->SystemID != NULL)
1288: cur->SystemID = xmlStrdup(nota->SystemID);
1289: else
1290: cur->SystemID = NULL;
1291: }
1292: return(ret);
1293: }
1294:
1295: /**
1296: * xmlDumpNotationTable:
1.9 daniel 1297: * @buf: the XML buffer output
1.5 daniel 1298: * @table: A notation table
1299: *
1300: * This will dump the content of the notation table as an XML DTD definition
1301: */
1302: void
1.8 daniel 1303: xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
1.5 daniel 1304: int i;
1305: xmlNotationPtr cur;
1306:
1307: if (table == NULL) return;
1308:
1309: for (i = 0;i < table->nb_notations;i++) {
1.15 daniel 1310: cur = table->table[i];
1.8 daniel 1311: xmlBufferWriteChar(buf, "<!NOTATION ");
1312: xmlBufferWriteCHAR(buf, cur->name);
1.5 daniel 1313: if (cur->PublicID != NULL) {
1.10 daniel 1314: xmlBufferWriteChar(buf, " PUBLIC ");
1315: xmlBufferWriteQuotedString(buf, cur->PublicID);
1.5 daniel 1316: if (cur->SystemID != NULL) {
1.8 daniel 1317: xmlBufferWriteChar(buf, " ");
1318: xmlBufferWriteCHAR(buf, cur->SystemID);
1.5 daniel 1319: }
1320: } else {
1.8 daniel 1321: xmlBufferWriteChar(buf, " SYSTEM ");
1322: xmlBufferWriteCHAR(buf, cur->SystemID);
1.5 daniel 1323: }
1.8 daniel 1324: xmlBufferWriteChar(buf, " >\n");
1.2 daniel 1325: }
1326: }
1.14 daniel 1327:
1328: /************************************************************************
1329: * *
1.27 daniel 1330: * IDs *
1.21 daniel 1331: * *
1332: ************************************************************************/
1333: /**
1334: * xmlCreateIDTable:
1335: *
1336: * create and initialize an empty id hash table.
1337: *
1338: * Returns the xmlIDTablePtr just created or NULL in case
1339: * of error.
1340: */
1341: xmlIDTablePtr
1342: xmlCreateIDTable(void) {
1343: xmlIDTablePtr ret;
1344:
1345: ret = (xmlIDTablePtr)
1.26 daniel 1346: xmlMalloc(sizeof(xmlIDTable));
1.21 daniel 1347: if (ret == NULL) {
1.26 daniel 1348: fprintf(stderr, "xmlCreateIDTable : xmlMalloc(%ld) failed\n",
1.21 daniel 1349: (long)sizeof(xmlIDTable));
1350: return(NULL);
1351: }
1352: ret->max_ids = XML_MIN_NOTATION_TABLE;
1353: ret->nb_ids = 0;
1354: ret->table = (xmlIDPtr *)
1.26 daniel 1355: xmlMalloc(ret->max_ids * sizeof(xmlIDPtr));
1.21 daniel 1356: if (ret == NULL) {
1.26 daniel 1357: fprintf(stderr, "xmlCreateIDTable : xmlMalloc(%ld) failed\n",
1.21 daniel 1358: ret->max_ids * (long)sizeof(xmlID));
1.26 daniel 1359: xmlFree(ret);
1.21 daniel 1360: return(NULL);
1361: }
1362: return(ret);
1363: }
1364:
1365:
1366: /**
1367: * xmlAddID:
1368: * @ctxt: the validation context
1369: * @doc: pointer to the document
1370: * @value: the value name
1371: * @attr: the attribute holding the ID
1372: *
1373: * Register a new id declaration
1374: *
1375: * Returns NULL if not, othervise the new xmlIDPtr
1376: */
1377: xmlIDPtr
1378: xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const CHAR *value,
1379: xmlAttrPtr attr) {
1380: xmlIDPtr ret, cur;
1381: xmlIDTablePtr table;
1382: int i;
1383:
1384: if (doc == NULL) {
1385: fprintf(stderr, "xmlAddIDDecl: doc == NULL\n");
1386: return(NULL);
1387: }
1388: if (value == NULL) {
1389: fprintf(stderr, "xmlAddIDDecl: value == NULL\n");
1390: return(NULL);
1391: }
1392: if (attr == NULL) {
1393: fprintf(stderr, "xmlAddIDDecl: attr == NULL\n");
1394: return(NULL);
1395: }
1396:
1397: /*
1398: * Create the ID table if needed.
1399: */
1400: table = doc->ids;
1401: if (table == NULL)
1402: table = doc->ids = xmlCreateIDTable();
1403: if (table == NULL) {
1404: fprintf(stderr, "xmlAddID: Table creation failed!\n");
1405: return(NULL);
1406: }
1407:
1408: /*
1409: * Validity Check:
1410: * Search the DTD for previous declarations of the ATTLIST
1411: */
1412: for (i = 0;i < table->nb_ids;i++) {
1413: cur = table->table[i];
1414: if (!xmlStrcmp(cur->value, value)) {
1415: /*
1416: * The id is already defined in this Dtd.
1417: */
1418: VERROR(ctxt->userData, "ID %s already defined\n", value);
1419: return(NULL);
1420: }
1421: }
1422:
1423: /*
1424: * Grow the table, if needed.
1425: */
1426: if (table->nb_ids >= table->max_ids) {
1427: /*
1428: * need more ids.
1429: */
1430: table->max_ids *= 2;
1431: table->table = (xmlIDPtr *)
1.26 daniel 1432: xmlRealloc(table->table, table->max_ids *
1.21 daniel 1433: sizeof(xmlIDPtr));
1434: if (table->table == NULL) {
1435: fprintf(stderr, "xmlAddID: out of memory\n");
1436: return(NULL);
1437: }
1438: }
1.26 daniel 1439: ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
1.21 daniel 1440: if (ret == NULL) {
1441: fprintf(stderr, "xmlAddID: out of memory\n");
1442: return(NULL);
1443: }
1444: table->table[table->nb_ids] = ret;
1445:
1446: /*
1447: * fill the structure.
1448: */
1449: ret->value = xmlStrdup(value);
1450: ret->attr = attr;
1451: table->nb_ids++;
1452:
1453: return(ret);
1454: }
1455:
1456: /**
1457: * xmlFreeID:
1458: * @not: A id
1459: *
1460: * Deallocate the memory used by an id definition
1461: */
1462: void
1463: xmlFreeID(xmlIDPtr id) {
1464: if (id == NULL) return;
1465: if (id->value != NULL)
1.26 daniel 1466: xmlFree((CHAR *) id->value);
1.21 daniel 1467: memset(id, -1, sizeof(xmlID));
1.26 daniel 1468: xmlFree(id);
1.21 daniel 1469: }
1470:
1471: /**
1472: * xmlFreeIDTable:
1473: * @table: An id table
1474: *
1475: * Deallocate the memory used by an ID hash table.
1476: */
1477: void
1478: xmlFreeIDTable(xmlIDTablePtr table) {
1479: int i;
1480:
1481: if (table == NULL) return;
1482:
1483: for (i = 0;i < table->nb_ids;i++) {
1484: xmlFreeID(table->table[i]);
1485: }
1.26 daniel 1486: xmlFree(table->table);
1487: xmlFree(table);
1.21 daniel 1488: }
1489:
1490: /**
1491: * xmlIsID
1492: * @doc: the document
1493: * @elem: the element carrying the attribute
1494: * @attr: the attribute
1495: *
1496: * Determine whether an attribute is of type ID. In case we have Dtd(s)
1497: * then this is simple, otherwise we use an heuristic: name ID (upper
1498: * or lowercase).
1499: *
1500: * Returns 0 or 1 depending on the lookup result
1501: */
1502: int
1503: xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
1504: if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
1505: if (((attr->name[0] == 'I') || (attr->name[0] == 'i')) &&
1506: ((attr->name[1] == 'D') || (attr->name[1] == 'd')) &&
1507: (attr->name[2] == 0)) return(1);
1508: } else {
1509: xmlAttributePtr attrDecl;
1510:
1511: attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
1512: if ((attrDecl == NULL) && (doc->extSubset != NULL))
1513: attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
1514: attr->name);
1515:
1.22 daniel 1516: if ((attrDecl != NULL) && (attrDecl->type == XML_ATTRIBUTE_ID))
1.21 daniel 1517: return(1);
1518: }
1519: return(0);
1520: }
1521:
1.22 daniel 1522: /**
1523: * xmlGetID:
1524: * @doc: pointer to the document
1525: * @ID: the ID value
1526: *
1527: * Search the attribute declaring the given ID
1528: *
1529: * Returns NULL if not found, otherwise the xmlAttrPtr defining the ID
1530: */
1531: xmlAttrPtr
1532: xmlGetID(xmlDocPtr doc, const CHAR *ID) {
1533: xmlIDPtr cur;
1534: xmlIDTablePtr table;
1535: int i;
1536:
1537: if (doc == NULL) {
1538: fprintf(stderr, "xmlGetID: doc == NULL\n");
1539: return(NULL);
1540: }
1541:
1542: if (ID == NULL) {
1543: fprintf(stderr, "xmlGetID: ID == NULL\n");
1544: return(NULL);
1545: }
1546:
1547: table = doc->ids;
1548: if (table == NULL)
1549: return(NULL);
1550:
1551: /*
1552: * Search the ID list.
1553: */
1554: for (i = 0;i < table->nb_ids;i++) {
1555: cur = table->table[i];
1556: if (!xmlStrcmp(cur->value, ID)) {
1557: return(cur->attr);
1558: }
1559: }
1560: return(NULL);
1561: }
1562:
1.21 daniel 1563: /************************************************************************
1564: * *
1.27 daniel 1565: * Refs *
1566: * *
1567: ************************************************************************/
1568: /**
1569: * xmlCreateRefTable:
1570: *
1571: * create and initialize an empty ref hash table.
1572: *
1573: * Returns the xmlRefTablePtr just created or NULL in case
1574: * of error.
1575: */
1576: xmlRefTablePtr
1577: xmlCreateRefTable(void) {
1578: xmlRefTablePtr ret;
1579:
1580: ret = (xmlRefTablePtr)
1581: xmlMalloc(sizeof(xmlRefTable));
1582: if (ret == NULL) {
1583: fprintf(stderr, "xmlCreateRefTable : xmlMalloc(%ld) failed\n",
1584: (long)sizeof(xmlRefTable));
1585: return(NULL);
1586: }
1587: ret->max_refs = XML_MIN_NOTATION_TABLE;
1588: ret->nb_refs = 0;
1589: ret->table = (xmlRefPtr *)
1590: xmlMalloc(ret->max_refs * sizeof(xmlRefPtr));
1591: if (ret == NULL) {
1592: fprintf(stderr, "xmlCreateRefTable : xmlMalloc(%ld) failed\n",
1593: ret->max_refs * (long)sizeof(xmlRef));
1594: xmlFree(ret);
1595: return(NULL);
1596: }
1597: return(ret);
1598: }
1599:
1600:
1601: /**
1602: * xmlAddRef:
1603: * @ctxt: the validation context
1604: * @doc: pointer to the document
1605: * @value: the value name
1606: * @attr: the attribute holding the Ref
1607: *
1608: * Register a new ref declaration
1609: *
1610: * Returns NULL if not, othervise the new xmlRefPtr
1611: */
1612: xmlRefPtr
1613: xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const CHAR *value,
1614: xmlAttrPtr attr) {
1.28 daniel 1615: xmlRefPtr ret;
1.27 daniel 1616: xmlRefTablePtr table;
1617:
1618: if (doc == NULL) {
1619: fprintf(stderr, "xmlAddRefDecl: doc == NULL\n");
1620: return(NULL);
1621: }
1622: if (value == NULL) {
1623: fprintf(stderr, "xmlAddRefDecl: value == NULL\n");
1624: return(NULL);
1625: }
1626: if (attr == NULL) {
1627: fprintf(stderr, "xmlAddRefDecl: attr == NULL\n");
1628: return(NULL);
1629: }
1630:
1631: /*
1632: * Create the Ref table if needed.
1633: */
1634: table = doc->refs;
1635: if (table == NULL)
1636: table = doc->refs = xmlCreateRefTable();
1637: if (table == NULL) {
1638: fprintf(stderr, "xmlAddRef: Table creation failed!\n");
1639: return(NULL);
1640: }
1641:
1642: /*
1643: * Grow the table, if needed.
1644: */
1645: if (table->nb_refs >= table->max_refs) {
1646: /*
1647: * need more refs.
1648: */
1649: table->max_refs *= 2;
1650: table->table = (xmlRefPtr *)
1651: xmlRealloc(table->table, table->max_refs *
1652: sizeof(xmlRefPtr));
1653: if (table->table == NULL) {
1654: fprintf(stderr, "xmlAddRef: out of memory\n");
1655: return(NULL);
1656: }
1657: }
1658: ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
1659: if (ret == NULL) {
1660: fprintf(stderr, "xmlAddRef: out of memory\n");
1661: return(NULL);
1662: }
1663: table->table[table->nb_refs] = ret;
1664:
1665: /*
1666: * fill the structure.
1667: */
1668: ret->value = xmlStrdup(value);
1669: ret->attr = attr;
1670: table->nb_refs++;
1671:
1672: return(ret);
1673: }
1674:
1675: /**
1676: * xmlFreeRef:
1677: * @not: A ref
1678: *
1679: * Deallocate the memory used by an ref definition
1680: */
1681: void
1682: xmlFreeRef(xmlRefPtr ref) {
1683: if (ref == NULL) return;
1684: if (ref->value != NULL)
1685: xmlFree((CHAR *) ref->value);
1686: memset(ref, -1, sizeof(xmlRef));
1687: xmlFree(ref);
1688: }
1689:
1690: /**
1691: * xmlFreeRefTable:
1692: * @table: An ref table
1693: *
1694: * Deallocate the memory used by an Ref hash table.
1695: */
1696: void
1697: xmlFreeRefTable(xmlRefTablePtr table) {
1698: int i;
1699:
1700: if (table == NULL) return;
1701:
1702: for (i = 0;i < table->nb_refs;i++) {
1703: xmlFreeRef(table->table[i]);
1704: }
1705: xmlFree(table->table);
1706: xmlFree(table);
1707: }
1708:
1709: /**
1710: * xmlIsRef
1711: * @doc: the document
1712: * @elem: the element carrying the attribute
1713: * @attr: the attribute
1714: *
1715: * Determine whether an attribute is of type Ref. In case we have Dtd(s)
1716: * then this is simple, otherwise we use an heuristic: name Ref (upper
1717: * or lowercase).
1718: *
1719: * Returns 0 or 1 depending on the lookup result
1720: */
1721: int
1722: xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
1723: if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
1724: return(0);
1725: /*******************
1726: if (((attr->name[0] == 'I') || (attr->name[0] == 'i')) &&
1727: ((attr->name[1] == 'D') || (attr->name[1] == 'd')) &&
1728: (attr->name[2] == 0)) return(1);
1729: *******************/
1730: } else {
1731: xmlAttributePtr attrDecl;
1732:
1733: attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
1734: if ((attrDecl == NULL) && (doc->extSubset != NULL))
1735: attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
1736: attr->name);
1737:
1738: if ((attrDecl != NULL) && (attrDecl->type == XML_ATTRIBUTE_IDREF))
1739: return(1);
1740: }
1741: return(0);
1742: }
1743:
1744: /**
1745: * xmlGetRef:
1746: * @doc: pointer to the document
1747: * @Ref: the Ref value
1748: *
1749: * Search the attribute declaring the given Ref
1750: *
1751: * Returns NULL if not found, otherwise the xmlAttrPtr defining the Ref
1752: */
1753: xmlAttrPtr
1754: xmlGetRef(xmlDocPtr doc, const CHAR *Ref) {
1755: xmlRefPtr cur;
1756: xmlRefTablePtr table;
1757: int i;
1758:
1759: if (doc == NULL) {
1760: fprintf(stderr, "xmlGetRef: doc == NULL\n");
1761: return(NULL);
1762: }
1763:
1764: if (Ref == NULL) {
1765: fprintf(stderr, "xmlGetRef: Ref == NULL\n");
1766: return(NULL);
1767: }
1768:
1769: table = doc->refs;
1770: if (table == NULL)
1771: return(NULL);
1772:
1773: /*
1774: * Search the Ref list.
1775: */
1776: for (i = 0;i < table->nb_refs;i++) {
1777: cur = table->table[i];
1778: if (!xmlStrcmp(cur->value, Ref)) {
1779: return(cur->attr);
1780: }
1781: }
1782: return(NULL);
1783: }
1784:
1785: /************************************************************************
1786: * *
1.14 daniel 1787: * Routines for validity checking *
1788: * *
1789: ************************************************************************/
1790:
1791: /**
1792: * xmlGetDtdElementDesc:
1793: * @dtd: a pointer to the DtD to search
1794: * @name: the element name
1795: *
1796: * Search the Dtd for the description of this element
1797: *
1798: * returns the xmlElementPtr if found or NULL
1799: */
1800:
1801: xmlElementPtr
1802: xmlGetDtdElementDesc(xmlDtdPtr dtd, const CHAR *name) {
1803: xmlElementTablePtr table;
1804: xmlElementPtr cur;
1805: int i;
1806:
1807: if (dtd == NULL) return(NULL);
1808: if (dtd->elements == NULL) return(NULL);
1809: table = dtd->elements;
1810:
1811: for (i = 0;i < table->nb_elements;i++) {
1.15 daniel 1812: cur = table->table[i];
1.14 daniel 1813: if (!xmlStrcmp(cur->name, name))
1814: return(cur);
1815: }
1816: return(NULL);
1817: }
1818:
1819: /**
1820: * xmlGetDtdAttrDesc:
1821: * @dtd: a pointer to the DtD to search
1.15 daniel 1822: * @elem: the element name
1.14 daniel 1823: * @name: the attribute name
1824: *
1.15 daniel 1825: * Search the Dtd for the description of this attribute on
1826: * this element.
1.14 daniel 1827: *
1828: * returns the xmlAttributePtr if found or NULL
1829: */
1830:
1831: xmlAttributePtr
1.15 daniel 1832: xmlGetDtdAttrDesc(xmlDtdPtr dtd, const CHAR *elem, const CHAR *name) {
1.14 daniel 1833: xmlAttributeTablePtr table;
1834: xmlAttributePtr cur;
1835: int i;
1836:
1837: if (dtd == NULL) return(NULL);
1838: if (dtd->attributes == NULL) return(NULL);
1839: table = dtd->attributes;
1840:
1841: for (i = 0;i < table->nb_attributes;i++) {
1.15 daniel 1842: cur = table->table[i];
1843: if ((!xmlStrcmp(cur->name, name)) &&
1844: (!xmlStrcmp(cur->elem, elem)))
1.14 daniel 1845: return(cur);
1846: }
1847: return(NULL);
1848: }
1849:
1850: /**
1851: * xmlGetDtdNotationDesc:
1852: * @dtd: a pointer to the DtD to search
1853: * @name: the notation name
1854: *
1855: * Search the Dtd for the description of this notation
1856: *
1857: * returns the xmlNotationPtr if found or NULL
1858: */
1859:
1860: xmlNotationPtr
1861: xmlGetDtdNotationDesc(xmlDtdPtr dtd, const CHAR *name) {
1862: xmlNotationTablePtr table;
1863: xmlNotationPtr cur;
1864: int i;
1865:
1866: if (dtd == NULL) return(NULL);
1867: if (dtd->notations == NULL) return(NULL);
1868: table = dtd->notations;
1869:
1870: for (i = 0;i < table->nb_notations;i++) {
1.15 daniel 1871: cur = table->table[i];
1.14 daniel 1872: if (!xmlStrcmp(cur->name, name))
1873: return(cur);
1874: }
1875: return(NULL);
1876: }
1877:
1878: /**
1.23 daniel 1879: * xmlValidateNotationUse:
1880: * @ctxt: the validation context
1881: * @doc: the document
1882: * @notationName: the notation name to check
1883: *
1884: * Validate that the given mame match a notation declaration.
1885: * - [ VC: Notation Declared ]
1886: *
1887: * returns 1 if valid or 0 otherwise
1888: */
1889:
1890: int
1891: xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
1892: const CHAR *notationName) {
1893: xmlNotationPtr notaDecl;
1894: if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
1895:
1896: notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
1897: if ((notaDecl == NULL) && (doc->extSubset != NULL))
1898: notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
1899:
1900: if (notaDecl == NULL) {
1901: VERROR(ctxt->userData, "NOTATION %s is not declared\n",
1902: notationName);
1903: return(0);
1904: }
1905: return(1);
1906: }
1907:
1908: /**
1.18 daniel 1909: * xmlIsMixedElement
1910: * @doc: the document
1911: * @name: the element name
1912: *
1913: * Search in the DtDs whether an element accept Mixed content (or ANY)
1914: * basically if it is supposed to accept text childs
1915: *
1916: * returns 0 if no, 1 if yes, and -1 if no element description is available
1917: */
1918:
1919: int
1920: xmlIsMixedElement(xmlDocPtr doc, const CHAR *name) {
1921: xmlElementPtr elemDecl;
1922:
1923: if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
1924:
1925: elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
1926: if ((elemDecl == NULL) && (doc->extSubset != NULL))
1927: elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
1928: if (elemDecl == NULL) return(-1);
1929: switch (elemDecl->type) {
1930: case XML_ELEMENT_TYPE_ELEMENT:
1931: return(0);
1932: case XML_ELEMENT_TYPE_EMPTY:
1933: /*
1934: * return 1 for EMPTY since we want VC error to pop up
1935: * on <empty> </empty> for example
1936: */
1937: case XML_ELEMENT_TYPE_ANY:
1938: case XML_ELEMENT_TYPE_MIXED:
1939: return(1);
1940: }
1941: return(1);
1942: }
1943:
1944: /**
1.16 daniel 1945: * xmlValidateNameValue:
1946: * @value: an Name value
1947: *
1948: * Validate that the given value match Name production
1949: *
1950: * returns 1 if valid or 0 otherwise
1951: */
1952:
1953: int
1954: xmlValidateNameValue(const CHAR *value) {
1955: const CHAR *cur;
1956:
1957: if (value == NULL) return(0);
1958: cur = value;
1959:
1960: if (!IS_LETTER(*cur) && (*cur != '_') &&
1961: (*cur != ':')) {
1962: return(0);
1963: }
1964:
1965: while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
1966: (*cur == '.') || (*cur == '-') ||
1967: (*cur == '_') || (*cur == ':') ||
1968: (IS_COMBINING(*cur)) ||
1969: (IS_EXTENDER(*cur)))
1970: cur++;
1971:
1972: if (*cur != 0) return(0);
1973:
1974: return(1);
1975: }
1976:
1977: /**
1978: * xmlValidateNamesValue:
1979: * @value: an Names value
1980: *
1981: * Validate that the given value match Names production
1982: *
1983: * returns 1 if valid or 0 otherwise
1984: */
1985:
1986: int
1987: xmlValidateNamesValue(const CHAR *value) {
1988: const CHAR *cur;
1989:
1990: if (value == NULL) return(0);
1991: cur = value;
1992:
1993: if (!IS_LETTER(*cur) && (*cur != '_') &&
1994: (*cur != ':')) {
1995: return(0);
1996: }
1997:
1998: while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
1999: (*cur == '.') || (*cur == '-') ||
2000: (*cur == '_') || (*cur == ':') ||
2001: (IS_COMBINING(*cur)) ||
2002: (IS_EXTENDER(*cur)))
2003: cur++;
2004:
2005: while (IS_BLANK(*cur)) {
2006: while (IS_BLANK(*cur)) cur++;
2007:
2008: if (!IS_LETTER(*cur) && (*cur != '_') &&
2009: (*cur != ':')) {
2010: return(0);
2011: }
2012:
2013: while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2014: (*cur == '.') || (*cur == '-') ||
2015: (*cur == '_') || (*cur == ':') ||
2016: (IS_COMBINING(*cur)) ||
2017: (IS_EXTENDER(*cur)))
2018: cur++;
2019: }
2020:
2021: if (*cur != 0) return(0);
2022:
2023: return(1);
2024: }
2025:
2026: /**
2027: * xmlValidateNmtokenValue:
2028: * @value: an Mntoken value
2029: *
2030: * Validate that the given value match Nmtoken production
2031: *
2032: * [ VC: Name Token ]
2033: *
2034: * returns 1 if valid or 0 otherwise
2035: */
2036:
2037: int
2038: xmlValidateNmtokenValue(const CHAR *value) {
2039: const CHAR *cur;
2040:
2041: if (value == NULL) return(0);
2042: cur = value;
2043:
2044: if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
2045: (*cur != '.') && (*cur != '-') &&
2046: (*cur != '_') && (*cur != ':') &&
2047: (!IS_COMBINING(*cur)) &&
2048: (!IS_EXTENDER(*cur)))
2049: return(0);
2050:
2051: while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2052: (*cur == '.') || (*cur == '-') ||
2053: (*cur == '_') || (*cur == ':') ||
2054: (IS_COMBINING(*cur)) ||
2055: (IS_EXTENDER(*cur)))
2056: cur++;
2057:
2058: if (*cur != 0) return(0);
2059:
2060: return(1);
2061: return(1);
2062: }
2063:
2064: /**
2065: * xmlValidateNmtokensValue:
2066: * @value: an Mntokens value
2067: *
2068: * Validate that the given value match Nmtokens production
2069: *
2070: * [ VC: Name Token ]
2071: *
2072: * returns 1 if valid or 0 otherwise
2073: */
2074:
2075: int
2076: xmlValidateNmtokensValue(const CHAR *value) {
2077: const CHAR *cur;
2078:
2079: if (value == NULL) return(0);
2080: cur = value;
2081:
2082: if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
2083: (*cur != '.') && (*cur != '-') &&
2084: (*cur != '_') && (*cur != ':') &&
2085: (!IS_COMBINING(*cur)) &&
2086: (!IS_EXTENDER(*cur)))
2087: return(0);
2088:
2089: while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2090: (*cur == '.') || (*cur == '-') ||
2091: (*cur == '_') || (*cur == ':') ||
2092: (IS_COMBINING(*cur)) ||
2093: (IS_EXTENDER(*cur)))
2094: cur++;
2095:
2096: while (IS_BLANK(*cur)) {
2097: while (IS_BLANK(*cur)) cur++;
2098:
2099: if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
2100: (*cur != '.') && (*cur != '-') &&
2101: (*cur != '_') && (*cur != ':') &&
2102: (!IS_COMBINING(*cur)) &&
2103: (!IS_EXTENDER(*cur)))
2104: return(0);
2105:
2106: while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2107: (*cur == '.') || (*cur == '-') ||
2108: (*cur == '_') || (*cur == ':') ||
2109: (IS_COMBINING(*cur)) ||
2110: (IS_EXTENDER(*cur)))
2111: cur++;
2112: }
2113:
2114: if (*cur != 0) return(0);
2115:
2116: return(1);
2117: }
2118:
2119: /**
2120: * xmlValidateNotationDecl:
1.23 daniel 2121: * @ctxt: the validation context
1.16 daniel 2122: * @doc: a document instance
2123: * @nota: a notation definition
2124: *
2125: * Try to validate a single notation definition
2126: * basically it does the following checks as described by the
2127: * XML-1.0 recommendation:
1.18 daniel 2128: * - it seems that no validity constraing exist on notation declarations
2129: * But this function get called anyway ...
1.16 daniel 2130: *
2131: * returns 1 if valid or 0 otherwise
2132: */
2133:
2134: int
2135: xmlValidateNotationDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2136: xmlNotationPtr nota) {
2137: int ret = 1;
2138:
2139: return(ret);
2140: }
2141:
2142: /**
2143: * xmlValidateAttributeValue:
2144: * @type: an attribute type
2145: * @value: an attribute value
2146: *
2147: * Validate that the given attribute value match the proper production
2148: *
2149: * [ VC: ID ]
2150: * Values of type ID must match the Name production....
2151: *
2152: * [ VC: IDREF ]
2153: * Values of type IDREF must match the Name production, and values
2154: * of type IDREFS must match Names ...
2155: *
2156: * [ VC: Entity Name ]
2157: * Values of type ENTITY must match the Name production, values
2158: * of type ENTITIES must match Names ...
2159: *
2160: * [ VC: Name Token ]
2161: * Values of type NMTOKEN must match the Nmtoken production; values
2162: * of type NMTOKENS must match Nmtokens.
2163: *
2164: * returns 1 if valid or 0 otherwise
2165: */
2166:
2167: int
2168: xmlValidateAttributeValue(xmlAttributeType type, const CHAR *value) {
2169: switch (type) {
1.24 daniel 2170: case XML_ATTRIBUTE_ENTITIES:
1.16 daniel 2171: case XML_ATTRIBUTE_IDREFS:
2172: return(xmlValidateNamesValue(value));
1.24 daniel 2173: case XML_ATTRIBUTE_ENTITY:
1.16 daniel 2174: case XML_ATTRIBUTE_IDREF:
2175: case XML_ATTRIBUTE_ID:
2176: case XML_ATTRIBUTE_NOTATION:
2177: return(xmlValidateNameValue(value));
2178: case XML_ATTRIBUTE_NMTOKENS:
2179: case XML_ATTRIBUTE_ENUMERATION:
2180: return(xmlValidateNmtokensValue(value));
2181: case XML_ATTRIBUTE_NMTOKEN:
2182: return(xmlValidateNmtokenValue(value));
2183: case XML_ATTRIBUTE_CDATA:
2184: break;
2185: }
2186: return(1);
2187: }
2188:
2189: /**
1.14 daniel 2190: * xmlValidateAttributeDecl:
1.23 daniel 2191: * @ctxt: the validation context
1.14 daniel 2192: * @doc: a document instance
2193: * @attr: an attribute definition
2194: *
2195: * Try to validate a single attribute definition
2196: * basically it does the following checks as described by the
2197: * XML-1.0 recommendation:
2198: * - [ VC: Attribute Default Legal ]
2199: * - [ VC: Enumeration ]
2200: * - [ VC: ID Attribute Default ]
2201: *
2202: * The ID/IDREF uniqueness and matching are done separately
2203: *
2204: * returns 1 if valid or 0 otherwise
2205: */
2206:
2207: int
2208: xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2209: xmlAttributePtr attr) {
1.16 daniel 2210: int ret = 1;
2211: int val;
1.14 daniel 2212: CHECK_DTD;
1.16 daniel 2213: if(attr == NULL) return(1);
2214:
2215: /* Attribute Default Legal */
2216: /* Enumeration */
2217: if (attr->defaultValue != NULL) {
2218: val = xmlValidateAttributeValue(attr->type, attr->defaultValue);
2219: if (val == 0) {
2220: VERROR(ctxt->userData,
2221: "Syntax of default value for attribute %s on %s is not valid\n",
2222: attr->name, attr->elem);
2223: }
2224: ret &= val;
2225: }
2226:
2227: /* ID Attribute Default */
2228: if ((attr->type == XML_ATTRIBUTE_ID)&&
2229: (attr->def != XML_ATTRIBUTE_IMPLIED) &&
2230: (attr->def != XML_ATTRIBUTE_REQUIRED)) {
2231: VERROR(ctxt->userData,
2232: "ID attribute %s on %s is not valid must be #IMPLIED or #REQUIRED\n",
2233: attr->name, attr->elem);
2234: ret = 0;
2235: }
2236:
1.24 daniel 2237: /* One ID per Element Type */
1.16 daniel 2238: if ((attr->type == XML_ATTRIBUTE_ID) && (doc->extSubset != NULL)) {
2239: int nbId = 0;
2240:
2241: /* the trick is taht we parse DtD as their own internal subset */
2242: xmlElementPtr elem = xmlGetDtdElementDesc(doc->extSubset,
2243: attr->elem);
2244: if (elem != NULL) {
2245: nbId = xmlScanIDAttributeDecl(NULL, elem);
2246: }
2247: if (nbId >= 1)
2248: VERROR(ctxt->userData,
2249: "Element %s has ID attribute defined in the external subset : %s\n",
2250: attr->elem, attr->name);
2251: }
1.14 daniel 2252:
1.16 daniel 2253: return(ret);
1.14 daniel 2254: }
2255:
2256: /**
2257: * xmlValidateElementDecl:
2258: * @ctxt: the validation context
2259: * @doc: a document instance
2260: * @elem: an element definition
2261: *
2262: * Try to validate a single element definition
2263: * basically it does the following checks as described by the
2264: * XML-1.0 recommendation:
2265: * - [ VC: One ID per Element Type ]
2266: * - [ VC: No Duplicate Types ]
2267: * - [ VC: Unique Element Type Declaration ]
2268: *
2269: * returns 1 if valid or 0 otherwise
2270: */
2271:
2272: int
1.16 daniel 2273: xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2274: xmlElementPtr elem) {
2275: int ret = 1;
2276: xmlElementPtr tst;
2277:
1.14 daniel 2278: CHECK_DTD;
1.16 daniel 2279:
2280: if (elem == NULL) return(1);
1.14 daniel 2281:
1.16 daniel 2282: /* No Duplicate Types */
2283: if (elem->type == XML_ELEMENT_TYPE_MIXED) {
2284: xmlElementContentPtr cur, next;
2285: const CHAR *name;
2286:
2287: cur = elem->content;
2288: while (cur != NULL) {
2289: if (cur->type != XML_ELEMENT_CONTENT_OR) break;
2290: if (cur->c1 == NULL) break;
2291: if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
2292: name = cur->c1->name;
2293: next = cur->c2;
2294: while (next != NULL) {
2295: if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
2296: if (!xmlStrcmp(next->name, name)) {
2297: VERROR(ctxt->userData,
2298: "Definition of %s has duplicate references of %s\n",
2299: elem->name, name);
2300: ret = 0;
2301: }
2302: break;
2303: }
2304: if (next->c1 == NULL) break;
2305: if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
2306: if (!xmlStrcmp(next->c1->name, name)) {
2307: VERROR(ctxt->userData,
2308: "Definition of %s has duplicate references of %s\n",
2309: elem->name, name);
2310: ret = 0;
2311: }
2312: next = next->c2;
2313: }
2314: }
2315: cur = cur->c2;
2316: }
2317: }
2318:
2319: /* VC: Unique Element Type Declaration */
2320: tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
2321: if ((tst != NULL ) && (tst != elem)) {
2322: VERROR(ctxt->userData, "Redefinition of element %s\n",
2323: elem->name);
2324: ret = 0;
2325: }
2326: tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
2327: if ((tst != NULL ) && (tst != elem)) {
2328: VERROR(ctxt->userData, "Redefinition of element %s\n",
2329: elem->name);
2330: ret = 0;
2331: }
2332:
2333: /* One ID per Element Type */
2334: if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
2335: ret = 0;
2336: }
2337: return(ret);
1.14 daniel 2338: }
2339:
2340: /**
2341: * xmlValidateOneAttribute:
2342: * @ctxt: the validation context
2343: * @doc: a document instance
2344: * @elem: an element instance
2345: * @attr: an attribute instance
2346: *
2347: * Try to validate a single attribute for an element
2348: * basically it * does the following checks as described by the
2349: * XML-1.0 recommendation:
1.18 daniel 2350: * - [ VC: Attribute Value Type ]
2351: * - [ VC: Fixed Attribute Default ]
1.14 daniel 2352: * - [ VC: Entity Name ]
2353: * - [ VC: Name Token ]
2354: * - [ VC: ID ]
2355: * - [ VC: IDREF ]
2356: * - [ VC: Entity Name ]
1.16 daniel 2357: * - [ VC: Notation Attributes ]
1.14 daniel 2358: *
2359: * The ID/IDREF uniqueness and matching are done separately
2360: *
2361: * returns 1 if valid or 0 otherwise
2362: */
2363:
2364: int
1.16 daniel 2365: xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
1.18 daniel 2366: xmlNodePtr elem, xmlAttrPtr attr, const CHAR *value) {
1.24 daniel 2367: /* xmlElementPtr elemDecl; */
1.18 daniel 2368: xmlAttributePtr attrDecl;
2369: int val;
2370: int ret = 1;
2371:
1.14 daniel 2372: CHECK_DTD;
1.18 daniel 2373: if ((elem == NULL) || (elem->name == NULL)) return(0);
2374: if ((attr == NULL) || (attr->name == NULL)) return(0);
2375:
2376: attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
2377: if ((attrDecl == NULL) && (doc->extSubset != NULL))
2378: attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, attr->name);
2379:
1.14 daniel 2380:
1.18 daniel 2381: /* Validity Constraint: Attribute Value Type */
2382: if (attrDecl == NULL) {
2383: VERROR(ctxt->userData,
2384: "No declaration for attribute %s on element %s\n",
2385: attr->name, elem->name);
2386: return(0);
2387: }
2388: val = xmlValidateAttributeValue(attrDecl->type, value);
2389: if (val == 0) {
2390: VERROR(ctxt->userData,
2391: "Syntax of value for attribute %s on %s is not valid\n",
2392: attr->name, elem->name);
2393: ret = 0;
1.22 daniel 2394: }
2395:
2396: /* Validity Constraint: ID uniqueness */
2397: if (attrDecl->type == XML_ATTRIBUTE_ID) {
2398: xmlAddID(ctxt, doc, value, attr);
1.18 daniel 2399: }
2400:
1.28 daniel 2401: if (attrDecl->type == XML_ATTRIBUTE_IDREF) {
2402: xmlAddRef(ctxt, doc, value, attr);
2403: }
2404:
1.18 daniel 2405: /* Validity Constraint: Notation Attributes */
2406: if (attrDecl->type == XML_ATTRIBUTE_NOTATION) {
2407: xmlEnumerationPtr tree = attrDecl->tree;
2408: xmlNotationPtr nota;
2409:
2410: /* First check that the given NOTATION was declared */
2411: nota = xmlGetDtdNotationDesc(doc->intSubset, value);
2412: if (nota == NULL)
2413: nota = xmlGetDtdNotationDesc(doc->extSubset, value);
2414:
2415: if (nota == NULL) {
2416: VERROR(ctxt->userData,
2417: "Value \"%s\" for attribute %s on %s is not a declared Notation\n",
2418: value, attr->name, elem->name);
2419: ret = 0;
2420: }
2421:
2422: /* Second, verify that it's among the list */
2423: while (tree != NULL) {
2424: if (!xmlStrcmp(tree->name, value)) break;
2425: tree = tree->next;
2426: }
2427: if (tree == NULL) {
2428: VERROR(ctxt->userData,
2429: "Value \"%s\" for attribute %s on %s is among the enumerated notations\n",
2430: value, attr->name, elem->name);
2431: ret = 0;
2432: }
2433: }
2434:
2435: /* Validity Constraint: Enumeration */
2436: if (attrDecl->type == XML_ATTRIBUTE_ENUMERATION) {
2437: xmlEnumerationPtr tree = attrDecl->tree;
2438: while (tree != NULL) {
2439: if (!xmlStrcmp(tree->name, value)) break;
2440: tree = tree->next;
2441: }
2442: if (tree == NULL) {
2443: VERROR(ctxt->userData,
2444: "Value \"%s\" for attribute %s on %s is among the enumerated set\n",
2445: value, attr->name, elem->name);
2446: ret = 0;
2447: }
2448: }
2449:
2450: /* Fixed Attribute Default */
2451: if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
2452: (xmlStrcmp(attrDecl->defaultValue, value))) {
2453: VERROR(ctxt->userData,
2454: "Value for attribute %s on %s must be \"%s\"\n",
2455: attr->name, elem->name, attrDecl->defaultValue);
2456: ret = 0;
2457: }
2458:
1.24 daniel 2459: /********
1.18 daniel 2460: elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
2461: if ((elemDecl == NULL) && (doc->extSubset != NULL))
2462: elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
2463: if (elemDecl == NULL) {
2464: return(0);
2465: }
1.24 daniel 2466: ********/
1.18 daniel 2467: return(ret);
2468: }
2469:
2470: int xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
2471: xmlElementContentPtr cont);
2472:
2473: /**
2474: * xmlValidateElementTypeExpr:
2475: * @ctxt: the validation context
2476: * @child: pointer to the child list
2477: * @cont: pointer to the content declaration
2478: *
2479: * Try to validate the content of an element of type element
2480: * but don't handle the occurence factor
2481: *
2482: * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
2483: * also update child value in-situ.
2484: */
2485:
2486: int
2487: xmlValidateElementTypeExpr(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
2488: xmlElementContentPtr cont) {
2489: xmlNodePtr cur;
2490: int ret = 1;
2491:
2492: if (cont == NULL) return(-1);
2493: while (*child != NULL) {
2494: if ((*child)->type == XML_PI_NODE) {
2495: *child = (*child)->next;
2496: continue;
2497: }
2498: if ((*child)->type == XML_COMMENT_NODE) {
2499: *child = (*child)->next;
2500: continue;
2501: }
2502: else if ((*child)->type != XML_ELEMENT_NODE) {
2503: return(-1);
2504: }
2505: break;
2506: }
2507: switch (cont->type) {
2508: case XML_ELEMENT_CONTENT_PCDATA:
2509: /* Internal error !!! */
2510: fprintf(stderr, "Internal: MIXED struct bad\n");
2511: return(-1);
2512: case XML_ELEMENT_CONTENT_ELEMENT:
1.20 daniel 2513: if (*child == NULL) return(0);
1.18 daniel 2514: ret = (!xmlStrcmp((*child)->name, cont->name));
2515: if (ret == 1)
2516: *child = (*child)->next;
2517: return(ret);
2518: case XML_ELEMENT_CONTENT_OR:
2519: cur = *child;
2520: ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
2521: if (ret == -1) return(-1);
2522: if (ret == 1) {
2523: return(1);
2524: }
2525: /* rollback and retry the other path */
2526: *child = cur;
2527: ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
2528: if (ret == -1) return(-1);
2529: if (ret == 0) {
2530: *child = cur;
2531: return(0);
2532: }
2533: return(1);
2534: case XML_ELEMENT_CONTENT_SEQ:
2535: cur = *child;
2536: ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
2537: if (ret == -1) return(-1);
2538: if (ret == 0) {
2539: *child = cur;
2540: return(0);
2541: }
2542: ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
2543: if (ret == -1) return(-1);
2544: if (ret == 0) {
2545: *child = cur;
2546: return(0);
2547: }
2548: return(1);
2549: }
2550: return(ret);
2551: }
2552:
2553: /**
2554: * xmlValidateElementTypeElement:
2555: * @ctxt: the validation context
2556: * @child: pointer to the child list
2557: * @cont: pointer to the content declaration
2558: *
2559: * Try to validate the content of an element of type element
2560: * yeah, Yet Another Regexp Implementation, and recursive
2561: *
2562: * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
2563: * also update child and content values in-situ.
2564: */
2565:
2566: int
2567: xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
2568: xmlElementContentPtr cont) {
2569: xmlNodePtr cur;
2570: int ret = 1;
2571:
2572: if (cont == NULL) return(-1);
2573: while (*child != NULL) {
2574: if ((*child)->type == XML_PI_NODE) {
2575: *child = (*child)->next;
2576: continue;
2577: }
2578: if ((*child)->type == XML_COMMENT_NODE) {
2579: *child = (*child)->next;
2580: continue;
2581: }
2582: else if ((*child)->type != XML_ELEMENT_NODE) {
2583: return(-1);
2584: }
2585: break;
2586: }
2587: cur = *child;
2588: ret = xmlValidateElementTypeExpr(ctxt, child, cont);
2589: if (ret == -1) return(-1);
2590: switch (cont->ocur) {
2591: case XML_ELEMENT_CONTENT_ONCE:
2592: if (ret == 1) {
2593: return(1);
2594: }
2595: *child = cur;
2596: return(0);
2597: case XML_ELEMENT_CONTENT_OPT:
2598: if (ret == 0) {
2599: *child = cur;
2600: return(1);
2601: }
1.19 daniel 2602: break;
1.18 daniel 2603: case XML_ELEMENT_CONTENT_MULT:
2604: if (ret == 0) {
2605: *child = cur;
1.19 daniel 2606: break;
1.18 daniel 2607: }
2608: /* no break on purpose */
2609: case XML_ELEMENT_CONTENT_PLUS:
2610: if (ret == 0) {
2611: *child = cur;
2612: return(0);
2613: }
2614: do {
2615: cur = *child;
2616: ret = xmlValidateElementTypeExpr(ctxt, child, cont);
2617: } while (ret == 1);
2618: if (ret == -1) return(-1);
2619: *child = cur;
1.19 daniel 2620: break;
2621: }
2622: while (*child != NULL) {
2623: if ((*child)->type == XML_PI_NODE) {
2624: *child = (*child)->next;
2625: continue;
2626: }
2627: if ((*child)->type == XML_COMMENT_NODE) {
2628: *child = (*child)->next;
2629: continue;
2630: }
2631: else if ((*child)->type != XML_ELEMENT_NODE) {
2632: return(-1);
2633: }
2634: break;
2635: }
2636: return(1);
2637: }
2638:
2639: /**
2640: * xmlSprintfElementChilds:
2641: * @buf: an output buffer
2642: * @content: An element
2643: * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
2644: *
2645: * This will dump the list of childs to the buffer
2646: * Intended just for the debug routine
2647: */
2648: void
2649: xmlSprintfElementChilds(char *buf, xmlNodePtr node, int glob) {
2650: xmlNodePtr cur;
2651:
2652: if (node == NULL) return;
2653: if (glob) strcat(buf, "(");
2654: cur = node->childs;
2655: while (cur != NULL) {
2656: switch (cur->type) {
2657: case XML_ELEMENT_NODE:
1.23 daniel 2658: strcat(buf, (char *) cur->name);
1.19 daniel 2659: if (cur->next != NULL)
2660: strcat(buf, " ");
2661: break;
2662: case XML_TEXT_NODE:
2663: case XML_CDATA_SECTION_NODE:
2664: case XML_ENTITY_REF_NODE:
2665: strcat(buf, "CDATA");
2666: if (cur->next != NULL)
2667: strcat(buf, " ");
2668: break;
2669: case XML_ATTRIBUTE_NODE:
2670: case XML_DOCUMENT_NODE:
2671: case XML_DOCUMENT_TYPE_NODE:
2672: case XML_DOCUMENT_FRAG_NODE:
2673: case XML_NOTATION_NODE:
2674: strcat(buf, "???");
2675: if (cur->next != NULL)
2676: strcat(buf, " ");
2677: break;
2678: case XML_ENTITY_NODE:
2679: case XML_PI_NODE:
2680: case XML_COMMENT_NODE:
2681: break;
2682: }
2683: cur = cur->next;
1.18 daniel 2684: }
1.19 daniel 2685: if (glob) strcat(buf, ")");
1.14 daniel 2686: }
2687:
1.19 daniel 2688:
1.14 daniel 2689: /**
2690: * xmlValidateOneElement:
2691: * @ctxt: the validation context
2692: * @doc: a document instance
2693: * @elem: an element instance
2694: *
2695: * Try to validate a single element and it's attributes,
2696: * basically it does the following checks as described by the
2697: * XML-1.0 recommendation:
2698: * - [ VC: Element Valid ]
2699: * - [ VC: Required Attribute ]
2700: * Then call xmlValidateOneAttribute() for each attribute present.
2701: *
2702: * The ID/IDREF checkings are done separately
2703: *
2704: * returns 1 if valid or 0 otherwise
2705: */
2706:
2707: int
1.16 daniel 2708: xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
1.18 daniel 2709: xmlNodePtr elem) {
2710: xmlElementPtr elemDecl;
2711: xmlElementContentPtr cont;
2712: xmlNodePtr child;
2713: int ret = 1;
2714: const CHAR *name;
2715:
1.14 daniel 2716: CHECK_DTD;
2717:
1.18 daniel 2718: if ((elem == NULL) || (elem->name == NULL)) return(0);
2719:
2720: elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
2721: if ((elemDecl == NULL) && (doc->extSubset != NULL))
2722: elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
2723: if (elemDecl == NULL) {
2724: VERROR(ctxt->userData, "No declaration for element %s\n",
2725: elem->name);
2726: return(0);
2727: }
2728:
2729: /* Check taht the element content matches the definition */
2730: switch (elemDecl->type) {
2731: case XML_ELEMENT_TYPE_EMPTY:
2732: if (elem->childs != NULL) {
2733: VERROR(ctxt->userData,
2734: "Element %s was declared EMPTY this one has content\n",
2735: elem->name);
2736: ret = 0;
2737: }
2738: break;
2739: case XML_ELEMENT_TYPE_ANY:
2740: /* I don't think anything is required then */
2741: break;
2742: case XML_ELEMENT_TYPE_MIXED:
2743: /* Hum, this start to get messy */
2744: child = elem->childs;
2745: while (child != NULL) {
2746: if (child->type == XML_ELEMENT_NODE) {
2747: name = child->name;
2748: cont = elemDecl->content;
2749: while (cont != NULL) {
2750: if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
2751: if (!xmlStrcmp(cont->name, name)) break;
2752: } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
2753: (cont->c1 != NULL) &&
2754: (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
2755: if (!xmlStrcmp(cont->c1->name, name)) break;
2756: } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
2757: (cont->c1 == NULL) ||
2758: (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
2759: /* Internal error !!! */
2760: fprintf(stderr, "Internal: MIXED struct bad\n");
2761: break;
2762: }
2763: cont = cont->c2;
2764: }
2765: if (cont == NULL) {
2766: VERROR(ctxt->userData,
2767: "Element %s is not declared in %s list of possible childs\n",
2768: name, elem->name);
2769: ret = 0;
2770: }
2771: }
2772: child = child->next;
2773: }
2774: break;
2775: case XML_ELEMENT_TYPE_ELEMENT:
2776: child = elem->childs;
2777: cont = elemDecl->content;
2778: ret = xmlValidateElementTypeElement(ctxt, &child, cont);
1.19 daniel 2779: if ((ret == 0) || (child != NULL)) {
2780: char expr[1000];
2781: char list[2000];
2782:
2783: expr[0] = 0;
2784: xmlSprintfElementContent(expr, cont, 1);
2785: list[0] = 0;
2786: xmlSprintfElementChilds(list, elem, 1);
2787:
1.18 daniel 2788: VERROR(ctxt->userData,
1.19 daniel 2789: "Element %s content doesn't follow the Dtd\nExpecting %s, got %s\n",
2790: elem->name, expr, list);
1.18 daniel 2791: ret = 0;
2792: }
2793: break;
2794: }
2795:
1.24 daniel 2796: /* TODO - [ VC: Required Attribute ] */
1.18 daniel 2797: return(ret);
1.14 daniel 2798: }
2799:
2800: /**
2801: * xmlValidateRoot:
2802: * @ctxt: the validation context
2803: * @doc: a document instance
2804: *
2805: * Try to validate a the root element
2806: * basically it does the following check as described by the
2807: * XML-1.0 recommendation:
2808: * - [ VC: Root Element Type ]
2809: * it doesn't try to recurse or apply other check to the element
2810: *
2811: * returns 1 if valid or 0 otherwise
2812: */
2813:
2814: int
2815: xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
2816: if (doc == NULL) return(0);
2817:
2818: if ((doc->intSubset == NULL) ||
2819: (doc->intSubset->name == NULL)) {
2820: VERROR(ctxt->userData, "Not valid: no DtD found\n");
2821: return(0);
2822: }
2823: if ((doc->root == NULL) || (doc->root->name == NULL)) {
2824: VERROR(ctxt->userData, "Not valid: no root element\n");
2825: return(0);
2826: }
2827: if (xmlStrcmp(doc->intSubset->name, doc->root->name)) {
2828: VERROR(ctxt->userData,
2829: "Not valid: root and DtD name do not match %s and %s\n",
2830: doc->root->name, doc->intSubset->name);
2831: return(0);
2832: }
2833: return(1);
2834: }
2835:
2836:
2837: /**
2838: * xmlValidateElement:
2839: * @ctxt: the validation context
2840: * @doc: a document instance
2841: * @elem: an element instance
2842: *
2843: * Try to validate the subtree under an element
2844: *
2845: * returns 1 if valid or 0 otherwise
2846: */
2847:
2848: int
1.18 daniel 2849: xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
1.27 daniel 2850: xmlNodePtr child;
2851: xmlAttrPtr attr;
2852: CHAR *value;
2853: int ret = 1;
2854:
2855: /* TODO xmlValidateElement */
2856:
2857: if (elem == NULL) return(0);
1.14 daniel 2858: CHECK_DTD;
2859:
1.27 daniel 2860: ret &= xmlValidateOneElement(ctxt, doc, elem);
2861: attr = elem->properties;
2862: while(attr != NULL) {
2863: value = xmlNodeListGetString(doc, attr->val, 0);
2864: ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
2865: if (value != NULL)
2866: free(value);
2867: attr= attr->next;
2868: }
2869: child = elem->childs;
2870: while (child != NULL) {
2871: ret &= xmlValidateElement(ctxt, doc, child);
2872: child = child->next;
2873: }
2874:
2875: return(ret);
1.14 daniel 2876: }
2877:
2878: /**
1.28 daniel 2879: * xmlValidateDocumentFinal:
2880: * @ctxt: the validation context
2881: * @doc: a document instance
2882: *
2883: * Does the final step for the document validation once all the
2884: * incremental validation steps have been completed
2885: *
2886: * basically it does the following checks described by the XML Rec
2887: *
2888: *
2889: * returns 1 if valid or 0 otherwise
2890: */
2891:
2892: int
2893: xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
2894: int ret = 1, i;
2895: xmlRefTablePtr table;
2896: xmlAttrPtr id;
2897:
2898: if (doc == NULL) {
2899: fprintf(stderr, "xmlValidateDocumentFinal: doc == NULL\n");
2900: return(0);
2901: }
2902:
2903: /*
2904: * Get the refs table
2905: */
2906: table = doc->refs;
2907: if (table != NULL) {
2908: for (i = 0; i < table->nb_refs; i++) {
2909: id = xmlGetID(doc, table->table[i]->value);
2910: if (id == NULL) {
2911: VERROR(ctxt->userData,
2912: "IDREF attribute %s reference an unknown ID '%s'\n",
2913: table->table[i]->attr->name, table->table[i]->value);
2914: ret = 0;
2915: }
2916: }
2917: }
2918: return(ret);
2919: }
2920:
2921: /**
1.14 daniel 2922: * xmlValidateDtd:
2923: * @ctxt: the validation context
2924: * @doc: a document instance
2925: * @dtd: a dtd instance
2926: *
2927: * Try to validate the dtd instance
2928: *
2929: * basically it does check all the definitions in the DtD.
2930: *
2931: * returns 1 if valid or 0 otherwise
2932: */
2933:
2934: int
2935: xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
1.27 daniel 2936: /* TODO xmlValidateDtd */
1.14 daniel 2937: return(1);
2938: }
2939:
2940: /**
2941: * xmlValidateDocument:
2942: * @ctxt: the validation context
2943: * @doc: a document instance
2944: *
2945: * Try to validate the document instance
2946: *
1.27 daniel 2947: * basically it does the all the checks described by the XML Rec
1.14 daniel 2948: * i.e. validates the internal and external subset (if present)
2949: * and validate the document tree.
2950: *
2951: * returns 1 if valid or 0 otherwise
2952: */
2953:
2954: int
2955: xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
1.27 daniel 2956: int ret;
2957:
1.14 daniel 2958: if (!xmlValidateRoot(ctxt, doc)) return(0);
2959:
1.27 daniel 2960: ret = xmlValidateElement(ctxt, doc, doc->root);
1.28 daniel 2961: ret &= xmlValidateDocumentFinal(ctxt, doc);
2962: return(ret);
1.14 daniel 2963: }
2964:
Webmaster