Annotation of XML/valid.c, revision 1.60
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.60 ! daniel 2566: * xmlValidNormalizeAttributeValue:
! 2567: * @doc: the document
! 2568: * @elem: the parent
! 2569: * @name: the attribute name
! 2570: * @value: the attribute value
! 2571: *
! 2572: * Does the validation related extra step of the normalization of attribute
! 2573: * values:
! 2574: *
! 2575: * If the declared value is not CDATA, then the XML processor must further
! 2576: * process the normalized attribute value by discarding any leading and
! 2577: * trailing space (#x20) characters, and by replacing sequences of space
! 2578: * (#x20) characters by single space (#x20) character.
! 2579: *
! 2580: * returns a new normalized string if normalization is needed, NULL otherwise
! 2581: * the caller must free the returned value.
! 2582: */
! 2583:
! 2584: xmlChar *
! 2585: xmlValidNormalizeAttributeValue(xmlDocPtr doc, xmlNodePtr elem,
! 2586: const xmlChar *name, const xmlChar *value) {
! 2587: xmlChar *ret, *dst;
! 2588: const xmlChar *src;
! 2589: xmlAttributePtr attrDecl;
! 2590:
! 2591: if (doc == NULL) return(NULL);
! 2592: if (elem == NULL) return(NULL);
! 2593: if (name == NULL) return(NULL);
! 2594: if (value == NULL) return(NULL);
! 2595:
! 2596: attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
! 2597: if ((attrDecl == NULL) && (doc->extSubset != NULL))
! 2598: attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
! 2599:
! 2600: if (attrDecl == NULL)
! 2601: return(NULL);
! 2602: if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
! 2603: return(NULL);
! 2604:
! 2605: ret = xmlStrdup(value);
! 2606: if (ret == NULL)
! 2607: return(NULL);
! 2608: src = value;
! 2609: dst = ret;
! 2610: while (*src == 0x20) src++;
! 2611: while (*src != 0) {
! 2612: if (*src == 0x20) {
! 2613: while (*src == 0x20) src++;
! 2614: if (*src != 0)
! 2615: *dst++ = 0x20;
! 2616: } else {
! 2617: *dst++ = *src++;
! 2618: }
! 2619: }
! 2620: *dst = 0;
! 2621: return(ret);
! 2622: }
! 2623:
! 2624: /**
1.14 daniel 2625: * xmlValidateAttributeDecl:
1.23 daniel 2626: * @ctxt: the validation context
1.14 daniel 2627: * @doc: a document instance
2628: * @attr: an attribute definition
2629: *
2630: * Try to validate a single attribute definition
2631: * basically it does the following checks as described by the
2632: * XML-1.0 recommendation:
2633: * - [ VC: Attribute Default Legal ]
2634: * - [ VC: Enumeration ]
2635: * - [ VC: ID Attribute Default ]
2636: *
2637: * The ID/IDREF uniqueness and matching are done separately
2638: *
2639: * returns 1 if valid or 0 otherwise
2640: */
2641:
2642: int
2643: xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2644: xmlAttributePtr attr) {
1.16 daniel 2645: int ret = 1;
2646: int val;
1.14 daniel 2647: CHECK_DTD;
1.16 daniel 2648: if(attr == NULL) return(1);
2649:
2650: /* Attribute Default Legal */
2651: /* Enumeration */
2652: if (attr->defaultValue != NULL) {
1.48 daniel 2653: val = xmlValidateAttributeValue(attr->atype, attr->defaultValue);
1.16 daniel 2654: if (val == 0) {
2655: VERROR(ctxt->userData,
2656: "Syntax of default value for attribute %s on %s is not valid\n",
2657: attr->name, attr->elem);
2658: }
2659: ret &= val;
2660: }
2661:
2662: /* ID Attribute Default */
1.48 daniel 2663: if ((attr->atype == XML_ATTRIBUTE_ID)&&
1.16 daniel 2664: (attr->def != XML_ATTRIBUTE_IMPLIED) &&
2665: (attr->def != XML_ATTRIBUTE_REQUIRED)) {
2666: VERROR(ctxt->userData,
2667: "ID attribute %s on %s is not valid must be #IMPLIED or #REQUIRED\n",
2668: attr->name, attr->elem);
2669: ret = 0;
2670: }
2671:
1.24 daniel 2672: /* One ID per Element Type */
1.54 daniel 2673: if (attr->atype == XML_ATTRIBUTE_ID) {
2674: int nbId;
1.16 daniel 2675:
2676: /* the trick is taht we parse DtD as their own internal subset */
1.54 daniel 2677: xmlElementPtr elem = xmlGetDtdElementDesc(doc->intSubset,
1.16 daniel 2678: attr->elem);
2679: if (elem != NULL) {
2680: nbId = xmlScanIDAttributeDecl(NULL, elem);
1.54 daniel 2681: } else {
2682: xmlAttributeTablePtr table;
2683: int i;
2684:
2685: /*
2686: * The attribute may be declared in the internal subset and the
2687: * element in the external subset.
2688: */
2689: nbId = 0;
2690: table = doc->intSubset->attributes;
2691: if (table != NULL) {
2692: for (i = 0;i < table->nb_attributes;i++) {
2693: if ((table->table[i]->atype == XML_ATTRIBUTE_ID) &&
2694: (!xmlStrcmp(table->table[i]->elem, attr->elem))) {
2695: nbId++;
2696: }
2697: }
2698: }
1.16 daniel 2699: }
1.54 daniel 2700: if (nbId > 1) {
1.16 daniel 2701: VERROR(ctxt->userData,
1.54 daniel 2702: "Element %s has %d ID attribute defined in the internal subset : %s\n",
2703: attr->elem, nbId, attr->name);
2704: } else if (doc->extSubset != NULL) {
1.57 daniel 2705: int extId = 0;
1.54 daniel 2706: elem = xmlGetDtdElementDesc(doc->extSubset, attr->elem);
2707: if (elem != NULL) {
2708: extId = xmlScanIDAttributeDecl(NULL, elem);
2709: }
2710: if (extId > 1) {
2711: VERROR(ctxt->userData,
2712: "Element %s has %d ID attribute defined in the external subset : %s\n",
2713: attr->elem, extId, attr->name);
2714: } else if (extId + nbId > 1) {
2715: VERROR(ctxt->userData,
2716: "Element %s has ID attributes defined in the internal and external subset : %s\n",
2717: attr->elem, attr->name);
2718: }
2719: }
1.16 daniel 2720: }
1.14 daniel 2721:
1.59 daniel 2722: /* Validity Constraint: Enumeration */
2723: if ((attr->defaultValue != NULL) && (attr->tree != NULL)) {
2724: xmlEnumerationPtr tree = attr->tree;
2725: while (tree != NULL) {
2726: if (!xmlStrcmp(tree->name, attr->defaultValue)) break;
2727: tree = tree->next;
2728: }
2729: if (tree == NULL) {
2730: VERROR(ctxt->userData,
2731: "Default value \"%s\" for attribute %s on %s is not among the enumerated set\n",
2732: attr->defaultValue, attr->name, attr->elem);
2733: ret = 0;
2734: }
2735: }
2736:
1.16 daniel 2737: return(ret);
1.14 daniel 2738: }
2739:
2740: /**
2741: * xmlValidateElementDecl:
2742: * @ctxt: the validation context
2743: * @doc: a document instance
2744: * @elem: an element definition
2745: *
2746: * Try to validate a single element definition
2747: * basically it does the following checks as described by the
2748: * XML-1.0 recommendation:
2749: * - [ VC: One ID per Element Type ]
2750: * - [ VC: No Duplicate Types ]
2751: * - [ VC: Unique Element Type Declaration ]
2752: *
2753: * returns 1 if valid or 0 otherwise
2754: */
2755:
2756: int
1.16 daniel 2757: xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2758: xmlElementPtr elem) {
2759: int ret = 1;
2760: xmlElementPtr tst;
2761:
1.14 daniel 2762: CHECK_DTD;
1.16 daniel 2763:
2764: if (elem == NULL) return(1);
1.14 daniel 2765:
1.16 daniel 2766: /* No Duplicate Types */
1.49 daniel 2767: if (elem->etype == XML_ELEMENT_TYPE_MIXED) {
1.16 daniel 2768: xmlElementContentPtr cur, next;
1.31 daniel 2769: const xmlChar *name;
1.16 daniel 2770:
2771: cur = elem->content;
2772: while (cur != NULL) {
2773: if (cur->type != XML_ELEMENT_CONTENT_OR) break;
2774: if (cur->c1 == NULL) break;
2775: if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
2776: name = cur->c1->name;
2777: next = cur->c2;
2778: while (next != NULL) {
2779: if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
2780: if (!xmlStrcmp(next->name, name)) {
2781: VERROR(ctxt->userData,
2782: "Definition of %s has duplicate references of %s\n",
2783: elem->name, name);
2784: ret = 0;
2785: }
2786: break;
2787: }
2788: if (next->c1 == NULL) break;
2789: if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
2790: if (!xmlStrcmp(next->c1->name, name)) {
2791: VERROR(ctxt->userData,
2792: "Definition of %s has duplicate references of %s\n",
2793: elem->name, name);
2794: ret = 0;
2795: }
2796: next = next->c2;
2797: }
2798: }
2799: cur = cur->c2;
2800: }
2801: }
2802:
2803: /* VC: Unique Element Type Declaration */
2804: tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
2805: if ((tst != NULL ) && (tst != elem)) {
2806: VERROR(ctxt->userData, "Redefinition of element %s\n",
2807: elem->name);
2808: ret = 0;
2809: }
2810: tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
2811: if ((tst != NULL ) && (tst != elem)) {
2812: VERROR(ctxt->userData, "Redefinition of element %s\n",
2813: elem->name);
2814: ret = 0;
2815: }
2816:
2817: /* One ID per Element Type */
2818: if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
2819: ret = 0;
2820: }
2821: return(ret);
1.14 daniel 2822: }
2823:
2824: /**
2825: * xmlValidateOneAttribute:
2826: * @ctxt: the validation context
2827: * @doc: a document instance
2828: * @elem: an element instance
2829: * @attr: an attribute instance
1.32 daniel 2830: * @value: the attribute value (without entities processing)
1.14 daniel 2831: *
2832: * Try to validate a single attribute for an element
1.59 daniel 2833: * basically it does the following checks as described by the
1.14 daniel 2834: * XML-1.0 recommendation:
1.18 daniel 2835: * - [ VC: Attribute Value Type ]
2836: * - [ VC: Fixed Attribute Default ]
1.14 daniel 2837: * - [ VC: Entity Name ]
2838: * - [ VC: Name Token ]
2839: * - [ VC: ID ]
2840: * - [ VC: IDREF ]
2841: * - [ VC: Entity Name ]
1.16 daniel 2842: * - [ VC: Notation Attributes ]
1.14 daniel 2843: *
2844: * The ID/IDREF uniqueness and matching are done separately
2845: *
2846: * returns 1 if valid or 0 otherwise
2847: */
2848:
2849: int
1.16 daniel 2850: xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
1.31 daniel 2851: xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value) {
1.24 daniel 2852: /* xmlElementPtr elemDecl; */
1.18 daniel 2853: xmlAttributePtr attrDecl;
2854: int val;
2855: int ret = 1;
2856:
1.14 daniel 2857: CHECK_DTD;
1.18 daniel 2858: if ((elem == NULL) || (elem->name == NULL)) return(0);
2859: if ((attr == NULL) || (attr->name == NULL)) return(0);
2860:
2861: attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
2862: if ((attrDecl == NULL) && (doc->extSubset != NULL))
2863: attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, attr->name);
2864:
1.14 daniel 2865:
1.18 daniel 2866: /* Validity Constraint: Attribute Value Type */
2867: if (attrDecl == NULL) {
2868: VERROR(ctxt->userData,
2869: "No declaration for attribute %s on element %s\n",
2870: attr->name, elem->name);
2871: return(0);
2872: }
1.56 daniel 2873: attr->atype = attrDecl->atype;
2874:
1.48 daniel 2875: val = xmlValidateAttributeValue(attrDecl->atype, value);
1.18 daniel 2876: if (val == 0) {
2877: VERROR(ctxt->userData,
2878: "Syntax of value for attribute %s on %s is not valid\n",
2879: attr->name, elem->name);
2880: ret = 0;
1.22 daniel 2881: }
2882:
1.59 daniel 2883: /* Validity constraint: Fixed Attribute Default */
2884: if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
2885: if (xmlStrcmp(value, attrDecl->defaultValue)) {
2886: VERROR(ctxt->userData,
2887: "Value for attribute %s on %s is differnt from default \"%s\"\n",
2888: attr->name, elem->name, attrDecl->defaultValue);
2889: ret = 0;
2890: }
2891: }
2892:
1.22 daniel 2893: /* Validity Constraint: ID uniqueness */
1.48 daniel 2894: if (attrDecl->atype == XML_ATTRIBUTE_ID) {
1.22 daniel 2895: xmlAddID(ctxt, doc, value, attr);
1.18 daniel 2896: }
2897:
1.56 daniel 2898: if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
2899: (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
1.28 daniel 2900: xmlAddRef(ctxt, doc, value, attr);
2901: }
2902:
1.18 daniel 2903: /* Validity Constraint: Notation Attributes */
1.48 daniel 2904: if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
1.18 daniel 2905: xmlEnumerationPtr tree = attrDecl->tree;
2906: xmlNotationPtr nota;
2907:
2908: /* First check that the given NOTATION was declared */
2909: nota = xmlGetDtdNotationDesc(doc->intSubset, value);
2910: if (nota == NULL)
2911: nota = xmlGetDtdNotationDesc(doc->extSubset, value);
2912:
2913: if (nota == NULL) {
2914: VERROR(ctxt->userData,
2915: "Value \"%s\" for attribute %s on %s is not a declared Notation\n",
2916: value, attr->name, elem->name);
2917: ret = 0;
2918: }
2919:
2920: /* Second, verify that it's among the list */
2921: while (tree != NULL) {
2922: if (!xmlStrcmp(tree->name, value)) break;
2923: tree = tree->next;
2924: }
2925: if (tree == NULL) {
2926: VERROR(ctxt->userData,
1.50 daniel 2927: "Value \"%s\" for attribute %s on %s is not among the enumerated notations\n",
1.18 daniel 2928: value, attr->name, elem->name);
2929: ret = 0;
2930: }
2931: }
2932:
2933: /* Validity Constraint: Enumeration */
1.48 daniel 2934: if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
1.18 daniel 2935: xmlEnumerationPtr tree = attrDecl->tree;
2936: while (tree != NULL) {
2937: if (!xmlStrcmp(tree->name, value)) break;
2938: tree = tree->next;
2939: }
2940: if (tree == NULL) {
2941: VERROR(ctxt->userData,
1.48 daniel 2942: "Value \"%s\" for attribute %s on %s is not among the enumerated set\n",
1.18 daniel 2943: value, attr->name, elem->name);
2944: ret = 0;
2945: }
2946: }
2947:
2948: /* Fixed Attribute Default */
2949: if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
2950: (xmlStrcmp(attrDecl->defaultValue, value))) {
2951: VERROR(ctxt->userData,
2952: "Value for attribute %s on %s must be \"%s\"\n",
2953: attr->name, elem->name, attrDecl->defaultValue);
2954: ret = 0;
2955: }
2956:
1.59 daniel 2957: /* Extra check for the attribute value */
2958: ret &= xmlValidateAttributeValue2(ctxt, doc, attr->name,
2959: attrDecl->atype, value);
1.56 daniel 2960:
1.18 daniel 2961: return(ret);
2962: }
2963:
2964: int xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
2965: xmlElementContentPtr cont);
2966:
2967: /**
2968: * xmlValidateElementTypeExpr:
2969: * @ctxt: the validation context
2970: * @child: pointer to the child list
2971: * @cont: pointer to the content declaration
2972: *
2973: * Try to validate the content of an element of type element
2974: * but don't handle the occurence factor
2975: *
2976: * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
2977: * also update child value in-situ.
2978: */
2979:
2980: int
2981: xmlValidateElementTypeExpr(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
2982: xmlElementContentPtr cont) {
2983: xmlNodePtr cur;
2984: int ret = 1;
2985:
2986: if (cont == NULL) return(-1);
1.58 daniel 2987: DEBUG_VALID_STATE(*child, cont)
1.18 daniel 2988: while (*child != NULL) {
1.58 daniel 2989: if ((*child)->type == XML_ENTITY_REF_NODE) {
2990: /*
2991: * If there is an entity declared an it's not empty
2992: * Push the current node on the stack and process with the
2993: * entity content.
2994: */
2995: if (((*child)->children != NULL) &&
2996: ((*child)->children->children != NULL)) {
2997: nodeVPush(ctxt, *child);
2998: *child = (*child)->children->children;
2999: } else
3000: *child = (*child)->next;
3001: continue;
3002: }
1.18 daniel 3003: if ((*child)->type == XML_PI_NODE) {
3004: *child = (*child)->next;
3005: continue;
3006: }
3007: if ((*child)->type == XML_COMMENT_NODE) {
3008: *child = (*child)->next;
3009: continue;
3010: }
3011: else if ((*child)->type != XML_ELEMENT_NODE) {
3012: return(-1);
3013: }
3014: break;
3015: }
1.58 daniel 3016: DEBUG_VALID_STATE(*child, cont)
1.18 daniel 3017: switch (cont->type) {
3018: case XML_ELEMENT_CONTENT_PCDATA:
1.45 daniel 3019: if (*child == NULL) return(0);
3020: if ((*child)->type == XML_TEXT_NODE) return(1);
3021: return(0);
1.18 daniel 3022: case XML_ELEMENT_CONTENT_ELEMENT:
1.20 daniel 3023: if (*child == NULL) return(0);
1.18 daniel 3024: ret = (!xmlStrcmp((*child)->name, cont->name));
1.58 daniel 3025: if (ret == 1) {
3026: while ((*child)->next == NULL) {
3027: if (((*child)->parent != NULL) &&
3028: ((*child)->parent->type == XML_ENTITY_DECL)) {
3029: *child = nodeVPop(ctxt);
3030: } else
3031: break;
3032: }
1.18 daniel 3033: *child = (*child)->next;
1.58 daniel 3034: }
1.18 daniel 3035: return(ret);
3036: case XML_ELEMENT_CONTENT_OR:
3037: cur = *child;
3038: ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
3039: if (ret == -1) return(-1);
3040: if (ret == 1) {
3041: return(1);
3042: }
3043: /* rollback and retry the other path */
3044: *child = cur;
3045: ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
3046: if (ret == -1) return(-1);
3047: if (ret == 0) {
3048: *child = cur;
3049: return(0);
3050: }
3051: return(1);
3052: case XML_ELEMENT_CONTENT_SEQ:
3053: cur = *child;
3054: ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
3055: if (ret == -1) return(-1);
3056: if (ret == 0) {
3057: *child = cur;
3058: return(0);
3059: }
3060: ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
3061: if (ret == -1) return(-1);
3062: if (ret == 0) {
3063: *child = cur;
3064: return(0);
3065: }
3066: return(1);
3067: }
3068: return(ret);
3069: }
3070:
3071: /**
3072: * xmlValidateElementTypeElement:
3073: * @ctxt: the validation context
3074: * @child: pointer to the child list
3075: * @cont: pointer to the content declaration
3076: *
3077: * Try to validate the content of an element of type element
3078: * yeah, Yet Another Regexp Implementation, and recursive
3079: *
3080: * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
3081: * also update child and content values in-situ.
3082: */
3083:
3084: int
3085: xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
3086: xmlElementContentPtr cont) {
3087: xmlNodePtr cur;
3088: int ret = 1;
3089:
3090: if (cont == NULL) return(-1);
1.58 daniel 3091:
3092: DEBUG_VALID_STATE(*child, cont)
1.18 daniel 3093: while (*child != NULL) {
1.58 daniel 3094: if ((*child)->type == XML_ENTITY_REF_NODE) {
3095: /*
3096: * If there is an entity declared an it's not empty
3097: * Push the current node on the stack and process with the
3098: * entity content.
3099: */
3100: if (((*child)->children != NULL) &&
3101: ((*child)->children->children != NULL)) {
3102: nodeVPush(ctxt, *child);
3103: *child = (*child)->children->children;
3104: } else
3105: *child = (*child)->next;
3106: continue;
3107: }
1.18 daniel 3108: if ((*child)->type == XML_PI_NODE) {
3109: *child = (*child)->next;
3110: continue;
3111: }
3112: if ((*child)->type == XML_COMMENT_NODE) {
3113: *child = (*child)->next;
3114: continue;
3115: }
3116: else if ((*child)->type != XML_ELEMENT_NODE) {
3117: return(-1);
3118: }
3119: break;
3120: }
1.58 daniel 3121: DEBUG_VALID_STATE(*child, cont)
1.18 daniel 3122: cur = *child;
3123: ret = xmlValidateElementTypeExpr(ctxt, child, cont);
3124: if (ret == -1) return(-1);
3125: switch (cont->ocur) {
3126: case XML_ELEMENT_CONTENT_ONCE:
3127: if (ret == 1) {
1.48 daniel 3128: /* skip ignorable elems */
3129: while ((*child != NULL) &&
3130: (((*child)->type == XML_PI_NODE) ||
3131: ((*child)->type == XML_COMMENT_NODE))) {
1.58 daniel 3132: while ((*child)->next == NULL) {
3133: if (((*child)->parent != NULL) &&
3134: ((*child)->parent->type == XML_ENTITY_REF_NODE)) {
3135: *child = (*child)->parent;
3136: } else
3137: break;
3138: }
3139: *child = (*child)->next;
1.48 daniel 3140: }
1.18 daniel 3141: return(1);
3142: }
3143: *child = cur;
3144: return(0);
3145: case XML_ELEMENT_CONTENT_OPT:
3146: if (ret == 0) {
3147: *child = cur;
3148: return(1);
3149: }
1.19 daniel 3150: break;
1.18 daniel 3151: case XML_ELEMENT_CONTENT_MULT:
3152: if (ret == 0) {
3153: *child = cur;
1.19 daniel 3154: break;
1.18 daniel 3155: }
3156: /* no break on purpose */
3157: case XML_ELEMENT_CONTENT_PLUS:
3158: if (ret == 0) {
3159: *child = cur;
3160: return(0);
3161: }
3162: do {
3163: cur = *child;
3164: ret = xmlValidateElementTypeExpr(ctxt, child, cont);
3165: } while (ret == 1);
3166: if (ret == -1) return(-1);
3167: *child = cur;
1.19 daniel 3168: break;
3169: }
3170: while (*child != NULL) {
1.58 daniel 3171: if ((*child)->type == XML_ENTITY_REF_NODE) {
3172: /*
3173: * If there is an entity declared an it's not empty
3174: * Push the current node on the stack and process with the
3175: * entity content.
3176: */
3177: if (((*child)->children != NULL) &&
3178: ((*child)->children->children != NULL)) {
3179: nodeVPush(ctxt, *child);
3180: *child = (*child)->children->children;
3181: } else
3182: *child = (*child)->next;
3183: continue;
3184: }
1.19 daniel 3185: if ((*child)->type == XML_PI_NODE) {
3186: *child = (*child)->next;
3187: continue;
3188: }
3189: if ((*child)->type == XML_COMMENT_NODE) {
3190: *child = (*child)->next;
3191: continue;
3192: }
3193: else if ((*child)->type != XML_ELEMENT_NODE) {
3194: return(-1);
3195: }
3196: break;
3197: }
3198: return(1);
3199: }
3200:
3201: /**
3202: * xmlSprintfElementChilds:
3203: * @buf: an output buffer
3204: * @content: An element
3205: * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
3206: *
3207: * This will dump the list of childs to the buffer
3208: * Intended just for the debug routine
3209: */
3210: void
3211: xmlSprintfElementChilds(char *buf, xmlNodePtr node, int glob) {
3212: xmlNodePtr cur;
3213:
3214: if (node == NULL) return;
3215: if (glob) strcat(buf, "(");
1.46 daniel 3216: cur = node->children;
1.19 daniel 3217: while (cur != NULL) {
3218: switch (cur->type) {
3219: case XML_ELEMENT_NODE:
1.23 daniel 3220: strcat(buf, (char *) cur->name);
1.19 daniel 3221: if (cur->next != NULL)
3222: strcat(buf, " ");
3223: break;
3224: case XML_TEXT_NODE:
3225: case XML_CDATA_SECTION_NODE:
3226: case XML_ENTITY_REF_NODE:
3227: strcat(buf, "CDATA");
3228: if (cur->next != NULL)
3229: strcat(buf, " ");
3230: break;
3231: case XML_ATTRIBUTE_NODE:
3232: case XML_DOCUMENT_NODE:
1.35 daniel 3233: case XML_HTML_DOCUMENT_NODE:
1.19 daniel 3234: case XML_DOCUMENT_TYPE_NODE:
3235: case XML_DOCUMENT_FRAG_NODE:
3236: case XML_NOTATION_NODE:
3237: strcat(buf, "???");
3238: if (cur->next != NULL)
3239: strcat(buf, " ");
3240: break;
3241: case XML_ENTITY_NODE:
3242: case XML_PI_NODE:
1.46 daniel 3243: case XML_DTD_NODE:
1.19 daniel 3244: case XML_COMMENT_NODE:
1.47 daniel 3245: case XML_ELEMENT_DECL:
3246: case XML_ATTRIBUTE_DECL:
1.53 daniel 3247: case XML_ENTITY_DECL:
1.19 daniel 3248: break;
3249: }
3250: cur = cur->next;
1.18 daniel 3251: }
1.19 daniel 3252: if (glob) strcat(buf, ")");
1.14 daniel 3253: }
3254:
1.19 daniel 3255:
1.14 daniel 3256: /**
3257: * xmlValidateOneElement:
3258: * @ctxt: the validation context
3259: * @doc: a document instance
3260: * @elem: an element instance
3261: *
3262: * Try to validate a single element and it's attributes,
3263: * basically it does the following checks as described by the
3264: * XML-1.0 recommendation:
3265: * - [ VC: Element Valid ]
3266: * - [ VC: Required Attribute ]
3267: * Then call xmlValidateOneAttribute() for each attribute present.
3268: *
3269: * The ID/IDREF checkings are done separately
3270: *
3271: * returns 1 if valid or 0 otherwise
3272: */
3273:
3274: int
1.16 daniel 3275: xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
1.18 daniel 3276: xmlNodePtr elem) {
3277: xmlElementPtr elemDecl;
3278: xmlElementContentPtr cont;
1.42 daniel 3279: xmlAttributePtr attr;
1.18 daniel 3280: xmlNodePtr child;
3281: int ret = 1;
1.31 daniel 3282: const xmlChar *name;
1.18 daniel 3283:
1.14 daniel 3284: CHECK_DTD;
3285:
1.39 daniel 3286: if (elem == NULL) return(0);
3287: if (elem->type == XML_TEXT_NODE) {
1.40 daniel 3288: }
3289: switch (elem->type) {
3290: case XML_ATTRIBUTE_NODE:
3291: VERROR(ctxt->userData,
3292: "Attribute element not expected here\n");
1.39 daniel 3293: return(0);
1.40 daniel 3294: case XML_TEXT_NODE:
1.46 daniel 3295: if (elem->children != NULL) {
1.40 daniel 3296: VERROR(ctxt->userData, "Text element has childs !\n");
3297: return(0);
3298: }
3299: if (elem->properties != NULL) {
3300: VERROR(ctxt->userData, "Text element has attributes !\n");
3301: return(0);
3302: }
3303: if (elem->ns != NULL) {
3304: VERROR(ctxt->userData, "Text element has namespace !\n");
3305: return(0);
3306: }
3307: if (elem->ns != NULL) {
3308: VERROR(ctxt->userData,
3309: "Text element carries namespace definitions !\n");
3310: return(0);
3311: }
3312: if (elem->content == NULL) {
3313: VERROR(ctxt->userData,
3314: "Text element has no content !\n");
3315: return(0);
3316: }
3317: return(1);
3318: case XML_CDATA_SECTION_NODE:
3319: case XML_ENTITY_REF_NODE:
3320: case XML_PI_NODE:
3321: case XML_COMMENT_NODE:
3322: return(1);
3323: case XML_ENTITY_NODE:
3324: VERROR(ctxt->userData,
3325: "Entity element not expected here\n");
1.39 daniel 3326: return(0);
1.40 daniel 3327: case XML_NOTATION_NODE:
3328: VERROR(ctxt->userData,
3329: "Notation element not expected here\n");
3330: return(0);
3331: case XML_DOCUMENT_NODE:
3332: case XML_DOCUMENT_TYPE_NODE:
3333: case XML_DOCUMENT_FRAG_NODE:
3334: VERROR(ctxt->userData,
3335: "Document element not expected here\n");
1.39 daniel 3336: return(0);
1.40 daniel 3337: case XML_HTML_DOCUMENT_NODE:
1.39 daniel 3338: VERROR(ctxt->userData,
1.40 daniel 3339: "\n");
1.39 daniel 3340: return(0);
1.40 daniel 3341: case XML_ELEMENT_NODE:
3342: break;
3343: default:
1.39 daniel 3344: VERROR(ctxt->userData,
1.40 daniel 3345: "unknown element type %d\n", elem->type);
1.39 daniel 3346: return(0);
3347: }
3348: if (elem->name == NULL) return(0);
1.18 daniel 3349:
3350: elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
3351: if ((elemDecl == NULL) && (doc->extSubset != NULL))
3352: elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
3353: if (elemDecl == NULL) {
3354: VERROR(ctxt->userData, "No declaration for element %s\n",
3355: elem->name);
3356: return(0);
3357: }
3358:
3359: /* Check taht the element content matches the definition */
1.47 daniel 3360: switch (elemDecl->etype) {
1.18 daniel 3361: case XML_ELEMENT_TYPE_EMPTY:
1.46 daniel 3362: if (elem->children != NULL) {
1.18 daniel 3363: VERROR(ctxt->userData,
3364: "Element %s was declared EMPTY this one has content\n",
3365: elem->name);
3366: ret = 0;
3367: }
3368: break;
3369: case XML_ELEMENT_TYPE_ANY:
3370: /* I don't think anything is required then */
3371: break;
3372: case XML_ELEMENT_TYPE_MIXED:
3373: /* Hum, this start to get messy */
1.46 daniel 3374: child = elem->children;
1.18 daniel 3375: while (child != NULL) {
3376: if (child->type == XML_ELEMENT_NODE) {
3377: name = child->name;
3378: cont = elemDecl->content;
3379: while (cont != NULL) {
3380: if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
3381: if (!xmlStrcmp(cont->name, name)) break;
3382: } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
3383: (cont->c1 != NULL) &&
3384: (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
3385: if (!xmlStrcmp(cont->c1->name, name)) break;
3386: } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
3387: (cont->c1 == NULL) ||
3388: (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
3389: /* Internal error !!! */
3390: fprintf(stderr, "Internal: MIXED struct bad\n");
3391: break;
3392: }
3393: cont = cont->c2;
3394: }
3395: if (cont == NULL) {
3396: VERROR(ctxt->userData,
3397: "Element %s is not declared in %s list of possible childs\n",
3398: name, elem->name);
3399: ret = 0;
3400: }
3401: }
3402: child = child->next;
3403: }
3404: break;
3405: case XML_ELEMENT_TYPE_ELEMENT:
1.46 daniel 3406: child = elem->children;
1.18 daniel 3407: cont = elemDecl->content;
3408: ret = xmlValidateElementTypeElement(ctxt, &child, cont);
1.19 daniel 3409: if ((ret == 0) || (child != NULL)) {
3410: char expr[1000];
3411: char list[2000];
3412:
3413: expr[0] = 0;
3414: xmlSprintfElementContent(expr, cont, 1);
3415: list[0] = 0;
3416: xmlSprintfElementChilds(list, elem, 1);
3417:
1.18 daniel 3418: VERROR(ctxt->userData,
1.19 daniel 3419: "Element %s content doesn't follow the Dtd\nExpecting %s, got %s\n",
3420: elem->name, expr, list);
1.18 daniel 3421: ret = 0;
3422: }
3423: break;
3424: }
3425:
1.42 daniel 3426: /* [ VC: Required Attribute ] */
3427: attr = elemDecl->attributes;
3428: while (attr != NULL) {
3429: if (attr->def == XML_ATTRIBUTE_REQUIRED) {
3430: xmlAttrPtr attrib;
3431: int qualified = -1;
3432:
3433: attrib = elem->properties;
3434: while (attrib != NULL) {
3435: if (!xmlStrcmp(attrib->name, attr->name)) {
3436: if (attr->prefix != NULL) {
3437: xmlNsPtr nameSpace = attrib->ns;
3438:
3439: if (nameSpace == NULL)
3440: nameSpace = elem->ns;
3441: /*
3442: * qualified names handling is problematic, having a
3443: * different prefix should be possible but DTDs don't
3444: * allow to define the URI instead of the prefix :-(
3445: */
3446: if (nameSpace == NULL) {
3447: if (qualified < 0)
3448: qualified = 0;
3449: } else if (xmlStrcmp(nameSpace->prefix, attr->prefix)) {
3450: if (qualified < 1)
3451: qualified = 1;
3452: } else
3453: goto found;
3454: } else {
3455: /*
3456: * We should allow applications to define namespaces
3457: * for their application even if the DTD doesn't
3458: * carry one, otherwise, basically we would always
3459: * break.
3460: */
3461: goto found;
3462: }
3463: }
3464: attrib = attrib->next;
3465: }
3466: if (qualified == -1) {
3467: if (attr->prefix == NULL) {
3468: VERROR(ctxt->userData,
3469: "Element %s doesn't carry attribute %s\n",
3470: elem->name, attr->name);
3471: } else {
3472: VERROR(ctxt->userData,
3473: "Element %s doesn't carry attribute %s:%s\n",
3474: elem->name, attr->prefix,attr->name);
3475: }
3476: } else if (qualified == 0) {
3477: VWARNING(ctxt->userData,
3478: "Element %s required attribute %s:%s has no prefix\n",
3479: elem->name, attr->prefix,attr->name);
3480: } else if (qualified == 1) {
3481: VWARNING(ctxt->userData,
3482: "Element %s required attribute %s:%s has different prefix\n",
3483: elem->name, attr->prefix,attr->name);
3484: }
3485: }
3486: found:
1.47 daniel 3487: attr = attr->nexth;
1.42 daniel 3488: }
1.18 daniel 3489: return(ret);
1.14 daniel 3490: }
3491:
3492: /**
3493: * xmlValidateRoot:
3494: * @ctxt: the validation context
3495: * @doc: a document instance
3496: *
3497: * Try to validate a the root element
3498: * basically it does the following check as described by the
3499: * XML-1.0 recommendation:
3500: * - [ VC: Root Element Type ]
3501: * it doesn't try to recurse or apply other check to the element
3502: *
3503: * returns 1 if valid or 0 otherwise
3504: */
3505:
3506: int
3507: xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
1.39 daniel 3508: xmlNodePtr root;
1.14 daniel 3509: if (doc == NULL) return(0);
3510:
3511: if ((doc->intSubset == NULL) ||
3512: (doc->intSubset->name == NULL)) {
3513: VERROR(ctxt->userData, "Not valid: no DtD found\n");
3514: return(0);
3515: }
1.39 daniel 3516: root = xmlDocGetRootElement(doc);
3517: if ((root == NULL) || (root->name == NULL)) {
1.14 daniel 3518: VERROR(ctxt->userData, "Not valid: no root element\n");
3519: return(0);
3520: }
1.39 daniel 3521: if (xmlStrcmp(doc->intSubset->name, root->name)) {
1.45 daniel 3522: if ((xmlStrcmp(doc->intSubset->name, BAD_CAST "HTML")) ||
3523: (xmlStrcmp(root->name, BAD_CAST "html"))) {
3524: VERROR(ctxt->userData,
3525: "Not valid: root and DtD name do not match '%s' and '%s'\n",
3526: root->name, doc->intSubset->name);
3527: return(0);
3528: }
1.14 daniel 3529: }
3530: return(1);
3531: }
3532:
3533:
3534: /**
3535: * xmlValidateElement:
3536: * @ctxt: the validation context
3537: * @doc: a document instance
3538: * @elem: an element instance
3539: *
3540: * Try to validate the subtree under an element
3541: *
3542: * returns 1 if valid or 0 otherwise
3543: */
3544:
3545: int
1.18 daniel 3546: xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
1.27 daniel 3547: xmlNodePtr child;
3548: xmlAttrPtr attr;
1.31 daniel 3549: xmlChar *value;
1.27 daniel 3550: int ret = 1;
3551:
3552: if (elem == NULL) return(0);
1.14 daniel 3553: CHECK_DTD;
3554:
1.27 daniel 3555: ret &= xmlValidateOneElement(ctxt, doc, elem);
3556: attr = elem->properties;
3557: while(attr != NULL) {
1.46 daniel 3558: value = xmlNodeListGetString(doc, attr->children, 0);
1.27 daniel 3559: ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
3560: if (value != NULL)
1.39 daniel 3561: xmlFree(value);
1.27 daniel 3562: attr= attr->next;
3563: }
1.46 daniel 3564: child = elem->children;
1.27 daniel 3565: while (child != NULL) {
3566: ret &= xmlValidateElement(ctxt, doc, child);
3567: child = child->next;
3568: }
3569:
3570: return(ret);
1.14 daniel 3571: }
3572:
3573: /**
1.28 daniel 3574: * xmlValidateDocumentFinal:
3575: * @ctxt: the validation context
3576: * @doc: a document instance
3577: *
3578: * Does the final step for the document validation once all the
3579: * incremental validation steps have been completed
3580: *
3581: * basically it does the following checks described by the XML Rec
3582: *
3583: *
3584: * returns 1 if valid or 0 otherwise
3585: */
3586:
3587: int
3588: xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
3589: int ret = 1, i;
3590: xmlRefTablePtr table;
3591: xmlAttrPtr id;
3592:
3593: if (doc == NULL) {
3594: fprintf(stderr, "xmlValidateDocumentFinal: doc == NULL\n");
3595: return(0);
3596: }
3597:
3598: /*
1.56 daniel 3599: * Check all the NOTATION/NOTATIONS attributes
3600: */
3601: /*
3602: * Check all the ENTITY/ENTITIES attributes definition for validity
3603: */
3604: /*
3605: * Check all the IDREF/IDREFS attributes definition for validity
1.28 daniel 3606: */
3607: table = doc->refs;
3608: if (table != NULL) {
3609: for (i = 0; i < table->nb_refs; i++) {
1.56 daniel 3610: if (table->table[i]->attr->atype == XML_ATTRIBUTE_IDREF) {
3611: id = xmlGetID(doc, table->table[i]->value);
3612: if (id == NULL) {
3613: VERROR(ctxt->userData,
1.55 daniel 3614: "IDREF attribute %s reference an unknown ID \"%s\"\n",
1.56 daniel 3615: table->table[i]->attr->name, table->table[i]->value);
3616: ret = 0;
3617: }
3618: } else if (table->table[i]->attr->atype == XML_ATTRIBUTE_IDREFS) {
1.57 daniel 3619: xmlChar *dup, *name = NULL, *cur, save;
1.56 daniel 3620:
3621: dup = xmlStrdup(table->table[i]->value);
3622: if (dup == NULL)
3623: return(0);
3624: cur = dup;
1.57 daniel 3625: while (*cur != 0) {
1.56 daniel 3626: name = cur;
3627: while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
3628: save = *cur;
3629: *cur = 0;
3630: id = xmlGetID(doc, name);
3631: if (id == NULL) {
3632: VERROR(ctxt->userData,
3633: "IDREFS attribute %s reference an unknown ID \"%s\"\n",
3634: table->table[i]->attr->name, name);
3635: ret = 0;
3636: }
3637: if (save == 0)
3638: break;
3639: *cur = save;
3640: while (IS_BLANK(*cur)) cur++;
3641: }
3642: xmlFree(dup);
1.28 daniel 3643: }
3644: }
3645: }
3646: return(ret);
3647: }
3648:
3649: /**
1.14 daniel 3650: * xmlValidateDtd:
3651: * @ctxt: the validation context
3652: * @doc: a document instance
3653: * @dtd: a dtd instance
3654: *
1.39 daniel 3655: * Try to validate the document against the dtd instance
1.14 daniel 3656: *
3657: * basically it does check all the definitions in the DtD.
3658: *
3659: * returns 1 if valid or 0 otherwise
3660: */
3661:
3662: int
3663: xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
1.39 daniel 3664: int ret;
3665: xmlDtdPtr oldExt;
3666: xmlNodePtr root;
3667:
3668: if (dtd == NULL) return(0);
3669: if (doc == NULL) return(0);
3670: oldExt = doc->extSubset;
3671: doc->extSubset = dtd;
3672: ret = xmlValidateRoot(ctxt, doc);
3673: if (ret == 0) {
3674: doc->extSubset = oldExt;
3675: return(ret);
3676: }
3677: root = xmlDocGetRootElement(doc);
3678: ret = xmlValidateElement(ctxt, doc, root);
3679: ret &= xmlValidateDocumentFinal(ctxt, doc);
3680: doc->extSubset = oldExt;
3681: return(ret);
1.14 daniel 3682: }
3683:
3684: /**
1.59 daniel 3685: * xmlValidateDtdFinal:
3686: * @ctxt: the validation context
3687: * @doc: a document instance
3688: *
3689: * Does the final step for the dtds validation once all the
3690: * subsets have been parsed
3691: *
3692: * basically it does the following checks described by the XML Rec
3693: * - check that ENTITY and ENTITIES type attributes default or
3694: * possible values matches one of the defined entities.
3695: * - check that NOTATION type attributes default or
3696: * possible values matches one of the defined notations.
3697: *
3698: * returns 1 if valid or 0 otherwise
3699: */
3700:
3701: int
3702: xmlValidateDtdFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
3703: int ret = 1, i;
3704: xmlDtdPtr dtd;
3705: xmlAttributeTablePtr table;
3706: xmlAttributePtr cur;
3707:
3708: if (doc == NULL) return(0);
3709: if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
3710: return(0);
3711: dtd = doc->intSubset;
3712: if ((dtd != NULL) && (dtd->attributes != NULL)) {
3713: table = dtd->attributes;
3714:
3715: for (i = 0;i < table->nb_attributes;i++) {
3716: cur = table->table[i];
3717: switch (cur->atype) {
3718: case XML_ATTRIBUTE_CDATA:
3719: case XML_ATTRIBUTE_ID:
3720: case XML_ATTRIBUTE_IDREF :
3721: case XML_ATTRIBUTE_IDREFS:
3722: case XML_ATTRIBUTE_NMTOKEN:
3723: case XML_ATTRIBUTE_NMTOKENS:
3724: case XML_ATTRIBUTE_ENUMERATION:
3725: break;
3726: case XML_ATTRIBUTE_ENTITY:
3727: case XML_ATTRIBUTE_ENTITIES:
3728: case XML_ATTRIBUTE_NOTATION:
3729: if (cur->defaultValue != NULL) {
3730: ret &= xmlValidateAttributeValue2(ctxt, doc, cur->name,
3731: cur->atype, cur->defaultValue);
3732: }
3733: if (cur->tree != NULL) {
3734: xmlEnumerationPtr tree = cur->tree;
3735: while (tree != NULL) {
3736: ret &= xmlValidateAttributeValue2(ctxt, doc,
3737: cur->name, cur->atype, tree->name);
3738: tree = tree->next;
3739: }
3740: }
3741: }
3742: }
3743: }
3744: dtd = doc->extSubset;
3745: if ((dtd != NULL) && (dtd->attributes != NULL)) {
3746: table = dtd->attributes;
3747:
3748: for (i = 0;i < table->nb_attributes;i++) {
3749: cur = table->table[i];
3750: switch (cur->atype) {
3751: case XML_ATTRIBUTE_CDATA:
3752: case XML_ATTRIBUTE_ID:
3753: case XML_ATTRIBUTE_IDREF :
3754: case XML_ATTRIBUTE_IDREFS:
3755: case XML_ATTRIBUTE_NMTOKEN:
3756: case XML_ATTRIBUTE_NMTOKENS:
3757: case XML_ATTRIBUTE_ENUMERATION:
3758: break;
3759: case XML_ATTRIBUTE_ENTITY:
3760: case XML_ATTRIBUTE_ENTITIES:
3761: case XML_ATTRIBUTE_NOTATION:
3762: if (cur->defaultValue != NULL) {
3763: ret &= xmlValidateAttributeValue2(ctxt, doc, cur->name,
3764: cur->atype, cur->defaultValue);
3765: }
3766: if (cur->tree != NULL) {
3767: xmlEnumerationPtr tree = cur->tree;
3768: while (tree != NULL) {
3769: ret &= xmlValidateAttributeValue2(ctxt, doc,
3770: cur->name, cur->atype, tree->name);
3771: tree = tree->next;
3772: }
3773: }
3774: }
3775: }
3776: }
3777: return(ret);
3778: }
3779:
3780: /**
1.14 daniel 3781: * xmlValidateDocument:
3782: * @ctxt: the validation context
3783: * @doc: a document instance
3784: *
3785: * Try to validate the document instance
3786: *
1.27 daniel 3787: * basically it does the all the checks described by the XML Rec
1.14 daniel 3788: * i.e. validates the internal and external subset (if present)
3789: * and validate the document tree.
3790: *
3791: * returns 1 if valid or 0 otherwise
3792: */
3793:
3794: int
3795: xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
1.27 daniel 3796: int ret;
1.39 daniel 3797: xmlNodePtr root;
3798:
3799: if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
3800: return(0);
3801: if ((doc->intSubset != NULL) && ((doc->intSubset->SystemID != NULL) ||
3802: (doc->intSubset->ExternalID != NULL)) && (doc->extSubset == NULL)) {
3803: doc->extSubset = xmlParseDTD(doc->intSubset->ExternalID,
3804: doc->intSubset->SystemID);
3805: if (doc->extSubset == NULL) {
3806: if (doc->intSubset->SystemID != NULL) {
3807: VERROR(ctxt->userData,
1.55 daniel 3808: "Could not load the external subset \"%s\"\n",
1.39 daniel 3809: doc->intSubset->SystemID);
3810: } else {
3811: VERROR(ctxt->userData,
1.55 daniel 3812: "Could not load the external subset \"%s\"\n",
1.39 daniel 3813: doc->intSubset->ExternalID);
3814: }
3815: return(0);
3816: }
3817: }
1.27 daniel 3818:
1.59 daniel 3819: ret = xmlValidateDtdFinal(ctxt, doc);
1.14 daniel 3820: if (!xmlValidateRoot(ctxt, doc)) return(0);
3821:
1.39 daniel 3822: root = xmlDocGetRootElement(doc);
1.59 daniel 3823: ret &= xmlValidateElement(ctxt, doc, root);
1.28 daniel 3824: ret &= xmlValidateDocumentFinal(ctxt, doc);
3825: return(ret);
1.14 daniel 3826: }
3827:
1.33 daniel 3828:
3829: /************************************************************************
3830: * *
3831: * Routines for dynamic validation editing *
3832: * *
3833: ************************************************************************/
3834:
3835: /**
1.34 daniel 3836: * xmlValidGetPotentialChildren:
3837: * @ctree: an element content tree
3838: * @list: an array to store the list of child names
3839: * @len: a pointer to the number of element in the list
3840: * @max: the size of the array
1.33 daniel 3841: *
1.34 daniel 3842: * Build/extend a list of potential children allowed by the content tree
1.33 daniel 3843: *
1.34 daniel 3844: * returns the number of element in the list, or -1 in case of error.
1.33 daniel 3845: */
3846:
1.34 daniel 3847: int
3848: xmlValidGetPotentialChildren(xmlElementContent *ctree, const xmlChar **list,
3849: int *len, int max) {
3850: int i;
3851:
3852: if ((ctree == NULL) || (list == NULL) || (len == NULL))
3853: return(-1);
3854: if (*len >= max) return(*len);
3855:
3856: switch (ctree->type) {
3857: case XML_ELEMENT_CONTENT_PCDATA:
3858: for (i = 0; i < *len;i++)
1.37 daniel 3859: if (!xmlStrcmp(BAD_CAST "#PCDATA", list[i])) return(*len);
3860: list[(*len)++] = BAD_CAST "#PCDATA";
1.34 daniel 3861: break;
3862: case XML_ELEMENT_CONTENT_ELEMENT:
3863: for (i = 0; i < *len;i++)
3864: if (!xmlStrcmp(ctree->name, list[i])) return(*len);
3865: list[(*len)++] = ctree->name;
3866: break;
3867: case XML_ELEMENT_CONTENT_SEQ:
3868: xmlValidGetPotentialChildren(ctree->c1, list, len, max);
3869: xmlValidGetPotentialChildren(ctree->c2, list, len, max);
3870: break;
3871: case XML_ELEMENT_CONTENT_OR:
3872: xmlValidGetPotentialChildren(ctree->c1, list, len, max);
3873: xmlValidGetPotentialChildren(ctree->c2, list, len, max);
3874: break;
3875: }
3876:
3877: return(*len);
1.33 daniel 3878: }
3879:
3880: /**
1.34 daniel 3881: * xmlValidGetValidElements:
3882: * @prev: an element to insert after
3883: * @next: an element to insert next
3884: * @list: an array to store the list of child names
3885: * @max: the size of the array
1.33 daniel 3886: *
1.34 daniel 3887: * This function returns the list of authorized children to insert
3888: * within an existing tree while respecting the validity constraints
3889: * forced by the Dtd. The insertion point is defined using @prev and
3890: * @next in the following ways:
3891: * to insert before 'node': xmlValidGetValidElements(node->prev, node, ...
3892: * to insert next 'node': xmlValidGetValidElements(node, node->next, ...
3893: * to replace 'node': xmlValidGetValidElements(node->prev, node->next, ...
3894: * to prepend a child to 'node': xmlValidGetValidElements(NULL, node->childs,
3895: * to append a child to 'node': xmlValidGetValidElements(node->last, NULL, ...
1.33 daniel 3896: *
1.34 daniel 3897: * pointers to the element names are inserted at the beginning of the array
3898: * and do not need to be freed.
3899: *
3900: * returns the number of element in the list, or -1 in case of error. If
3901: * the function returns the value @max the caller is invited to grow the
3902: * receiving array and retry.
1.33 daniel 3903: */
3904:
1.34 daniel 3905: int
3906: xmlValidGetValidElements(xmlNode *prev, xmlNode *next, const xmlChar **list,
3907: int max) {
3908: int nb_valid_elements = 0;
3909: const xmlChar *elements[256];
3910: int nb_elements = 0, i;
3911:
3912: xmlNode *ref_node;
3913: xmlNode *parent;
3914: xmlNode *test_node;
3915:
3916: xmlNode *prev_next;
3917: xmlNode *next_prev;
3918: xmlNode *parent_childs;
3919: xmlNode *parent_last;
3920:
3921: xmlElement *element_desc;
3922:
3923: if (prev == NULL && next == NULL)
3924: return(-1);
3925:
3926: if (list == NULL) return(-1);
3927: if (max <= 0) return(-1);
3928:
3929: nb_valid_elements = 0;
3930: ref_node = prev ? prev : next;
3931: parent = ref_node->parent;
3932:
3933: /*
3934: * Retrieves the parent element declaration
3935: */
3936: element_desc = xmlGetDtdElementDesc(parent->doc->intSubset,
3937: parent->name);
3938: if ((element_desc == NULL) && (parent->doc->extSubset != NULL))
3939: element_desc = xmlGetDtdElementDesc(parent->doc->extSubset,
3940: parent->name);
3941: if (element_desc == NULL) return(-1);
3942:
3943: /*
3944: * Do a backup of the current tree structure
3945: */
3946: prev_next = prev ? prev->next : NULL;
3947: next_prev = next ? next->prev : NULL;
1.46 daniel 3948: parent_childs = parent->children;
1.34 daniel 3949: parent_last = parent->last;
3950:
3951: /*
3952: * Creates a dummy node and insert it into the tree
3953: */
1.37 daniel 3954: test_node = xmlNewNode (NULL, BAD_CAST "<!dummy?>");
1.34 daniel 3955: test_node->doc = ref_node->doc;
3956: test_node->parent = parent;
3957: test_node->prev = prev;
3958: test_node->next = next;
3959:
3960: if (prev) prev->next = test_node;
1.46 daniel 3961: else parent->children = test_node;
1.34 daniel 3962:
3963: if (next) next->prev = test_node;
3964: else parent->last = test_node;
3965:
3966: /*
3967: * Insert each potential child node and check if the parent is
3968: * still valid
3969: */
3970: nb_elements = xmlValidGetPotentialChildren(element_desc->content,
3971: elements, &nb_elements, 256);
3972:
3973: for (i = 0;i < nb_elements;i++) {
3974: test_node->name = elements[i];
3975: if (xmlValidateOneElement(NULL, parent->doc, parent)) {
3976: int j;
3977:
3978: for (j = 0; j < nb_valid_elements;j++)
3979: if (!xmlStrcmp(elements[i], list[j])) break;
3980: list[nb_valid_elements++] = elements[i];
3981: if (nb_valid_elements >= max) break;
3982: }
1.33 daniel 3983: }
3984:
1.34 daniel 3985: /*
3986: * Restore the tree structure
3987: */
3988: if (prev) prev->next = prev_next;
3989: if (next) next->prev = next_prev;
1.46 daniel 3990: parent->children = parent_childs;
1.34 daniel 3991: parent->last = parent_last;
3992:
3993: return(nb_valid_elements);
1.33 daniel 3994: }
Webmaster