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