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