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