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