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