Annotation of XML/valid.c, revision 1.36
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.31 daniel 39: xmlElementPtr xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name);
40: xmlAttributePtr xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem);
1.15 daniel 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.31 daniel 58: xmlNewElementContent(xmlChar *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);
1.31 daniel 106: ret = xmlNewElementContent((xmlChar *) 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.31 daniel 128: if (cur->name != NULL) xmlFree((xmlChar *) 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.32 daniel 300: * @ctxt: the validation context
1.6 daniel 301: * @dtd: pointer to the DTD
1.1 daniel 302: * @name: the entity name
1.6 daniel 303: * @type: the element type
304: * @content: the element content tree or NULL
1.1 daniel 305: *
306: * Register a new element declaration
307: *
1.6 daniel 308: * Returns NULL if not, othervise the entity
1.1 daniel 309: */
310: xmlElementPtr
1.31 daniel 311: xmlAddElementDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name,
1.36 ! daniel 312: xmlElementTypeVal type, xmlElementContentPtr content) {
1.2 daniel 313: xmlElementPtr ret, cur;
314: xmlElementTablePtr table;
315: int i;
1.1 daniel 316:
317: if (dtd == NULL) {
318: fprintf(stderr, "xmlAddElementDecl: dtd == NULL\n");
319: return(NULL);
320: }
321: if (name == NULL) {
322: fprintf(stderr, "xmlAddElementDecl: name == NULL\n");
323: return(NULL);
324: }
325: switch (type) {
326: case XML_ELEMENT_TYPE_EMPTY:
327: if (content != NULL) {
328: fprintf(stderr,
329: "xmlAddElementDecl: content != NULL for EMPTY\n");
330: return(NULL);
331: }
332: break;
333: case XML_ELEMENT_TYPE_ANY:
334: if (content != NULL) {
335: fprintf(stderr,
336: "xmlAddElementDecl: content != NULL for ANY\n");
337: return(NULL);
338: }
339: break;
340: case XML_ELEMENT_TYPE_MIXED:
341: if (content == NULL) {
342: fprintf(stderr,
343: "xmlAddElementDecl: content == NULL for MIXED\n");
344: return(NULL);
345: }
346: break;
347: case XML_ELEMENT_TYPE_ELEMENT:
348: if (content == NULL) {
349: fprintf(stderr,
350: "xmlAddElementDecl: content == NULL for ELEMENT\n");
351: return(NULL);
352: }
353: break;
354: default:
355: fprintf(stderr, "xmlAddElementDecl: unknown type %d\n", type);
356: return(NULL);
357: }
358:
359: /*
1.2 daniel 360: * Create the Element table if needed.
361: */
362: table = dtd->elements;
363: if (table == NULL)
364: table = dtd->elements = xmlCreateElementTable();
365: if (table == NULL) {
366: fprintf(stderr, "xmlAddElementDecl: Table creation failed!\n");
367: return(NULL);
368: }
369:
370: /*
1.1 daniel 371: * Validity Check:
372: * Search the DTD for previous declarations of the ELEMENT
373: */
1.2 daniel 374: for (i = 0;i < table->nb_elements;i++) {
1.15 daniel 375: cur = table->table[i];
1.2 daniel 376: if (!xmlStrcmp(cur->name, name)) {
377: /*
378: * The element is already defined in this Dtd.
379: */
1.16 daniel 380: VERROR(ctxt->userData, "Redefinition of element %s\n", name);
1.2 daniel 381: return(NULL);
382: }
383: }
1.1 daniel 384:
385: /*
1.2 daniel 386: * Grow the table, if needed.
1.1 daniel 387: */
1.2 daniel 388: if (table->nb_elements >= table->max_elements) {
389: /*
390: * need more elements.
391: */
392: table->max_elements *= 2;
1.15 daniel 393: table->table = (xmlElementPtr *)
1.26 daniel 394: xmlRealloc(table->table, table->max_elements * sizeof(xmlElementPtr));
1.13 daniel 395: if (table->table == NULL) {
1.2 daniel 396: fprintf(stderr, "xmlAddElementDecl: out of memory\n");
397: return(NULL);
398: }
1.1 daniel 399: }
1.26 daniel 400: ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1.15 daniel 401: if (ret == NULL) {
402: fprintf(stderr, "xmlAddElementDecl: out of memory\n");
403: return(NULL);
404: }
405: table->table[table->nb_elements] = ret;
1.2 daniel 406:
407: /*
408: * fill the structure.
409: */
1.1 daniel 410: ret->type = type;
411: ret->name = xmlStrdup(name);
1.11 daniel 412: ret->content = xmlCopyElementContent(content);
1.15 daniel 413: ret->attributes = xmlScanAttributeDecl(dtd, name);
1.2 daniel 414: table->nb_elements++;
415:
416: return(ret);
417: }
418:
419: /**
420: * xmlFreeElement:
421: * @elem: An element
422: *
423: * Deallocate the memory used by an element definition
424: */
425: void
426: xmlFreeElement(xmlElementPtr elem) {
427: if (elem == NULL) return;
428: xmlFreeElementContent(elem->content);
429: if (elem->name != NULL)
1.31 daniel 430: xmlFree((xmlChar *) elem->name);
1.2 daniel 431: memset(elem, -1, sizeof(xmlElement));
1.26 daniel 432: xmlFree(elem);
1.2 daniel 433: }
1.1 daniel 434:
1.2 daniel 435: /**
436: * xmlFreeElementTable:
437: * @table: An element table
438: *
1.4 daniel 439: * Deallocate the memory used by an element hash table.
1.2 daniel 440: */
441: void
442: xmlFreeElementTable(xmlElementTablePtr table) {
443: int i;
444:
445: if (table == NULL) return;
446:
447: for (i = 0;i < table->nb_elements;i++) {
1.15 daniel 448: xmlFreeElement(table->table[i]);
1.2 daniel 449: }
1.26 daniel 450: xmlFree(table->table);
451: xmlFree(table);
1.2 daniel 452: }
453:
454: /**
455: * xmlCopyElementTable:
456: * @table: An element table
457: *
458: * Build a copy of an element table.
459: *
1.6 daniel 460: * Returns the new xmlElementTablePtr or NULL in case of error.
1.2 daniel 461: */
462: xmlElementTablePtr
463: xmlCopyElementTable(xmlElementTablePtr table) {
464: xmlElementTablePtr ret;
465: xmlElementPtr cur, ent;
466: int i;
1.1 daniel 467:
1.26 daniel 468: ret = (xmlElementTablePtr) xmlMalloc(sizeof(xmlElementTable));
1.2 daniel 469: if (ret == NULL) {
470: fprintf(stderr, "xmlCopyElementTable: out of memory !\n");
471: return(NULL);
472: }
1.26 daniel 473: ret->table = (xmlElementPtr *) xmlMalloc(table->max_elements *
1.15 daniel 474: sizeof(xmlElementPtr));
1.2 daniel 475: if (ret->table == NULL) {
476: fprintf(stderr, "xmlCopyElementTable: out of memory !\n");
1.26 daniel 477: xmlFree(ret);
1.2 daniel 478: return(NULL);
479: }
480: ret->max_elements = table->max_elements;
481: ret->nb_elements = table->nb_elements;
482: for (i = 0;i < ret->nb_elements;i++) {
1.26 daniel 483: cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1.15 daniel 484: if (cur == NULL) {
485: fprintf(stderr, "xmlCopyElementTable: out of memory !\n");
1.26 daniel 486: xmlFree(ret);
487: xmlFree(ret->table);
1.15 daniel 488: return(NULL);
489: }
490: ret->table[i] = cur;
491: ent = table->table[i];
1.2 daniel 492: cur->type = ent->type;
493: if (ent->name != NULL)
494: cur->name = xmlStrdup(ent->name);
495: else
496: cur->name = NULL;
497: cur->content = xmlCopyElementContent(ent->content);
1.15 daniel 498: cur->attributes = NULL;
1.2 daniel 499: }
1.1 daniel 500: return(ret);
501: }
502:
1.2 daniel 503: /**
504: * xmlDumpElementTable:
1.9 daniel 505: * @buf: the XML buffer output
1.2 daniel 506: * @table: An element table
507: *
508: * This will dump the content of the element table as an XML DTD definition
509: */
510: void
1.8 daniel 511: xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) {
1.2 daniel 512: int i;
513: xmlElementPtr cur;
514:
515: if (table == NULL) return;
516:
517: for (i = 0;i < table->nb_elements;i++) {
1.15 daniel 518: cur = table->table[i];
1.2 daniel 519: switch (cur->type) {
520: case XML_ELEMENT_TYPE_EMPTY:
1.8 daniel 521: xmlBufferWriteChar(buf, "<!ELEMENT ");
522: xmlBufferWriteCHAR(buf, cur->name);
523: xmlBufferWriteChar(buf, " EMPTY>\n");
1.2 daniel 524: break;
525: case XML_ELEMENT_TYPE_ANY:
1.8 daniel 526: xmlBufferWriteChar(buf, "<!ELEMENT ");
527: xmlBufferWriteCHAR(buf, cur->name);
528: xmlBufferWriteChar(buf, " ANY>\n");
1.2 daniel 529: break;
530: case XML_ELEMENT_TYPE_MIXED:
1.8 daniel 531: xmlBufferWriteChar(buf, "<!ELEMENT ");
532: xmlBufferWriteCHAR(buf, cur->name);
533: xmlBufferWriteChar(buf, " ");
534: xmlDumpElementContent(buf, cur->content, 1);
535: xmlBufferWriteChar(buf, ">\n");
1.2 daniel 536: break;
537: case XML_ELEMENT_TYPE_ELEMENT:
1.8 daniel 538: xmlBufferWriteChar(buf, "<!ELEMENT ");
539: xmlBufferWriteCHAR(buf, cur->name);
540: xmlBufferWriteChar(buf, " ");
541: xmlDumpElementContent(buf, cur->content, 1);
542: xmlBufferWriteChar(buf, ">\n");
1.2 daniel 543: break;
544: default:
545: fprintf(stderr,
546: "xmlDumpElementTable: internal: unknown type %d\n",
547: cur->type);
548: }
1.4 daniel 549: }
550: }
551:
552: /**
553: * xmlCreateEnumeration:
554: * @name: the enumeration name or NULL
555: *
556: * create and initialize an enumeration attribute node.
557: *
1.6 daniel 558: * Returns the xmlEnumerationPtr just created or NULL in case
1.4 daniel 559: * of error.
560: */
561: xmlEnumerationPtr
1.31 daniel 562: xmlCreateEnumeration(xmlChar *name) {
1.4 daniel 563: xmlEnumerationPtr ret;
564:
1.26 daniel 565: ret = (xmlEnumerationPtr) xmlMalloc(sizeof(xmlEnumeration));
1.4 daniel 566: if (ret == NULL) {
1.26 daniel 567: fprintf(stderr, "xmlCreateEnumeration : xmlMalloc(%ld) failed\n",
1.12 daniel 568: (long)sizeof(xmlEnumeration));
1.4 daniel 569: return(NULL);
570: }
571:
572: if (name != NULL)
573: ret->name = xmlStrdup(name);
574: else
575: ret->name = NULL;
576: ret->next = NULL;
577: return(ret);
578: }
579:
580: /**
581: * xmlFreeEnumeration:
582: * @cur: the tree to free.
583: *
584: * free an enumeration attribute node (recursive).
585: */
586: void
587: xmlFreeEnumeration(xmlEnumerationPtr cur) {
588: if (cur == NULL) return;
589:
590: if (cur->next != NULL) xmlFreeEnumeration(cur->next);
591:
1.31 daniel 592: if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
1.4 daniel 593: memset(cur, -1, sizeof(xmlEnumeration));
1.26 daniel 594: xmlFree(cur);
1.4 daniel 595: }
596:
597: /**
598: * xmlCopyEnumeration:
599: * @cur: the tree to copy.
600: *
601: * Copy an enumeration attribute node (recursive).
602: *
1.6 daniel 603: * Returns the xmlEnumerationPtr just created or NULL in case
1.4 daniel 604: * of error.
605: */
606: xmlEnumerationPtr
607: xmlCopyEnumeration(xmlEnumerationPtr cur) {
608: xmlEnumerationPtr ret;
609:
610: if (cur == NULL) return(NULL);
1.31 daniel 611: ret = xmlCreateEnumeration((xmlChar *) cur->name);
1.4 daniel 612:
613: if (cur->next != NULL) ret->next = xmlCopyEnumeration(cur->next);
614: else ret->next = NULL;
615:
616: return(ret);
617: }
618:
619: /**
1.18 daniel 620: * xmlDumpEnumeration:
621: * @buf: the XML buffer output
622: * @enum: An enumeration
623: *
624: * This will dump the content of the enumeration
625: */
626: void
627: xmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) {
628: if (cur == NULL) return;
629:
630: xmlBufferWriteCHAR(buf, cur->name);
631: if (cur->next == NULL)
632: xmlBufferWriteChar(buf, ")");
633: else {
634: xmlBufferWriteChar(buf, " | ");
635: xmlDumpEnumeration(buf, cur->next);
636: }
637: }
638:
639: /**
1.4 daniel 640: * xmlCreateAttributeTable:
641: *
642: * create and initialize an empty attribute hash table.
643: *
1.6 daniel 644: * Returns the xmlAttributeTablePtr just created or NULL in case
1.4 daniel 645: * of error.
646: */
647: xmlAttributeTablePtr
648: xmlCreateAttributeTable(void) {
649: xmlAttributeTablePtr ret;
650:
651: ret = (xmlAttributeTablePtr)
1.26 daniel 652: xmlMalloc(sizeof(xmlAttributeTable));
1.4 daniel 653: if (ret == NULL) {
1.26 daniel 654: fprintf(stderr, "xmlCreateAttributeTable : xmlMalloc(%ld) failed\n",
1.12 daniel 655: (long)sizeof(xmlAttributeTable));
1.4 daniel 656: return(NULL);
657: }
658: ret->max_attributes = XML_MIN_ATTRIBUTE_TABLE;
659: ret->nb_attributes = 0;
1.15 daniel 660: ret->table = (xmlAttributePtr *)
1.26 daniel 661: xmlMalloc(ret->max_attributes * sizeof(xmlAttributePtr));
1.4 daniel 662: if (ret == NULL) {
1.26 daniel 663: fprintf(stderr, "xmlCreateAttributeTable : xmlMalloc(%ld) failed\n",
1.15 daniel 664: ret->max_attributes * (long)sizeof(xmlAttributePtr));
1.26 daniel 665: xmlFree(ret);
1.4 daniel 666: return(NULL);
667: }
668: return(ret);
669: }
670:
1.15 daniel 671: /**
672: * xmlScanAttributeDecl:
673: * @dtd: pointer to the DTD
674: * @elem: the element name
675: *
676: * When inserting a new element scan the DtD for existing attributes
677: * for taht element and initialize the Attribute chain
678: *
679: * Returns the pointer to the first attribute decl in the chain,
680: * possibly NULL.
681: */
682: xmlAttributePtr
1.31 daniel 683: xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem) {
1.16 daniel 684: xmlAttributePtr ret = NULL;
1.15 daniel 685: xmlAttributeTablePtr table;
686: int i;
687:
688: if (dtd == NULL) {
689: fprintf(stderr, "xmlScanAttributeDecl: dtd == NULL\n");
690: return(NULL);
691: }
692: if (elem == NULL) {
693: fprintf(stderr, "xmlScanAttributeDecl: elem == NULL\n");
694: return(NULL);
695: }
696: table = dtd->attributes;
697: if (table == NULL)
698: return(NULL);
699:
700: for (i = 0;i < table->nb_attributes;i++) {
701: if (!xmlStrcmp(table->table[i]->elem, elem)) {
1.16 daniel 702: table->table[i]->next = ret;
703: ret = table->table[i];
704: }
705: }
706: return(ret);
707: }
708:
709: /**
710: * xmlScanIDAttributeDecl:
711: * @ctxt: the validation context
712: * @elem: the element name
713: *
714: * Veryfy that the element don't have too many ID attributes
715: * declared.
716: *
717: * Returns the number of ID attributes found.
718: */
719: int
720: xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
721: xmlAttributePtr cur;
722: int ret = 0;
723:
724: if (elem == NULL) return(0);
725: cur = elem->attributes;
726: while (cur != NULL) {
727: if (cur->type == XML_ATTRIBUTE_ID) {
728: ret ++;
729: if (ret > 1)
730: VERROR(ctxt->userData,
731: "Element %s has too may ID attributes defined : %s\n",
732: elem->name, cur->name);
1.15 daniel 733: }
1.16 daniel 734: cur = cur->next;
1.15 daniel 735: }
736: return(ret);
737: }
738:
1.4 daniel 739:
740: /**
741: * xmlAddAttributeDecl:
1.16 daniel 742: * @ctxt: the validation context
1.6 daniel 743: * @dtd: pointer to the DTD
744: * @elem: the element name
745: * @name: the attribute name
746: * @type: the attribute type
747: * @def: the attribute default type
748: * @defaultValue: the attribute default value
749: * @tree: if it's an enumeration, the associated list
1.4 daniel 750: *
751: * Register a new attribute declaration
752: *
1.6 daniel 753: * Returns NULL if not, othervise the entity
1.4 daniel 754: */
755: xmlAttributePtr
1.31 daniel 756: xmlAddAttributeDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *elem,
757: const xmlChar *name, xmlAttributeType type,
758: xmlAttributeDefault def, const xmlChar *defaultValue,
1.25 daniel 759: xmlEnumerationPtr tree) {
1.4 daniel 760: xmlAttributePtr ret, cur;
761: xmlAttributeTablePtr table;
1.15 daniel 762: xmlElementPtr elemDef;
1.4 daniel 763: int i;
764:
765: if (dtd == NULL) {
766: fprintf(stderr, "xmlAddAttributeDecl: dtd == NULL\n");
767: return(NULL);
768: }
769: if (name == NULL) {
770: fprintf(stderr, "xmlAddAttributeDecl: name == NULL\n");
771: return(NULL);
772: }
773: if (elem == NULL) {
774: fprintf(stderr, "xmlAddAttributeDecl: elem == NULL\n");
775: return(NULL);
776: }
1.23 daniel 777: /*
778: * Check the type and possibly the default value.
779: */
1.4 daniel 780: switch (type) {
781: case XML_ATTRIBUTE_CDATA:
782: break;
783: case XML_ATTRIBUTE_ID:
784: break;
785: case XML_ATTRIBUTE_IDREF:
786: break;
787: case XML_ATTRIBUTE_IDREFS:
788: break;
789: case XML_ATTRIBUTE_ENTITY:
790: break;
791: case XML_ATTRIBUTE_ENTITIES:
792: break;
793: case XML_ATTRIBUTE_NMTOKEN:
794: break;
795: case XML_ATTRIBUTE_NMTOKENS:
796: break;
797: case XML_ATTRIBUTE_ENUMERATION:
798: break;
799: case XML_ATTRIBUTE_NOTATION:
800: break;
801: default:
802: fprintf(stderr, "xmlAddAttributeDecl: unknown type %d\n", type);
803: return(NULL);
804: }
1.23 daniel 805: if ((defaultValue != NULL) &&
806: (!xmlValidateAttributeValue(type, defaultValue))) {
807: VERROR(ctxt->userData, "Attribute %s on %s: invalid default value\n",
808: elem, name, defaultValue);
809: defaultValue = NULL;
810: }
1.4 daniel 811:
812: /*
813: * Create the Attribute table if needed.
814: */
815: table = dtd->attributes;
816: if (table == NULL)
817: table = dtd->attributes = xmlCreateAttributeTable();
818: if (table == NULL) {
819: fprintf(stderr, "xmlAddAttributeDecl: Table creation failed!\n");
820: return(NULL);
821: }
822:
823: /*
824: * Validity Check:
825: * Search the DTD for previous declarations of the ATTLIST
826: */
827: for (i = 0;i < table->nb_attributes;i++) {
1.15 daniel 828: cur = table->table[i];
1.4 daniel 829: if ((!xmlStrcmp(cur->name, name)) && (!xmlStrcmp(cur->elem, elem))) {
830: /*
831: * The attribute is already defined in this Dtd.
832: */
1.23 daniel 833: VERROR(ctxt->userData, "Attribute %s on %s: already defined\n",
834: elem, name);
1.4 daniel 835: }
836: }
837:
838: /*
839: * Grow the table, if needed.
840: */
841: if (table->nb_attributes >= table->max_attributes) {
842: /*
843: * need more attributes.
844: */
845: table->max_attributes *= 2;
1.15 daniel 846: table->table = (xmlAttributePtr *)
1.26 daniel 847: xmlRealloc(table->table, table->max_attributes *
1.15 daniel 848: sizeof(xmlAttributePtr));
1.13 daniel 849: if (table->table == NULL) {
1.4 daniel 850: fprintf(stderr, "xmlAddAttributeDecl: out of memory\n");
851: return(NULL);
852: }
853: }
1.26 daniel 854: ret = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
1.15 daniel 855: if (ret == NULL) {
856: fprintf(stderr, "xmlAddAttributeDecl: out of memory\n");
857: return(NULL);
858: }
859: table->table[table->nb_attributes] = ret;
1.4 daniel 860:
861: /*
862: * fill the structure.
863: */
864: ret->type = type;
865: ret->name = xmlStrdup(name);
866: ret->elem = xmlStrdup(elem);
867: ret->def = def;
868: ret->tree = tree;
869: if (defaultValue != NULL)
870: ret->defaultValue = xmlStrdup(defaultValue);
871: else
872: ret->defaultValue = NULL;
1.15 daniel 873: elemDef = xmlGetDtdElementDesc(dtd, elem);
874: if (elemDef != NULL) {
1.16 daniel 875: if ((type == XML_ATTRIBUTE_ID) &&
876: (xmlScanIDAttributeDecl(NULL, elemDef) != 0))
877: VERROR(ctxt->userData,
878: "Element %s has too may ID attributes defined : %s\n",
879: elem, name);
1.15 daniel 880: ret->next = elemDef->attributes;
881: elemDef->attributes = ret;
882: }
1.4 daniel 883: table->nb_attributes++;
884:
885: return(ret);
886: }
887:
888: /**
889: * xmlFreeAttribute:
890: * @elem: An attribute
891: *
892: * Deallocate the memory used by an attribute definition
893: */
894: void
895: xmlFreeAttribute(xmlAttributePtr attr) {
896: if (attr == NULL) return;
897: if (attr->tree != NULL)
898: xmlFreeEnumeration(attr->tree);
899: if (attr->elem != NULL)
1.31 daniel 900: xmlFree((xmlChar *) attr->elem);
1.4 daniel 901: if (attr->name != NULL)
1.31 daniel 902: xmlFree((xmlChar *) attr->name);
1.4 daniel 903: if (attr->defaultValue != NULL)
1.31 daniel 904: xmlFree((xmlChar *) attr->defaultValue);
1.4 daniel 905: memset(attr, -1, sizeof(xmlAttribute));
1.26 daniel 906: xmlFree(attr);
1.4 daniel 907: }
908:
909: /**
910: * xmlFreeAttributeTable:
911: * @table: An attribute table
912: *
913: * Deallocate the memory used by an entities hash table.
914: */
915: void
916: xmlFreeAttributeTable(xmlAttributeTablePtr table) {
917: int i;
918:
919: if (table == NULL) return;
920:
921: for (i = 0;i < table->nb_attributes;i++) {
1.15 daniel 922: xmlFreeAttribute(table->table[i]);
1.4 daniel 923: }
1.26 daniel 924: xmlFree(table->table);
925: xmlFree(table);
1.4 daniel 926: }
927:
928: /**
929: * xmlCopyAttributeTable:
930: * @table: An attribute table
931: *
932: * Build a copy of an attribute table.
933: *
1.6 daniel 934: * Returns the new xmlAttributeTablePtr or NULL in case of error.
1.4 daniel 935: */
936: xmlAttributeTablePtr
937: xmlCopyAttributeTable(xmlAttributeTablePtr table) {
938: xmlAttributeTablePtr ret;
939: xmlAttributePtr cur, attr;
940: int i;
941:
1.26 daniel 942: ret = (xmlAttributeTablePtr) xmlMalloc(sizeof(xmlAttributeTable));
1.4 daniel 943: if (ret == NULL) {
944: fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
945: return(NULL);
946: }
1.26 daniel 947: ret->table = (xmlAttributePtr *) xmlMalloc(table->max_attributes *
1.15 daniel 948: sizeof(xmlAttributePtr));
1.4 daniel 949: if (ret->table == NULL) {
950: fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
1.26 daniel 951: xmlFree(ret);
1.4 daniel 952: return(NULL);
953: }
954: ret->max_attributes = table->max_attributes;
955: ret->nb_attributes = table->nb_attributes;
956: for (i = 0;i < ret->nb_attributes;i++) {
1.15 daniel 957: attr = table->table[i];
1.26 daniel 958: cur = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
1.15 daniel 959: if (cur == NULL) {
960: fprintf(stderr, "xmlCopyAttributeTable: out of memory !\n");
1.26 daniel 961: xmlFree(ret);
962: xmlFree(ret->table);
1.15 daniel 963: return(NULL);
964: }
965: ret->table[i] = cur;
1.4 daniel 966: cur->type = attr->type;
967: cur->def = attr->def;
968: cur->tree = xmlCopyEnumeration(attr->tree);
969: if (attr->elem != NULL)
970: cur->elem = xmlStrdup(attr->elem);
971: else
972: cur->elem = NULL;
973: if (attr->name != NULL)
974: cur->name = xmlStrdup(attr->name);
975: else
976: cur->name = NULL;
977: if (attr->defaultValue != NULL)
978: cur->defaultValue = xmlStrdup(attr->defaultValue);
979: else
980: cur->defaultValue = NULL;
1.15 daniel 981: /* NEED to rebuild the next chain !!!!!! */
1.4 daniel 982: }
983: return(ret);
984: }
985:
986: /**
987: * xmlDumpAttributeTable:
1.9 daniel 988: * @buf: the XML buffer output
1.4 daniel 989: * @table: An attribute table
990: *
991: * This will dump the content of the attribute table as an XML DTD definition
992: */
993: void
1.8 daniel 994: xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) {
1.4 daniel 995: int i;
996: xmlAttributePtr cur;
997:
998: if (table == NULL) return;
999:
1000: for (i = 0;i < table->nb_attributes;i++) {
1.15 daniel 1001: cur = table->table[i];
1.8 daniel 1002: xmlBufferWriteChar(buf, "<!ATTLIST ");
1003: xmlBufferWriteCHAR(buf, cur->elem);
1004: xmlBufferWriteChar(buf, " ");
1005: xmlBufferWriteCHAR(buf, cur->name);
1.4 daniel 1006: switch (cur->type) {
1007: case XML_ATTRIBUTE_CDATA:
1.8 daniel 1008: xmlBufferWriteChar(buf, " CDATA");
1.4 daniel 1009: break;
1010: case XML_ATTRIBUTE_ID:
1.8 daniel 1011: xmlBufferWriteChar(buf, " ID");
1.4 daniel 1012: break;
1013: case XML_ATTRIBUTE_IDREF:
1.8 daniel 1014: xmlBufferWriteChar(buf, " IDREF");
1.4 daniel 1015: break;
1016: case XML_ATTRIBUTE_IDREFS:
1.8 daniel 1017: xmlBufferWriteChar(buf, " IDREFS");
1.4 daniel 1018: break;
1019: case XML_ATTRIBUTE_ENTITY:
1.8 daniel 1020: xmlBufferWriteChar(buf, " ENTITY");
1.4 daniel 1021: break;
1022: case XML_ATTRIBUTE_ENTITIES:
1.8 daniel 1023: xmlBufferWriteChar(buf, " ENTITIES");
1.4 daniel 1024: break;
1025: case XML_ATTRIBUTE_NMTOKEN:
1.8 daniel 1026: xmlBufferWriteChar(buf, " NMTOKEN");
1.4 daniel 1027: break;
1028: case XML_ATTRIBUTE_NMTOKENS:
1.8 daniel 1029: xmlBufferWriteChar(buf, " NMTOKENS");
1.4 daniel 1030: break;
1031: case XML_ATTRIBUTE_ENUMERATION:
1.18 daniel 1032: xmlBufferWriteChar(buf, " (");
1033: xmlDumpEnumeration(buf, cur->tree);
1.4 daniel 1034: break;
1035: case XML_ATTRIBUTE_NOTATION:
1.18 daniel 1036: xmlBufferWriteChar(buf, " NOTATION (");
1037: xmlDumpEnumeration(buf, cur->tree);
1.4 daniel 1038: break;
1039: default:
1040: fprintf(stderr,
1041: "xmlDumpAttributeTable: internal: unknown type %d\n",
1042: cur->type);
1043: }
1044: switch (cur->def) {
1045: case XML_ATTRIBUTE_NONE:
1046: break;
1047: case XML_ATTRIBUTE_REQUIRED:
1.8 daniel 1048: xmlBufferWriteChar(buf, " #REQUIRED");
1.4 daniel 1049: break;
1050: case XML_ATTRIBUTE_IMPLIED:
1.8 daniel 1051: xmlBufferWriteChar(buf, " #IMPLIED");
1.4 daniel 1052: break;
1053: case XML_ATTRIBUTE_FIXED:
1.17 daniel 1054: xmlBufferWriteChar(buf, " #FIXED");
1.4 daniel 1055: break;
1056: default:
1057: fprintf(stderr,
1058: "xmlDumpAttributeTable: internal: unknown default %d\n",
1059: cur->def);
1060: }
1.17 daniel 1061: if (cur->defaultValue != NULL) {
1062: xmlBufferWriteChar(buf, " ");
1063: xmlBufferWriteQuotedString(buf, cur->defaultValue);
1064: }
1.8 daniel 1065: xmlBufferWriteChar(buf, ">\n");
1.5 daniel 1066: }
1067: }
1068:
1069: /************************************************************************
1070: * *
1071: * NOTATIONs *
1072: * *
1073: ************************************************************************/
1074: /**
1075: * xmlCreateNotationTable:
1076: *
1077: * create and initialize an empty notation hash table.
1078: *
1.6 daniel 1079: * Returns the xmlNotationTablePtr just created or NULL in case
1.5 daniel 1080: * of error.
1081: */
1082: xmlNotationTablePtr
1083: xmlCreateNotationTable(void) {
1084: xmlNotationTablePtr ret;
1085:
1086: ret = (xmlNotationTablePtr)
1.26 daniel 1087: xmlMalloc(sizeof(xmlNotationTable));
1.5 daniel 1088: if (ret == NULL) {
1.26 daniel 1089: fprintf(stderr, "xmlCreateNotationTable : xmlMalloc(%ld) failed\n",
1.12 daniel 1090: (long)sizeof(xmlNotationTable));
1.5 daniel 1091: return(NULL);
1092: }
1093: ret->max_notations = XML_MIN_NOTATION_TABLE;
1094: ret->nb_notations = 0;
1.15 daniel 1095: ret->table = (xmlNotationPtr *)
1.26 daniel 1096: xmlMalloc(ret->max_notations * sizeof(xmlNotationPtr));
1.5 daniel 1097: if (ret == NULL) {
1.26 daniel 1098: fprintf(stderr, "xmlCreateNotationTable : xmlMalloc(%ld) failed\n",
1.12 daniel 1099: ret->max_notations * (long)sizeof(xmlNotation));
1.26 daniel 1100: xmlFree(ret);
1.5 daniel 1101: return(NULL);
1102: }
1103: return(ret);
1104: }
1105:
1106:
1107: /**
1108: * xmlAddNotationDecl:
1.6 daniel 1109: * @dtd: pointer to the DTD
1.16 daniel 1110: * @ctxt: the validation context
1.5 daniel 1111: * @name: the entity name
1.6 daniel 1112: * @PublicID: the public identifier or NULL
1113: * @SystemID: the system identifier or NULL
1.5 daniel 1114: *
1115: * Register a new notation declaration
1116: *
1.6 daniel 1117: * Returns NULL if not, othervise the entity
1.5 daniel 1118: */
1119: xmlNotationPtr
1.31 daniel 1120: xmlAddNotationDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name,
1121: const xmlChar *PublicID, const xmlChar *SystemID) {
1.5 daniel 1122: xmlNotationPtr ret, cur;
1123: xmlNotationTablePtr table;
1124: int i;
1125:
1126: if (dtd == NULL) {
1127: fprintf(stderr, "xmlAddNotationDecl: dtd == NULL\n");
1128: return(NULL);
1129: }
1130: if (name == NULL) {
1131: fprintf(stderr, "xmlAddNotationDecl: name == NULL\n");
1132: return(NULL);
1133: }
1134: if ((PublicID == NULL) && (SystemID == NULL)) {
1135: fprintf(stderr, "xmlAddNotationDecl: no PUBLIC ID nor SYSTEM ID\n");
1136: }
1137:
1138: /*
1139: * Create the Notation table if needed.
1140: */
1141: table = dtd->notations;
1142: if (table == NULL)
1143: table = dtd->notations = xmlCreateNotationTable();
1144: if (table == NULL) {
1145: fprintf(stderr, "xmlAddNotationDecl: Table creation failed!\n");
1146: return(NULL);
1147: }
1148:
1149: /*
1150: * Validity Check:
1151: * Search the DTD for previous declarations of the ATTLIST
1152: */
1153: for (i = 0;i < table->nb_notations;i++) {
1.15 daniel 1154: cur = table->table[i];
1.5 daniel 1155: if (!xmlStrcmp(cur->name, name)) {
1156: /*
1157: * The notation is already defined in this Dtd.
1158: */
1159: fprintf(stderr,
1160: "xmlAddNotationDecl: %s already defined\n", name);
1161: }
1162: }
1163:
1164: /*
1165: * Grow the table, if needed.
1166: */
1167: if (table->nb_notations >= table->max_notations) {
1168: /*
1169: * need more notations.
1170: */
1171: table->max_notations *= 2;
1.15 daniel 1172: table->table = (xmlNotationPtr *)
1.26 daniel 1173: xmlRealloc(table->table, table->max_notations *
1.15 daniel 1174: sizeof(xmlNotationPtr));
1.13 daniel 1175: if (table->table == NULL) {
1.5 daniel 1176: fprintf(stderr, "xmlAddNotationDecl: out of memory\n");
1177: return(NULL);
1178: }
1179: }
1.26 daniel 1180: ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
1.15 daniel 1181: if (ret == NULL) {
1182: fprintf(stderr, "xmlAddNotationDecl: out of memory\n");
1183: return(NULL);
1184: }
1185: table->table[table->nb_notations] = ret;
1.5 daniel 1186:
1187: /*
1188: * fill the structure.
1189: */
1190: ret->name = xmlStrdup(name);
1191: if (SystemID != NULL)
1192: ret->SystemID = xmlStrdup(SystemID);
1193: else
1194: ret->SystemID = NULL;
1195: if (PublicID != NULL)
1196: ret->PublicID = xmlStrdup(PublicID);
1197: else
1198: ret->PublicID = NULL;
1199: table->nb_notations++;
1200:
1201: return(ret);
1202: }
1203:
1204: /**
1205: * xmlFreeNotation:
1206: * @not: A notation
1207: *
1208: * Deallocate the memory used by an notation definition
1209: */
1210: void
1211: xmlFreeNotation(xmlNotationPtr nota) {
1212: if (nota == NULL) return;
1213: if (nota->name != NULL)
1.31 daniel 1214: xmlFree((xmlChar *) nota->name);
1.5 daniel 1215: if (nota->PublicID != NULL)
1.31 daniel 1216: xmlFree((xmlChar *) nota->PublicID);
1.5 daniel 1217: if (nota->SystemID != NULL)
1.31 daniel 1218: xmlFree((xmlChar *) nota->SystemID);
1.5 daniel 1219: memset(nota, -1, sizeof(xmlNotation));
1.26 daniel 1220: xmlFree(nota);
1.5 daniel 1221: }
1222:
1223: /**
1224: * xmlFreeNotationTable:
1225: * @table: An notation table
1226: *
1227: * Deallocate the memory used by an entities hash table.
1228: */
1229: void
1230: xmlFreeNotationTable(xmlNotationTablePtr table) {
1231: int i;
1232:
1233: if (table == NULL) return;
1234:
1235: for (i = 0;i < table->nb_notations;i++) {
1.15 daniel 1236: xmlFreeNotation(table->table[i]);
1.5 daniel 1237: }
1.26 daniel 1238: xmlFree(table->table);
1239: xmlFree(table);
1.5 daniel 1240: }
1241:
1242: /**
1243: * xmlCopyNotationTable:
1244: * @table: A notation table
1245: *
1246: * Build a copy of a notation table.
1247: *
1.6 daniel 1248: * Returns the new xmlNotationTablePtr or NULL in case of error.
1.5 daniel 1249: */
1250: xmlNotationTablePtr
1251: xmlCopyNotationTable(xmlNotationTablePtr table) {
1252: xmlNotationTablePtr ret;
1253: xmlNotationPtr cur, nota;
1254: int i;
1255:
1.26 daniel 1256: ret = (xmlNotationTablePtr) xmlMalloc(sizeof(xmlNotationTable));
1.5 daniel 1257: if (ret == NULL) {
1258: fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
1259: return(NULL);
1260: }
1.26 daniel 1261: ret->table = (xmlNotationPtr *) xmlMalloc(table->max_notations *
1.15 daniel 1262: sizeof(xmlNotationPtr));
1.5 daniel 1263: if (ret->table == NULL) {
1264: fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
1.26 daniel 1265: xmlFree(ret);
1.5 daniel 1266: return(NULL);
1267: }
1268: ret->max_notations = table->max_notations;
1269: ret->nb_notations = table->nb_notations;
1270: for (i = 0;i < ret->nb_notations;i++) {
1.26 daniel 1271: cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
1.15 daniel 1272: if (cur == NULL) {
1273: fprintf(stderr, "xmlCopyNotationTable: out of memory !\n");
1.26 daniel 1274: xmlFree(ret);
1275: xmlFree(ret->table);
1.15 daniel 1276: return(NULL);
1277: }
1278: ret->table[i] = cur;
1279: nota = table->table[i];
1.5 daniel 1280: if (nota->name != NULL)
1281: cur->name = xmlStrdup(nota->name);
1282: else
1283: cur->name = NULL;
1284: if (nota->PublicID != NULL)
1285: cur->PublicID = xmlStrdup(nota->PublicID);
1286: else
1287: cur->PublicID = NULL;
1288: if (nota->SystemID != NULL)
1289: cur->SystemID = xmlStrdup(nota->SystemID);
1290: else
1291: cur->SystemID = NULL;
1292: }
1293: return(ret);
1294: }
1295:
1296: /**
1297: * xmlDumpNotationTable:
1.9 daniel 1298: * @buf: the XML buffer output
1.5 daniel 1299: * @table: A notation table
1300: *
1301: * This will dump the content of the notation table as an XML DTD definition
1302: */
1303: void
1.8 daniel 1304: xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
1.5 daniel 1305: int i;
1306: xmlNotationPtr cur;
1307:
1308: if (table == NULL) return;
1309:
1310: for (i = 0;i < table->nb_notations;i++) {
1.15 daniel 1311: cur = table->table[i];
1.8 daniel 1312: xmlBufferWriteChar(buf, "<!NOTATION ");
1313: xmlBufferWriteCHAR(buf, cur->name);
1.5 daniel 1314: if (cur->PublicID != NULL) {
1.10 daniel 1315: xmlBufferWriteChar(buf, " PUBLIC ");
1316: xmlBufferWriteQuotedString(buf, cur->PublicID);
1.5 daniel 1317: if (cur->SystemID != NULL) {
1.8 daniel 1318: xmlBufferWriteChar(buf, " ");
1319: xmlBufferWriteCHAR(buf, cur->SystemID);
1.5 daniel 1320: }
1321: } else {
1.8 daniel 1322: xmlBufferWriteChar(buf, " SYSTEM ");
1323: xmlBufferWriteCHAR(buf, cur->SystemID);
1.5 daniel 1324: }
1.8 daniel 1325: xmlBufferWriteChar(buf, " >\n");
1.2 daniel 1326: }
1327: }
1.14 daniel 1328:
1329: /************************************************************************
1330: * *
1.27 daniel 1331: * IDs *
1.21 daniel 1332: * *
1333: ************************************************************************/
1334: /**
1335: * xmlCreateIDTable:
1336: *
1337: * create and initialize an empty id hash table.
1338: *
1339: * Returns the xmlIDTablePtr just created or NULL in case
1340: * of error.
1341: */
1342: xmlIDTablePtr
1343: xmlCreateIDTable(void) {
1344: xmlIDTablePtr ret;
1345:
1346: ret = (xmlIDTablePtr)
1.26 daniel 1347: xmlMalloc(sizeof(xmlIDTable));
1.21 daniel 1348: if (ret == NULL) {
1.26 daniel 1349: fprintf(stderr, "xmlCreateIDTable : xmlMalloc(%ld) failed\n",
1.21 daniel 1350: (long)sizeof(xmlIDTable));
1351: return(NULL);
1352: }
1353: ret->max_ids = XML_MIN_NOTATION_TABLE;
1354: ret->nb_ids = 0;
1355: ret->table = (xmlIDPtr *)
1.26 daniel 1356: xmlMalloc(ret->max_ids * sizeof(xmlIDPtr));
1.21 daniel 1357: if (ret == NULL) {
1.26 daniel 1358: fprintf(stderr, "xmlCreateIDTable : xmlMalloc(%ld) failed\n",
1.21 daniel 1359: ret->max_ids * (long)sizeof(xmlID));
1.26 daniel 1360: xmlFree(ret);
1.21 daniel 1361: return(NULL);
1362: }
1363: return(ret);
1364: }
1365:
1366:
1367: /**
1368: * xmlAddID:
1369: * @ctxt: the validation context
1370: * @doc: pointer to the document
1371: * @value: the value name
1372: * @attr: the attribute holding the ID
1373: *
1374: * Register a new id declaration
1375: *
1376: * Returns NULL if not, othervise the new xmlIDPtr
1377: */
1378: xmlIDPtr
1.31 daniel 1379: xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
1.21 daniel 1380: xmlAttrPtr attr) {
1381: xmlIDPtr ret, cur;
1382: xmlIDTablePtr table;
1383: int i;
1384:
1385: if (doc == NULL) {
1386: fprintf(stderr, "xmlAddIDDecl: doc == NULL\n");
1387: return(NULL);
1388: }
1389: if (value == NULL) {
1390: fprintf(stderr, "xmlAddIDDecl: value == NULL\n");
1391: return(NULL);
1392: }
1393: if (attr == NULL) {
1394: fprintf(stderr, "xmlAddIDDecl: attr == NULL\n");
1395: return(NULL);
1396: }
1397:
1398: /*
1399: * Create the ID table if needed.
1400: */
1401: table = doc->ids;
1402: if (table == NULL)
1403: table = doc->ids = xmlCreateIDTable();
1404: if (table == NULL) {
1405: fprintf(stderr, "xmlAddID: Table creation failed!\n");
1406: return(NULL);
1407: }
1408:
1409: /*
1410: * Validity Check:
1411: * Search the DTD for previous declarations of the ATTLIST
1412: */
1413: for (i = 0;i < table->nb_ids;i++) {
1414: cur = table->table[i];
1415: if (!xmlStrcmp(cur->value, value)) {
1416: /*
1417: * The id is already defined in this Dtd.
1418: */
1419: VERROR(ctxt->userData, "ID %s already defined\n", value);
1420: return(NULL);
1421: }
1422: }
1423:
1424: /*
1425: * Grow the table, if needed.
1426: */
1427: if (table->nb_ids >= table->max_ids) {
1428: /*
1429: * need more ids.
1430: */
1431: table->max_ids *= 2;
1432: table->table = (xmlIDPtr *)
1.26 daniel 1433: xmlRealloc(table->table, table->max_ids *
1.21 daniel 1434: sizeof(xmlIDPtr));
1435: if (table->table == NULL) {
1436: fprintf(stderr, "xmlAddID: out of memory\n");
1437: return(NULL);
1438: }
1439: }
1.26 daniel 1440: ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
1.21 daniel 1441: if (ret == NULL) {
1442: fprintf(stderr, "xmlAddID: out of memory\n");
1443: return(NULL);
1444: }
1445: table->table[table->nb_ids] = ret;
1446:
1447: /*
1448: * fill the structure.
1449: */
1450: ret->value = xmlStrdup(value);
1451: ret->attr = attr;
1452: table->nb_ids++;
1453:
1454: return(ret);
1455: }
1456:
1457: /**
1458: * xmlFreeID:
1459: * @not: A id
1460: *
1461: * Deallocate the memory used by an id definition
1462: */
1463: void
1464: xmlFreeID(xmlIDPtr id) {
1465: if (id == NULL) return;
1466: if (id->value != NULL)
1.31 daniel 1467: xmlFree((xmlChar *) id->value);
1.21 daniel 1468: memset(id, -1, sizeof(xmlID));
1.26 daniel 1469: xmlFree(id);
1.21 daniel 1470: }
1471:
1472: /**
1473: * xmlFreeIDTable:
1474: * @table: An id table
1475: *
1476: * Deallocate the memory used by an ID hash table.
1477: */
1478: void
1479: xmlFreeIDTable(xmlIDTablePtr table) {
1480: int i;
1481:
1482: if (table == NULL) return;
1483:
1484: for (i = 0;i < table->nb_ids;i++) {
1485: xmlFreeID(table->table[i]);
1486: }
1.26 daniel 1487: xmlFree(table->table);
1488: xmlFree(table);
1.21 daniel 1489: }
1490:
1491: /**
1492: * xmlIsID
1493: * @doc: the document
1494: * @elem: the element carrying the attribute
1495: * @attr: the attribute
1496: *
1497: * Determine whether an attribute is of type ID. In case we have Dtd(s)
1498: * then this is simple, otherwise we use an heuristic: name ID (upper
1499: * or lowercase).
1500: *
1501: * Returns 0 or 1 depending on the lookup result
1502: */
1503: int
1504: xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
1505: if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
1506: if (((attr->name[0] == 'I') || (attr->name[0] == 'i')) &&
1507: ((attr->name[1] == 'D') || (attr->name[1] == 'd')) &&
1508: (attr->name[2] == 0)) return(1);
1509: } else {
1510: xmlAttributePtr attrDecl;
1511:
1512: attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
1513: if ((attrDecl == NULL) && (doc->extSubset != NULL))
1514: attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
1515: attr->name);
1516:
1.22 daniel 1517: if ((attrDecl != NULL) && (attrDecl->type == XML_ATTRIBUTE_ID))
1.21 daniel 1518: return(1);
1519: }
1520: return(0);
1521: }
1522:
1.22 daniel 1523: /**
1524: * xmlGetID:
1525: * @doc: pointer to the document
1526: * @ID: the ID value
1527: *
1528: * Search the attribute declaring the given ID
1529: *
1530: * Returns NULL if not found, otherwise the xmlAttrPtr defining the ID
1531: */
1532: xmlAttrPtr
1.31 daniel 1533: xmlGetID(xmlDocPtr doc, const xmlChar *ID) {
1.22 daniel 1534: xmlIDPtr cur;
1535: xmlIDTablePtr table;
1536: int i;
1537:
1538: if (doc == NULL) {
1539: fprintf(stderr, "xmlGetID: doc == NULL\n");
1540: return(NULL);
1541: }
1542:
1543: if (ID == NULL) {
1544: fprintf(stderr, "xmlGetID: ID == NULL\n");
1545: return(NULL);
1546: }
1547:
1548: table = doc->ids;
1549: if (table == NULL)
1550: return(NULL);
1551:
1552: /*
1553: * Search the ID list.
1554: */
1555: for (i = 0;i < table->nb_ids;i++) {
1556: cur = table->table[i];
1557: if (!xmlStrcmp(cur->value, ID)) {
1558: return(cur->attr);
1559: }
1560: }
1561: return(NULL);
1562: }
1563:
1.21 daniel 1564: /************************************************************************
1565: * *
1.27 daniel 1566: * Refs *
1567: * *
1568: ************************************************************************/
1569: /**
1570: * xmlCreateRefTable:
1571: *
1572: * create and initialize an empty ref hash table.
1573: *
1574: * Returns the xmlRefTablePtr just created or NULL in case
1575: * of error.
1576: */
1577: xmlRefTablePtr
1578: xmlCreateRefTable(void) {
1579: xmlRefTablePtr ret;
1580:
1581: ret = (xmlRefTablePtr)
1582: xmlMalloc(sizeof(xmlRefTable));
1583: if (ret == NULL) {
1584: fprintf(stderr, "xmlCreateRefTable : xmlMalloc(%ld) failed\n",
1585: (long)sizeof(xmlRefTable));
1586: return(NULL);
1587: }
1588: ret->max_refs = XML_MIN_NOTATION_TABLE;
1589: ret->nb_refs = 0;
1590: ret->table = (xmlRefPtr *)
1591: xmlMalloc(ret->max_refs * sizeof(xmlRefPtr));
1592: if (ret == NULL) {
1593: fprintf(stderr, "xmlCreateRefTable : xmlMalloc(%ld) failed\n",
1594: ret->max_refs * (long)sizeof(xmlRef));
1595: xmlFree(ret);
1596: return(NULL);
1597: }
1598: return(ret);
1599: }
1600:
1601:
1602: /**
1603: * xmlAddRef:
1604: * @ctxt: the validation context
1605: * @doc: pointer to the document
1606: * @value: the value name
1607: * @attr: the attribute holding the Ref
1608: *
1609: * Register a new ref declaration
1610: *
1611: * Returns NULL if not, othervise the new xmlRefPtr
1612: */
1613: xmlRefPtr
1.31 daniel 1614: xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
1.27 daniel 1615: xmlAttrPtr attr) {
1.28 daniel 1616: xmlRefPtr ret;
1.27 daniel 1617: xmlRefTablePtr table;
1618:
1619: if (doc == NULL) {
1620: fprintf(stderr, "xmlAddRefDecl: doc == NULL\n");
1621: return(NULL);
1622: }
1623: if (value == NULL) {
1624: fprintf(stderr, "xmlAddRefDecl: value == NULL\n");
1625: return(NULL);
1626: }
1627: if (attr == NULL) {
1628: fprintf(stderr, "xmlAddRefDecl: attr == NULL\n");
1629: return(NULL);
1630: }
1631:
1632: /*
1633: * Create the Ref table if needed.
1634: */
1635: table = doc->refs;
1636: if (table == NULL)
1637: table = doc->refs = xmlCreateRefTable();
1638: if (table == NULL) {
1639: fprintf(stderr, "xmlAddRef: Table creation failed!\n");
1640: return(NULL);
1641: }
1642:
1643: /*
1644: * Grow the table, if needed.
1645: */
1646: if (table->nb_refs >= table->max_refs) {
1647: /*
1648: * need more refs.
1649: */
1650: table->max_refs *= 2;
1651: table->table = (xmlRefPtr *)
1652: xmlRealloc(table->table, table->max_refs *
1653: sizeof(xmlRefPtr));
1654: if (table->table == NULL) {
1655: fprintf(stderr, "xmlAddRef: out of memory\n");
1656: return(NULL);
1657: }
1658: }
1659: ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
1660: if (ret == NULL) {
1661: fprintf(stderr, "xmlAddRef: out of memory\n");
1662: return(NULL);
1663: }
1664: table->table[table->nb_refs] = ret;
1665:
1666: /*
1667: * fill the structure.
1668: */
1669: ret->value = xmlStrdup(value);
1670: ret->attr = attr;
1671: table->nb_refs++;
1672:
1673: return(ret);
1674: }
1675:
1676: /**
1677: * xmlFreeRef:
1678: * @not: A ref
1679: *
1680: * Deallocate the memory used by an ref definition
1681: */
1682: void
1683: xmlFreeRef(xmlRefPtr ref) {
1684: if (ref == NULL) return;
1685: if (ref->value != NULL)
1.31 daniel 1686: xmlFree((xmlChar *) ref->value);
1.27 daniel 1687: memset(ref, -1, sizeof(xmlRef));
1688: xmlFree(ref);
1689: }
1690:
1691: /**
1692: * xmlFreeRefTable:
1693: * @table: An ref table
1694: *
1695: * Deallocate the memory used by an Ref hash table.
1696: */
1697: void
1698: xmlFreeRefTable(xmlRefTablePtr table) {
1699: int i;
1700:
1701: if (table == NULL) return;
1702:
1703: for (i = 0;i < table->nb_refs;i++) {
1704: xmlFreeRef(table->table[i]);
1705: }
1706: xmlFree(table->table);
1707: xmlFree(table);
1708: }
1709:
1710: /**
1711: * xmlIsRef
1712: * @doc: the document
1713: * @elem: the element carrying the attribute
1714: * @attr: the attribute
1715: *
1716: * Determine whether an attribute is of type Ref. In case we have Dtd(s)
1717: * then this is simple, otherwise we use an heuristic: name Ref (upper
1718: * or lowercase).
1719: *
1720: * Returns 0 or 1 depending on the lookup result
1721: */
1722: int
1723: xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
1724: if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
1725: return(0);
1726: /*******************
1727: if (((attr->name[0] == 'I') || (attr->name[0] == 'i')) &&
1728: ((attr->name[1] == 'D') || (attr->name[1] == 'd')) &&
1729: (attr->name[2] == 0)) return(1);
1730: *******************/
1731: } else {
1732: xmlAttributePtr attrDecl;
1733:
1734: attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
1735: if ((attrDecl == NULL) && (doc->extSubset != NULL))
1736: attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
1737: attr->name);
1738:
1739: if ((attrDecl != NULL) && (attrDecl->type == XML_ATTRIBUTE_IDREF))
1740: return(1);
1741: }
1742: return(0);
1743: }
1744:
1745: /**
1746: * xmlGetRef:
1747: * @doc: pointer to the document
1748: * @Ref: the Ref value
1749: *
1750: * Search the attribute declaring the given Ref
1751: *
1752: * Returns NULL if not found, otherwise the xmlAttrPtr defining the Ref
1753: */
1754: xmlAttrPtr
1.31 daniel 1755: xmlGetRef(xmlDocPtr doc, const xmlChar *Ref) {
1.27 daniel 1756: xmlRefPtr cur;
1757: xmlRefTablePtr table;
1758: int i;
1759:
1760: if (doc == NULL) {
1761: fprintf(stderr, "xmlGetRef: doc == NULL\n");
1762: return(NULL);
1763: }
1764:
1765: if (Ref == NULL) {
1766: fprintf(stderr, "xmlGetRef: Ref == NULL\n");
1767: return(NULL);
1768: }
1769:
1770: table = doc->refs;
1771: if (table == NULL)
1772: return(NULL);
1773:
1774: /*
1775: * Search the Ref list.
1776: */
1777: for (i = 0;i < table->nb_refs;i++) {
1778: cur = table->table[i];
1779: if (!xmlStrcmp(cur->value, Ref)) {
1780: return(cur->attr);
1781: }
1782: }
1783: return(NULL);
1784: }
1785:
1786: /************************************************************************
1787: * *
1.14 daniel 1788: * Routines for validity checking *
1789: * *
1790: ************************************************************************/
1791:
1792: /**
1793: * xmlGetDtdElementDesc:
1794: * @dtd: a pointer to the DtD to search
1795: * @name: the element name
1796: *
1797: * Search the Dtd for the description of this element
1798: *
1799: * returns the xmlElementPtr if found or NULL
1800: */
1801:
1802: xmlElementPtr
1.31 daniel 1803: xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) {
1.14 daniel 1804: xmlElementTablePtr table;
1805: xmlElementPtr cur;
1806: int i;
1807:
1808: if (dtd == NULL) return(NULL);
1809: if (dtd->elements == NULL) return(NULL);
1810: table = dtd->elements;
1811:
1812: for (i = 0;i < table->nb_elements;i++) {
1.15 daniel 1813: cur = table->table[i];
1.14 daniel 1814: if (!xmlStrcmp(cur->name, name))
1815: return(cur);
1816: }
1817: return(NULL);
1818: }
1819:
1820: /**
1821: * xmlGetDtdAttrDesc:
1822: * @dtd: a pointer to the DtD to search
1.15 daniel 1823: * @elem: the element name
1.14 daniel 1824: * @name: the attribute name
1825: *
1.15 daniel 1826: * Search the Dtd for the description of this attribute on
1827: * this element.
1.14 daniel 1828: *
1829: * returns the xmlAttributePtr if found or NULL
1830: */
1831:
1832: xmlAttributePtr
1.31 daniel 1833: xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) {
1.14 daniel 1834: xmlAttributeTablePtr table;
1835: xmlAttributePtr cur;
1836: int i;
1837:
1838: if (dtd == NULL) return(NULL);
1839: if (dtd->attributes == NULL) return(NULL);
1840: table = dtd->attributes;
1841:
1842: for (i = 0;i < table->nb_attributes;i++) {
1.15 daniel 1843: cur = table->table[i];
1844: if ((!xmlStrcmp(cur->name, name)) &&
1845: (!xmlStrcmp(cur->elem, elem)))
1.14 daniel 1846: return(cur);
1847: }
1848: return(NULL);
1849: }
1850:
1851: /**
1852: * xmlGetDtdNotationDesc:
1853: * @dtd: a pointer to the DtD to search
1854: * @name: the notation name
1855: *
1856: * Search the Dtd for the description of this notation
1857: *
1858: * returns the xmlNotationPtr if found or NULL
1859: */
1860:
1861: xmlNotationPtr
1.31 daniel 1862: xmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) {
1.14 daniel 1863: xmlNotationTablePtr table;
1864: xmlNotationPtr cur;
1865: int i;
1866:
1867: if (dtd == NULL) return(NULL);
1868: if (dtd->notations == NULL) return(NULL);
1869: table = dtd->notations;
1870:
1871: for (i = 0;i < table->nb_notations;i++) {
1.15 daniel 1872: cur = table->table[i];
1.14 daniel 1873: if (!xmlStrcmp(cur->name, name))
1874: return(cur);
1875: }
1876: return(NULL);
1877: }
1878:
1879: /**
1.23 daniel 1880: * xmlValidateNotationUse:
1881: * @ctxt: the validation context
1882: * @doc: the document
1883: * @notationName: the notation name to check
1884: *
1885: * Validate that the given mame match a notation declaration.
1886: * - [ VC: Notation Declared ]
1887: *
1888: * returns 1 if valid or 0 otherwise
1889: */
1890:
1891: int
1892: xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
1.31 daniel 1893: const xmlChar *notationName) {
1.23 daniel 1894: xmlNotationPtr notaDecl;
1895: if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
1896:
1897: notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
1898: if ((notaDecl == NULL) && (doc->extSubset != NULL))
1899: notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
1900:
1901: if (notaDecl == NULL) {
1902: VERROR(ctxt->userData, "NOTATION %s is not declared\n",
1903: notationName);
1904: return(0);
1905: }
1906: return(1);
1907: }
1908:
1909: /**
1.18 daniel 1910: * xmlIsMixedElement
1911: * @doc: the document
1912: * @name: the element name
1913: *
1914: * Search in the DtDs whether an element accept Mixed content (or ANY)
1915: * basically if it is supposed to accept text childs
1916: *
1917: * returns 0 if no, 1 if yes, and -1 if no element description is available
1918: */
1919:
1920: int
1.31 daniel 1921: xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) {
1.18 daniel 1922: xmlElementPtr elemDecl;
1923:
1924: if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
1925:
1926: elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
1927: if ((elemDecl == NULL) && (doc->extSubset != NULL))
1928: elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
1929: if (elemDecl == NULL) return(-1);
1930: switch (elemDecl->type) {
1931: case XML_ELEMENT_TYPE_ELEMENT:
1932: return(0);
1933: case XML_ELEMENT_TYPE_EMPTY:
1934: /*
1935: * return 1 for EMPTY since we want VC error to pop up
1936: * on <empty> </empty> for example
1937: */
1938: case XML_ELEMENT_TYPE_ANY:
1939: case XML_ELEMENT_TYPE_MIXED:
1940: return(1);
1941: }
1942: return(1);
1943: }
1944:
1945: /**
1.16 daniel 1946: * xmlValidateNameValue:
1947: * @value: an Name value
1948: *
1949: * Validate that the given value match Name production
1950: *
1951: * returns 1 if valid or 0 otherwise
1952: */
1953:
1954: int
1.31 daniel 1955: xmlValidateNameValue(const xmlChar *value) {
1956: const xmlChar *cur;
1.16 daniel 1957:
1958: if (value == NULL) return(0);
1959: cur = value;
1960:
1961: if (!IS_LETTER(*cur) && (*cur != '_') &&
1962: (*cur != ':')) {
1963: return(0);
1964: }
1965:
1966: while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
1967: (*cur == '.') || (*cur == '-') ||
1968: (*cur == '_') || (*cur == ':') ||
1969: (IS_COMBINING(*cur)) ||
1970: (IS_EXTENDER(*cur)))
1971: cur++;
1972:
1973: if (*cur != 0) return(0);
1974:
1975: return(1);
1976: }
1977:
1978: /**
1979: * xmlValidateNamesValue:
1980: * @value: an Names value
1981: *
1982: * Validate that the given value match Names production
1983: *
1984: * returns 1 if valid or 0 otherwise
1985: */
1986:
1987: int
1.31 daniel 1988: xmlValidateNamesValue(const xmlChar *value) {
1989: const xmlChar *cur;
1.16 daniel 1990:
1991: if (value == NULL) return(0);
1992: cur = value;
1993:
1994: if (!IS_LETTER(*cur) && (*cur != '_') &&
1995: (*cur != ':')) {
1996: return(0);
1997: }
1998:
1999: while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2000: (*cur == '.') || (*cur == '-') ||
2001: (*cur == '_') || (*cur == ':') ||
2002: (IS_COMBINING(*cur)) ||
2003: (IS_EXTENDER(*cur)))
2004: cur++;
2005:
2006: while (IS_BLANK(*cur)) {
2007: while (IS_BLANK(*cur)) cur++;
2008:
2009: if (!IS_LETTER(*cur) && (*cur != '_') &&
2010: (*cur != ':')) {
2011: return(0);
2012: }
2013:
2014: while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2015: (*cur == '.') || (*cur == '-') ||
2016: (*cur == '_') || (*cur == ':') ||
2017: (IS_COMBINING(*cur)) ||
2018: (IS_EXTENDER(*cur)))
2019: cur++;
2020: }
2021:
2022: if (*cur != 0) return(0);
2023:
2024: return(1);
2025: }
2026:
2027: /**
2028: * xmlValidateNmtokenValue:
2029: * @value: an Mntoken value
2030: *
2031: * Validate that the given value match Nmtoken production
2032: *
2033: * [ VC: Name Token ]
2034: *
2035: * returns 1 if valid or 0 otherwise
2036: */
2037:
2038: int
1.31 daniel 2039: xmlValidateNmtokenValue(const xmlChar *value) {
2040: const xmlChar *cur;
1.16 daniel 2041:
2042: if (value == NULL) return(0);
2043: cur = value;
2044:
2045: if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
2046: (*cur != '.') && (*cur != '-') &&
2047: (*cur != '_') && (*cur != ':') &&
2048: (!IS_COMBINING(*cur)) &&
2049: (!IS_EXTENDER(*cur)))
2050: return(0);
2051:
2052: while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2053: (*cur == '.') || (*cur == '-') ||
2054: (*cur == '_') || (*cur == ':') ||
2055: (IS_COMBINING(*cur)) ||
2056: (IS_EXTENDER(*cur)))
2057: cur++;
2058:
2059: if (*cur != 0) return(0);
2060:
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
1.31 daniel 2076: xmlValidateNmtokensValue(const xmlChar *value) {
2077: const xmlChar *cur;
1.16 daniel 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
1.31 daniel 2168: xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) {
1.16 daniel 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;
1.31 daniel 2285: const xmlChar *name;
1.16 daniel 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
1.32 daniel 2346: * @value: the attribute value (without entities processing)
1.14 daniel 2347: *
2348: * Try to validate a single attribute for an element
2349: * basically it * does the following checks as described by the
2350: * XML-1.0 recommendation:
1.18 daniel 2351: * - [ VC: Attribute Value Type ]
2352: * - [ VC: Fixed Attribute Default ]
1.14 daniel 2353: * - [ VC: Entity Name ]
2354: * - [ VC: Name Token ]
2355: * - [ VC: ID ]
2356: * - [ VC: IDREF ]
2357: * - [ VC: Entity Name ]
1.16 daniel 2358: * - [ VC: Notation Attributes ]
1.14 daniel 2359: *
2360: * The ID/IDREF uniqueness and matching are done separately
2361: *
2362: * returns 1 if valid or 0 otherwise
2363: */
2364:
2365: int
1.16 daniel 2366: xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
1.31 daniel 2367: xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value) {
1.24 daniel 2368: /* xmlElementPtr elemDecl; */
1.18 daniel 2369: xmlAttributePtr attrDecl;
2370: int val;
2371: int ret = 1;
2372:
1.14 daniel 2373: CHECK_DTD;
1.18 daniel 2374: if ((elem == NULL) || (elem->name == NULL)) return(0);
2375: if ((attr == NULL) || (attr->name == NULL)) return(0);
2376:
2377: attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
2378: if ((attrDecl == NULL) && (doc->extSubset != NULL))
2379: attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, attr->name);
2380:
1.14 daniel 2381:
1.18 daniel 2382: /* Validity Constraint: Attribute Value Type */
2383: if (attrDecl == NULL) {
2384: VERROR(ctxt->userData,
2385: "No declaration for attribute %s on element %s\n",
2386: attr->name, elem->name);
2387: return(0);
2388: }
2389: val = xmlValidateAttributeValue(attrDecl->type, value);
2390: if (val == 0) {
2391: VERROR(ctxt->userData,
2392: "Syntax of value for attribute %s on %s is not valid\n",
2393: attr->name, elem->name);
2394: ret = 0;
1.22 daniel 2395: }
2396:
2397: /* Validity Constraint: ID uniqueness */
2398: if (attrDecl->type == XML_ATTRIBUTE_ID) {
2399: xmlAddID(ctxt, doc, value, attr);
1.18 daniel 2400: }
2401:
1.28 daniel 2402: if (attrDecl->type == XML_ATTRIBUTE_IDREF) {
2403: xmlAddRef(ctxt, doc, value, attr);
2404: }
2405:
1.18 daniel 2406: /* Validity Constraint: Notation Attributes */
2407: if (attrDecl->type == XML_ATTRIBUTE_NOTATION) {
2408: xmlEnumerationPtr tree = attrDecl->tree;
2409: xmlNotationPtr nota;
2410:
2411: /* First check that the given NOTATION was declared */
2412: nota = xmlGetDtdNotationDesc(doc->intSubset, value);
2413: if (nota == NULL)
2414: nota = xmlGetDtdNotationDesc(doc->extSubset, value);
2415:
2416: if (nota == NULL) {
2417: VERROR(ctxt->userData,
2418: "Value \"%s\" for attribute %s on %s is not a declared Notation\n",
2419: value, attr->name, elem->name);
2420: ret = 0;
2421: }
2422:
2423: /* Second, verify that it's among the list */
2424: while (tree != NULL) {
2425: if (!xmlStrcmp(tree->name, value)) break;
2426: tree = tree->next;
2427: }
2428: if (tree == NULL) {
2429: VERROR(ctxt->userData,
2430: "Value \"%s\" for attribute %s on %s is among the enumerated notations\n",
2431: value, attr->name, elem->name);
2432: ret = 0;
2433: }
2434: }
2435:
2436: /* Validity Constraint: Enumeration */
2437: if (attrDecl->type == XML_ATTRIBUTE_ENUMERATION) {
2438: xmlEnumerationPtr tree = attrDecl->tree;
2439: while (tree != NULL) {
2440: if (!xmlStrcmp(tree->name, value)) break;
2441: tree = tree->next;
2442: }
2443: if (tree == NULL) {
2444: VERROR(ctxt->userData,
2445: "Value \"%s\" for attribute %s on %s is among the enumerated set\n",
2446: value, attr->name, elem->name);
2447: ret = 0;
2448: }
2449: }
2450:
2451: /* Fixed Attribute Default */
2452: if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
2453: (xmlStrcmp(attrDecl->defaultValue, value))) {
2454: VERROR(ctxt->userData,
2455: "Value for attribute %s on %s must be \"%s\"\n",
2456: attr->name, elem->name, attrDecl->defaultValue);
2457: ret = 0;
2458: }
2459:
1.24 daniel 2460: /********
1.18 daniel 2461: elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
2462: if ((elemDecl == NULL) && (doc->extSubset != NULL))
2463: elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
2464: if (elemDecl == NULL) {
2465: return(0);
2466: }
1.24 daniel 2467: ********/
1.18 daniel 2468: return(ret);
2469: }
2470:
2471: int xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
2472: xmlElementContentPtr cont);
2473:
2474: /**
2475: * xmlValidateElementTypeExpr:
2476: * @ctxt: the validation context
2477: * @child: pointer to the child list
2478: * @cont: pointer to the content declaration
2479: *
2480: * Try to validate the content of an element of type element
2481: * but don't handle the occurence factor
2482: *
2483: * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
2484: * also update child value in-situ.
2485: */
2486:
2487: int
2488: xmlValidateElementTypeExpr(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
2489: xmlElementContentPtr cont) {
2490: xmlNodePtr cur;
2491: int ret = 1;
2492:
2493: if (cont == NULL) return(-1);
2494: while (*child != NULL) {
2495: if ((*child)->type == XML_PI_NODE) {
2496: *child = (*child)->next;
2497: continue;
2498: }
2499: if ((*child)->type == XML_COMMENT_NODE) {
2500: *child = (*child)->next;
2501: continue;
2502: }
2503: else if ((*child)->type != XML_ELEMENT_NODE) {
2504: return(-1);
2505: }
2506: break;
2507: }
2508: switch (cont->type) {
2509: case XML_ELEMENT_CONTENT_PCDATA:
2510: /* Internal error !!! */
2511: fprintf(stderr, "Internal: MIXED struct bad\n");
2512: return(-1);
2513: case XML_ELEMENT_CONTENT_ELEMENT:
1.20 daniel 2514: if (*child == NULL) return(0);
1.18 daniel 2515: ret = (!xmlStrcmp((*child)->name, cont->name));
2516: if (ret == 1)
2517: *child = (*child)->next;
2518: return(ret);
2519: case XML_ELEMENT_CONTENT_OR:
2520: cur = *child;
2521: ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
2522: if (ret == -1) return(-1);
2523: if (ret == 1) {
2524: return(1);
2525: }
2526: /* rollback and retry the other path */
2527: *child = cur;
2528: ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
2529: if (ret == -1) return(-1);
2530: if (ret == 0) {
2531: *child = cur;
2532: return(0);
2533: }
2534: return(1);
2535: case XML_ELEMENT_CONTENT_SEQ:
2536: cur = *child;
2537: ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
2538: if (ret == -1) return(-1);
2539: if (ret == 0) {
2540: *child = cur;
2541: return(0);
2542: }
2543: ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
2544: if (ret == -1) return(-1);
2545: if (ret == 0) {
2546: *child = cur;
2547: return(0);
2548: }
2549: return(1);
2550: }
2551: return(ret);
2552: }
2553:
2554: /**
2555: * xmlValidateElementTypeElement:
2556: * @ctxt: the validation context
2557: * @child: pointer to the child list
2558: * @cont: pointer to the content declaration
2559: *
2560: * Try to validate the content of an element of type element
2561: * yeah, Yet Another Regexp Implementation, and recursive
2562: *
2563: * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
2564: * also update child and content values in-situ.
2565: */
2566:
2567: int
2568: xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
2569: xmlElementContentPtr cont) {
2570: xmlNodePtr cur;
2571: int ret = 1;
2572:
2573: if (cont == NULL) return(-1);
2574: while (*child != NULL) {
2575: if ((*child)->type == XML_PI_NODE) {
2576: *child = (*child)->next;
2577: continue;
2578: }
2579: if ((*child)->type == XML_COMMENT_NODE) {
2580: *child = (*child)->next;
2581: continue;
2582: }
2583: else if ((*child)->type != XML_ELEMENT_NODE) {
2584: return(-1);
2585: }
2586: break;
2587: }
2588: cur = *child;
2589: ret = xmlValidateElementTypeExpr(ctxt, child, cont);
2590: if (ret == -1) return(-1);
2591: switch (cont->ocur) {
2592: case XML_ELEMENT_CONTENT_ONCE:
2593: if (ret == 1) {
2594: return(1);
2595: }
2596: *child = cur;
2597: return(0);
2598: case XML_ELEMENT_CONTENT_OPT:
2599: if (ret == 0) {
2600: *child = cur;
2601: return(1);
2602: }
1.19 daniel 2603: break;
1.18 daniel 2604: case XML_ELEMENT_CONTENT_MULT:
2605: if (ret == 0) {
2606: *child = cur;
1.19 daniel 2607: break;
1.18 daniel 2608: }
2609: /* no break on purpose */
2610: case XML_ELEMENT_CONTENT_PLUS:
2611: if (ret == 0) {
2612: *child = cur;
2613: return(0);
2614: }
2615: do {
2616: cur = *child;
2617: ret = xmlValidateElementTypeExpr(ctxt, child, cont);
2618: } while (ret == 1);
2619: if (ret == -1) return(-1);
2620: *child = cur;
1.19 daniel 2621: break;
2622: }
2623: while (*child != NULL) {
2624: if ((*child)->type == XML_PI_NODE) {
2625: *child = (*child)->next;
2626: continue;
2627: }
2628: if ((*child)->type == XML_COMMENT_NODE) {
2629: *child = (*child)->next;
2630: continue;
2631: }
2632: else if ((*child)->type != XML_ELEMENT_NODE) {
2633: return(-1);
2634: }
2635: break;
2636: }
2637: return(1);
2638: }
2639:
2640: /**
2641: * xmlSprintfElementChilds:
2642: * @buf: an output buffer
2643: * @content: An element
2644: * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
2645: *
2646: * This will dump the list of childs to the buffer
2647: * Intended just for the debug routine
2648: */
2649: void
2650: xmlSprintfElementChilds(char *buf, xmlNodePtr node, int glob) {
2651: xmlNodePtr cur;
2652:
2653: if (node == NULL) return;
2654: if (glob) strcat(buf, "(");
2655: cur = node->childs;
2656: while (cur != NULL) {
2657: switch (cur->type) {
2658: case XML_ELEMENT_NODE:
1.23 daniel 2659: strcat(buf, (char *) cur->name);
1.19 daniel 2660: if (cur->next != NULL)
2661: strcat(buf, " ");
2662: break;
2663: case XML_TEXT_NODE:
2664: case XML_CDATA_SECTION_NODE:
2665: case XML_ENTITY_REF_NODE:
2666: strcat(buf, "CDATA");
2667: if (cur->next != NULL)
2668: strcat(buf, " ");
2669: break;
2670: case XML_ATTRIBUTE_NODE:
2671: case XML_DOCUMENT_NODE:
1.35 daniel 2672: case XML_HTML_DOCUMENT_NODE:
1.19 daniel 2673: case XML_DOCUMENT_TYPE_NODE:
2674: case XML_DOCUMENT_FRAG_NODE:
2675: case XML_NOTATION_NODE:
2676: strcat(buf, "???");
2677: if (cur->next != NULL)
2678: strcat(buf, " ");
2679: break;
2680: case XML_ENTITY_NODE:
2681: case XML_PI_NODE:
2682: case XML_COMMENT_NODE:
2683: break;
2684: }
2685: cur = cur->next;
1.18 daniel 2686: }
1.19 daniel 2687: if (glob) strcat(buf, ")");
1.14 daniel 2688: }
2689:
1.19 daniel 2690:
1.14 daniel 2691: /**
2692: * xmlValidateOneElement:
2693: * @ctxt: the validation context
2694: * @doc: a document instance
2695: * @elem: an element instance
2696: *
2697: * Try to validate a single element and it's attributes,
2698: * basically it does the following checks as described by the
2699: * XML-1.0 recommendation:
2700: * - [ VC: Element Valid ]
2701: * - [ VC: Required Attribute ]
2702: * Then call xmlValidateOneAttribute() for each attribute present.
2703: *
2704: * The ID/IDREF checkings are done separately
2705: *
2706: * returns 1 if valid or 0 otherwise
2707: */
2708:
2709: int
1.16 daniel 2710: xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
1.18 daniel 2711: xmlNodePtr elem) {
2712: xmlElementPtr elemDecl;
2713: xmlElementContentPtr cont;
2714: xmlNodePtr child;
2715: int ret = 1;
1.31 daniel 2716: const xmlChar *name;
1.18 daniel 2717:
1.14 daniel 2718: CHECK_DTD;
2719:
1.18 daniel 2720: if ((elem == NULL) || (elem->name == NULL)) return(0);
2721:
2722: elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
2723: if ((elemDecl == NULL) && (doc->extSubset != NULL))
2724: elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
2725: if (elemDecl == NULL) {
2726: VERROR(ctxt->userData, "No declaration for element %s\n",
2727: elem->name);
2728: return(0);
2729: }
2730:
2731: /* Check taht the element content matches the definition */
2732: switch (elemDecl->type) {
2733: case XML_ELEMENT_TYPE_EMPTY:
2734: if (elem->childs != NULL) {
2735: VERROR(ctxt->userData,
2736: "Element %s was declared EMPTY this one has content\n",
2737: elem->name);
2738: ret = 0;
2739: }
2740: break;
2741: case XML_ELEMENT_TYPE_ANY:
2742: /* I don't think anything is required then */
2743: break;
2744: case XML_ELEMENT_TYPE_MIXED:
2745: /* Hum, this start to get messy */
2746: child = elem->childs;
2747: while (child != NULL) {
2748: if (child->type == XML_ELEMENT_NODE) {
2749: name = child->name;
2750: cont = elemDecl->content;
2751: while (cont != NULL) {
2752: if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
2753: if (!xmlStrcmp(cont->name, name)) break;
2754: } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
2755: (cont->c1 != NULL) &&
2756: (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
2757: if (!xmlStrcmp(cont->c1->name, name)) break;
2758: } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
2759: (cont->c1 == NULL) ||
2760: (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
2761: /* Internal error !!! */
2762: fprintf(stderr, "Internal: MIXED struct bad\n");
2763: break;
2764: }
2765: cont = cont->c2;
2766: }
2767: if (cont == NULL) {
2768: VERROR(ctxt->userData,
2769: "Element %s is not declared in %s list of possible childs\n",
2770: name, elem->name);
2771: ret = 0;
2772: }
2773: }
2774: child = child->next;
2775: }
2776: break;
2777: case XML_ELEMENT_TYPE_ELEMENT:
2778: child = elem->childs;
2779: cont = elemDecl->content;
2780: ret = xmlValidateElementTypeElement(ctxt, &child, cont);
1.19 daniel 2781: if ((ret == 0) || (child != NULL)) {
2782: char expr[1000];
2783: char list[2000];
2784:
2785: expr[0] = 0;
2786: xmlSprintfElementContent(expr, cont, 1);
2787: list[0] = 0;
2788: xmlSprintfElementChilds(list, elem, 1);
2789:
1.18 daniel 2790: VERROR(ctxt->userData,
1.19 daniel 2791: "Element %s content doesn't follow the Dtd\nExpecting %s, got %s\n",
2792: elem->name, expr, list);
1.18 daniel 2793: ret = 0;
2794: }
2795: break;
2796: }
2797:
1.24 daniel 2798: /* TODO - [ VC: Required Attribute ] */
1.18 daniel 2799: return(ret);
1.14 daniel 2800: }
2801:
2802: /**
2803: * xmlValidateRoot:
2804: * @ctxt: the validation context
2805: * @doc: a document instance
2806: *
2807: * Try to validate a the root element
2808: * basically it does the following check as described by the
2809: * XML-1.0 recommendation:
2810: * - [ VC: Root Element Type ]
2811: * it doesn't try to recurse or apply other check to the element
2812: *
2813: * returns 1 if valid or 0 otherwise
2814: */
2815:
2816: int
2817: xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
2818: if (doc == NULL) return(0);
2819:
2820: if ((doc->intSubset == NULL) ||
2821: (doc->intSubset->name == NULL)) {
2822: VERROR(ctxt->userData, "Not valid: no DtD found\n");
2823: return(0);
2824: }
2825: if ((doc->root == NULL) || (doc->root->name == NULL)) {
2826: VERROR(ctxt->userData, "Not valid: no root element\n");
2827: return(0);
2828: }
2829: if (xmlStrcmp(doc->intSubset->name, doc->root->name)) {
2830: VERROR(ctxt->userData,
2831: "Not valid: root and DtD name do not match %s and %s\n",
2832: doc->root->name, doc->intSubset->name);
2833: return(0);
2834: }
2835: return(1);
2836: }
2837:
2838:
2839: /**
2840: * xmlValidateElement:
2841: * @ctxt: the validation context
2842: * @doc: a document instance
2843: * @elem: an element instance
2844: *
2845: * Try to validate the subtree under an element
2846: *
2847: * returns 1 if valid or 0 otherwise
2848: */
2849:
2850: int
1.18 daniel 2851: xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
1.27 daniel 2852: xmlNodePtr child;
2853: xmlAttrPtr attr;
1.31 daniel 2854: xmlChar *value;
1.27 daniel 2855: int ret = 1;
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:
1.33 daniel 2965:
2966: /************************************************************************
2967: * *
2968: * Routines for dynamic validation editing *
2969: * *
2970: ************************************************************************/
2971:
2972: /**
1.34 daniel 2973: * xmlValidGetPotentialChildren:
2974: * @ctree: an element content tree
2975: * @list: an array to store the list of child names
2976: * @len: a pointer to the number of element in the list
2977: * @max: the size of the array
1.33 daniel 2978: *
1.34 daniel 2979: * Build/extend a list of potential children allowed by the content tree
1.33 daniel 2980: *
1.34 daniel 2981: * returns the number of element in the list, or -1 in case of error.
1.33 daniel 2982: */
2983:
1.34 daniel 2984: int
2985: xmlValidGetPotentialChildren(xmlElementContent *ctree, const xmlChar **list,
2986: int *len, int max) {
2987: int i;
2988:
2989: if ((ctree == NULL) || (list == NULL) || (len == NULL))
2990: return(-1);
2991: if (*len >= max) return(*len);
2992:
2993: switch (ctree->type) {
2994: case XML_ELEMENT_CONTENT_PCDATA:
2995: for (i = 0; i < *len;i++)
2996: if (!xmlStrcmp("#PCDATA", list[i])) return(*len);
2997: list[(*len)++] = "#PCDATA";
2998: break;
2999: case XML_ELEMENT_CONTENT_ELEMENT:
3000: for (i = 0; i < *len;i++)
3001: if (!xmlStrcmp(ctree->name, list[i])) return(*len);
3002: list[(*len)++] = ctree->name;
3003: break;
3004: case XML_ELEMENT_CONTENT_SEQ:
3005: xmlValidGetPotentialChildren(ctree->c1, list, len, max);
3006: xmlValidGetPotentialChildren(ctree->c2, list, len, max);
3007: break;
3008: case XML_ELEMENT_CONTENT_OR:
3009: xmlValidGetPotentialChildren(ctree->c1, list, len, max);
3010: xmlValidGetPotentialChildren(ctree->c2, list, len, max);
3011: break;
3012: }
3013:
3014: return(*len);
1.33 daniel 3015: }
3016:
3017: /**
1.34 daniel 3018: * xmlValidGetValidElements:
3019: * @prev: an element to insert after
3020: * @next: an element to insert next
3021: * @list: an array to store the list of child names
3022: * @max: the size of the array
1.33 daniel 3023: *
1.34 daniel 3024: * This function returns the list of authorized children to insert
3025: * within an existing tree while respecting the validity constraints
3026: * forced by the Dtd. The insertion point is defined using @prev and
3027: * @next in the following ways:
3028: * to insert before 'node': xmlValidGetValidElements(node->prev, node, ...
3029: * to insert next 'node': xmlValidGetValidElements(node, node->next, ...
3030: * to replace 'node': xmlValidGetValidElements(node->prev, node->next, ...
3031: * to prepend a child to 'node': xmlValidGetValidElements(NULL, node->childs,
3032: * to append a child to 'node': xmlValidGetValidElements(node->last, NULL, ...
1.33 daniel 3033: *
1.34 daniel 3034: * pointers to the element names are inserted at the beginning of the array
3035: * and do not need to be freed.
3036: *
3037: * returns the number of element in the list, or -1 in case of error. If
3038: * the function returns the value @max the caller is invited to grow the
3039: * receiving array and retry.
1.33 daniel 3040: */
3041:
1.34 daniel 3042: int
3043: xmlValidGetValidElements(xmlNode *prev, xmlNode *next, const xmlChar **list,
3044: int max) {
3045: int nb_valid_elements = 0;
3046: const xmlChar *elements[256];
3047: int nb_elements = 0, i;
3048:
3049: xmlNode *ref_node;
3050: xmlNode *parent;
3051: xmlNode *test_node;
3052:
3053: xmlNode *prev_next;
3054: xmlNode *next_prev;
3055: xmlNode *parent_childs;
3056: xmlNode *parent_last;
3057:
3058: xmlElement *element_desc;
3059:
3060: if (prev == NULL && next == NULL)
3061: return(-1);
3062:
3063: if (list == NULL) return(-1);
3064: if (max <= 0) return(-1);
3065:
3066: nb_valid_elements = 0;
3067: ref_node = prev ? prev : next;
3068: parent = ref_node->parent;
3069:
3070: /*
3071: * Retrieves the parent element declaration
3072: */
3073: element_desc = xmlGetDtdElementDesc(parent->doc->intSubset,
3074: parent->name);
3075: if ((element_desc == NULL) && (parent->doc->extSubset != NULL))
3076: element_desc = xmlGetDtdElementDesc(parent->doc->extSubset,
3077: parent->name);
3078: if (element_desc == NULL) return(-1);
3079:
3080: /*
3081: * Do a backup of the current tree structure
3082: */
3083: prev_next = prev ? prev->next : NULL;
3084: next_prev = next ? next->prev : NULL;
3085: parent_childs = parent->childs;
3086: parent_last = parent->last;
3087:
3088: /*
3089: * Creates a dummy node and insert it into the tree
3090: */
3091: test_node = xmlNewNode (NULL, "<!dummy?>");
3092: test_node->doc = ref_node->doc;
3093: test_node->parent = parent;
3094: test_node->prev = prev;
3095: test_node->next = next;
3096:
3097: if (prev) prev->next = test_node;
3098: else parent->childs = test_node;
3099:
3100: if (next) next->prev = test_node;
3101: else parent->last = test_node;
3102:
3103: /*
3104: * Insert each potential child node and check if the parent is
3105: * still valid
3106: */
3107: nb_elements = xmlValidGetPotentialChildren(element_desc->content,
3108: elements, &nb_elements, 256);
3109:
3110: for (i = 0;i < nb_elements;i++) {
3111: test_node->name = elements[i];
3112: if (xmlValidateOneElement(NULL, parent->doc, parent)) {
3113: int j;
3114:
3115: for (j = 0; j < nb_valid_elements;j++)
3116: if (!xmlStrcmp(elements[i], list[j])) break;
3117: list[nb_valid_elements++] = elements[i];
3118: if (nb_valid_elements >= max) break;
3119: }
1.33 daniel 3120: }
3121:
1.34 daniel 3122: /*
3123: * Restore the tree structure
3124: */
3125: if (prev) prev->next = prev_next;
3126: if (next) next->prev = next_prev;
3127: parent->childs = parent_childs;
3128: parent->last = parent_last;
3129:
3130: return(nb_valid_elements);
1.33 daniel 3131: }
Webmaster