Annotation of XML/valid.c, revision 1.67
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;
570: if ((!xmlStrcmp(cur->name, name)) &&
571: ((ns == NULL) || (!xmlStrcmp(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++) {
930: if (!xmlStrcmp(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: }
! 1083: if ((!xmlStrcmp(cur->name, name)) &&
! 1084: ((ns == NULL) || (!xmlStrcmp(cur->prefix, ns)))) {
! 1085: /*
! 1086: * The attribute is already defined in this Dtd.
! 1087: */
! 1088: VWARNING(ctxt->userData,
! 1089: "Attribute %s on %s: already defined\n",
! 1090: elem, name);
! 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;
! 1104: if ((!xmlStrcmp(cur->name, name)) &&
! 1105: (!xmlStrcmp(cur->elem, elem)) &&
! 1106: ((ns == NULL) || (!xmlStrcmp(cur->prefix, ns)))) {
! 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.5 daniel 1464: if (!xmlStrcmp(cur->name, name)) {
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];
1733: if (!xmlStrcmp(cur->value, value)) {
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) {
1830: if ((!xmlStrcmp(BAD_CAST "id", attr->name)) ||
1831: (!xmlStrcmp(BAD_CAST "name", attr->name)))
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];
1919: if (!xmlStrcmp(cur->value, ID)) {
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];
2180: if (!xmlStrcmp(cur->value, Ref)) {
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];
! 2216: if (!xmlStrcmp(cur->name, name))
! 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.67 ! veillard 2221: if (!xmlStrcmp(cur->name, name)) {
! 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];
2235: if ((!xmlStrcmp(cur->name, uqname)) &&
2236: ((prefix == cur->prefix) ||
2237: ((prefix != NULL) && (cur->prefix != NULL) &&
2238: (!xmlStrcmp(cur->prefix, prefix))))) {
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];
2273: if (!xmlStrcmp(cur->name, name) &&
2274: ((prefix == cur->prefix) ||
2275: ((prefix != NULL) && (cur->prefix != NULL) &&
2276: (!xmlStrcmp(cur->prefix, prefix)))))
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;
2297: xmlAttributePtr cur;
1.62 daniel 2298: xmlChar *uqname = NULL, *prefix = NULL;
1.14 daniel 2299: int i;
2300:
2301: if (dtd == NULL) return(NULL);
2302: if (dtd->attributes == NULL) return(NULL);
1.64 veillard 2303: table = (xmlAttributeTablePtr) dtd->attributes;
1.14 daniel 2304:
2305: for (i = 0;i < table->nb_attributes;i++) {
1.15 daniel 2306: cur = table->table[i];
2307: if ((!xmlStrcmp(cur->name, name)) &&
2308: (!xmlStrcmp(cur->elem, elem)))
1.14 daniel 2309: return(cur);
2310: }
1.62 daniel 2311:
2312: /*
2313: * Specific case if name is a QName.
2314: */
2315: uqname = xmlSplitQName2(name, &prefix);
2316: if (uqname == NULL) return(NULL);
2317:
2318: for (i = 0;i < table->nb_attributes;i++) {
2319: cur = table->table[i];
2320: if ((!xmlStrcmp(cur->name, uqname)) &&
2321: (!xmlStrcmp(cur->elem, elem)) &&
2322: ((prefix == cur->prefix) ||
2323: ((prefix != NULL) && (cur->prefix != NULL) &&
2324: (!xmlStrcmp(cur->prefix, prefix))))) {
2325: if (prefix != NULL) xmlFree(prefix);
2326: if (uqname != NULL) xmlFree(uqname);
2327: return(cur);
2328: }
2329: }
2330: if (prefix != NULL) xmlFree(prefix);
2331: if (uqname != NULL) xmlFree(uqname);
2332: return(NULL);
2333: }
2334:
2335: /**
2336: * xmlGetDtdQAttrDesc:
2337: * @dtd: a pointer to the DtD to search
2338: * @elem: the element name
2339: * @name: the attribute name
2340: * @prefix: the attribute namespace prefix
2341: *
2342: * Search the Dtd for the description of this qualified attribute on
2343: * this element.
2344: *
2345: * returns the xmlAttributePtr if found or NULL
2346: */
2347:
2348: xmlAttributePtr
2349: xmlGetDtdQAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name,
2350: const xmlChar *prefix) {
2351: xmlAttributeTablePtr table;
2352: xmlAttributePtr cur;
2353: int i;
2354:
2355: if (dtd == NULL) return(NULL);
2356: if (dtd->attributes == NULL) return(NULL);
1.64 veillard 2357: table = (xmlAttributeTablePtr) dtd->attributes;
1.62 daniel 2358:
2359: for (i = 0;i < table->nb_attributes;i++) {
2360: cur = table->table[i];
2361: if ((!xmlStrcmp(cur->name, name)) &&
2362: (!xmlStrcmp(cur->elem, elem)) &&
2363: ((prefix == cur->prefix) ||
2364: ((prefix != NULL) && (cur->prefix != NULL) &&
2365: (!xmlStrcmp(cur->prefix, prefix)))))
2366: return(cur);
2367: }
1.14 daniel 2368: return(NULL);
2369: }
2370:
2371: /**
2372: * xmlGetDtdNotationDesc:
2373: * @dtd: a pointer to the DtD to search
2374: * @name: the notation name
2375: *
2376: * Search the Dtd for the description of this notation
2377: *
2378: * returns the xmlNotationPtr if found or NULL
2379: */
2380:
2381: xmlNotationPtr
1.31 daniel 2382: xmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) {
1.14 daniel 2383: xmlNotationTablePtr table;
2384: xmlNotationPtr cur;
2385: int i;
2386:
2387: if (dtd == NULL) return(NULL);
2388: if (dtd->notations == NULL) return(NULL);
1.64 veillard 2389: table = (xmlNotationTablePtr) dtd->notations;
1.14 daniel 2390:
2391: for (i = 0;i < table->nb_notations;i++) {
1.15 daniel 2392: cur = table->table[i];
1.14 daniel 2393: if (!xmlStrcmp(cur->name, name))
2394: return(cur);
2395: }
2396: return(NULL);
2397: }
2398:
2399: /**
1.23 daniel 2400: * xmlValidateNotationUse:
2401: * @ctxt: the validation context
2402: * @doc: the document
2403: * @notationName: the notation name to check
2404: *
2405: * Validate that the given mame match a notation declaration.
2406: * - [ VC: Notation Declared ]
2407: *
2408: * returns 1 if valid or 0 otherwise
2409: */
2410:
2411: int
2412: xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
1.31 daniel 2413: const xmlChar *notationName) {
1.23 daniel 2414: xmlNotationPtr notaDecl;
2415: if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
2416:
2417: notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
2418: if ((notaDecl == NULL) && (doc->extSubset != NULL))
2419: notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
2420:
2421: if (notaDecl == NULL) {
2422: VERROR(ctxt->userData, "NOTATION %s is not declared\n",
2423: notationName);
2424: return(0);
2425: }
2426: return(1);
2427: }
2428:
2429: /**
1.18 daniel 2430: * xmlIsMixedElement
2431: * @doc: the document
2432: * @name: the element name
2433: *
2434: * Search in the DtDs whether an element accept Mixed content (or ANY)
2435: * basically if it is supposed to accept text childs
2436: *
2437: * returns 0 if no, 1 if yes, and -1 if no element description is available
2438: */
2439:
2440: int
1.31 daniel 2441: xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) {
1.18 daniel 2442: xmlElementPtr elemDecl;
2443:
2444: if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
2445:
2446: elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
2447: if ((elemDecl == NULL) && (doc->extSubset != NULL))
2448: elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
2449: if (elemDecl == NULL) return(-1);
1.47 daniel 2450: switch (elemDecl->etype) {
1.18 daniel 2451: case XML_ELEMENT_TYPE_ELEMENT:
2452: return(0);
2453: case XML_ELEMENT_TYPE_EMPTY:
2454: /*
2455: * return 1 for EMPTY since we want VC error to pop up
2456: * on <empty> </empty> for example
2457: */
2458: case XML_ELEMENT_TYPE_ANY:
2459: case XML_ELEMENT_TYPE_MIXED:
2460: return(1);
2461: }
2462: return(1);
2463: }
2464:
2465: /**
1.16 daniel 2466: * xmlValidateNameValue:
2467: * @value: an Name value
2468: *
2469: * Validate that the given value match Name production
2470: *
2471: * returns 1 if valid or 0 otherwise
2472: */
2473:
2474: int
1.31 daniel 2475: xmlValidateNameValue(const xmlChar *value) {
2476: const xmlChar *cur;
1.16 daniel 2477:
2478: if (value == NULL) return(0);
2479: cur = value;
2480:
2481: if (!IS_LETTER(*cur) && (*cur != '_') &&
2482: (*cur != ':')) {
2483: return(0);
2484: }
2485:
2486: while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2487: (*cur == '.') || (*cur == '-') ||
2488: (*cur == '_') || (*cur == ':') ||
2489: (IS_COMBINING(*cur)) ||
2490: (IS_EXTENDER(*cur)))
2491: cur++;
2492:
2493: if (*cur != 0) return(0);
2494:
2495: return(1);
2496: }
2497:
2498: /**
2499: * xmlValidateNamesValue:
2500: * @value: an Names value
2501: *
2502: * Validate that the given value match Names production
2503: *
2504: * returns 1 if valid or 0 otherwise
2505: */
2506:
2507: int
1.31 daniel 2508: xmlValidateNamesValue(const xmlChar *value) {
2509: const xmlChar *cur;
1.16 daniel 2510:
2511: if (value == NULL) return(0);
2512: cur = value;
2513:
2514: if (!IS_LETTER(*cur) && (*cur != '_') &&
2515: (*cur != ':')) {
2516: return(0);
2517: }
2518:
2519: while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2520: (*cur == '.') || (*cur == '-') ||
2521: (*cur == '_') || (*cur == ':') ||
2522: (IS_COMBINING(*cur)) ||
2523: (IS_EXTENDER(*cur)))
2524: cur++;
2525:
2526: while (IS_BLANK(*cur)) {
2527: while (IS_BLANK(*cur)) cur++;
2528:
2529: if (!IS_LETTER(*cur) && (*cur != '_') &&
2530: (*cur != ':')) {
2531: return(0);
2532: }
2533:
2534: while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2535: (*cur == '.') || (*cur == '-') ||
2536: (*cur == '_') || (*cur == ':') ||
2537: (IS_COMBINING(*cur)) ||
2538: (IS_EXTENDER(*cur)))
2539: cur++;
2540: }
2541:
2542: if (*cur != 0) return(0);
2543:
2544: return(1);
2545: }
2546:
2547: /**
2548: * xmlValidateNmtokenValue:
2549: * @value: an Mntoken value
2550: *
2551: * Validate that the given value match Nmtoken production
2552: *
2553: * [ VC: Name Token ]
2554: *
2555: * returns 1 if valid or 0 otherwise
2556: */
2557:
2558: int
1.31 daniel 2559: xmlValidateNmtokenValue(const xmlChar *value) {
2560: const xmlChar *cur;
1.16 daniel 2561:
2562: if (value == NULL) return(0);
2563: cur = value;
2564:
2565: if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
2566: (*cur != '.') && (*cur != '-') &&
2567: (*cur != '_') && (*cur != ':') &&
2568: (!IS_COMBINING(*cur)) &&
2569: (!IS_EXTENDER(*cur)))
2570: return(0);
2571:
2572: while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2573: (*cur == '.') || (*cur == '-') ||
2574: (*cur == '_') || (*cur == ':') ||
2575: (IS_COMBINING(*cur)) ||
2576: (IS_EXTENDER(*cur)))
2577: cur++;
2578:
2579: if (*cur != 0) return(0);
2580:
2581: return(1);
2582: }
2583:
2584: /**
2585: * xmlValidateNmtokensValue:
2586: * @value: an Mntokens value
2587: *
2588: * Validate that the given value match Nmtokens production
2589: *
2590: * [ VC: Name Token ]
2591: *
2592: * returns 1 if valid or 0 otherwise
2593: */
2594:
2595: int
1.31 daniel 2596: xmlValidateNmtokensValue(const xmlChar *value) {
2597: const xmlChar *cur;
1.16 daniel 2598:
2599: if (value == NULL) return(0);
2600: cur = value;
2601:
1.51 daniel 2602: while (IS_BLANK(*cur)) cur++;
1.16 daniel 2603: if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
2604: (*cur != '.') && (*cur != '-') &&
2605: (*cur != '_') && (*cur != ':') &&
2606: (!IS_COMBINING(*cur)) &&
2607: (!IS_EXTENDER(*cur)))
2608: return(0);
2609:
2610: while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2611: (*cur == '.') || (*cur == '-') ||
2612: (*cur == '_') || (*cur == ':') ||
2613: (IS_COMBINING(*cur)) ||
2614: (IS_EXTENDER(*cur)))
2615: cur++;
2616:
2617: while (IS_BLANK(*cur)) {
2618: while (IS_BLANK(*cur)) cur++;
1.51 daniel 2619: if (*cur == 0) return(1);
1.16 daniel 2620:
2621: if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
2622: (*cur != '.') && (*cur != '-') &&
2623: (*cur != '_') && (*cur != ':') &&
2624: (!IS_COMBINING(*cur)) &&
2625: (!IS_EXTENDER(*cur)))
2626: return(0);
2627:
2628: while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2629: (*cur == '.') || (*cur == '-') ||
2630: (*cur == '_') || (*cur == ':') ||
2631: (IS_COMBINING(*cur)) ||
2632: (IS_EXTENDER(*cur)))
2633: cur++;
2634: }
2635:
2636: if (*cur != 0) return(0);
2637:
2638: return(1);
2639: }
2640:
2641: /**
2642: * xmlValidateNotationDecl:
1.23 daniel 2643: * @ctxt: the validation context
1.16 daniel 2644: * @doc: a document instance
2645: * @nota: a notation definition
2646: *
2647: * Try to validate a single notation definition
2648: * basically it does the following checks as described by the
2649: * XML-1.0 recommendation:
1.18 daniel 2650: * - it seems that no validity constraing exist on notation declarations
2651: * But this function get called anyway ...
1.16 daniel 2652: *
2653: * returns 1 if valid or 0 otherwise
2654: */
2655:
2656: int
2657: xmlValidateNotationDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2658: xmlNotationPtr nota) {
2659: int ret = 1;
2660:
2661: return(ret);
2662: }
2663:
2664: /**
2665: * xmlValidateAttributeValue:
2666: * @type: an attribute type
2667: * @value: an attribute value
2668: *
2669: * Validate that the given attribute value match the proper production
2670: *
2671: * [ VC: ID ]
2672: * Values of type ID must match the Name production....
2673: *
2674: * [ VC: IDREF ]
2675: * Values of type IDREF must match the Name production, and values
2676: * of type IDREFS must match Names ...
2677: *
2678: * [ VC: Entity Name ]
2679: * Values of type ENTITY must match the Name production, values
2680: * of type ENTITIES must match Names ...
2681: *
2682: * [ VC: Name Token ]
2683: * Values of type NMTOKEN must match the Nmtoken production; values
2684: * of type NMTOKENS must match Nmtokens.
2685: *
2686: * returns 1 if valid or 0 otherwise
2687: */
2688:
2689: int
1.31 daniel 2690: xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) {
1.16 daniel 2691: switch (type) {
1.24 daniel 2692: case XML_ATTRIBUTE_ENTITIES:
1.16 daniel 2693: case XML_ATTRIBUTE_IDREFS:
2694: return(xmlValidateNamesValue(value));
1.24 daniel 2695: case XML_ATTRIBUTE_ENTITY:
1.16 daniel 2696: case XML_ATTRIBUTE_IDREF:
2697: case XML_ATTRIBUTE_ID:
2698: case XML_ATTRIBUTE_NOTATION:
2699: return(xmlValidateNameValue(value));
2700: case XML_ATTRIBUTE_NMTOKENS:
2701: case XML_ATTRIBUTE_ENUMERATION:
2702: return(xmlValidateNmtokensValue(value));
2703: case XML_ATTRIBUTE_NMTOKEN:
2704: return(xmlValidateNmtokenValue(value));
2705: case XML_ATTRIBUTE_CDATA:
2706: break;
2707: }
2708: return(1);
2709: }
2710:
2711: /**
1.59 daniel 2712: * xmlValidateAttributeValue2:
2713: * @ctxt: the validation context
2714: * @doc: the document
2715: * @name: the attribute name (used for error reporting only)
2716: * @type: the attribute type
2717: * @value: the attribute value
2718: *
2719: * Validate that the given attribute value match a given type.
2720: * This typically cannot be done before having finished parsing
2721: * the subsets.
2722: *
2723: * [ VC: IDREF ]
2724: * Values of type IDREF must match one of the declared IDs
2725: * Values of type IDREFS must match a sequence of the declared IDs
2726: * each Name must match the value of an ID attribute on some element
2727: * in the XML document; i.e. IDREF values must match the value of
2728: * some ID attribute
2729: *
2730: * [ VC: Entity Name ]
2731: * Values of type ENTITY must match one declared entity
2732: * Values of type ENTITIES must match a sequence of declared entities
2733: *
2734: * [ VC: Notation Attributes ]
2735: * all notation names in the declaration must be declared.
2736: *
2737: * returns 1 if valid or 0 otherwise
2738: */
2739:
2740: int
2741: xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2742: const xmlChar *name, xmlAttributeType type, const xmlChar *value) {
2743: int ret = 1;
2744: switch (type) {
2745: case XML_ATTRIBUTE_IDREFS:
2746: case XML_ATTRIBUTE_IDREF:
2747: case XML_ATTRIBUTE_ID:
2748: case XML_ATTRIBUTE_NMTOKENS:
2749: case XML_ATTRIBUTE_ENUMERATION:
2750: case XML_ATTRIBUTE_NMTOKEN:
2751: case XML_ATTRIBUTE_CDATA:
2752: break;
2753: case XML_ATTRIBUTE_ENTITY: {
2754: xmlEntityPtr ent;
2755:
2756: ent = xmlGetDocEntity(doc, value);
2757: if (ent == NULL) {
2758: VERROR(ctxt->userData,
2759: "ENTITY attribute %s reference an unknown entity \"%s\"\n",
2760: name, value);
2761: ret = 0;
2762: } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
2763: VERROR(ctxt->userData,
2764: "ENTITY attribute %s reference an entity \"%s\" of wrong type\n",
2765: name, value);
2766: ret = 0;
2767: }
2768: break;
2769: }
2770: case XML_ATTRIBUTE_ENTITIES: {
2771: xmlChar *dup, *nam = NULL, *cur, save;
2772: xmlEntityPtr ent;
2773:
2774: dup = xmlStrdup(value);
2775: if (dup == NULL)
2776: return(0);
2777: cur = dup;
2778: while (*cur != 0) {
2779: nam = cur;
2780: while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
2781: save = *cur;
2782: *cur = 0;
2783: ent = xmlGetDocEntity(doc, nam);
2784: if (ent == NULL) {
2785: VERROR(ctxt->userData,
2786: "ENTITIES attribute %s reference an unknown entity \"%s\"\n",
2787: name, nam);
2788: ret = 0;
2789: } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
2790: VERROR(ctxt->userData,
2791: "ENTITIES attribute %s reference an entity \"%s\" of wrong type\n",
2792: name, nam);
2793: ret = 0;
2794: }
2795: if (save == 0)
2796: break;
2797: *cur = save;
2798: while (IS_BLANK(*cur)) cur++;
2799: }
2800: xmlFree(dup);
2801: break;
2802: }
2803: case XML_ATTRIBUTE_NOTATION: {
2804: xmlNotationPtr nota;
2805:
2806: nota = xmlGetDtdNotationDesc(doc->intSubset, value);
2807: if ((nota == NULL) && (doc->extSubset != NULL))
2808: nota = xmlGetDtdNotationDesc(doc->extSubset, value);
2809:
2810: if (nota == NULL) {
2811: VERROR(ctxt->userData,
2812: "NOTATION attribute %s reference an unknown notation \"%s\"\n",
2813: name, value);
2814: ret = 0;
2815: }
2816: break;
2817: }
2818: }
2819: return(ret);
2820: }
2821:
2822: /**
1.60 daniel 2823: * xmlValidNormalizeAttributeValue:
2824: * @doc: the document
2825: * @elem: the parent
2826: * @name: the attribute name
2827: * @value: the attribute value
2828: *
2829: * Does the validation related extra step of the normalization of attribute
2830: * values:
2831: *
2832: * If the declared value is not CDATA, then the XML processor must further
2833: * process the normalized attribute value by discarding any leading and
2834: * trailing space (#x20) characters, and by replacing sequences of space
2835: * (#x20) characters by single space (#x20) character.
2836: *
2837: * returns a new normalized string if normalization is needed, NULL otherwise
2838: * the caller must free the returned value.
2839: */
2840:
2841: xmlChar *
2842: xmlValidNormalizeAttributeValue(xmlDocPtr doc, xmlNodePtr elem,
2843: const xmlChar *name, const xmlChar *value) {
2844: xmlChar *ret, *dst;
2845: const xmlChar *src;
1.62 daniel 2846: xmlAttributePtr attrDecl = NULL;
1.60 daniel 2847:
2848: if (doc == NULL) return(NULL);
2849: if (elem == NULL) return(NULL);
2850: if (name == NULL) return(NULL);
2851: if (value == NULL) return(NULL);
2852:
1.62 daniel 2853: if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
2854: xmlChar qname[500];
2855: #ifdef HAVE_SNPRINTF
2856: snprintf((char *) qname, sizeof(qname), "%s:%s",
2857: elem->ns->prefix, elem->name);
2858: #else
2859: sprintf(qname, "%s:%s", elem->name, elem->ns->prefix);
2860: #endif
2861: attrDecl = xmlGetDtdAttrDesc(doc->intSubset, qname, name);
2862: if ((attrDecl == NULL) && (doc->extSubset != NULL))
2863: attrDecl = xmlGetDtdAttrDesc(doc->extSubset, qname, name);
2864: }
1.60 daniel 2865: attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
2866: if ((attrDecl == NULL) && (doc->extSubset != NULL))
2867: attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
2868:
2869: if (attrDecl == NULL)
2870: return(NULL);
2871: if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
2872: return(NULL);
2873:
2874: ret = xmlStrdup(value);
2875: if (ret == NULL)
2876: return(NULL);
2877: src = value;
2878: dst = ret;
2879: while (*src == 0x20) src++;
2880: while (*src != 0) {
2881: if (*src == 0x20) {
2882: while (*src == 0x20) src++;
2883: if (*src != 0)
2884: *dst++ = 0x20;
2885: } else {
2886: *dst++ = *src++;
2887: }
2888: }
2889: *dst = 0;
2890: return(ret);
2891: }
2892:
2893: /**
1.14 daniel 2894: * xmlValidateAttributeDecl:
1.23 daniel 2895: * @ctxt: the validation context
1.14 daniel 2896: * @doc: a document instance
2897: * @attr: an attribute definition
2898: *
2899: * Try to validate a single attribute definition
2900: * basically it does the following checks as described by the
2901: * XML-1.0 recommendation:
2902: * - [ VC: Attribute Default Legal ]
2903: * - [ VC: Enumeration ]
2904: * - [ VC: ID Attribute Default ]
2905: *
2906: * The ID/IDREF uniqueness and matching are done separately
2907: *
2908: * returns 1 if valid or 0 otherwise
2909: */
2910:
2911: int
2912: xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
2913: xmlAttributePtr attr) {
1.16 daniel 2914: int ret = 1;
2915: int val;
1.14 daniel 2916: CHECK_DTD;
1.16 daniel 2917: if(attr == NULL) return(1);
2918:
2919: /* Attribute Default Legal */
2920: /* Enumeration */
2921: if (attr->defaultValue != NULL) {
1.48 daniel 2922: val = xmlValidateAttributeValue(attr->atype, attr->defaultValue);
1.16 daniel 2923: if (val == 0) {
2924: VERROR(ctxt->userData,
2925: "Syntax of default value for attribute %s on %s is not valid\n",
2926: attr->name, attr->elem);
2927: }
2928: ret &= val;
2929: }
2930:
2931: /* ID Attribute Default */
1.48 daniel 2932: if ((attr->atype == XML_ATTRIBUTE_ID)&&
1.16 daniel 2933: (attr->def != XML_ATTRIBUTE_IMPLIED) &&
2934: (attr->def != XML_ATTRIBUTE_REQUIRED)) {
2935: VERROR(ctxt->userData,
2936: "ID attribute %s on %s is not valid must be #IMPLIED or #REQUIRED\n",
2937: attr->name, attr->elem);
2938: ret = 0;
2939: }
2940:
1.24 daniel 2941: /* One ID per Element Type */
1.54 daniel 2942: if (attr->atype == XML_ATTRIBUTE_ID) {
2943: int nbId;
1.16 daniel 2944:
2945: /* the trick is taht we parse DtD as their own internal subset */
1.54 daniel 2946: xmlElementPtr elem = xmlGetDtdElementDesc(doc->intSubset,
1.16 daniel 2947: attr->elem);
2948: if (elem != NULL) {
2949: nbId = xmlScanIDAttributeDecl(NULL, elem);
1.54 daniel 2950: } else {
2951: xmlAttributeTablePtr table;
2952: int i;
2953:
2954: /*
2955: * The attribute may be declared in the internal subset and the
2956: * element in the external subset.
2957: */
2958: nbId = 0;
1.64 veillard 2959: table = (xmlAttributeTablePtr) doc->intSubset->attributes;
1.54 daniel 2960: if (table != NULL) {
2961: for (i = 0;i < table->nb_attributes;i++) {
2962: if ((table->table[i]->atype == XML_ATTRIBUTE_ID) &&
2963: (!xmlStrcmp(table->table[i]->elem, attr->elem))) {
2964: nbId++;
2965: }
2966: }
2967: }
1.16 daniel 2968: }
1.54 daniel 2969: if (nbId > 1) {
1.16 daniel 2970: VERROR(ctxt->userData,
1.54 daniel 2971: "Element %s has %d ID attribute defined in the internal subset : %s\n",
2972: attr->elem, nbId, attr->name);
2973: } else if (doc->extSubset != NULL) {
1.57 daniel 2974: int extId = 0;
1.54 daniel 2975: elem = xmlGetDtdElementDesc(doc->extSubset, attr->elem);
2976: if (elem != NULL) {
2977: extId = xmlScanIDAttributeDecl(NULL, elem);
2978: }
2979: if (extId > 1) {
2980: VERROR(ctxt->userData,
2981: "Element %s has %d ID attribute defined in the external subset : %s\n",
2982: attr->elem, extId, attr->name);
2983: } else if (extId + nbId > 1) {
2984: VERROR(ctxt->userData,
2985: "Element %s has ID attributes defined in the internal and external subset : %s\n",
2986: attr->elem, attr->name);
2987: }
2988: }
1.16 daniel 2989: }
1.14 daniel 2990:
1.59 daniel 2991: /* Validity Constraint: Enumeration */
2992: if ((attr->defaultValue != NULL) && (attr->tree != NULL)) {
2993: xmlEnumerationPtr tree = attr->tree;
2994: while (tree != NULL) {
2995: if (!xmlStrcmp(tree->name, attr->defaultValue)) break;
2996: tree = tree->next;
2997: }
2998: if (tree == NULL) {
2999: VERROR(ctxt->userData,
3000: "Default value \"%s\" for attribute %s on %s is not among the enumerated set\n",
3001: attr->defaultValue, attr->name, attr->elem);
3002: ret = 0;
3003: }
3004: }
3005:
1.16 daniel 3006: return(ret);
1.14 daniel 3007: }
3008:
3009: /**
3010: * xmlValidateElementDecl:
3011: * @ctxt: the validation context
3012: * @doc: a document instance
3013: * @elem: an element definition
3014: *
3015: * Try to validate a single element definition
3016: * basically it does the following checks as described by the
3017: * XML-1.0 recommendation:
3018: * - [ VC: One ID per Element Type ]
3019: * - [ VC: No Duplicate Types ]
3020: * - [ VC: Unique Element Type Declaration ]
3021: *
3022: * returns 1 if valid or 0 otherwise
3023: */
3024:
3025: int
1.16 daniel 3026: xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3027: xmlElementPtr elem) {
3028: int ret = 1;
3029: xmlElementPtr tst;
3030:
1.14 daniel 3031: CHECK_DTD;
1.16 daniel 3032:
3033: if (elem == NULL) return(1);
1.14 daniel 3034:
1.16 daniel 3035: /* No Duplicate Types */
1.49 daniel 3036: if (elem->etype == XML_ELEMENT_TYPE_MIXED) {
1.16 daniel 3037: xmlElementContentPtr cur, next;
1.31 daniel 3038: const xmlChar *name;
1.16 daniel 3039:
3040: cur = elem->content;
3041: while (cur != NULL) {
3042: if (cur->type != XML_ELEMENT_CONTENT_OR) break;
3043: if (cur->c1 == NULL) break;
3044: if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
3045: name = cur->c1->name;
3046: next = cur->c2;
3047: while (next != NULL) {
3048: if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
3049: if (!xmlStrcmp(next->name, name)) {
3050: VERROR(ctxt->userData,
3051: "Definition of %s has duplicate references of %s\n",
3052: elem->name, name);
3053: ret = 0;
3054: }
3055: break;
3056: }
3057: if (next->c1 == NULL) break;
3058: if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
3059: if (!xmlStrcmp(next->c1->name, name)) {
3060: VERROR(ctxt->userData,
3061: "Definition of %s has duplicate references of %s\n",
3062: elem->name, name);
3063: ret = 0;
3064: }
3065: next = next->c2;
3066: }
3067: }
3068: cur = cur->c2;
3069: }
3070: }
3071:
3072: /* VC: Unique Element Type Declaration */
3073: tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
3074: if ((tst != NULL ) && (tst != elem)) {
3075: VERROR(ctxt->userData, "Redefinition of element %s\n",
3076: elem->name);
3077: ret = 0;
3078: }
3079: tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
3080: if ((tst != NULL ) && (tst != elem)) {
3081: VERROR(ctxt->userData, "Redefinition of element %s\n",
3082: elem->name);
3083: ret = 0;
3084: }
3085:
3086: /* One ID per Element Type */
3087: if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
3088: ret = 0;
3089: }
3090: return(ret);
1.14 daniel 3091: }
3092:
3093: /**
3094: * xmlValidateOneAttribute:
3095: * @ctxt: the validation context
3096: * @doc: a document instance
3097: * @elem: an element instance
3098: * @attr: an attribute instance
1.32 daniel 3099: * @value: the attribute value (without entities processing)
1.14 daniel 3100: *
3101: * Try to validate a single attribute for an element
1.59 daniel 3102: * basically it does the following checks as described by the
1.14 daniel 3103: * XML-1.0 recommendation:
1.18 daniel 3104: * - [ VC: Attribute Value Type ]
3105: * - [ VC: Fixed Attribute Default ]
1.14 daniel 3106: * - [ VC: Entity Name ]
3107: * - [ VC: Name Token ]
3108: * - [ VC: ID ]
3109: * - [ VC: IDREF ]
3110: * - [ VC: Entity Name ]
1.16 daniel 3111: * - [ VC: Notation Attributes ]
1.14 daniel 3112: *
3113: * The ID/IDREF uniqueness and matching are done separately
3114: *
3115: * returns 1 if valid or 0 otherwise
3116: */
3117:
3118: int
1.16 daniel 3119: xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
1.31 daniel 3120: xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value) {
1.24 daniel 3121: /* xmlElementPtr elemDecl; */
1.62 daniel 3122: xmlAttributePtr attrDecl = NULL;
1.18 daniel 3123: int val;
3124: int ret = 1;
3125:
1.14 daniel 3126: CHECK_DTD;
1.18 daniel 3127: if ((elem == NULL) || (elem->name == NULL)) return(0);
3128: if ((attr == NULL) || (attr->name == NULL)) return(0);
3129:
1.62 daniel 3130: if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
3131: xmlChar qname[500];
3132: #ifdef HAVE_SNPRINTF
3133: snprintf((char *) qname, sizeof(qname), "%s:%s",
3134: elem->ns->prefix, elem->name);
3135: #else
3136: sprintf(qname, "%s:%s", elem->name, elem->ns->prefix);
3137: #endif
3138: if (attr->ns != NULL) {
3139: attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, qname,
3140: attr->name, attr->ns->prefix);
3141: if ((attrDecl == NULL) && (doc->extSubset != NULL))
3142: attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, qname,
3143: attr->name, attr->ns->prefix);
3144: } else {
3145: attrDecl = xmlGetDtdAttrDesc(doc->intSubset, qname, attr->name);
3146: if ((attrDecl == NULL) && (doc->extSubset != NULL))
3147: attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
3148: qname, attr->name);
3149: }
3150: }
3151: if (attrDecl == NULL) {
3152: if (attr->ns != NULL) {
3153: attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
3154: attr->name, attr->ns->prefix);
3155: if ((attrDecl == NULL) && (doc->extSubset != NULL))
3156: attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
3157: attr->name, attr->ns->prefix);
3158: } else {
3159: attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
3160: elem->name, attr->name);
3161: if ((attrDecl == NULL) && (doc->extSubset != NULL))
3162: attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
3163: elem->name, attr->name);
3164: }
3165: }
1.18 daniel 3166:
1.14 daniel 3167:
1.18 daniel 3168: /* Validity Constraint: Attribute Value Type */
3169: if (attrDecl == NULL) {
3170: VERROR(ctxt->userData,
3171: "No declaration for attribute %s on element %s\n",
3172: attr->name, elem->name);
3173: return(0);
3174: }
1.56 daniel 3175: attr->atype = attrDecl->atype;
3176:
1.48 daniel 3177: val = xmlValidateAttributeValue(attrDecl->atype, value);
1.18 daniel 3178: if (val == 0) {
3179: VERROR(ctxt->userData,
3180: "Syntax of value for attribute %s on %s is not valid\n",
3181: attr->name, elem->name);
3182: ret = 0;
1.22 daniel 3183: }
3184:
1.59 daniel 3185: /* Validity constraint: Fixed Attribute Default */
3186: if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
3187: if (xmlStrcmp(value, attrDecl->defaultValue)) {
3188: VERROR(ctxt->userData,
3189: "Value for attribute %s on %s is differnt from default \"%s\"\n",
3190: attr->name, elem->name, attrDecl->defaultValue);
3191: ret = 0;
3192: }
3193: }
3194:
1.22 daniel 3195: /* Validity Constraint: ID uniqueness */
1.48 daniel 3196: if (attrDecl->atype == XML_ATTRIBUTE_ID) {
1.22 daniel 3197: xmlAddID(ctxt, doc, value, attr);
1.18 daniel 3198: }
3199:
1.56 daniel 3200: if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
3201: (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
1.28 daniel 3202: xmlAddRef(ctxt, doc, value, attr);
3203: }
3204:
1.18 daniel 3205: /* Validity Constraint: Notation Attributes */
1.48 daniel 3206: if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
1.18 daniel 3207: xmlEnumerationPtr tree = attrDecl->tree;
3208: xmlNotationPtr nota;
3209:
3210: /* First check that the given NOTATION was declared */
3211: nota = xmlGetDtdNotationDesc(doc->intSubset, value);
3212: if (nota == NULL)
3213: nota = xmlGetDtdNotationDesc(doc->extSubset, value);
3214:
3215: if (nota == NULL) {
3216: VERROR(ctxt->userData,
3217: "Value \"%s\" for attribute %s on %s is not a declared Notation\n",
3218: value, attr->name, elem->name);
3219: ret = 0;
3220: }
3221:
3222: /* Second, verify that it's among the list */
3223: while (tree != NULL) {
3224: if (!xmlStrcmp(tree->name, value)) break;
3225: tree = tree->next;
3226: }
3227: if (tree == NULL) {
3228: VERROR(ctxt->userData,
1.50 daniel 3229: "Value \"%s\" for attribute %s on %s is not among the enumerated notations\n",
1.18 daniel 3230: value, attr->name, elem->name);
3231: ret = 0;
3232: }
3233: }
3234:
3235: /* Validity Constraint: Enumeration */
1.48 daniel 3236: if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
1.18 daniel 3237: xmlEnumerationPtr tree = attrDecl->tree;
3238: while (tree != NULL) {
3239: if (!xmlStrcmp(tree->name, value)) break;
3240: tree = tree->next;
3241: }
3242: if (tree == NULL) {
3243: VERROR(ctxt->userData,
1.48 daniel 3244: "Value \"%s\" for attribute %s on %s is not among the enumerated set\n",
1.18 daniel 3245: value, attr->name, elem->name);
3246: ret = 0;
3247: }
3248: }
3249:
3250: /* Fixed Attribute Default */
3251: if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
3252: (xmlStrcmp(attrDecl->defaultValue, value))) {
3253: VERROR(ctxt->userData,
3254: "Value for attribute %s on %s must be \"%s\"\n",
3255: attr->name, elem->name, attrDecl->defaultValue);
3256: ret = 0;
3257: }
3258:
1.59 daniel 3259: /* Extra check for the attribute value */
3260: ret &= xmlValidateAttributeValue2(ctxt, doc, attr->name,
3261: attrDecl->atype, value);
1.56 daniel 3262:
1.18 daniel 3263: return(ret);
3264: }
3265:
3266: int xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
3267: xmlElementContentPtr cont);
3268:
3269: /**
3270: * xmlValidateElementTypeExpr:
3271: * @ctxt: the validation context
3272: * @child: pointer to the child list
3273: * @cont: pointer to the content declaration
3274: *
3275: * Try to validate the content of an element of type element
3276: * but don't handle the occurence factor
3277: *
3278: * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
3279: * also update child value in-situ.
3280: */
3281:
3282: int
3283: xmlValidateElementTypeExpr(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
3284: xmlElementContentPtr cont) {
3285: xmlNodePtr cur;
3286: int ret = 1;
3287:
3288: if (cont == NULL) return(-1);
1.58 daniel 3289: DEBUG_VALID_STATE(*child, cont)
1.18 daniel 3290: while (*child != NULL) {
1.58 daniel 3291: if ((*child)->type == XML_ENTITY_REF_NODE) {
3292: /*
3293: * If there is an entity declared an it's not empty
3294: * Push the current node on the stack and process with the
3295: * entity content.
3296: */
3297: if (((*child)->children != NULL) &&
3298: ((*child)->children->children != NULL)) {
3299: nodeVPush(ctxt, *child);
3300: *child = (*child)->children->children;
3301: } else
3302: *child = (*child)->next;
3303: continue;
3304: }
1.18 daniel 3305: if ((*child)->type == XML_PI_NODE) {
3306: *child = (*child)->next;
3307: continue;
3308: }
3309: if ((*child)->type == XML_COMMENT_NODE) {
3310: *child = (*child)->next;
3311: continue;
3312: }
3313: else if ((*child)->type != XML_ELEMENT_NODE) {
3314: return(-1);
3315: }
3316: break;
3317: }
1.58 daniel 3318: DEBUG_VALID_STATE(*child, cont)
1.18 daniel 3319: switch (cont->type) {
3320: case XML_ELEMENT_CONTENT_PCDATA:
1.45 daniel 3321: if (*child == NULL) return(0);
3322: if ((*child)->type == XML_TEXT_NODE) return(1);
3323: return(0);
1.18 daniel 3324: case XML_ELEMENT_CONTENT_ELEMENT:
1.20 daniel 3325: if (*child == NULL) return(0);
1.18 daniel 3326: ret = (!xmlStrcmp((*child)->name, cont->name));
1.58 daniel 3327: if (ret == 1) {
3328: while ((*child)->next == NULL) {
3329: if (((*child)->parent != NULL) &&
3330: ((*child)->parent->type == XML_ENTITY_DECL)) {
3331: *child = nodeVPop(ctxt);
3332: } else
3333: break;
3334: }
1.18 daniel 3335: *child = (*child)->next;
1.58 daniel 3336: }
1.18 daniel 3337: return(ret);
3338: case XML_ELEMENT_CONTENT_OR:
3339: cur = *child;
3340: ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
3341: if (ret == -1) return(-1);
3342: if (ret == 1) {
3343: return(1);
3344: }
3345: /* rollback and retry the other path */
3346: *child = cur;
3347: ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
3348: if (ret == -1) return(-1);
3349: if (ret == 0) {
3350: *child = cur;
3351: return(0);
3352: }
3353: return(1);
3354: case XML_ELEMENT_CONTENT_SEQ:
3355: cur = *child;
3356: ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
3357: if (ret == -1) return(-1);
3358: if (ret == 0) {
3359: *child = cur;
3360: return(0);
3361: }
3362: ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
3363: if (ret == -1) return(-1);
3364: if (ret == 0) {
3365: *child = cur;
3366: return(0);
3367: }
3368: return(1);
3369: }
3370: return(ret);
3371: }
3372:
3373: /**
3374: * xmlValidateElementTypeElement:
3375: * @ctxt: the validation context
3376: * @child: pointer to the child list
3377: * @cont: pointer to the content declaration
3378: *
3379: * Try to validate the content of an element of type element
3380: * yeah, Yet Another Regexp Implementation, and recursive
3381: *
3382: * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
3383: * also update child and content values in-situ.
3384: */
3385:
3386: int
3387: xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
3388: xmlElementContentPtr cont) {
3389: xmlNodePtr cur;
3390: int ret = 1;
3391:
3392: if (cont == NULL) return(-1);
1.58 daniel 3393:
3394: DEBUG_VALID_STATE(*child, cont)
1.18 daniel 3395: while (*child != NULL) {
1.58 daniel 3396: if ((*child)->type == XML_ENTITY_REF_NODE) {
3397: /*
3398: * If there is an entity declared an it's not empty
3399: * Push the current node on the stack and process with the
3400: * entity content.
3401: */
3402: if (((*child)->children != NULL) &&
3403: ((*child)->children->children != NULL)) {
3404: nodeVPush(ctxt, *child);
3405: *child = (*child)->children->children;
3406: } else
3407: *child = (*child)->next;
3408: continue;
3409: }
1.18 daniel 3410: if ((*child)->type == XML_PI_NODE) {
3411: *child = (*child)->next;
3412: continue;
3413: }
3414: if ((*child)->type == XML_COMMENT_NODE) {
3415: *child = (*child)->next;
3416: continue;
3417: }
3418: else if ((*child)->type != XML_ELEMENT_NODE) {
3419: return(-1);
3420: }
3421: break;
3422: }
1.58 daniel 3423: DEBUG_VALID_STATE(*child, cont)
1.18 daniel 3424: cur = *child;
3425: ret = xmlValidateElementTypeExpr(ctxt, child, cont);
3426: if (ret == -1) return(-1);
3427: switch (cont->ocur) {
3428: case XML_ELEMENT_CONTENT_ONCE:
3429: if (ret == 1) {
1.48 daniel 3430: /* skip ignorable elems */
3431: while ((*child != NULL) &&
3432: (((*child)->type == XML_PI_NODE) ||
3433: ((*child)->type == XML_COMMENT_NODE))) {
1.58 daniel 3434: while ((*child)->next == NULL) {
3435: if (((*child)->parent != NULL) &&
3436: ((*child)->parent->type == XML_ENTITY_REF_NODE)) {
3437: *child = (*child)->parent;
3438: } else
3439: break;
3440: }
3441: *child = (*child)->next;
1.48 daniel 3442: }
1.18 daniel 3443: return(1);
3444: }
3445: *child = cur;
3446: return(0);
3447: case XML_ELEMENT_CONTENT_OPT:
3448: if (ret == 0) {
3449: *child = cur;
3450: return(1);
3451: }
1.19 daniel 3452: break;
1.18 daniel 3453: case XML_ELEMENT_CONTENT_MULT:
3454: if (ret == 0) {
3455: *child = cur;
1.19 daniel 3456: break;
1.18 daniel 3457: }
3458: /* no break on purpose */
3459: case XML_ELEMENT_CONTENT_PLUS:
3460: if (ret == 0) {
3461: *child = cur;
3462: return(0);
3463: }
3464: do {
3465: cur = *child;
3466: ret = xmlValidateElementTypeExpr(ctxt, child, cont);
3467: } while (ret == 1);
3468: if (ret == -1) return(-1);
3469: *child = cur;
1.19 daniel 3470: break;
3471: }
3472: while (*child != NULL) {
1.58 daniel 3473: if ((*child)->type == XML_ENTITY_REF_NODE) {
3474: /*
3475: * If there is an entity declared an it's not empty
3476: * Push the current node on the stack and process with the
3477: * entity content.
3478: */
3479: if (((*child)->children != NULL) &&
3480: ((*child)->children->children != NULL)) {
3481: nodeVPush(ctxt, *child);
3482: *child = (*child)->children->children;
3483: } else
3484: *child = (*child)->next;
3485: continue;
3486: }
1.19 daniel 3487: if ((*child)->type == XML_PI_NODE) {
3488: *child = (*child)->next;
3489: continue;
3490: }
3491: if ((*child)->type == XML_COMMENT_NODE) {
3492: *child = (*child)->next;
3493: continue;
3494: }
3495: else if ((*child)->type != XML_ELEMENT_NODE) {
3496: return(-1);
3497: }
3498: break;
3499: }
3500: return(1);
3501: }
3502:
3503: /**
3504: * xmlSprintfElementChilds:
3505: * @buf: an output buffer
3506: * @content: An element
3507: * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
3508: *
3509: * This will dump the list of childs to the buffer
3510: * Intended just for the debug routine
3511: */
3512: void
3513: xmlSprintfElementChilds(char *buf, xmlNodePtr node, int glob) {
3514: xmlNodePtr cur;
3515:
3516: if (node == NULL) return;
3517: if (glob) strcat(buf, "(");
1.46 daniel 3518: cur = node->children;
1.19 daniel 3519: while (cur != NULL) {
3520: switch (cur->type) {
3521: case XML_ELEMENT_NODE:
1.23 daniel 3522: strcat(buf, (char *) cur->name);
1.19 daniel 3523: if (cur->next != NULL)
3524: strcat(buf, " ");
3525: break;
3526: case XML_TEXT_NODE:
3527: case XML_CDATA_SECTION_NODE:
3528: case XML_ENTITY_REF_NODE:
3529: strcat(buf, "CDATA");
3530: if (cur->next != NULL)
3531: strcat(buf, " ");
3532: break;
3533: case XML_ATTRIBUTE_NODE:
3534: case XML_DOCUMENT_NODE:
1.35 daniel 3535: case XML_HTML_DOCUMENT_NODE:
1.19 daniel 3536: case XML_DOCUMENT_TYPE_NODE:
3537: case XML_DOCUMENT_FRAG_NODE:
3538: case XML_NOTATION_NODE:
3539: strcat(buf, "???");
3540: if (cur->next != NULL)
3541: strcat(buf, " ");
3542: break;
3543: case XML_ENTITY_NODE:
3544: case XML_PI_NODE:
1.46 daniel 3545: case XML_DTD_NODE:
1.19 daniel 3546: case XML_COMMENT_NODE:
1.47 daniel 3547: case XML_ELEMENT_DECL:
3548: case XML_ATTRIBUTE_DECL:
1.53 daniel 3549: case XML_ENTITY_DECL:
1.19 daniel 3550: break;
3551: }
3552: cur = cur->next;
1.18 daniel 3553: }
1.19 daniel 3554: if (glob) strcat(buf, ")");
1.14 daniel 3555: }
3556:
1.19 daniel 3557:
1.14 daniel 3558: /**
3559: * xmlValidateOneElement:
3560: * @ctxt: the validation context
3561: * @doc: a document instance
3562: * @elem: an element instance
3563: *
3564: * Try to validate a single element and it's attributes,
3565: * basically it does the following checks as described by the
3566: * XML-1.0 recommendation:
3567: * - [ VC: Element Valid ]
3568: * - [ VC: Required Attribute ]
3569: * Then call xmlValidateOneAttribute() for each attribute present.
3570: *
3571: * The ID/IDREF checkings are done separately
3572: *
3573: * returns 1 if valid or 0 otherwise
3574: */
3575:
3576: int
1.16 daniel 3577: xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
1.18 daniel 3578: xmlNodePtr elem) {
1.62 daniel 3579: xmlElementPtr elemDecl = NULL;
1.18 daniel 3580: xmlElementContentPtr cont;
1.42 daniel 3581: xmlAttributePtr attr;
1.18 daniel 3582: xmlNodePtr child;
3583: int ret = 1;
1.31 daniel 3584: const xmlChar *name;
1.18 daniel 3585:
1.14 daniel 3586: CHECK_DTD;
3587:
1.39 daniel 3588: if (elem == NULL) return(0);
3589: if (elem->type == XML_TEXT_NODE) {
1.40 daniel 3590: }
3591: switch (elem->type) {
3592: case XML_ATTRIBUTE_NODE:
3593: VERROR(ctxt->userData,
3594: "Attribute element not expected here\n");
1.39 daniel 3595: return(0);
1.40 daniel 3596: case XML_TEXT_NODE:
1.46 daniel 3597: if (elem->children != NULL) {
1.40 daniel 3598: VERROR(ctxt->userData, "Text element has childs !\n");
3599: return(0);
3600: }
3601: if (elem->properties != NULL) {
3602: VERROR(ctxt->userData, "Text element has attributes !\n");
3603: return(0);
3604: }
3605: if (elem->ns != NULL) {
3606: VERROR(ctxt->userData, "Text element has namespace !\n");
3607: return(0);
3608: }
1.66 veillard 3609: if (elem->nsDef != NULL) {
1.40 daniel 3610: VERROR(ctxt->userData,
3611: "Text element carries namespace definitions !\n");
3612: return(0);
3613: }
3614: if (elem->content == NULL) {
3615: VERROR(ctxt->userData,
3616: "Text element has no content !\n");
3617: return(0);
3618: }
3619: return(1);
3620: case XML_CDATA_SECTION_NODE:
3621: case XML_ENTITY_REF_NODE:
3622: case XML_PI_NODE:
3623: case XML_COMMENT_NODE:
3624: return(1);
3625: case XML_ENTITY_NODE:
3626: VERROR(ctxt->userData,
3627: "Entity element not expected here\n");
1.39 daniel 3628: return(0);
1.40 daniel 3629: case XML_NOTATION_NODE:
3630: VERROR(ctxt->userData,
3631: "Notation element not expected here\n");
3632: return(0);
3633: case XML_DOCUMENT_NODE:
3634: case XML_DOCUMENT_TYPE_NODE:
3635: case XML_DOCUMENT_FRAG_NODE:
3636: VERROR(ctxt->userData,
3637: "Document element not expected here\n");
1.39 daniel 3638: return(0);
1.40 daniel 3639: case XML_HTML_DOCUMENT_NODE:
1.39 daniel 3640: VERROR(ctxt->userData,
1.40 daniel 3641: "\n");
1.39 daniel 3642: return(0);
1.40 daniel 3643: case XML_ELEMENT_NODE:
3644: break;
3645: default:
1.39 daniel 3646: VERROR(ctxt->userData,
1.40 daniel 3647: "unknown element type %d\n", elem->type);
1.39 daniel 3648: return(0);
3649: }
3650: if (elem->name == NULL) return(0);
1.18 daniel 3651:
1.62 daniel 3652: /*
3653: * Fetch the declaration for the qualified name
3654: */
3655: if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
3656: elemDecl = xmlGetDtdQElementDesc(doc->intSubset,
3657: elem->name, elem->ns->prefix);
3658: if ((elemDecl == NULL) && (doc->extSubset != NULL))
3659: elemDecl = xmlGetDtdQElementDesc(doc->extSubset,
3660: elem->name, elem->ns->prefix);
3661: }
3662:
3663: /*
3664: * Fetch the declaration for the non qualified name
3665: */
3666: if (elemDecl == NULL) {
3667: elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
3668: if ((elemDecl == NULL) && (doc->extSubset != NULL))
3669: elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
3670: }
1.18 daniel 3671: if (elemDecl == NULL) {
3672: VERROR(ctxt->userData, "No declaration for element %s\n",
3673: elem->name);
3674: return(0);
3675: }
3676:
3677: /* Check taht the element content matches the definition */
1.47 daniel 3678: switch (elemDecl->etype) {
1.18 daniel 3679: case XML_ELEMENT_TYPE_EMPTY:
1.46 daniel 3680: if (elem->children != NULL) {
1.18 daniel 3681: VERROR(ctxt->userData,
3682: "Element %s was declared EMPTY this one has content\n",
3683: elem->name);
3684: ret = 0;
3685: }
3686: break;
3687: case XML_ELEMENT_TYPE_ANY:
3688: /* I don't think anything is required then */
3689: break;
3690: case XML_ELEMENT_TYPE_MIXED:
3691: /* Hum, this start to get messy */
1.46 daniel 3692: child = elem->children;
1.18 daniel 3693: while (child != NULL) {
3694: if (child->type == XML_ELEMENT_NODE) {
3695: name = child->name;
1.62 daniel 3696: if ((child->ns != NULL) && (child->ns->prefix != NULL)) {
3697: xmlChar qname[500];
3698: #ifdef HAVE_SNPRINTF
3699: snprintf((char *) qname, sizeof(qname), "%s:%s",
3700: child->ns->prefix, child->name);
3701: #else
3702: sprintf(qname, "%s:%s", child->name, child->ns->prefix);
3703: #endif
3704: cont = elemDecl->content;
3705: while (cont != NULL) {
3706: if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
3707: if (!xmlStrcmp(cont->name, qname)) break;
3708: } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
3709: (cont->c1 != NULL) &&
3710: (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
3711: if (!xmlStrcmp(cont->c1->name, qname)) break;
3712: } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
3713: (cont->c1 == NULL) ||
3714: (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
3715: /* Internal error !!! */
3716: fprintf(stderr, "Internal: MIXED struct bad\n");
3717: break;
3718: }
3719: cont = cont->c2;
3720: }
3721: if (cont != NULL)
3722: goto child_ok;
3723: }
1.18 daniel 3724: cont = elemDecl->content;
3725: while (cont != NULL) {
3726: if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
3727: if (!xmlStrcmp(cont->name, name)) break;
3728: } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
3729: (cont->c1 != NULL) &&
3730: (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
3731: if (!xmlStrcmp(cont->c1->name, name)) break;
3732: } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
3733: (cont->c1 == NULL) ||
3734: (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
3735: /* Internal error !!! */
3736: fprintf(stderr, "Internal: MIXED struct bad\n");
3737: break;
3738: }
3739: cont = cont->c2;
3740: }
3741: if (cont == NULL) {
3742: VERROR(ctxt->userData,
3743: "Element %s is not declared in %s list of possible childs\n",
3744: name, elem->name);
3745: ret = 0;
3746: }
3747: }
1.62 daniel 3748: child_ok:
1.18 daniel 3749: child = child->next;
3750: }
3751: break;
3752: case XML_ELEMENT_TYPE_ELEMENT:
1.46 daniel 3753: child = elem->children;
1.18 daniel 3754: cont = elemDecl->content;
3755: ret = xmlValidateElementTypeElement(ctxt, &child, cont);
1.19 daniel 3756: if ((ret == 0) || (child != NULL)) {
3757: char expr[1000];
3758: char list[2000];
3759:
3760: expr[0] = 0;
3761: xmlSprintfElementContent(expr, cont, 1);
3762: list[0] = 0;
3763: xmlSprintfElementChilds(list, elem, 1);
3764:
1.18 daniel 3765: VERROR(ctxt->userData,
1.19 daniel 3766: "Element %s content doesn't follow the Dtd\nExpecting %s, got %s\n",
3767: elem->name, expr, list);
1.18 daniel 3768: ret = 0;
3769: }
3770: break;
3771: }
3772:
1.42 daniel 3773: /* [ VC: Required Attribute ] */
3774: attr = elemDecl->attributes;
3775: while (attr != NULL) {
3776: if (attr->def == XML_ATTRIBUTE_REQUIRED) {
3777: xmlAttrPtr attrib;
3778: int qualified = -1;
3779:
3780: attrib = elem->properties;
3781: while (attrib != NULL) {
3782: if (!xmlStrcmp(attrib->name, attr->name)) {
3783: if (attr->prefix != NULL) {
3784: xmlNsPtr nameSpace = attrib->ns;
3785:
3786: if (nameSpace == NULL)
3787: nameSpace = elem->ns;
3788: /*
3789: * qualified names handling is problematic, having a
3790: * different prefix should be possible but DTDs don't
3791: * allow to define the URI instead of the prefix :-(
3792: */
3793: if (nameSpace == NULL) {
3794: if (qualified < 0)
3795: qualified = 0;
3796: } else if (xmlStrcmp(nameSpace->prefix, attr->prefix)) {
3797: if (qualified < 1)
3798: qualified = 1;
3799: } else
3800: goto found;
3801: } else {
3802: /*
3803: * We should allow applications to define namespaces
3804: * for their application even if the DTD doesn't
3805: * carry one, otherwise, basically we would always
3806: * break.
3807: */
3808: goto found;
3809: }
3810: }
3811: attrib = attrib->next;
3812: }
3813: if (qualified == -1) {
3814: if (attr->prefix == NULL) {
3815: VERROR(ctxt->userData,
3816: "Element %s doesn't carry attribute %s\n",
3817: elem->name, attr->name);
3818: } else {
3819: VERROR(ctxt->userData,
3820: "Element %s doesn't carry attribute %s:%s\n",
3821: elem->name, attr->prefix,attr->name);
3822: }
3823: } else if (qualified == 0) {
3824: VWARNING(ctxt->userData,
3825: "Element %s required attribute %s:%s has no prefix\n",
3826: elem->name, attr->prefix,attr->name);
3827: } else if (qualified == 1) {
3828: VWARNING(ctxt->userData,
3829: "Element %s required attribute %s:%s has different prefix\n",
3830: elem->name, attr->prefix,attr->name);
3831: }
3832: }
3833: found:
1.47 daniel 3834: attr = attr->nexth;
1.42 daniel 3835: }
1.18 daniel 3836: return(ret);
1.14 daniel 3837: }
3838:
3839: /**
3840: * xmlValidateRoot:
3841: * @ctxt: the validation context
3842: * @doc: a document instance
3843: *
3844: * Try to validate a the root element
3845: * basically it does the following check as described by the
3846: * XML-1.0 recommendation:
3847: * - [ VC: Root Element Type ]
3848: * it doesn't try to recurse or apply other check to the element
3849: *
3850: * returns 1 if valid or 0 otherwise
3851: */
3852:
3853: int
3854: xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
1.39 daniel 3855: xmlNodePtr root;
1.14 daniel 3856: if (doc == NULL) return(0);
3857:
3858: if ((doc->intSubset == NULL) ||
3859: (doc->intSubset->name == NULL)) {
3860: VERROR(ctxt->userData, "Not valid: no DtD found\n");
3861: return(0);
3862: }
1.39 daniel 3863: root = xmlDocGetRootElement(doc);
3864: if ((root == NULL) || (root->name == NULL)) {
1.14 daniel 3865: VERROR(ctxt->userData, "Not valid: no root element\n");
3866: return(0);
3867: }
1.62 daniel 3868:
3869: /*
3870: * Check first the document root against the NQName
3871: */
1.39 daniel 3872: if (xmlStrcmp(doc->intSubset->name, root->name)) {
1.62 daniel 3873: if ((root->ns != NULL) && (root->ns->prefix != NULL)) {
3874: xmlChar qname[500];
3875: #ifdef HAVE_SNPRINTF
3876: snprintf((char *) qname, sizeof(qname), "%s:%s",
3877: root->ns->prefix, root->name);
3878: #else
3879: sprintf(qname, "%s:%s", root->name, root->ns->prefix);
3880: #endif
3881: if (!xmlStrcmp(doc->intSubset->name, qname))
3882: goto name_ok;
3883: }
3884: if ((!xmlStrcmp(doc->intSubset->name, BAD_CAST "HTML")) &&
3885: (!xmlStrcmp(root->name, BAD_CAST "html")))
3886: goto name_ok;
3887: VERROR(ctxt->userData,
3888: "Not valid: root and DtD name do not match '%s' and '%s'\n",
3889: root->name, doc->intSubset->name);
3890: return(0);
3891:
1.14 daniel 3892: }
1.62 daniel 3893: name_ok:
1.14 daniel 3894: return(1);
3895: }
3896:
3897:
3898: /**
3899: * xmlValidateElement:
3900: * @ctxt: the validation context
3901: * @doc: a document instance
3902: * @elem: an element instance
3903: *
3904: * Try to validate the subtree under an element
3905: *
3906: * returns 1 if valid or 0 otherwise
3907: */
3908:
3909: int
1.18 daniel 3910: xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
1.27 daniel 3911: xmlNodePtr child;
3912: xmlAttrPtr attr;
1.31 daniel 3913: xmlChar *value;
1.27 daniel 3914: int ret = 1;
3915:
3916: if (elem == NULL) return(0);
1.14 daniel 3917: CHECK_DTD;
3918:
1.27 daniel 3919: ret &= xmlValidateOneElement(ctxt, doc, elem);
3920: attr = elem->properties;
3921: while(attr != NULL) {
1.46 daniel 3922: value = xmlNodeListGetString(doc, attr->children, 0);
1.27 daniel 3923: ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
3924: if (value != NULL)
1.39 daniel 3925: xmlFree(value);
1.27 daniel 3926: attr= attr->next;
3927: }
1.46 daniel 3928: child = elem->children;
1.27 daniel 3929: while (child != NULL) {
3930: ret &= xmlValidateElement(ctxt, doc, child);
3931: child = child->next;
3932: }
3933:
3934: return(ret);
1.14 daniel 3935: }
3936:
3937: /**
1.28 daniel 3938: * xmlValidateDocumentFinal:
3939: * @ctxt: the validation context
3940: * @doc: a document instance
3941: *
3942: * Does the final step for the document validation once all the
3943: * incremental validation steps have been completed
3944: *
3945: * basically it does the following checks described by the XML Rec
3946: *
3947: *
3948: * returns 1 if valid or 0 otherwise
3949: */
3950:
3951: int
3952: xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
3953: int ret = 1, i;
3954: xmlRefTablePtr table;
3955: xmlAttrPtr id;
3956:
3957: if (doc == NULL) {
3958: fprintf(stderr, "xmlValidateDocumentFinal: doc == NULL\n");
3959: return(0);
3960: }
3961:
3962: /*
1.56 daniel 3963: * Check all the NOTATION/NOTATIONS attributes
3964: */
3965: /*
3966: * Check all the ENTITY/ENTITIES attributes definition for validity
3967: */
3968: /*
3969: * Check all the IDREF/IDREFS attributes definition for validity
1.28 daniel 3970: */
1.64 veillard 3971: table = (xmlRefTablePtr) doc->refs;
1.28 daniel 3972: if (table != NULL) {
3973: for (i = 0; i < table->nb_refs; i++) {
1.56 daniel 3974: if (table->table[i]->attr->atype == XML_ATTRIBUTE_IDREF) {
3975: id = xmlGetID(doc, table->table[i]->value);
3976: if (id == NULL) {
3977: VERROR(ctxt->userData,
1.55 daniel 3978: "IDREF attribute %s reference an unknown ID \"%s\"\n",
1.56 daniel 3979: table->table[i]->attr->name, table->table[i]->value);
3980: ret = 0;
3981: }
3982: } else if (table->table[i]->attr->atype == XML_ATTRIBUTE_IDREFS) {
1.57 daniel 3983: xmlChar *dup, *name = NULL, *cur, save;
1.56 daniel 3984:
3985: dup = xmlStrdup(table->table[i]->value);
3986: if (dup == NULL)
3987: return(0);
3988: cur = dup;
1.57 daniel 3989: while (*cur != 0) {
1.56 daniel 3990: name = cur;
3991: while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
3992: save = *cur;
3993: *cur = 0;
3994: id = xmlGetID(doc, name);
3995: if (id == NULL) {
3996: VERROR(ctxt->userData,
3997: "IDREFS attribute %s reference an unknown ID \"%s\"\n",
3998: table->table[i]->attr->name, name);
3999: ret = 0;
4000: }
4001: if (save == 0)
4002: break;
4003: *cur = save;
4004: while (IS_BLANK(*cur)) cur++;
4005: }
4006: xmlFree(dup);
1.28 daniel 4007: }
4008: }
4009: }
4010: return(ret);
4011: }
4012:
4013: /**
1.14 daniel 4014: * xmlValidateDtd:
4015: * @ctxt: the validation context
4016: * @doc: a document instance
4017: * @dtd: a dtd instance
4018: *
1.39 daniel 4019: * Try to validate the document against the dtd instance
1.14 daniel 4020: *
4021: * basically it does check all the definitions in the DtD.
4022: *
4023: * returns 1 if valid or 0 otherwise
4024: */
4025:
4026: int
4027: xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
1.39 daniel 4028: int ret;
4029: xmlDtdPtr oldExt;
4030: xmlNodePtr root;
4031:
4032: if (dtd == NULL) return(0);
4033: if (doc == NULL) return(0);
4034: oldExt = doc->extSubset;
4035: doc->extSubset = dtd;
4036: ret = xmlValidateRoot(ctxt, doc);
4037: if (ret == 0) {
4038: doc->extSubset = oldExt;
4039: return(ret);
4040: }
4041: root = xmlDocGetRootElement(doc);
4042: ret = xmlValidateElement(ctxt, doc, root);
4043: ret &= xmlValidateDocumentFinal(ctxt, doc);
4044: doc->extSubset = oldExt;
4045: return(ret);
1.14 daniel 4046: }
4047:
4048: /**
1.59 daniel 4049: * xmlValidateDtdFinal:
4050: * @ctxt: the validation context
4051: * @doc: a document instance
4052: *
4053: * Does the final step for the dtds validation once all the
4054: * subsets have been parsed
4055: *
4056: * basically it does the following checks described by the XML Rec
4057: * - check that ENTITY and ENTITIES type attributes default or
4058: * possible values matches one of the defined entities.
4059: * - check that NOTATION type attributes default or
4060: * possible values matches one of the defined notations.
4061: *
4062: * returns 1 if valid or 0 otherwise
4063: */
4064:
4065: int
4066: xmlValidateDtdFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
4067: int ret = 1, i;
4068: xmlDtdPtr dtd;
4069: xmlAttributeTablePtr table;
4070: xmlAttributePtr cur;
4071:
4072: if (doc == NULL) return(0);
4073: if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
4074: return(0);
4075: dtd = doc->intSubset;
4076: if ((dtd != NULL) && (dtd->attributes != NULL)) {
1.64 veillard 4077: table = (xmlAttributeTablePtr) dtd->attributes;
1.59 daniel 4078:
4079: for (i = 0;i < table->nb_attributes;i++) {
4080: cur = table->table[i];
4081: switch (cur->atype) {
4082: case XML_ATTRIBUTE_CDATA:
4083: case XML_ATTRIBUTE_ID:
4084: case XML_ATTRIBUTE_IDREF :
4085: case XML_ATTRIBUTE_IDREFS:
4086: case XML_ATTRIBUTE_NMTOKEN:
4087: case XML_ATTRIBUTE_NMTOKENS:
4088: case XML_ATTRIBUTE_ENUMERATION:
4089: break;
4090: case XML_ATTRIBUTE_ENTITY:
4091: case XML_ATTRIBUTE_ENTITIES:
4092: case XML_ATTRIBUTE_NOTATION:
4093: if (cur->defaultValue != NULL) {
4094: ret &= xmlValidateAttributeValue2(ctxt, doc, cur->name,
4095: cur->atype, cur->defaultValue);
4096: }
4097: if (cur->tree != NULL) {
4098: xmlEnumerationPtr tree = cur->tree;
4099: while (tree != NULL) {
4100: ret &= xmlValidateAttributeValue2(ctxt, doc,
4101: cur->name, cur->atype, tree->name);
4102: tree = tree->next;
4103: }
4104: }
4105: }
4106: }
4107: }
4108: dtd = doc->extSubset;
4109: if ((dtd != NULL) && (dtd->attributes != NULL)) {
1.64 veillard 4110: table = (xmlAttributeTablePtr) dtd->attributes;
1.59 daniel 4111:
4112: for (i = 0;i < table->nb_attributes;i++) {
4113: cur = table->table[i];
4114: switch (cur->atype) {
4115: case XML_ATTRIBUTE_CDATA:
4116: case XML_ATTRIBUTE_ID:
4117: case XML_ATTRIBUTE_IDREF :
4118: case XML_ATTRIBUTE_IDREFS:
4119: case XML_ATTRIBUTE_NMTOKEN:
4120: case XML_ATTRIBUTE_NMTOKENS:
4121: case XML_ATTRIBUTE_ENUMERATION:
4122: break;
4123: case XML_ATTRIBUTE_ENTITY:
4124: case XML_ATTRIBUTE_ENTITIES:
4125: case XML_ATTRIBUTE_NOTATION:
4126: if (cur->defaultValue != NULL) {
4127: ret &= xmlValidateAttributeValue2(ctxt, doc, cur->name,
4128: cur->atype, cur->defaultValue);
4129: }
4130: if (cur->tree != NULL) {
4131: xmlEnumerationPtr tree = cur->tree;
4132: while (tree != NULL) {
4133: ret &= xmlValidateAttributeValue2(ctxt, doc,
4134: cur->name, cur->atype, tree->name);
4135: tree = tree->next;
4136: }
4137: }
4138: }
4139: }
4140: }
4141: return(ret);
4142: }
4143:
4144: /**
1.14 daniel 4145: * xmlValidateDocument:
4146: * @ctxt: the validation context
4147: * @doc: a document instance
4148: *
4149: * Try to validate the document instance
4150: *
1.27 daniel 4151: * basically it does the all the checks described by the XML Rec
1.14 daniel 4152: * i.e. validates the internal and external subset (if present)
4153: * and validate the document tree.
4154: *
4155: * returns 1 if valid or 0 otherwise
4156: */
4157:
4158: int
4159: xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
1.27 daniel 4160: int ret;
1.39 daniel 4161: xmlNodePtr root;
4162:
4163: if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
4164: return(0);
4165: if ((doc->intSubset != NULL) && ((doc->intSubset->SystemID != NULL) ||
4166: (doc->intSubset->ExternalID != NULL)) && (doc->extSubset == NULL)) {
4167: doc->extSubset = xmlParseDTD(doc->intSubset->ExternalID,
4168: doc->intSubset->SystemID);
4169: if (doc->extSubset == NULL) {
4170: if (doc->intSubset->SystemID != NULL) {
4171: VERROR(ctxt->userData,
1.55 daniel 4172: "Could not load the external subset \"%s\"\n",
1.39 daniel 4173: doc->intSubset->SystemID);
4174: } else {
4175: VERROR(ctxt->userData,
1.55 daniel 4176: "Could not load the external subset \"%s\"\n",
1.39 daniel 4177: doc->intSubset->ExternalID);
4178: }
4179: return(0);
4180: }
4181: }
1.27 daniel 4182:
1.59 daniel 4183: ret = xmlValidateDtdFinal(ctxt, doc);
1.14 daniel 4184: if (!xmlValidateRoot(ctxt, doc)) return(0);
4185:
1.39 daniel 4186: root = xmlDocGetRootElement(doc);
1.59 daniel 4187: ret &= xmlValidateElement(ctxt, doc, root);
1.28 daniel 4188: ret &= xmlValidateDocumentFinal(ctxt, doc);
4189: return(ret);
1.14 daniel 4190: }
4191:
1.33 daniel 4192:
4193: /************************************************************************
4194: * *
4195: * Routines for dynamic validation editing *
4196: * *
4197: ************************************************************************/
4198:
4199: /**
1.34 daniel 4200: * xmlValidGetPotentialChildren:
4201: * @ctree: an element content tree
4202: * @list: an array to store the list of child names
4203: * @len: a pointer to the number of element in the list
4204: * @max: the size of the array
1.33 daniel 4205: *
1.34 daniel 4206: * Build/extend a list of potential children allowed by the content tree
1.33 daniel 4207: *
1.34 daniel 4208: * returns the number of element in the list, or -1 in case of error.
1.33 daniel 4209: */
4210:
1.34 daniel 4211: int
4212: xmlValidGetPotentialChildren(xmlElementContent *ctree, const xmlChar **list,
4213: int *len, int max) {
4214: int i;
4215:
4216: if ((ctree == NULL) || (list == NULL) || (len == NULL))
4217: return(-1);
4218: if (*len >= max) return(*len);
4219:
4220: switch (ctree->type) {
4221: case XML_ELEMENT_CONTENT_PCDATA:
4222: for (i = 0; i < *len;i++)
1.37 daniel 4223: if (!xmlStrcmp(BAD_CAST "#PCDATA", list[i])) return(*len);
4224: list[(*len)++] = BAD_CAST "#PCDATA";
1.34 daniel 4225: break;
4226: case XML_ELEMENT_CONTENT_ELEMENT:
4227: for (i = 0; i < *len;i++)
4228: if (!xmlStrcmp(ctree->name, list[i])) return(*len);
4229: list[(*len)++] = ctree->name;
4230: break;
4231: case XML_ELEMENT_CONTENT_SEQ:
4232: xmlValidGetPotentialChildren(ctree->c1, list, len, max);
4233: xmlValidGetPotentialChildren(ctree->c2, list, len, max);
4234: break;
4235: case XML_ELEMENT_CONTENT_OR:
4236: xmlValidGetPotentialChildren(ctree->c1, list, len, max);
4237: xmlValidGetPotentialChildren(ctree->c2, list, len, max);
4238: break;
4239: }
4240:
4241: return(*len);
1.33 daniel 4242: }
4243:
4244: /**
1.34 daniel 4245: * xmlValidGetValidElements:
4246: * @prev: an element to insert after
4247: * @next: an element to insert next
4248: * @list: an array to store the list of child names
4249: * @max: the size of the array
1.33 daniel 4250: *
1.34 daniel 4251: * This function returns the list of authorized children to insert
4252: * within an existing tree while respecting the validity constraints
4253: * forced by the Dtd. The insertion point is defined using @prev and
4254: * @next in the following ways:
4255: * to insert before 'node': xmlValidGetValidElements(node->prev, node, ...
4256: * to insert next 'node': xmlValidGetValidElements(node, node->next, ...
4257: * to replace 'node': xmlValidGetValidElements(node->prev, node->next, ...
4258: * to prepend a child to 'node': xmlValidGetValidElements(NULL, node->childs,
4259: * to append a child to 'node': xmlValidGetValidElements(node->last, NULL, ...
1.33 daniel 4260: *
1.34 daniel 4261: * pointers to the element names are inserted at the beginning of the array
4262: * and do not need to be freed.
4263: *
4264: * returns the number of element in the list, or -1 in case of error. If
4265: * the function returns the value @max the caller is invited to grow the
4266: * receiving array and retry.
1.33 daniel 4267: */
4268:
1.34 daniel 4269: int
4270: xmlValidGetValidElements(xmlNode *prev, xmlNode *next, const xmlChar **list,
4271: int max) {
4272: int nb_valid_elements = 0;
4273: const xmlChar *elements[256];
4274: int nb_elements = 0, i;
4275:
4276: xmlNode *ref_node;
4277: xmlNode *parent;
4278: xmlNode *test_node;
4279:
4280: xmlNode *prev_next;
4281: xmlNode *next_prev;
4282: xmlNode *parent_childs;
4283: xmlNode *parent_last;
4284:
4285: xmlElement *element_desc;
4286:
4287: if (prev == NULL && next == NULL)
4288: return(-1);
4289:
4290: if (list == NULL) return(-1);
4291: if (max <= 0) return(-1);
4292:
4293: nb_valid_elements = 0;
4294: ref_node = prev ? prev : next;
4295: parent = ref_node->parent;
4296:
4297: /*
4298: * Retrieves the parent element declaration
4299: */
4300: element_desc = xmlGetDtdElementDesc(parent->doc->intSubset,
4301: parent->name);
4302: if ((element_desc == NULL) && (parent->doc->extSubset != NULL))
4303: element_desc = xmlGetDtdElementDesc(parent->doc->extSubset,
4304: parent->name);
4305: if (element_desc == NULL) return(-1);
4306:
4307: /*
4308: * Do a backup of the current tree structure
4309: */
4310: prev_next = prev ? prev->next : NULL;
4311: next_prev = next ? next->prev : NULL;
1.46 daniel 4312: parent_childs = parent->children;
1.34 daniel 4313: parent_last = parent->last;
4314:
4315: /*
4316: * Creates a dummy node and insert it into the tree
4317: */
1.37 daniel 4318: test_node = xmlNewNode (NULL, BAD_CAST "<!dummy?>");
1.34 daniel 4319: test_node->doc = ref_node->doc;
4320: test_node->parent = parent;
4321: test_node->prev = prev;
4322: test_node->next = next;
4323:
4324: if (prev) prev->next = test_node;
1.46 daniel 4325: else parent->children = test_node;
1.34 daniel 4326:
4327: if (next) next->prev = test_node;
4328: else parent->last = test_node;
4329:
4330: /*
4331: * Insert each potential child node and check if the parent is
4332: * still valid
4333: */
4334: nb_elements = xmlValidGetPotentialChildren(element_desc->content,
4335: elements, &nb_elements, 256);
4336:
4337: for (i = 0;i < nb_elements;i++) {
4338: test_node->name = elements[i];
4339: if (xmlValidateOneElement(NULL, parent->doc, parent)) {
4340: int j;
4341:
4342: for (j = 0; j < nb_valid_elements;j++)
4343: if (!xmlStrcmp(elements[i], list[j])) break;
4344: list[nb_valid_elements++] = elements[i];
4345: if (nb_valid_elements >= max) break;
4346: }
1.33 daniel 4347: }
4348:
1.34 daniel 4349: /*
4350: * Restore the tree structure
4351: */
4352: if (prev) prev->next = prev_next;
4353: if (next) next->prev = next_prev;
1.46 daniel 4354: parent->children = parent_childs;
1.34 daniel 4355: parent->last = parent_last;
4356:
4357: return(nb_valid_elements);
1.33 daniel 4358: }
Webmaster