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