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