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