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