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