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