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