Annotation of embedaddon/libxml2/valid.c, revision 1.1
1.1 ! misho 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.com
! 8: */
! 9:
! 10: #define IN_LIBXML
! 11: #include "libxml.h"
! 12:
! 13: #include <string.h>
! 14:
! 15: #ifdef HAVE_STDLIB_H
! 16: #include <stdlib.h>
! 17: #endif
! 18:
! 19: #include <libxml/xmlmemory.h>
! 20: #include <libxml/hash.h>
! 21: #include <libxml/uri.h>
! 22: #include <libxml/valid.h>
! 23: #include <libxml/parser.h>
! 24: #include <libxml/parserInternals.h>
! 25: #include <libxml/xmlerror.h>
! 26: #include <libxml/list.h>
! 27: #include <libxml/globals.h>
! 28:
! 29: static xmlElementPtr xmlGetDtdElementDesc2(xmlDtdPtr dtd, const xmlChar *name,
! 30: int create);
! 31: /* #define DEBUG_VALID_ALGO */
! 32: /* #define DEBUG_REGEXP_ALGO */
! 33:
! 34: #define TODO \
! 35: xmlGenericError(xmlGenericErrorContext, \
! 36: "Unimplemented block at %s:%d\n", \
! 37: __FILE__, __LINE__);
! 38:
! 39: #ifdef LIBXML_VALID_ENABLED
! 40: static int
! 41: xmlValidateAttributeValueInternal(xmlDocPtr doc, xmlAttributeType type,
! 42: const xmlChar *value);
! 43: #endif
! 44: /************************************************************************
! 45: * *
! 46: * Error handling routines *
! 47: * *
! 48: ************************************************************************/
! 49:
! 50: /**
! 51: * xmlVErrMemory:
! 52: * @ctxt: an XML validation parser context
! 53: * @extra: extra informations
! 54: *
! 55: * Handle an out of memory error
! 56: */
! 57: static void
! 58: xmlVErrMemory(xmlValidCtxtPtr ctxt, const char *extra)
! 59: {
! 60: xmlGenericErrorFunc channel = NULL;
! 61: xmlParserCtxtPtr pctxt = NULL;
! 62: void *data = NULL;
! 63:
! 64: if (ctxt != NULL) {
! 65: channel = ctxt->error;
! 66: data = ctxt->userData;
! 67: /* Use the special values to detect if it is part of a parsing
! 68: context */
! 69: if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
! 70: (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
! 71: long delta = (char *) ctxt - (char *) ctxt->userData;
! 72: if ((delta > 0) && (delta < 250))
! 73: pctxt = ctxt->userData;
! 74: }
! 75: }
! 76: if (extra)
! 77: __xmlRaiseError(NULL, channel, data,
! 78: pctxt, NULL, XML_FROM_VALID, XML_ERR_NO_MEMORY,
! 79: XML_ERR_FATAL, NULL, 0, extra, NULL, NULL, 0, 0,
! 80: "Memory allocation failed : %s\n", extra);
! 81: else
! 82: __xmlRaiseError(NULL, channel, data,
! 83: pctxt, NULL, XML_FROM_VALID, XML_ERR_NO_MEMORY,
! 84: XML_ERR_FATAL, NULL, 0, NULL, NULL, NULL, 0, 0,
! 85: "Memory allocation failed\n");
! 86: }
! 87:
! 88: /**
! 89: * xmlErrValid:
! 90: * @ctxt: an XML validation parser context
! 91: * @error: the error number
! 92: * @extra: extra informations
! 93: *
! 94: * Handle a validation error
! 95: */
! 96: static void
! 97: xmlErrValid(xmlValidCtxtPtr ctxt, xmlParserErrors error,
! 98: const char *msg, const char *extra)
! 99: {
! 100: xmlGenericErrorFunc channel = NULL;
! 101: xmlParserCtxtPtr pctxt = NULL;
! 102: void *data = NULL;
! 103:
! 104: if (ctxt != NULL) {
! 105: channel = ctxt->error;
! 106: data = ctxt->userData;
! 107: /* Use the special values to detect if it is part of a parsing
! 108: context */
! 109: if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
! 110: (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
! 111: long delta = (char *) ctxt - (char *) ctxt->userData;
! 112: if ((delta > 0) && (delta < 250))
! 113: pctxt = ctxt->userData;
! 114: }
! 115: }
! 116: if (extra)
! 117: __xmlRaiseError(NULL, channel, data,
! 118: pctxt, NULL, XML_FROM_VALID, error,
! 119: XML_ERR_ERROR, NULL, 0, extra, NULL, NULL, 0, 0,
! 120: msg, extra);
! 121: else
! 122: __xmlRaiseError(NULL, channel, data,
! 123: pctxt, NULL, XML_FROM_VALID, error,
! 124: XML_ERR_ERROR, NULL, 0, NULL, NULL, NULL, 0, 0,
! 125: "%s", msg);
! 126: }
! 127:
! 128: #if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
! 129: /**
! 130: * xmlErrValidNode:
! 131: * @ctxt: an XML validation parser context
! 132: * @node: the node raising the error
! 133: * @error: the error number
! 134: * @str1: extra informations
! 135: * @str2: extra informations
! 136: * @str3: extra informations
! 137: *
! 138: * Handle a validation error, provide contextual informations
! 139: */
! 140: static void
! 141: xmlErrValidNode(xmlValidCtxtPtr ctxt,
! 142: xmlNodePtr node, xmlParserErrors error,
! 143: const char *msg, const xmlChar * str1,
! 144: const xmlChar * str2, const xmlChar * str3)
! 145: {
! 146: xmlStructuredErrorFunc schannel = NULL;
! 147: xmlGenericErrorFunc channel = NULL;
! 148: xmlParserCtxtPtr pctxt = NULL;
! 149: void *data = NULL;
! 150:
! 151: if (ctxt != NULL) {
! 152: channel = ctxt->error;
! 153: data = ctxt->userData;
! 154: /* Use the special values to detect if it is part of a parsing
! 155: context */
! 156: if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
! 157: (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
! 158: long delta = (char *) ctxt - (char *) ctxt->userData;
! 159: if ((delta > 0) && (delta < 250))
! 160: pctxt = ctxt->userData;
! 161: }
! 162: }
! 163: __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
! 164: XML_ERR_ERROR, NULL, 0,
! 165: (const char *) str1,
! 166: (const char *) str1,
! 167: (const char *) str3, 0, 0, msg, str1, str2, str3);
! 168: }
! 169: #endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */
! 170:
! 171: #ifdef LIBXML_VALID_ENABLED
! 172: /**
! 173: * xmlErrValidNodeNr:
! 174: * @ctxt: an XML validation parser context
! 175: * @node: the node raising the error
! 176: * @error: the error number
! 177: * @str1: extra informations
! 178: * @int2: extra informations
! 179: * @str3: extra informations
! 180: *
! 181: * Handle a validation error, provide contextual informations
! 182: */
! 183: static void
! 184: xmlErrValidNodeNr(xmlValidCtxtPtr ctxt,
! 185: xmlNodePtr node, xmlParserErrors error,
! 186: const char *msg, const xmlChar * str1,
! 187: int int2, const xmlChar * str3)
! 188: {
! 189: xmlStructuredErrorFunc schannel = NULL;
! 190: xmlGenericErrorFunc channel = NULL;
! 191: xmlParserCtxtPtr pctxt = NULL;
! 192: void *data = NULL;
! 193:
! 194: if (ctxt != NULL) {
! 195: channel = ctxt->error;
! 196: data = ctxt->userData;
! 197: /* Use the special values to detect if it is part of a parsing
! 198: context */
! 199: if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
! 200: (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
! 201: long delta = (char *) ctxt - (char *) ctxt->userData;
! 202: if ((delta > 0) && (delta < 250))
! 203: pctxt = ctxt->userData;
! 204: }
! 205: }
! 206: __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
! 207: XML_ERR_ERROR, NULL, 0,
! 208: (const char *) str1,
! 209: (const char *) str3,
! 210: NULL, int2, 0, msg, str1, int2, str3);
! 211: }
! 212:
! 213: /**
! 214: * xmlErrValidWarning:
! 215: * @ctxt: an XML validation parser context
! 216: * @node: the node raising the error
! 217: * @error: the error number
! 218: * @str1: extra information
! 219: * @str2: extra information
! 220: * @str3: extra information
! 221: *
! 222: * Handle a validation error, provide contextual information
! 223: */
! 224: static void
! 225: xmlErrValidWarning(xmlValidCtxtPtr ctxt,
! 226: xmlNodePtr node, xmlParserErrors error,
! 227: const char *msg, const xmlChar * str1,
! 228: const xmlChar * str2, const xmlChar * str3)
! 229: {
! 230: xmlStructuredErrorFunc schannel = NULL;
! 231: xmlGenericErrorFunc channel = NULL;
! 232: xmlParserCtxtPtr pctxt = NULL;
! 233: void *data = NULL;
! 234:
! 235: if (ctxt != NULL) {
! 236: channel = ctxt->warning;
! 237: data = ctxt->userData;
! 238: /* Use the special values to detect if it is part of a parsing
! 239: context */
! 240: if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
! 241: (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
! 242: long delta = (char *) ctxt - (char *) ctxt->userData;
! 243: if ((delta > 0) && (delta < 250))
! 244: pctxt = ctxt->userData;
! 245: }
! 246: }
! 247: __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
! 248: XML_ERR_WARNING, NULL, 0,
! 249: (const char *) str1,
! 250: (const char *) str1,
! 251: (const char *) str3, 0, 0, msg, str1, str2, str3);
! 252: }
! 253:
! 254:
! 255:
! 256: #ifdef LIBXML_REGEXP_ENABLED
! 257: /*
! 258: * If regexp are enabled we can do continuous validation without the
! 259: * need of a tree to validate the content model. this is done in each
! 260: * callbacks.
! 261: * Each xmlValidState represent the validation state associated to the
! 262: * set of nodes currently open from the document root to the current element.
! 263: */
! 264:
! 265:
! 266: typedef struct _xmlValidState {
! 267: xmlElementPtr elemDecl; /* pointer to the content model */
! 268: xmlNodePtr node; /* pointer to the current node */
! 269: xmlRegExecCtxtPtr exec; /* regexp runtime */
! 270: } _xmlValidState;
! 271:
! 272:
! 273: static int
! 274: vstateVPush(xmlValidCtxtPtr ctxt, xmlElementPtr elemDecl, xmlNodePtr node) {
! 275: if ((ctxt->vstateMax == 0) || (ctxt->vstateTab == NULL)) {
! 276: ctxt->vstateMax = 10;
! 277: ctxt->vstateTab = (xmlValidState *) xmlMalloc(ctxt->vstateMax *
! 278: sizeof(ctxt->vstateTab[0]));
! 279: if (ctxt->vstateTab == NULL) {
! 280: xmlVErrMemory(ctxt, "malloc failed");
! 281: return(-1);
! 282: }
! 283: }
! 284:
! 285: if (ctxt->vstateNr >= ctxt->vstateMax) {
! 286: xmlValidState *tmp;
! 287:
! 288: tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
! 289: 2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
! 290: if (tmp == NULL) {
! 291: xmlVErrMemory(ctxt, "realloc failed");
! 292: return(-1);
! 293: }
! 294: ctxt->vstateMax *= 2;
! 295: ctxt->vstateTab = tmp;
! 296: }
! 297: ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr];
! 298: ctxt->vstateTab[ctxt->vstateNr].elemDecl = elemDecl;
! 299: ctxt->vstateTab[ctxt->vstateNr].node = node;
! 300: if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) {
! 301: if (elemDecl->contModel == NULL)
! 302: xmlValidBuildContentModel(ctxt, elemDecl);
! 303: if (elemDecl->contModel != NULL) {
! 304: ctxt->vstateTab[ctxt->vstateNr].exec =
! 305: xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
! 306: } else {
! 307: ctxt->vstateTab[ctxt->vstateNr].exec = NULL;
! 308: xmlErrValidNode(ctxt, (xmlNodePtr) elemDecl,
! 309: XML_ERR_INTERNAL_ERROR,
! 310: "Failed to build content model regexp for %s\n",
! 311: node->name, NULL, NULL);
! 312: }
! 313: }
! 314: return(ctxt->vstateNr++);
! 315: }
! 316:
! 317: static int
! 318: vstateVPop(xmlValidCtxtPtr ctxt) {
! 319: xmlElementPtr elemDecl;
! 320:
! 321: if (ctxt->vstateNr < 1) return(-1);
! 322: ctxt->vstateNr--;
! 323: elemDecl = ctxt->vstateTab[ctxt->vstateNr].elemDecl;
! 324: ctxt->vstateTab[ctxt->vstateNr].elemDecl = NULL;
! 325: ctxt->vstateTab[ctxt->vstateNr].node = NULL;
! 326: if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) {
! 327: xmlRegFreeExecCtxt(ctxt->vstateTab[ctxt->vstateNr].exec);
! 328: }
! 329: ctxt->vstateTab[ctxt->vstateNr].exec = NULL;
! 330: if (ctxt->vstateNr >= 1)
! 331: ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr - 1];
! 332: else
! 333: ctxt->vstate = NULL;
! 334: return(ctxt->vstateNr);
! 335: }
! 336:
! 337: #else /* not LIBXML_REGEXP_ENABLED */
! 338: /*
! 339: * If regexp are not enabled, it uses a home made algorithm less
! 340: * complex and easier to
! 341: * debug/maintain than a generic NFA -> DFA state based algo. The
! 342: * only restriction is on the deepness of the tree limited by the
! 343: * size of the occurs bitfield
! 344: *
! 345: * this is the content of a saved state for rollbacks
! 346: */
! 347:
! 348: #define ROLLBACK_OR 0
! 349: #define ROLLBACK_PARENT 1
! 350:
! 351: typedef struct _xmlValidState {
! 352: xmlElementContentPtr cont; /* pointer to the content model subtree */
! 353: xmlNodePtr node; /* pointer to the current node in the list */
! 354: long occurs;/* bitfield for multiple occurrences */
! 355: unsigned char depth; /* current depth in the overall tree */
! 356: unsigned char state; /* ROLLBACK_XXX */
! 357: } _xmlValidState;
! 358:
! 359: #define MAX_RECURSE 25000
! 360: #define MAX_DEPTH ((sizeof(_xmlValidState.occurs)) * 8)
! 361: #define CONT ctxt->vstate->cont
! 362: #define NODE ctxt->vstate->node
! 363: #define DEPTH ctxt->vstate->depth
! 364: #define OCCURS ctxt->vstate->occurs
! 365: #define STATE ctxt->vstate->state
! 366:
! 367: #define OCCURRENCE (ctxt->vstate->occurs & (1 << DEPTH))
! 368: #define PARENT_OCCURRENCE (ctxt->vstate->occurs & ((1 << DEPTH) - 1))
! 369:
! 370: #define SET_OCCURRENCE ctxt->vstate->occurs |= (1 << DEPTH)
! 371: #define RESET_OCCURRENCE ctxt->vstate->occurs &= ((1 << DEPTH) - 1)
! 372:
! 373: static int
! 374: vstateVPush(xmlValidCtxtPtr ctxt, xmlElementContentPtr cont,
! 375: xmlNodePtr node, unsigned char depth, long occurs,
! 376: unsigned char state) {
! 377: int i = ctxt->vstateNr - 1;
! 378:
! 379: if (ctxt->vstateNr > MAX_RECURSE) {
! 380: return(-1);
! 381: }
! 382: if (ctxt->vstateTab == NULL) {
! 383: ctxt->vstateMax = 8;
! 384: ctxt->vstateTab = (xmlValidState *) xmlMalloc(
! 385: ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
! 386: if (ctxt->vstateTab == NULL) {
! 387: xmlVErrMemory(ctxt, "malloc failed");
! 388: return(-1);
! 389: }
! 390: }
! 391: if (ctxt->vstateNr >= ctxt->vstateMax) {
! 392: xmlValidState *tmp;
! 393:
! 394: tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
! 395: 2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
! 396: if (tmp == NULL) {
! 397: xmlVErrMemory(ctxt, "malloc failed");
! 398: return(-1);
! 399: }
! 400: ctxt->vstateMax *= 2;
! 401: ctxt->vstateTab = tmp;
! 402: ctxt->vstate = &ctxt->vstateTab[0];
! 403: }
! 404: /*
! 405: * Don't push on the stack a state already here
! 406: */
! 407: if ((i >= 0) && (ctxt->vstateTab[i].cont == cont) &&
! 408: (ctxt->vstateTab[i].node == node) &&
! 409: (ctxt->vstateTab[i].depth == depth) &&
! 410: (ctxt->vstateTab[i].occurs == occurs) &&
! 411: (ctxt->vstateTab[i].state == state))
! 412: return(ctxt->vstateNr);
! 413: ctxt->vstateTab[ctxt->vstateNr].cont = cont;
! 414: ctxt->vstateTab[ctxt->vstateNr].node = node;
! 415: ctxt->vstateTab[ctxt->vstateNr].depth = depth;
! 416: ctxt->vstateTab[ctxt->vstateNr].occurs = occurs;
! 417: ctxt->vstateTab[ctxt->vstateNr].state = state;
! 418: return(ctxt->vstateNr++);
! 419: }
! 420:
! 421: static int
! 422: vstateVPop(xmlValidCtxtPtr ctxt) {
! 423: if (ctxt->vstateNr <= 1) return(-1);
! 424: ctxt->vstateNr--;
! 425: ctxt->vstate = &ctxt->vstateTab[0];
! 426: ctxt->vstate->cont = ctxt->vstateTab[ctxt->vstateNr].cont;
! 427: ctxt->vstate->node = ctxt->vstateTab[ctxt->vstateNr].node;
! 428: ctxt->vstate->depth = ctxt->vstateTab[ctxt->vstateNr].depth;
! 429: ctxt->vstate->occurs = ctxt->vstateTab[ctxt->vstateNr].occurs;
! 430: ctxt->vstate->state = ctxt->vstateTab[ctxt->vstateNr].state;
! 431: return(ctxt->vstateNr);
! 432: }
! 433:
! 434: #endif /* LIBXML_REGEXP_ENABLED */
! 435:
! 436: static int
! 437: nodeVPush(xmlValidCtxtPtr ctxt, xmlNodePtr value)
! 438: {
! 439: if (ctxt->nodeMax <= 0) {
! 440: ctxt->nodeMax = 4;
! 441: ctxt->nodeTab =
! 442: (xmlNodePtr *) xmlMalloc(ctxt->nodeMax *
! 443: sizeof(ctxt->nodeTab[0]));
! 444: if (ctxt->nodeTab == NULL) {
! 445: xmlVErrMemory(ctxt, "malloc failed");
! 446: ctxt->nodeMax = 0;
! 447: return (0);
! 448: }
! 449: }
! 450: if (ctxt->nodeNr >= ctxt->nodeMax) {
! 451: xmlNodePtr *tmp;
! 452: tmp = (xmlNodePtr *) xmlRealloc(ctxt->nodeTab,
! 453: ctxt->nodeMax * 2 * sizeof(ctxt->nodeTab[0]));
! 454: if (tmp == NULL) {
! 455: xmlVErrMemory(ctxt, "realloc failed");
! 456: return (0);
! 457: }
! 458: ctxt->nodeMax *= 2;
! 459: ctxt->nodeTab = tmp;
! 460: }
! 461: ctxt->nodeTab[ctxt->nodeNr] = value;
! 462: ctxt->node = value;
! 463: return (ctxt->nodeNr++);
! 464: }
! 465: static xmlNodePtr
! 466: nodeVPop(xmlValidCtxtPtr ctxt)
! 467: {
! 468: xmlNodePtr ret;
! 469:
! 470: if (ctxt->nodeNr <= 0)
! 471: return (NULL);
! 472: ctxt->nodeNr--;
! 473: if (ctxt->nodeNr > 0)
! 474: ctxt->node = ctxt->nodeTab[ctxt->nodeNr - 1];
! 475: else
! 476: ctxt->node = NULL;
! 477: ret = ctxt->nodeTab[ctxt->nodeNr];
! 478: ctxt->nodeTab[ctxt->nodeNr] = NULL;
! 479: return (ret);
! 480: }
! 481:
! 482: #ifdef DEBUG_VALID_ALGO
! 483: static void
! 484: xmlValidPrintNode(xmlNodePtr cur) {
! 485: if (cur == NULL) {
! 486: xmlGenericError(xmlGenericErrorContext, "null");
! 487: return;
! 488: }
! 489: switch (cur->type) {
! 490: case XML_ELEMENT_NODE:
! 491: xmlGenericError(xmlGenericErrorContext, "%s ", cur->name);
! 492: break;
! 493: case XML_TEXT_NODE:
! 494: xmlGenericError(xmlGenericErrorContext, "text ");
! 495: break;
! 496: case XML_CDATA_SECTION_NODE:
! 497: xmlGenericError(xmlGenericErrorContext, "cdata ");
! 498: break;
! 499: case XML_ENTITY_REF_NODE:
! 500: xmlGenericError(xmlGenericErrorContext, "&%s; ", cur->name);
! 501: break;
! 502: case XML_PI_NODE:
! 503: xmlGenericError(xmlGenericErrorContext, "pi(%s) ", cur->name);
! 504: break;
! 505: case XML_COMMENT_NODE:
! 506: xmlGenericError(xmlGenericErrorContext, "comment ");
! 507: break;
! 508: case XML_ATTRIBUTE_NODE:
! 509: xmlGenericError(xmlGenericErrorContext, "?attr? ");
! 510: break;
! 511: case XML_ENTITY_NODE:
! 512: xmlGenericError(xmlGenericErrorContext, "?ent? ");
! 513: break;
! 514: case XML_DOCUMENT_NODE:
! 515: xmlGenericError(xmlGenericErrorContext, "?doc? ");
! 516: break;
! 517: case XML_DOCUMENT_TYPE_NODE:
! 518: xmlGenericError(xmlGenericErrorContext, "?doctype? ");
! 519: break;
! 520: case XML_DOCUMENT_FRAG_NODE:
! 521: xmlGenericError(xmlGenericErrorContext, "?frag? ");
! 522: break;
! 523: case XML_NOTATION_NODE:
! 524: xmlGenericError(xmlGenericErrorContext, "?nota? ");
! 525: break;
! 526: case XML_HTML_DOCUMENT_NODE:
! 527: xmlGenericError(xmlGenericErrorContext, "?html? ");
! 528: break;
! 529: #ifdef LIBXML_DOCB_ENABLED
! 530: case XML_DOCB_DOCUMENT_NODE:
! 531: xmlGenericError(xmlGenericErrorContext, "?docb? ");
! 532: break;
! 533: #endif
! 534: case XML_DTD_NODE:
! 535: xmlGenericError(xmlGenericErrorContext, "?dtd? ");
! 536: break;
! 537: case XML_ELEMENT_DECL:
! 538: xmlGenericError(xmlGenericErrorContext, "?edecl? ");
! 539: break;
! 540: case XML_ATTRIBUTE_DECL:
! 541: xmlGenericError(xmlGenericErrorContext, "?adecl? ");
! 542: break;
! 543: case XML_ENTITY_DECL:
! 544: xmlGenericError(xmlGenericErrorContext, "?entdecl? ");
! 545: break;
! 546: case XML_NAMESPACE_DECL:
! 547: xmlGenericError(xmlGenericErrorContext, "?nsdecl? ");
! 548: break;
! 549: case XML_XINCLUDE_START:
! 550: xmlGenericError(xmlGenericErrorContext, "incstart ");
! 551: break;
! 552: case XML_XINCLUDE_END:
! 553: xmlGenericError(xmlGenericErrorContext, "incend ");
! 554: break;
! 555: }
! 556: }
! 557:
! 558: static void
! 559: xmlValidPrintNodeList(xmlNodePtr cur) {
! 560: if (cur == NULL)
! 561: xmlGenericError(xmlGenericErrorContext, "null ");
! 562: while (cur != NULL) {
! 563: xmlValidPrintNode(cur);
! 564: cur = cur->next;
! 565: }
! 566: }
! 567:
! 568: static void
! 569: xmlValidDebug(xmlNodePtr cur, xmlElementContentPtr cont) {
! 570: char expr[5000];
! 571:
! 572: expr[0] = 0;
! 573: xmlGenericError(xmlGenericErrorContext, "valid: ");
! 574: xmlValidPrintNodeList(cur);
! 575: xmlGenericError(xmlGenericErrorContext, "against ");
! 576: xmlSnprintfElementContent(expr, 5000, cont, 1);
! 577: xmlGenericError(xmlGenericErrorContext, "%s\n", expr);
! 578: }
! 579:
! 580: static void
! 581: xmlValidDebugState(xmlValidStatePtr state) {
! 582: xmlGenericError(xmlGenericErrorContext, "(");
! 583: if (state->cont == NULL)
! 584: xmlGenericError(xmlGenericErrorContext, "null,");
! 585: else
! 586: switch (state->cont->type) {
! 587: case XML_ELEMENT_CONTENT_PCDATA:
! 588: xmlGenericError(xmlGenericErrorContext, "pcdata,");
! 589: break;
! 590: case XML_ELEMENT_CONTENT_ELEMENT:
! 591: xmlGenericError(xmlGenericErrorContext, "%s,",
! 592: state->cont->name);
! 593: break;
! 594: case XML_ELEMENT_CONTENT_SEQ:
! 595: xmlGenericError(xmlGenericErrorContext, "seq,");
! 596: break;
! 597: case XML_ELEMENT_CONTENT_OR:
! 598: xmlGenericError(xmlGenericErrorContext, "or,");
! 599: break;
! 600: }
! 601: xmlValidPrintNode(state->node);
! 602: xmlGenericError(xmlGenericErrorContext, ",%d,%X,%d)",
! 603: state->depth, state->occurs, state->state);
! 604: }
! 605:
! 606: static void
! 607: xmlValidStateDebug(xmlValidCtxtPtr ctxt) {
! 608: int i, j;
! 609:
! 610: xmlGenericError(xmlGenericErrorContext, "state: ");
! 611: xmlValidDebugState(ctxt->vstate);
! 612: xmlGenericError(xmlGenericErrorContext, " stack: %d ",
! 613: ctxt->vstateNr - 1);
! 614: for (i = 0, j = ctxt->vstateNr - 1;(i < 3) && (j > 0);i++,j--)
! 615: xmlValidDebugState(&ctxt->vstateTab[j]);
! 616: xmlGenericError(xmlGenericErrorContext, "\n");
! 617: }
! 618:
! 619: /*****
! 620: #define DEBUG_VALID_STATE(n,c) xmlValidDebug(n,c);
! 621: *****/
! 622:
! 623: #define DEBUG_VALID_STATE(n,c) xmlValidStateDebug(ctxt);
! 624: #define DEBUG_VALID_MSG(m) \
! 625: xmlGenericError(xmlGenericErrorContext, "%s\n", m);
! 626:
! 627: #else
! 628: #define DEBUG_VALID_STATE(n,c)
! 629: #define DEBUG_VALID_MSG(m)
! 630: #endif
! 631:
! 632: /* TODO: use hash table for accesses to elem and attribute definitions */
! 633:
! 634:
! 635: #define CHECK_DTD \
! 636: if (doc == NULL) return(0); \
! 637: else if ((doc->intSubset == NULL) && \
! 638: (doc->extSubset == NULL)) return(0)
! 639:
! 640: #ifdef LIBXML_REGEXP_ENABLED
! 641:
! 642: /************************************************************************
! 643: * *
! 644: * Content model validation based on the regexps *
! 645: * *
! 646: ************************************************************************/
! 647:
! 648: /**
! 649: * xmlValidBuildAContentModel:
! 650: * @content: the content model
! 651: * @ctxt: the schema parser context
! 652: * @name: the element name whose content is being built
! 653: *
! 654: * Generate the automata sequence needed for that type
! 655: *
! 656: * Returns 1 if successful or 0 in case of error.
! 657: */
! 658: static int
! 659: xmlValidBuildAContentModel(xmlElementContentPtr content,
! 660: xmlValidCtxtPtr ctxt,
! 661: const xmlChar *name) {
! 662: if (content == NULL) {
! 663: xmlErrValidNode(ctxt, NULL, XML_ERR_INTERNAL_ERROR,
! 664: "Found NULL content in content model of %s\n",
! 665: name, NULL, NULL);
! 666: return(0);
! 667: }
! 668: switch (content->type) {
! 669: case XML_ELEMENT_CONTENT_PCDATA:
! 670: xmlErrValidNode(ctxt, NULL, XML_ERR_INTERNAL_ERROR,
! 671: "Found PCDATA in content model of %s\n",
! 672: name, NULL, NULL);
! 673: return(0);
! 674: break;
! 675: case XML_ELEMENT_CONTENT_ELEMENT: {
! 676: xmlAutomataStatePtr oldstate = ctxt->state;
! 677: xmlChar fn[50];
! 678: xmlChar *fullname;
! 679:
! 680: fullname = xmlBuildQName(content->name, content->prefix, fn, 50);
! 681: if (fullname == NULL) {
! 682: xmlVErrMemory(ctxt, "Building content model");
! 683: return(0);
! 684: }
! 685:
! 686: switch (content->ocur) {
! 687: case XML_ELEMENT_CONTENT_ONCE:
! 688: ctxt->state = xmlAutomataNewTransition(ctxt->am,
! 689: ctxt->state, NULL, fullname, NULL);
! 690: break;
! 691: case XML_ELEMENT_CONTENT_OPT:
! 692: ctxt->state = xmlAutomataNewTransition(ctxt->am,
! 693: ctxt->state, NULL, fullname, NULL);
! 694: xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
! 695: break;
! 696: case XML_ELEMENT_CONTENT_PLUS:
! 697: ctxt->state = xmlAutomataNewTransition(ctxt->am,
! 698: ctxt->state, NULL, fullname, NULL);
! 699: xmlAutomataNewTransition(ctxt->am, ctxt->state,
! 700: ctxt->state, fullname, NULL);
! 701: break;
! 702: case XML_ELEMENT_CONTENT_MULT:
! 703: ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
! 704: ctxt->state, NULL);
! 705: xmlAutomataNewTransition(ctxt->am,
! 706: ctxt->state, ctxt->state, fullname, NULL);
! 707: break;
! 708: }
! 709: if ((fullname != fn) && (fullname != content->name))
! 710: xmlFree(fullname);
! 711: break;
! 712: }
! 713: case XML_ELEMENT_CONTENT_SEQ: {
! 714: xmlAutomataStatePtr oldstate, oldend;
! 715: xmlElementContentOccur ocur;
! 716:
! 717: /*
! 718: * Simply iterate over the content
! 719: */
! 720: oldstate = ctxt->state;
! 721: ocur = content->ocur;
! 722: if (ocur != XML_ELEMENT_CONTENT_ONCE) {
! 723: ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
! 724: oldstate = ctxt->state;
! 725: }
! 726: do {
! 727: xmlValidBuildAContentModel(content->c1, ctxt, name);
! 728: content = content->c2;
! 729: } while ((content->type == XML_ELEMENT_CONTENT_SEQ) &&
! 730: (content->ocur == XML_ELEMENT_CONTENT_ONCE));
! 731: xmlValidBuildAContentModel(content, ctxt, name);
! 732: oldend = ctxt->state;
! 733: ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL);
! 734: switch (ocur) {
! 735: case XML_ELEMENT_CONTENT_ONCE:
! 736: break;
! 737: case XML_ELEMENT_CONTENT_OPT:
! 738: xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
! 739: break;
! 740: case XML_ELEMENT_CONTENT_MULT:
! 741: xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
! 742: xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
! 743: break;
! 744: case XML_ELEMENT_CONTENT_PLUS:
! 745: xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
! 746: break;
! 747: }
! 748: break;
! 749: }
! 750: case XML_ELEMENT_CONTENT_OR: {
! 751: xmlAutomataStatePtr oldstate, oldend;
! 752: xmlElementContentOccur ocur;
! 753:
! 754: ocur = content->ocur;
! 755: if ((ocur == XML_ELEMENT_CONTENT_PLUS) ||
! 756: (ocur == XML_ELEMENT_CONTENT_MULT)) {
! 757: ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
! 758: ctxt->state, NULL);
! 759: }
! 760: oldstate = ctxt->state;
! 761: oldend = xmlAutomataNewState(ctxt->am);
! 762:
! 763: /*
! 764: * iterate over the subtypes and remerge the end with an
! 765: * epsilon transition
! 766: */
! 767: do {
! 768: ctxt->state = oldstate;
! 769: xmlValidBuildAContentModel(content->c1, ctxt, name);
! 770: xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend);
! 771: content = content->c2;
! 772: } while ((content->type == XML_ELEMENT_CONTENT_OR) &&
! 773: (content->ocur == XML_ELEMENT_CONTENT_ONCE));
! 774: ctxt->state = oldstate;
! 775: xmlValidBuildAContentModel(content, ctxt, name);
! 776: xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend);
! 777: ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL);
! 778: switch (ocur) {
! 779: case XML_ELEMENT_CONTENT_ONCE:
! 780: break;
! 781: case XML_ELEMENT_CONTENT_OPT:
! 782: xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
! 783: break;
! 784: case XML_ELEMENT_CONTENT_MULT:
! 785: xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
! 786: xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
! 787: break;
! 788: case XML_ELEMENT_CONTENT_PLUS:
! 789: xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
! 790: break;
! 791: }
! 792: break;
! 793: }
! 794: default:
! 795: xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
! 796: "ContentModel broken for element %s\n",
! 797: (const char *) name);
! 798: return(0);
! 799: }
! 800: return(1);
! 801: }
! 802: /**
! 803: * xmlValidBuildContentModel:
! 804: * @ctxt: a validation context
! 805: * @elem: an element declaration node
! 806: *
! 807: * (Re)Build the automata associated to the content model of this
! 808: * element
! 809: *
! 810: * Returns 1 in case of success, 0 in case of error
! 811: */
! 812: int
! 813: xmlValidBuildContentModel(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
! 814:
! 815: if ((ctxt == NULL) || (elem == NULL))
! 816: return(0);
! 817: if (elem->type != XML_ELEMENT_DECL)
! 818: return(0);
! 819: if (elem->etype != XML_ELEMENT_TYPE_ELEMENT)
! 820: return(1);
! 821: /* TODO: should we rebuild in this case ? */
! 822: if (elem->contModel != NULL) {
! 823: if (!xmlRegexpIsDeterminist(elem->contModel)) {
! 824: ctxt->valid = 0;
! 825: return(0);
! 826: }
! 827: return(1);
! 828: }
! 829:
! 830: ctxt->am = xmlNewAutomata();
! 831: if (ctxt->am == NULL) {
! 832: xmlErrValidNode(ctxt, (xmlNodePtr) elem,
! 833: XML_ERR_INTERNAL_ERROR,
! 834: "Cannot create automata for element %s\n",
! 835: elem->name, NULL, NULL);
! 836: return(0);
! 837: }
! 838: ctxt->state = xmlAutomataGetInitState(ctxt->am);
! 839: xmlValidBuildAContentModel(elem->content, ctxt, elem->name);
! 840: xmlAutomataSetFinalState(ctxt->am, ctxt->state);
! 841: elem->contModel = xmlAutomataCompile(ctxt->am);
! 842: if (xmlRegexpIsDeterminist(elem->contModel) != 1) {
! 843: char expr[5000];
! 844: expr[0] = 0;
! 845: xmlSnprintfElementContent(expr, 5000, elem->content, 1);
! 846: xmlErrValidNode(ctxt, (xmlNodePtr) elem,
! 847: XML_DTD_CONTENT_NOT_DETERMINIST,
! 848: "Content model of %s is not determinist: %s\n",
! 849: elem->name, BAD_CAST expr, NULL);
! 850: #ifdef DEBUG_REGEXP_ALGO
! 851: xmlRegexpPrint(stderr, elem->contModel);
! 852: #endif
! 853: ctxt->valid = 0;
! 854: ctxt->state = NULL;
! 855: xmlFreeAutomata(ctxt->am);
! 856: ctxt->am = NULL;
! 857: return(0);
! 858: }
! 859: ctxt->state = NULL;
! 860: xmlFreeAutomata(ctxt->am);
! 861: ctxt->am = NULL;
! 862: return(1);
! 863: }
! 864:
! 865: #endif /* LIBXML_REGEXP_ENABLED */
! 866:
! 867: /****************************************************************
! 868: * *
! 869: * Util functions for data allocation/deallocation *
! 870: * *
! 871: ****************************************************************/
! 872:
! 873: /**
! 874: * xmlNewValidCtxt:
! 875: *
! 876: * Allocate a validation context structure.
! 877: *
! 878: * Returns NULL if not, otherwise the new validation context structure
! 879: */
! 880: xmlValidCtxtPtr xmlNewValidCtxt(void) {
! 881: xmlValidCtxtPtr ret;
! 882:
! 883: if ((ret = xmlMalloc(sizeof (xmlValidCtxt))) == NULL) {
! 884: xmlVErrMemory(NULL, "malloc failed");
! 885: return (NULL);
! 886: }
! 887:
! 888: (void) memset(ret, 0, sizeof (xmlValidCtxt));
! 889:
! 890: return (ret);
! 891: }
! 892:
! 893: /**
! 894: * xmlFreeValidCtxt:
! 895: * @cur: the validation context to free
! 896: *
! 897: * Free a validation context structure.
! 898: */
! 899: void
! 900: xmlFreeValidCtxt(xmlValidCtxtPtr cur) {
! 901: if (cur->vstateTab != NULL)
! 902: xmlFree(cur->vstateTab);
! 903: if (cur->nodeTab != NULL)
! 904: xmlFree(cur->nodeTab);
! 905: xmlFree(cur);
! 906: }
! 907:
! 908: #endif /* LIBXML_VALID_ENABLED */
! 909:
! 910: /**
! 911: * xmlNewDocElementContent:
! 912: * @doc: the document
! 913: * @name: the subelement name or NULL
! 914: * @type: the type of element content decl
! 915: *
! 916: * Allocate an element content structure for the document.
! 917: *
! 918: * Returns NULL if not, otherwise the new element content structure
! 919: */
! 920: xmlElementContentPtr
! 921: xmlNewDocElementContent(xmlDocPtr doc, const xmlChar *name,
! 922: xmlElementContentType type) {
! 923: xmlElementContentPtr ret;
! 924: xmlDictPtr dict = NULL;
! 925:
! 926: if (doc != NULL)
! 927: dict = doc->dict;
! 928:
! 929: switch(type) {
! 930: case XML_ELEMENT_CONTENT_ELEMENT:
! 931: if (name == NULL) {
! 932: xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
! 933: "xmlNewElementContent : name == NULL !\n",
! 934: NULL);
! 935: }
! 936: break;
! 937: case XML_ELEMENT_CONTENT_PCDATA:
! 938: case XML_ELEMENT_CONTENT_SEQ:
! 939: case XML_ELEMENT_CONTENT_OR:
! 940: if (name != NULL) {
! 941: xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
! 942: "xmlNewElementContent : name != NULL !\n",
! 943: NULL);
! 944: }
! 945: break;
! 946: default:
! 947: xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
! 948: "Internal: ELEMENT content corrupted invalid type\n",
! 949: NULL);
! 950: return(NULL);
! 951: }
! 952: ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
! 953: if (ret == NULL) {
! 954: xmlVErrMemory(NULL, "malloc failed");
! 955: return(NULL);
! 956: }
! 957: memset(ret, 0, sizeof(xmlElementContent));
! 958: ret->type = type;
! 959: ret->ocur = XML_ELEMENT_CONTENT_ONCE;
! 960: if (name != NULL) {
! 961: int l;
! 962: const xmlChar *tmp;
! 963:
! 964: tmp = xmlSplitQName3(name, &l);
! 965: if (tmp == NULL) {
! 966: if (dict == NULL)
! 967: ret->name = xmlStrdup(name);
! 968: else
! 969: ret->name = xmlDictLookup(dict, name, -1);
! 970: } else {
! 971: if (dict == NULL) {
! 972: ret->prefix = xmlStrndup(name, l);
! 973: ret->name = xmlStrdup(tmp);
! 974: } else {
! 975: ret->prefix = xmlDictLookup(dict, name, l);
! 976: ret->name = xmlDictLookup(dict, tmp, -1);
! 977: }
! 978: }
! 979: }
! 980: return(ret);
! 981: }
! 982:
! 983: /**
! 984: * xmlNewElementContent:
! 985: * @name: the subelement name or NULL
! 986: * @type: the type of element content decl
! 987: *
! 988: * Allocate an element content structure.
! 989: * Deprecated in favor of xmlNewDocElementContent
! 990: *
! 991: * Returns NULL if not, otherwise the new element content structure
! 992: */
! 993: xmlElementContentPtr
! 994: xmlNewElementContent(const xmlChar *name, xmlElementContentType type) {
! 995: return(xmlNewDocElementContent(NULL, name, type));
! 996: }
! 997:
! 998: /**
! 999: * xmlCopyDocElementContent:
! 1000: * @doc: the document owning the element declaration
! 1001: * @cur: An element content pointer.
! 1002: *
! 1003: * Build a copy of an element content description.
! 1004: *
! 1005: * Returns the new xmlElementContentPtr or NULL in case of error.
! 1006: */
! 1007: xmlElementContentPtr
! 1008: xmlCopyDocElementContent(xmlDocPtr doc, xmlElementContentPtr cur) {
! 1009: xmlElementContentPtr ret = NULL, prev = NULL, tmp;
! 1010: xmlDictPtr dict = NULL;
! 1011:
! 1012: if (cur == NULL) return(NULL);
! 1013:
! 1014: if (doc != NULL)
! 1015: dict = doc->dict;
! 1016:
! 1017: ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
! 1018: if (ret == NULL) {
! 1019: xmlVErrMemory(NULL, "malloc failed");
! 1020: return(NULL);
! 1021: }
! 1022: memset(ret, 0, sizeof(xmlElementContent));
! 1023: ret->type = cur->type;
! 1024: ret->ocur = cur->ocur;
! 1025: if (cur->name != NULL) {
! 1026: if (dict)
! 1027: ret->name = xmlDictLookup(dict, cur->name, -1);
! 1028: else
! 1029: ret->name = xmlStrdup(cur->name);
! 1030: }
! 1031:
! 1032: if (cur->prefix != NULL) {
! 1033: if (dict)
! 1034: ret->prefix = xmlDictLookup(dict, cur->prefix, -1);
! 1035: else
! 1036: ret->prefix = xmlStrdup(cur->prefix);
! 1037: }
! 1038: if (cur->c1 != NULL)
! 1039: ret->c1 = xmlCopyDocElementContent(doc, cur->c1);
! 1040: if (ret->c1 != NULL)
! 1041: ret->c1->parent = ret;
! 1042: if (cur->c2 != NULL) {
! 1043: prev = ret;
! 1044: cur = cur->c2;
! 1045: while (cur != NULL) {
! 1046: tmp = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
! 1047: if (tmp == NULL) {
! 1048: xmlVErrMemory(NULL, "malloc failed");
! 1049: return(ret);
! 1050: }
! 1051: memset(tmp, 0, sizeof(xmlElementContent));
! 1052: tmp->type = cur->type;
! 1053: tmp->ocur = cur->ocur;
! 1054: prev->c2 = tmp;
! 1055: if (cur->name != NULL) {
! 1056: if (dict)
! 1057: tmp->name = xmlDictLookup(dict, cur->name, -1);
! 1058: else
! 1059: tmp->name = xmlStrdup(cur->name);
! 1060: }
! 1061:
! 1062: if (cur->prefix != NULL) {
! 1063: if (dict)
! 1064: tmp->prefix = xmlDictLookup(dict, cur->prefix, -1);
! 1065: else
! 1066: tmp->prefix = xmlStrdup(cur->prefix);
! 1067: }
! 1068: if (cur->c1 != NULL)
! 1069: tmp->c1 = xmlCopyDocElementContent(doc,cur->c1);
! 1070: if (tmp->c1 != NULL)
! 1071: tmp->c1->parent = ret;
! 1072: prev = tmp;
! 1073: cur = cur->c2;
! 1074: }
! 1075: }
! 1076: return(ret);
! 1077: }
! 1078:
! 1079: /**
! 1080: * xmlCopyElementContent:
! 1081: * @cur: An element content pointer.
! 1082: *
! 1083: * Build a copy of an element content description.
! 1084: * Deprecated, use xmlCopyDocElementContent instead
! 1085: *
! 1086: * Returns the new xmlElementContentPtr or NULL in case of error.
! 1087: */
! 1088: xmlElementContentPtr
! 1089: xmlCopyElementContent(xmlElementContentPtr cur) {
! 1090: return(xmlCopyDocElementContent(NULL, cur));
! 1091: }
! 1092:
! 1093: /**
! 1094: * xmlFreeDocElementContent:
! 1095: * @doc: the document owning the element declaration
! 1096: * @cur: the element content tree to free
! 1097: *
! 1098: * Free an element content structure. The whole subtree is removed.
! 1099: */
! 1100: void
! 1101: xmlFreeDocElementContent(xmlDocPtr doc, xmlElementContentPtr cur) {
! 1102: xmlElementContentPtr next;
! 1103: xmlDictPtr dict = NULL;
! 1104:
! 1105: if (doc != NULL)
! 1106: dict = doc->dict;
! 1107:
! 1108: while (cur != NULL) {
! 1109: next = cur->c2;
! 1110: switch (cur->type) {
! 1111: case XML_ELEMENT_CONTENT_PCDATA:
! 1112: case XML_ELEMENT_CONTENT_ELEMENT:
! 1113: case XML_ELEMENT_CONTENT_SEQ:
! 1114: case XML_ELEMENT_CONTENT_OR:
! 1115: break;
! 1116: default:
! 1117: xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
! 1118: "Internal: ELEMENT content corrupted invalid type\n",
! 1119: NULL);
! 1120: return;
! 1121: }
! 1122: if (cur->c1 != NULL) xmlFreeDocElementContent(doc, cur->c1);
! 1123: if (dict) {
! 1124: if ((cur->name != NULL) && (!xmlDictOwns(dict, cur->name)))
! 1125: xmlFree((xmlChar *) cur->name);
! 1126: if ((cur->prefix != NULL) && (!xmlDictOwns(dict, cur->prefix)))
! 1127: xmlFree((xmlChar *) cur->prefix);
! 1128: } else {
! 1129: if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
! 1130: if (cur->prefix != NULL) xmlFree((xmlChar *) cur->prefix);
! 1131: }
! 1132: xmlFree(cur);
! 1133: cur = next;
! 1134: }
! 1135: }
! 1136:
! 1137: /**
! 1138: * xmlFreeElementContent:
! 1139: * @cur: the element content tree to free
! 1140: *
! 1141: * Free an element content structure. The whole subtree is removed.
! 1142: * Deprecated, use xmlFreeDocElementContent instead
! 1143: */
! 1144: void
! 1145: xmlFreeElementContent(xmlElementContentPtr cur) {
! 1146: xmlFreeDocElementContent(NULL, cur);
! 1147: }
! 1148:
! 1149: #ifdef LIBXML_OUTPUT_ENABLED
! 1150: /**
! 1151: * xmlDumpElementContent:
! 1152: * @buf: An XML buffer
! 1153: * @content: An element table
! 1154: * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
! 1155: *
! 1156: * This will dump the content of the element table as an XML DTD definition
! 1157: */
! 1158: static void
! 1159: xmlDumpElementContent(xmlBufferPtr buf, xmlElementContentPtr content, int glob) {
! 1160: if (content == NULL) return;
! 1161:
! 1162: if (glob) xmlBufferWriteChar(buf, "(");
! 1163: switch (content->type) {
! 1164: case XML_ELEMENT_CONTENT_PCDATA:
! 1165: xmlBufferWriteChar(buf, "#PCDATA");
! 1166: break;
! 1167: case XML_ELEMENT_CONTENT_ELEMENT:
! 1168: if (content->prefix != NULL) {
! 1169: xmlBufferWriteCHAR(buf, content->prefix);
! 1170: xmlBufferWriteChar(buf, ":");
! 1171: }
! 1172: xmlBufferWriteCHAR(buf, content->name);
! 1173: break;
! 1174: case XML_ELEMENT_CONTENT_SEQ:
! 1175: if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
! 1176: (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
! 1177: xmlDumpElementContent(buf, content->c1, 1);
! 1178: else
! 1179: xmlDumpElementContent(buf, content->c1, 0);
! 1180: xmlBufferWriteChar(buf, " , ");
! 1181: if ((content->c2->type == XML_ELEMENT_CONTENT_OR) ||
! 1182: ((content->c2->type == XML_ELEMENT_CONTENT_SEQ) &&
! 1183: (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)))
! 1184: xmlDumpElementContent(buf, content->c2, 1);
! 1185: else
! 1186: xmlDumpElementContent(buf, content->c2, 0);
! 1187: break;
! 1188: case XML_ELEMENT_CONTENT_OR:
! 1189: if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
! 1190: (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
! 1191: xmlDumpElementContent(buf, content->c1, 1);
! 1192: else
! 1193: xmlDumpElementContent(buf, content->c1, 0);
! 1194: xmlBufferWriteChar(buf, " | ");
! 1195: if ((content->c2->type == XML_ELEMENT_CONTENT_SEQ) ||
! 1196: ((content->c2->type == XML_ELEMENT_CONTENT_OR) &&
! 1197: (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)))
! 1198: xmlDumpElementContent(buf, content->c2, 1);
! 1199: else
! 1200: xmlDumpElementContent(buf, content->c2, 0);
! 1201: break;
! 1202: default:
! 1203: xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
! 1204: "Internal: ELEMENT content corrupted invalid type\n",
! 1205: NULL);
! 1206: }
! 1207: if (glob)
! 1208: xmlBufferWriteChar(buf, ")");
! 1209: switch (content->ocur) {
! 1210: case XML_ELEMENT_CONTENT_ONCE:
! 1211: break;
! 1212: case XML_ELEMENT_CONTENT_OPT:
! 1213: xmlBufferWriteChar(buf, "?");
! 1214: break;
! 1215: case XML_ELEMENT_CONTENT_MULT:
! 1216: xmlBufferWriteChar(buf, "*");
! 1217: break;
! 1218: case XML_ELEMENT_CONTENT_PLUS:
! 1219: xmlBufferWriteChar(buf, "+");
! 1220: break;
! 1221: }
! 1222: }
! 1223:
! 1224: /**
! 1225: * xmlSprintfElementContent:
! 1226: * @buf: an output buffer
! 1227: * @content: An element table
! 1228: * @englob: 1 if one must print the englobing parenthesis, 0 otherwise
! 1229: *
! 1230: * Deprecated, unsafe, use xmlSnprintfElementContent
! 1231: */
! 1232: void
! 1233: xmlSprintfElementContent(char *buf ATTRIBUTE_UNUSED,
! 1234: xmlElementContentPtr content ATTRIBUTE_UNUSED,
! 1235: int englob ATTRIBUTE_UNUSED) {
! 1236: }
! 1237: #endif /* LIBXML_OUTPUT_ENABLED */
! 1238:
! 1239: /**
! 1240: * xmlSnprintfElementContent:
! 1241: * @buf: an output buffer
! 1242: * @size: the buffer size
! 1243: * @content: An element table
! 1244: * @englob: 1 if one must print the englobing parenthesis, 0 otherwise
! 1245: *
! 1246: * This will dump the content of the element content definition
! 1247: * Intended just for the debug routine
! 1248: */
! 1249: void
! 1250: xmlSnprintfElementContent(char *buf, int size, xmlElementContentPtr content, int englob) {
! 1251: int len;
! 1252:
! 1253: if (content == NULL) return;
! 1254: len = strlen(buf);
! 1255: if (size - len < 50) {
! 1256: if ((size - len > 4) && (buf[len - 1] != '.'))
! 1257: strcat(buf, " ...");
! 1258: return;
! 1259: }
! 1260: if (englob) strcat(buf, "(");
! 1261: switch (content->type) {
! 1262: case XML_ELEMENT_CONTENT_PCDATA:
! 1263: strcat(buf, "#PCDATA");
! 1264: break;
! 1265: case XML_ELEMENT_CONTENT_ELEMENT:
! 1266: if (content->prefix != NULL) {
! 1267: if (size - len < xmlStrlen(content->prefix) + 10) {
! 1268: strcat(buf, " ...");
! 1269: return;
! 1270: }
! 1271: strcat(buf, (char *) content->prefix);
! 1272: strcat(buf, ":");
! 1273: }
! 1274: if (size - len < xmlStrlen(content->name) + 10) {
! 1275: strcat(buf, " ...");
! 1276: return;
! 1277: }
! 1278: if (content->name != NULL)
! 1279: strcat(buf, (char *) content->name);
! 1280: break;
! 1281: case XML_ELEMENT_CONTENT_SEQ:
! 1282: if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
! 1283: (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
! 1284: xmlSnprintfElementContent(buf, size, content->c1, 1);
! 1285: else
! 1286: xmlSnprintfElementContent(buf, size, content->c1, 0);
! 1287: len = strlen(buf);
! 1288: if (size - len < 50) {
! 1289: if ((size - len > 4) && (buf[len - 1] != '.'))
! 1290: strcat(buf, " ...");
! 1291: return;
! 1292: }
! 1293: strcat(buf, " , ");
! 1294: if (((content->c2->type == XML_ELEMENT_CONTENT_OR) ||
! 1295: (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
! 1296: (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
! 1297: xmlSnprintfElementContent(buf, size, content->c2, 1);
! 1298: else
! 1299: xmlSnprintfElementContent(buf, size, content->c2, 0);
! 1300: break;
! 1301: case XML_ELEMENT_CONTENT_OR:
! 1302: if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
! 1303: (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
! 1304: xmlSnprintfElementContent(buf, size, content->c1, 1);
! 1305: else
! 1306: xmlSnprintfElementContent(buf, size, content->c1, 0);
! 1307: len = strlen(buf);
! 1308: if (size - len < 50) {
! 1309: if ((size - len > 4) && (buf[len - 1] != '.'))
! 1310: strcat(buf, " ...");
! 1311: return;
! 1312: }
! 1313: strcat(buf, " | ");
! 1314: if (((content->c2->type == XML_ELEMENT_CONTENT_SEQ) ||
! 1315: (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
! 1316: (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
! 1317: xmlSnprintfElementContent(buf, size, content->c2, 1);
! 1318: else
! 1319: xmlSnprintfElementContent(buf, size, content->c2, 0);
! 1320: break;
! 1321: }
! 1322: if (englob)
! 1323: strcat(buf, ")");
! 1324: switch (content->ocur) {
! 1325: case XML_ELEMENT_CONTENT_ONCE:
! 1326: break;
! 1327: case XML_ELEMENT_CONTENT_OPT:
! 1328: strcat(buf, "?");
! 1329: break;
! 1330: case XML_ELEMENT_CONTENT_MULT:
! 1331: strcat(buf, "*");
! 1332: break;
! 1333: case XML_ELEMENT_CONTENT_PLUS:
! 1334: strcat(buf, "+");
! 1335: break;
! 1336: }
! 1337: }
! 1338:
! 1339: /****************************************************************
! 1340: * *
! 1341: * Registration of DTD declarations *
! 1342: * *
! 1343: ****************************************************************/
! 1344:
! 1345: /**
! 1346: * xmlFreeElement:
! 1347: * @elem: An element
! 1348: *
! 1349: * Deallocate the memory used by an element definition
! 1350: */
! 1351: static void
! 1352: xmlFreeElement(xmlElementPtr elem) {
! 1353: if (elem == NULL) return;
! 1354: xmlUnlinkNode((xmlNodePtr) elem);
! 1355: xmlFreeDocElementContent(elem->doc, elem->content);
! 1356: if (elem->name != NULL)
! 1357: xmlFree((xmlChar *) elem->name);
! 1358: if (elem->prefix != NULL)
! 1359: xmlFree((xmlChar *) elem->prefix);
! 1360: #ifdef LIBXML_REGEXP_ENABLED
! 1361: if (elem->contModel != NULL)
! 1362: xmlRegFreeRegexp(elem->contModel);
! 1363: #endif
! 1364: xmlFree(elem);
! 1365: }
! 1366:
! 1367:
! 1368: /**
! 1369: * xmlAddElementDecl:
! 1370: * @ctxt: the validation context
! 1371: * @dtd: pointer to the DTD
! 1372: * @name: the entity name
! 1373: * @type: the element type
! 1374: * @content: the element content tree or NULL
! 1375: *
! 1376: * Register a new element declaration
! 1377: *
! 1378: * Returns NULL if not, otherwise the entity
! 1379: */
! 1380: xmlElementPtr
! 1381: xmlAddElementDecl(xmlValidCtxtPtr ctxt,
! 1382: xmlDtdPtr dtd, const xmlChar *name,
! 1383: xmlElementTypeVal type,
! 1384: xmlElementContentPtr content) {
! 1385: xmlElementPtr ret;
! 1386: xmlElementTablePtr table;
! 1387: xmlAttributePtr oldAttributes = NULL;
! 1388: xmlChar *ns, *uqname;
! 1389:
! 1390: if (dtd == NULL) {
! 1391: return(NULL);
! 1392: }
! 1393: if (name == NULL) {
! 1394: return(NULL);
! 1395: }
! 1396:
! 1397: switch (type) {
! 1398: case XML_ELEMENT_TYPE_EMPTY:
! 1399: if (content != NULL) {
! 1400: xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
! 1401: "xmlAddElementDecl: content != NULL for EMPTY\n",
! 1402: NULL);
! 1403: return(NULL);
! 1404: }
! 1405: break;
! 1406: case XML_ELEMENT_TYPE_ANY:
! 1407: if (content != NULL) {
! 1408: xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
! 1409: "xmlAddElementDecl: content != NULL for ANY\n",
! 1410: NULL);
! 1411: return(NULL);
! 1412: }
! 1413: break;
! 1414: case XML_ELEMENT_TYPE_MIXED:
! 1415: if (content == NULL) {
! 1416: xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
! 1417: "xmlAddElementDecl: content == NULL for MIXED\n",
! 1418: NULL);
! 1419: return(NULL);
! 1420: }
! 1421: break;
! 1422: case XML_ELEMENT_TYPE_ELEMENT:
! 1423: if (content == NULL) {
! 1424: xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
! 1425: "xmlAddElementDecl: content == NULL for ELEMENT\n",
! 1426: NULL);
! 1427: return(NULL);
! 1428: }
! 1429: break;
! 1430: default:
! 1431: xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
! 1432: "Internal: ELEMENT decl corrupted invalid type\n",
! 1433: NULL);
! 1434: return(NULL);
! 1435: }
! 1436:
! 1437: /*
! 1438: * check if name is a QName
! 1439: */
! 1440: uqname = xmlSplitQName2(name, &ns);
! 1441: if (uqname != NULL)
! 1442: name = uqname;
! 1443:
! 1444: /*
! 1445: * Create the Element table if needed.
! 1446: */
! 1447: table = (xmlElementTablePtr) dtd->elements;
! 1448: if (table == NULL) {
! 1449: xmlDictPtr dict = NULL;
! 1450:
! 1451: if (dtd->doc != NULL)
! 1452: dict = dtd->doc->dict;
! 1453: table = xmlHashCreateDict(0, dict);
! 1454: dtd->elements = (void *) table;
! 1455: }
! 1456: if (table == NULL) {
! 1457: xmlVErrMemory(ctxt,
! 1458: "xmlAddElementDecl: Table creation failed!\n");
! 1459: if (uqname != NULL)
! 1460: xmlFree(uqname);
! 1461: if (ns != NULL)
! 1462: xmlFree(ns);
! 1463: return(NULL);
! 1464: }
! 1465:
! 1466: /*
! 1467: * lookup old attributes inserted on an undefined element in the
! 1468: * internal subset.
! 1469: */
! 1470: if ((dtd->doc != NULL) && (dtd->doc->intSubset != NULL)) {
! 1471: ret = xmlHashLookup2(dtd->doc->intSubset->elements, name, ns);
! 1472: if ((ret != NULL) && (ret->etype == XML_ELEMENT_TYPE_UNDEFINED)) {
! 1473: oldAttributes = ret->attributes;
! 1474: ret->attributes = NULL;
! 1475: xmlHashRemoveEntry2(dtd->doc->intSubset->elements, name, ns, NULL);
! 1476: xmlFreeElement(ret);
! 1477: }
! 1478: }
! 1479:
! 1480: /*
! 1481: * The element may already be present if one of its attribute
! 1482: * was registered first
! 1483: */
! 1484: ret = xmlHashLookup2(table, name, ns);
! 1485: if (ret != NULL) {
! 1486: if (ret->etype != XML_ELEMENT_TYPE_UNDEFINED) {
! 1487: #ifdef LIBXML_VALID_ENABLED
! 1488: /*
! 1489: * The element is already defined in this DTD.
! 1490: */
! 1491: xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED,
! 1492: "Redefinition of element %s\n",
! 1493: name, NULL, NULL);
! 1494: #endif /* LIBXML_VALID_ENABLED */
! 1495: if (uqname != NULL)
! 1496: xmlFree(uqname);
! 1497: if (ns != NULL)
! 1498: xmlFree(ns);
! 1499: return(NULL);
! 1500: }
! 1501: if (ns != NULL) {
! 1502: xmlFree(ns);
! 1503: ns = NULL;
! 1504: }
! 1505: } else {
! 1506: ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
! 1507: if (ret == NULL) {
! 1508: xmlVErrMemory(ctxt, "malloc failed");
! 1509: if (uqname != NULL)
! 1510: xmlFree(uqname);
! 1511: if (ns != NULL)
! 1512: xmlFree(ns);
! 1513: return(NULL);
! 1514: }
! 1515: memset(ret, 0, sizeof(xmlElement));
! 1516: ret->type = XML_ELEMENT_DECL;
! 1517:
! 1518: /*
! 1519: * fill the structure.
! 1520: */
! 1521: ret->name = xmlStrdup(name);
! 1522: if (ret->name == NULL) {
! 1523: xmlVErrMemory(ctxt, "malloc failed");
! 1524: if (uqname != NULL)
! 1525: xmlFree(uqname);
! 1526: if (ns != NULL)
! 1527: xmlFree(ns);
! 1528: xmlFree(ret);
! 1529: return(NULL);
! 1530: }
! 1531: ret->prefix = ns;
! 1532:
! 1533: /*
! 1534: * Validity Check:
! 1535: * Insertion must not fail
! 1536: */
! 1537: if (xmlHashAddEntry2(table, name, ns, ret)) {
! 1538: #ifdef LIBXML_VALID_ENABLED
! 1539: /*
! 1540: * The element is already defined in this DTD.
! 1541: */
! 1542: xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED,
! 1543: "Redefinition of element %s\n",
! 1544: name, NULL, NULL);
! 1545: #endif /* LIBXML_VALID_ENABLED */
! 1546: xmlFreeElement(ret);
! 1547: if (uqname != NULL)
! 1548: xmlFree(uqname);
! 1549: return(NULL);
! 1550: }
! 1551: /*
! 1552: * For new element, may have attributes from earlier
! 1553: * definition in internal subset
! 1554: */
! 1555: ret->attributes = oldAttributes;
! 1556: }
! 1557:
! 1558: /*
! 1559: * Finish to fill the structure.
! 1560: */
! 1561: ret->etype = type;
! 1562: /*
! 1563: * Avoid a stupid copy when called by the parser
! 1564: * and flag it by setting a special parent value
! 1565: * so the parser doesn't unallocate it.
! 1566: */
! 1567: if ((ctxt != NULL) &&
! 1568: ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
! 1569: (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1))) {
! 1570: ret->content = content;
! 1571: if (content != NULL)
! 1572: content->parent = (xmlElementContentPtr) 1;
! 1573: } else {
! 1574: ret->content = xmlCopyDocElementContent(dtd->doc, content);
! 1575: }
! 1576:
! 1577: /*
! 1578: * Link it to the DTD
! 1579: */
! 1580: ret->parent = dtd;
! 1581: ret->doc = dtd->doc;
! 1582: if (dtd->last == NULL) {
! 1583: dtd->children = dtd->last = (xmlNodePtr) ret;
! 1584: } else {
! 1585: dtd->last->next = (xmlNodePtr) ret;
! 1586: ret->prev = dtd->last;
! 1587: dtd->last = (xmlNodePtr) ret;
! 1588: }
! 1589: if (uqname != NULL)
! 1590: xmlFree(uqname);
! 1591: return(ret);
! 1592: }
! 1593:
! 1594: /**
! 1595: * xmlFreeElementTable:
! 1596: * @table: An element table
! 1597: *
! 1598: * Deallocate the memory used by an element hash table.
! 1599: */
! 1600: void
! 1601: xmlFreeElementTable(xmlElementTablePtr table) {
! 1602: xmlHashFree(table, (xmlHashDeallocator) xmlFreeElement);
! 1603: }
! 1604:
! 1605: #ifdef LIBXML_TREE_ENABLED
! 1606: /**
! 1607: * xmlCopyElement:
! 1608: * @elem: An element
! 1609: *
! 1610: * Build a copy of an element.
! 1611: *
! 1612: * Returns the new xmlElementPtr or NULL in case of error.
! 1613: */
! 1614: static xmlElementPtr
! 1615: xmlCopyElement(xmlElementPtr elem) {
! 1616: xmlElementPtr cur;
! 1617:
! 1618: cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
! 1619: if (cur == NULL) {
! 1620: xmlVErrMemory(NULL, "malloc failed");
! 1621: return(NULL);
! 1622: }
! 1623: memset(cur, 0, sizeof(xmlElement));
! 1624: cur->type = XML_ELEMENT_DECL;
! 1625: cur->etype = elem->etype;
! 1626: if (elem->name != NULL)
! 1627: cur->name = xmlStrdup(elem->name);
! 1628: else
! 1629: cur->name = NULL;
! 1630: if (elem->prefix != NULL)
! 1631: cur->prefix = xmlStrdup(elem->prefix);
! 1632: else
! 1633: cur->prefix = NULL;
! 1634: cur->content = xmlCopyElementContent(elem->content);
! 1635: /* TODO : rebuild the attribute list on the copy */
! 1636: cur->attributes = NULL;
! 1637: return(cur);
! 1638: }
! 1639:
! 1640: /**
! 1641: * xmlCopyElementTable:
! 1642: * @table: An element table
! 1643: *
! 1644: * Build a copy of an element table.
! 1645: *
! 1646: * Returns the new xmlElementTablePtr or NULL in case of error.
! 1647: */
! 1648: xmlElementTablePtr
! 1649: xmlCopyElementTable(xmlElementTablePtr table) {
! 1650: return((xmlElementTablePtr) xmlHashCopy(table,
! 1651: (xmlHashCopier) xmlCopyElement));
! 1652: }
! 1653: #endif /* LIBXML_TREE_ENABLED */
! 1654:
! 1655: #ifdef LIBXML_OUTPUT_ENABLED
! 1656: /**
! 1657: * xmlDumpElementDecl:
! 1658: * @buf: the XML buffer output
! 1659: * @elem: An element table
! 1660: *
! 1661: * This will dump the content of the element declaration as an XML
! 1662: * DTD definition
! 1663: */
! 1664: void
! 1665: xmlDumpElementDecl(xmlBufferPtr buf, xmlElementPtr elem) {
! 1666: if ((buf == NULL) || (elem == NULL))
! 1667: return;
! 1668: switch (elem->etype) {
! 1669: case XML_ELEMENT_TYPE_EMPTY:
! 1670: xmlBufferWriteChar(buf, "<!ELEMENT ");
! 1671: if (elem->prefix != NULL) {
! 1672: xmlBufferWriteCHAR(buf, elem->prefix);
! 1673: xmlBufferWriteChar(buf, ":");
! 1674: }
! 1675: xmlBufferWriteCHAR(buf, elem->name);
! 1676: xmlBufferWriteChar(buf, " EMPTY>\n");
! 1677: break;
! 1678: case XML_ELEMENT_TYPE_ANY:
! 1679: xmlBufferWriteChar(buf, "<!ELEMENT ");
! 1680: if (elem->prefix != NULL) {
! 1681: xmlBufferWriteCHAR(buf, elem->prefix);
! 1682: xmlBufferWriteChar(buf, ":");
! 1683: }
! 1684: xmlBufferWriteCHAR(buf, elem->name);
! 1685: xmlBufferWriteChar(buf, " ANY>\n");
! 1686: break;
! 1687: case XML_ELEMENT_TYPE_MIXED:
! 1688: xmlBufferWriteChar(buf, "<!ELEMENT ");
! 1689: if (elem->prefix != NULL) {
! 1690: xmlBufferWriteCHAR(buf, elem->prefix);
! 1691: xmlBufferWriteChar(buf, ":");
! 1692: }
! 1693: xmlBufferWriteCHAR(buf, elem->name);
! 1694: xmlBufferWriteChar(buf, " ");
! 1695: xmlDumpElementContent(buf, elem->content, 1);
! 1696: xmlBufferWriteChar(buf, ">\n");
! 1697: break;
! 1698: case XML_ELEMENT_TYPE_ELEMENT:
! 1699: xmlBufferWriteChar(buf, "<!ELEMENT ");
! 1700: if (elem->prefix != NULL) {
! 1701: xmlBufferWriteCHAR(buf, elem->prefix);
! 1702: xmlBufferWriteChar(buf, ":");
! 1703: }
! 1704: xmlBufferWriteCHAR(buf, elem->name);
! 1705: xmlBufferWriteChar(buf, " ");
! 1706: xmlDumpElementContent(buf, elem->content, 1);
! 1707: xmlBufferWriteChar(buf, ">\n");
! 1708: break;
! 1709: default:
! 1710: xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
! 1711: "Internal: ELEMENT struct corrupted invalid type\n",
! 1712: NULL);
! 1713: }
! 1714: }
! 1715:
! 1716: /**
! 1717: * xmlDumpElementDeclScan:
! 1718: * @elem: An element table
! 1719: * @buf: the XML buffer output
! 1720: *
! 1721: * This routine is used by the hash scan function. It just reverses
! 1722: * the arguments.
! 1723: */
! 1724: static void
! 1725: xmlDumpElementDeclScan(xmlElementPtr elem, xmlBufferPtr buf) {
! 1726: xmlDumpElementDecl(buf, elem);
! 1727: }
! 1728:
! 1729: /**
! 1730: * xmlDumpElementTable:
! 1731: * @buf: the XML buffer output
! 1732: * @table: An element table
! 1733: *
! 1734: * This will dump the content of the element table as an XML DTD definition
! 1735: */
! 1736: void
! 1737: xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) {
! 1738: if ((buf == NULL) || (table == NULL))
! 1739: return;
! 1740: xmlHashScan(table, (xmlHashScanner) xmlDumpElementDeclScan, buf);
! 1741: }
! 1742: #endif /* LIBXML_OUTPUT_ENABLED */
! 1743:
! 1744: /**
! 1745: * xmlCreateEnumeration:
! 1746: * @name: the enumeration name or NULL
! 1747: *
! 1748: * create and initialize an enumeration attribute node.
! 1749: *
! 1750: * Returns the xmlEnumerationPtr just created or NULL in case
! 1751: * of error.
! 1752: */
! 1753: xmlEnumerationPtr
! 1754: xmlCreateEnumeration(const xmlChar *name) {
! 1755: xmlEnumerationPtr ret;
! 1756:
! 1757: ret = (xmlEnumerationPtr) xmlMalloc(sizeof(xmlEnumeration));
! 1758: if (ret == NULL) {
! 1759: xmlVErrMemory(NULL, "malloc failed");
! 1760: return(NULL);
! 1761: }
! 1762: memset(ret, 0, sizeof(xmlEnumeration));
! 1763:
! 1764: if (name != NULL)
! 1765: ret->name = xmlStrdup(name);
! 1766: return(ret);
! 1767: }
! 1768:
! 1769: /**
! 1770: * xmlFreeEnumeration:
! 1771: * @cur: the tree to free.
! 1772: *
! 1773: * free an enumeration attribute node (recursive).
! 1774: */
! 1775: void
! 1776: xmlFreeEnumeration(xmlEnumerationPtr cur) {
! 1777: if (cur == NULL) return;
! 1778:
! 1779: if (cur->next != NULL) xmlFreeEnumeration(cur->next);
! 1780:
! 1781: if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
! 1782: xmlFree(cur);
! 1783: }
! 1784:
! 1785: #ifdef LIBXML_TREE_ENABLED
! 1786: /**
! 1787: * xmlCopyEnumeration:
! 1788: * @cur: the tree to copy.
! 1789: *
! 1790: * Copy an enumeration attribute node (recursive).
! 1791: *
! 1792: * Returns the xmlEnumerationPtr just created or NULL in case
! 1793: * of error.
! 1794: */
! 1795: xmlEnumerationPtr
! 1796: xmlCopyEnumeration(xmlEnumerationPtr cur) {
! 1797: xmlEnumerationPtr ret;
! 1798:
! 1799: if (cur == NULL) return(NULL);
! 1800: ret = xmlCreateEnumeration((xmlChar *) cur->name);
! 1801:
! 1802: if (cur->next != NULL) ret->next = xmlCopyEnumeration(cur->next);
! 1803: else ret->next = NULL;
! 1804:
! 1805: return(ret);
! 1806: }
! 1807: #endif /* LIBXML_TREE_ENABLED */
! 1808:
! 1809: #ifdef LIBXML_OUTPUT_ENABLED
! 1810: /**
! 1811: * xmlDumpEnumeration:
! 1812: * @buf: the XML buffer output
! 1813: * @enum: An enumeration
! 1814: *
! 1815: * This will dump the content of the enumeration
! 1816: */
! 1817: static void
! 1818: xmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) {
! 1819: if ((buf == NULL) || (cur == NULL))
! 1820: return;
! 1821:
! 1822: xmlBufferWriteCHAR(buf, cur->name);
! 1823: if (cur->next == NULL)
! 1824: xmlBufferWriteChar(buf, ")");
! 1825: else {
! 1826: xmlBufferWriteChar(buf, " | ");
! 1827: xmlDumpEnumeration(buf, cur->next);
! 1828: }
! 1829: }
! 1830: #endif /* LIBXML_OUTPUT_ENABLED */
! 1831:
! 1832: #ifdef LIBXML_VALID_ENABLED
! 1833: /**
! 1834: * xmlScanIDAttributeDecl:
! 1835: * @ctxt: the validation context
! 1836: * @elem: the element name
! 1837: * @err: whether to raise errors here
! 1838: *
! 1839: * Verify that the element don't have too many ID attributes
! 1840: * declared.
! 1841: *
! 1842: * Returns the number of ID attributes found.
! 1843: */
! 1844: static int
! 1845: xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem, int err) {
! 1846: xmlAttributePtr cur;
! 1847: int ret = 0;
! 1848:
! 1849: if (elem == NULL) return(0);
! 1850: cur = elem->attributes;
! 1851: while (cur != NULL) {
! 1852: if (cur->atype == XML_ATTRIBUTE_ID) {
! 1853: ret ++;
! 1854: if ((ret > 1) && (err))
! 1855: xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_MULTIPLE_ID,
! 1856: "Element %s has too many ID attributes defined : %s\n",
! 1857: elem->name, cur->name, NULL);
! 1858: }
! 1859: cur = cur->nexth;
! 1860: }
! 1861: return(ret);
! 1862: }
! 1863: #endif /* LIBXML_VALID_ENABLED */
! 1864:
! 1865: /**
! 1866: * xmlFreeAttribute:
! 1867: * @elem: An attribute
! 1868: *
! 1869: * Deallocate the memory used by an attribute definition
! 1870: */
! 1871: static void
! 1872: xmlFreeAttribute(xmlAttributePtr attr) {
! 1873: xmlDictPtr dict;
! 1874:
! 1875: if (attr == NULL) return;
! 1876: if (attr->doc != NULL)
! 1877: dict = attr->doc->dict;
! 1878: else
! 1879: dict = NULL;
! 1880: xmlUnlinkNode((xmlNodePtr) attr);
! 1881: if (attr->tree != NULL)
! 1882: xmlFreeEnumeration(attr->tree);
! 1883: if (dict) {
! 1884: if ((attr->elem != NULL) && (!xmlDictOwns(dict, attr->elem)))
! 1885: xmlFree((xmlChar *) attr->elem);
! 1886: if ((attr->name != NULL) && (!xmlDictOwns(dict, attr->name)))
! 1887: xmlFree((xmlChar *) attr->name);
! 1888: if ((attr->prefix != NULL) && (!xmlDictOwns(dict, attr->prefix)))
! 1889: xmlFree((xmlChar *) attr->prefix);
! 1890: if ((attr->defaultValue != NULL) &&
! 1891: (!xmlDictOwns(dict, attr->defaultValue)))
! 1892: xmlFree((xmlChar *) attr->defaultValue);
! 1893: } else {
! 1894: if (attr->elem != NULL)
! 1895: xmlFree((xmlChar *) attr->elem);
! 1896: if (attr->name != NULL)
! 1897: xmlFree((xmlChar *) attr->name);
! 1898: if (attr->defaultValue != NULL)
! 1899: xmlFree((xmlChar *) attr->defaultValue);
! 1900: if (attr->prefix != NULL)
! 1901: xmlFree((xmlChar *) attr->prefix);
! 1902: }
! 1903: xmlFree(attr);
! 1904: }
! 1905:
! 1906:
! 1907: /**
! 1908: * xmlAddAttributeDecl:
! 1909: * @ctxt: the validation context
! 1910: * @dtd: pointer to the DTD
! 1911: * @elem: the element name
! 1912: * @name: the attribute name
! 1913: * @ns: the attribute namespace prefix
! 1914: * @type: the attribute type
! 1915: * @def: the attribute default type
! 1916: * @defaultValue: the attribute default value
! 1917: * @tree: if it's an enumeration, the associated list
! 1918: *
! 1919: * Register a new attribute declaration
! 1920: * Note that @tree becomes the ownership of the DTD
! 1921: *
! 1922: * Returns NULL if not new, otherwise the attribute decl
! 1923: */
! 1924: xmlAttributePtr
! 1925: xmlAddAttributeDecl(xmlValidCtxtPtr ctxt,
! 1926: xmlDtdPtr dtd, const xmlChar *elem,
! 1927: const xmlChar *name, const xmlChar *ns,
! 1928: xmlAttributeType type, xmlAttributeDefault def,
! 1929: const xmlChar *defaultValue, xmlEnumerationPtr tree) {
! 1930: xmlAttributePtr ret;
! 1931: xmlAttributeTablePtr table;
! 1932: xmlElementPtr elemDef;
! 1933: xmlDictPtr dict = NULL;
! 1934:
! 1935: if (dtd == NULL) {
! 1936: xmlFreeEnumeration(tree);
! 1937: return(NULL);
! 1938: }
! 1939: if (name == NULL) {
! 1940: xmlFreeEnumeration(tree);
! 1941: return(NULL);
! 1942: }
! 1943: if (elem == NULL) {
! 1944: xmlFreeEnumeration(tree);
! 1945: return(NULL);
! 1946: }
! 1947: if (dtd->doc != NULL)
! 1948: dict = dtd->doc->dict;
! 1949:
! 1950: #ifdef LIBXML_VALID_ENABLED
! 1951: /*
! 1952: * Check the type and possibly the default value.
! 1953: */
! 1954: switch (type) {
! 1955: case XML_ATTRIBUTE_CDATA:
! 1956: break;
! 1957: case XML_ATTRIBUTE_ID:
! 1958: break;
! 1959: case XML_ATTRIBUTE_IDREF:
! 1960: break;
! 1961: case XML_ATTRIBUTE_IDREFS:
! 1962: break;
! 1963: case XML_ATTRIBUTE_ENTITY:
! 1964: break;
! 1965: case XML_ATTRIBUTE_ENTITIES:
! 1966: break;
! 1967: case XML_ATTRIBUTE_NMTOKEN:
! 1968: break;
! 1969: case XML_ATTRIBUTE_NMTOKENS:
! 1970: break;
! 1971: case XML_ATTRIBUTE_ENUMERATION:
! 1972: break;
! 1973: case XML_ATTRIBUTE_NOTATION:
! 1974: break;
! 1975: default:
! 1976: xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
! 1977: "Internal: ATTRIBUTE struct corrupted invalid type\n",
! 1978: NULL);
! 1979: xmlFreeEnumeration(tree);
! 1980: return(NULL);
! 1981: }
! 1982: if ((defaultValue != NULL) &&
! 1983: (!xmlValidateAttributeValueInternal(dtd->doc, type, defaultValue))) {
! 1984: xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_DEFAULT,
! 1985: "Attribute %s of %s: invalid default value\n",
! 1986: elem, name, defaultValue);
! 1987: defaultValue = NULL;
! 1988: if (ctxt != NULL)
! 1989: ctxt->valid = 0;
! 1990: }
! 1991: #endif /* LIBXML_VALID_ENABLED */
! 1992:
! 1993: /*
! 1994: * Check first that an attribute defined in the external subset wasn't
! 1995: * already defined in the internal subset
! 1996: */
! 1997: if ((dtd->doc != NULL) && (dtd->doc->extSubset == dtd) &&
! 1998: (dtd->doc->intSubset != NULL) &&
! 1999: (dtd->doc->intSubset->attributes != NULL)) {
! 2000: ret = xmlHashLookup3(dtd->doc->intSubset->attributes, name, ns, elem);
! 2001: if (ret != NULL) {
! 2002: xmlFreeEnumeration(tree);
! 2003: return(NULL);
! 2004: }
! 2005: }
! 2006:
! 2007: /*
! 2008: * Create the Attribute table if needed.
! 2009: */
! 2010: table = (xmlAttributeTablePtr) dtd->attributes;
! 2011: if (table == NULL) {
! 2012: table = xmlHashCreateDict(0, dict);
! 2013: dtd->attributes = (void *) table;
! 2014: }
! 2015: if (table == NULL) {
! 2016: xmlVErrMemory(ctxt,
! 2017: "xmlAddAttributeDecl: Table creation failed!\n");
! 2018: xmlFreeEnumeration(tree);
! 2019: return(NULL);
! 2020: }
! 2021:
! 2022:
! 2023: ret = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
! 2024: if (ret == NULL) {
! 2025: xmlVErrMemory(ctxt, "malloc failed");
! 2026: xmlFreeEnumeration(tree);
! 2027: return(NULL);
! 2028: }
! 2029: memset(ret, 0, sizeof(xmlAttribute));
! 2030: ret->type = XML_ATTRIBUTE_DECL;
! 2031:
! 2032: /*
! 2033: * fill the structure.
! 2034: */
! 2035: ret->atype = type;
! 2036: /*
! 2037: * doc must be set before possible error causes call
! 2038: * to xmlFreeAttribute (because it's used to check on
! 2039: * dict use)
! 2040: */
! 2041: ret->doc = dtd->doc;
! 2042: if (dict) {
! 2043: ret->name = xmlDictLookup(dict, name, -1);
! 2044: ret->prefix = xmlDictLookup(dict, ns, -1);
! 2045: ret->elem = xmlDictLookup(dict, elem, -1);
! 2046: } else {
! 2047: ret->name = xmlStrdup(name);
! 2048: ret->prefix = xmlStrdup(ns);
! 2049: ret->elem = xmlStrdup(elem);
! 2050: }
! 2051: ret->def = def;
! 2052: ret->tree = tree;
! 2053: if (defaultValue != NULL) {
! 2054: if (dict)
! 2055: ret->defaultValue = xmlDictLookup(dict, defaultValue, -1);
! 2056: else
! 2057: ret->defaultValue = xmlStrdup(defaultValue);
! 2058: }
! 2059:
! 2060: /*
! 2061: * Validity Check:
! 2062: * Search the DTD for previous declarations of the ATTLIST
! 2063: */
! 2064: if (xmlHashAddEntry3(table, ret->name, ret->prefix, ret->elem, ret) < 0) {
! 2065: #ifdef LIBXML_VALID_ENABLED
! 2066: /*
! 2067: * The attribute is already defined in this DTD.
! 2068: */
! 2069: xmlErrValidWarning(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_REDEFINED,
! 2070: "Attribute %s of element %s: already defined\n",
! 2071: name, elem, NULL);
! 2072: #endif /* LIBXML_VALID_ENABLED */
! 2073: xmlFreeAttribute(ret);
! 2074: return(NULL);
! 2075: }
! 2076:
! 2077: /*
! 2078: * Validity Check:
! 2079: * Multiple ID per element
! 2080: */
! 2081: elemDef = xmlGetDtdElementDesc2(dtd, elem, 1);
! 2082: if (elemDef != NULL) {
! 2083:
! 2084: #ifdef LIBXML_VALID_ENABLED
! 2085: if ((type == XML_ATTRIBUTE_ID) &&
! 2086: (xmlScanIDAttributeDecl(NULL, elemDef, 1) != 0)) {
! 2087: xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_MULTIPLE_ID,
! 2088: "Element %s has too may ID attributes defined : %s\n",
! 2089: elem, name, NULL);
! 2090: if (ctxt != NULL)
! 2091: ctxt->valid = 0;
! 2092: }
! 2093: #endif /* LIBXML_VALID_ENABLED */
! 2094:
! 2095: /*
! 2096: * Insert namespace default def first they need to be
! 2097: * processed first.
! 2098: */
! 2099: if ((xmlStrEqual(ret->name, BAD_CAST "xmlns")) ||
! 2100: ((ret->prefix != NULL &&
! 2101: (xmlStrEqual(ret->prefix, BAD_CAST "xmlns"))))) {
! 2102: ret->nexth = elemDef->attributes;
! 2103: elemDef->attributes = ret;
! 2104: } else {
! 2105: xmlAttributePtr tmp = elemDef->attributes;
! 2106:
! 2107: while ((tmp != NULL) &&
! 2108: ((xmlStrEqual(tmp->name, BAD_CAST "xmlns")) ||
! 2109: ((ret->prefix != NULL &&
! 2110: (xmlStrEqual(ret->prefix, BAD_CAST "xmlns")))))) {
! 2111: if (tmp->nexth == NULL)
! 2112: break;
! 2113: tmp = tmp->nexth;
! 2114: }
! 2115: if (tmp != NULL) {
! 2116: ret->nexth = tmp->nexth;
! 2117: tmp->nexth = ret;
! 2118: } else {
! 2119: ret->nexth = elemDef->attributes;
! 2120: elemDef->attributes = ret;
! 2121: }
! 2122: }
! 2123: }
! 2124:
! 2125: /*
! 2126: * Link it to the DTD
! 2127: */
! 2128: ret->parent = dtd;
! 2129: if (dtd->last == NULL) {
! 2130: dtd->children = dtd->last = (xmlNodePtr) ret;
! 2131: } else {
! 2132: dtd->last->next = (xmlNodePtr) ret;
! 2133: ret->prev = dtd->last;
! 2134: dtd->last = (xmlNodePtr) ret;
! 2135: }
! 2136: return(ret);
! 2137: }
! 2138:
! 2139: /**
! 2140: * xmlFreeAttributeTable:
! 2141: * @table: An attribute table
! 2142: *
! 2143: * Deallocate the memory used by an entities hash table.
! 2144: */
! 2145: void
! 2146: xmlFreeAttributeTable(xmlAttributeTablePtr table) {
! 2147: xmlHashFree(table, (xmlHashDeallocator) xmlFreeAttribute);
! 2148: }
! 2149:
! 2150: #ifdef LIBXML_TREE_ENABLED
! 2151: /**
! 2152: * xmlCopyAttribute:
! 2153: * @attr: An attribute
! 2154: *
! 2155: * Build a copy of an attribute.
! 2156: *
! 2157: * Returns the new xmlAttributePtr or NULL in case of error.
! 2158: */
! 2159: static xmlAttributePtr
! 2160: xmlCopyAttribute(xmlAttributePtr attr) {
! 2161: xmlAttributePtr cur;
! 2162:
! 2163: cur = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
! 2164: if (cur == NULL) {
! 2165: xmlVErrMemory(NULL, "malloc failed");
! 2166: return(NULL);
! 2167: }
! 2168: memset(cur, 0, sizeof(xmlAttribute));
! 2169: cur->type = XML_ATTRIBUTE_DECL;
! 2170: cur->atype = attr->atype;
! 2171: cur->def = attr->def;
! 2172: cur->tree = xmlCopyEnumeration(attr->tree);
! 2173: if (attr->elem != NULL)
! 2174: cur->elem = xmlStrdup(attr->elem);
! 2175: if (attr->name != NULL)
! 2176: cur->name = xmlStrdup(attr->name);
! 2177: if (attr->prefix != NULL)
! 2178: cur->prefix = xmlStrdup(attr->prefix);
! 2179: if (attr->defaultValue != NULL)
! 2180: cur->defaultValue = xmlStrdup(attr->defaultValue);
! 2181: return(cur);
! 2182: }
! 2183:
! 2184: /**
! 2185: * xmlCopyAttributeTable:
! 2186: * @table: An attribute table
! 2187: *
! 2188: * Build a copy of an attribute table.
! 2189: *
! 2190: * Returns the new xmlAttributeTablePtr or NULL in case of error.
! 2191: */
! 2192: xmlAttributeTablePtr
! 2193: xmlCopyAttributeTable(xmlAttributeTablePtr table) {
! 2194: return((xmlAttributeTablePtr) xmlHashCopy(table,
! 2195: (xmlHashCopier) xmlCopyAttribute));
! 2196: }
! 2197: #endif /* LIBXML_TREE_ENABLED */
! 2198:
! 2199: #ifdef LIBXML_OUTPUT_ENABLED
! 2200: /**
! 2201: * xmlDumpAttributeDecl:
! 2202: * @buf: the XML buffer output
! 2203: * @attr: An attribute declaration
! 2204: *
! 2205: * This will dump the content of the attribute declaration as an XML
! 2206: * DTD definition
! 2207: */
! 2208: void
! 2209: xmlDumpAttributeDecl(xmlBufferPtr buf, xmlAttributePtr attr) {
! 2210: if ((buf == NULL) || (attr == NULL))
! 2211: return;
! 2212: xmlBufferWriteChar(buf, "<!ATTLIST ");
! 2213: xmlBufferWriteCHAR(buf, attr->elem);
! 2214: xmlBufferWriteChar(buf, " ");
! 2215: if (attr->prefix != NULL) {
! 2216: xmlBufferWriteCHAR(buf, attr->prefix);
! 2217: xmlBufferWriteChar(buf, ":");
! 2218: }
! 2219: xmlBufferWriteCHAR(buf, attr->name);
! 2220: switch (attr->atype) {
! 2221: case XML_ATTRIBUTE_CDATA:
! 2222: xmlBufferWriteChar(buf, " CDATA");
! 2223: break;
! 2224: case XML_ATTRIBUTE_ID:
! 2225: xmlBufferWriteChar(buf, " ID");
! 2226: break;
! 2227: case XML_ATTRIBUTE_IDREF:
! 2228: xmlBufferWriteChar(buf, " IDREF");
! 2229: break;
! 2230: case XML_ATTRIBUTE_IDREFS:
! 2231: xmlBufferWriteChar(buf, " IDREFS");
! 2232: break;
! 2233: case XML_ATTRIBUTE_ENTITY:
! 2234: xmlBufferWriteChar(buf, " ENTITY");
! 2235: break;
! 2236: case XML_ATTRIBUTE_ENTITIES:
! 2237: xmlBufferWriteChar(buf, " ENTITIES");
! 2238: break;
! 2239: case XML_ATTRIBUTE_NMTOKEN:
! 2240: xmlBufferWriteChar(buf, " NMTOKEN");
! 2241: break;
! 2242: case XML_ATTRIBUTE_NMTOKENS:
! 2243: xmlBufferWriteChar(buf, " NMTOKENS");
! 2244: break;
! 2245: case XML_ATTRIBUTE_ENUMERATION:
! 2246: xmlBufferWriteChar(buf, " (");
! 2247: xmlDumpEnumeration(buf, attr->tree);
! 2248: break;
! 2249: case XML_ATTRIBUTE_NOTATION:
! 2250: xmlBufferWriteChar(buf, " NOTATION (");
! 2251: xmlDumpEnumeration(buf, attr->tree);
! 2252: break;
! 2253: default:
! 2254: xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
! 2255: "Internal: ATTRIBUTE struct corrupted invalid type\n",
! 2256: NULL);
! 2257: }
! 2258: switch (attr->def) {
! 2259: case XML_ATTRIBUTE_NONE:
! 2260: break;
! 2261: case XML_ATTRIBUTE_REQUIRED:
! 2262: xmlBufferWriteChar(buf, " #REQUIRED");
! 2263: break;
! 2264: case XML_ATTRIBUTE_IMPLIED:
! 2265: xmlBufferWriteChar(buf, " #IMPLIED");
! 2266: break;
! 2267: case XML_ATTRIBUTE_FIXED:
! 2268: xmlBufferWriteChar(buf, " #FIXED");
! 2269: break;
! 2270: default:
! 2271: xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
! 2272: "Internal: ATTRIBUTE struct corrupted invalid def\n",
! 2273: NULL);
! 2274: }
! 2275: if (attr->defaultValue != NULL) {
! 2276: xmlBufferWriteChar(buf, " ");
! 2277: xmlBufferWriteQuotedString(buf, attr->defaultValue);
! 2278: }
! 2279: xmlBufferWriteChar(buf, ">\n");
! 2280: }
! 2281:
! 2282: /**
! 2283: * xmlDumpAttributeDeclScan:
! 2284: * @attr: An attribute declaration
! 2285: * @buf: the XML buffer output
! 2286: *
! 2287: * This is used with the hash scan function - just reverses arguments
! 2288: */
! 2289: static void
! 2290: xmlDumpAttributeDeclScan(xmlAttributePtr attr, xmlBufferPtr buf) {
! 2291: xmlDumpAttributeDecl(buf, attr);
! 2292: }
! 2293:
! 2294: /**
! 2295: * xmlDumpAttributeTable:
! 2296: * @buf: the XML buffer output
! 2297: * @table: An attribute table
! 2298: *
! 2299: * This will dump the content of the attribute table as an XML DTD definition
! 2300: */
! 2301: void
! 2302: xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) {
! 2303: if ((buf == NULL) || (table == NULL))
! 2304: return;
! 2305: xmlHashScan(table, (xmlHashScanner) xmlDumpAttributeDeclScan, buf);
! 2306: }
! 2307: #endif /* LIBXML_OUTPUT_ENABLED */
! 2308:
! 2309: /************************************************************************
! 2310: * *
! 2311: * NOTATIONs *
! 2312: * *
! 2313: ************************************************************************/
! 2314: /**
! 2315: * xmlFreeNotation:
! 2316: * @not: A notation
! 2317: *
! 2318: * Deallocate the memory used by an notation definition
! 2319: */
! 2320: static void
! 2321: xmlFreeNotation(xmlNotationPtr nota) {
! 2322: if (nota == NULL) return;
! 2323: if (nota->name != NULL)
! 2324: xmlFree((xmlChar *) nota->name);
! 2325: if (nota->PublicID != NULL)
! 2326: xmlFree((xmlChar *) nota->PublicID);
! 2327: if (nota->SystemID != NULL)
! 2328: xmlFree((xmlChar *) nota->SystemID);
! 2329: xmlFree(nota);
! 2330: }
! 2331:
! 2332:
! 2333: /**
! 2334: * xmlAddNotationDecl:
! 2335: * @dtd: pointer to the DTD
! 2336: * @ctxt: the validation context
! 2337: * @name: the entity name
! 2338: * @PublicID: the public identifier or NULL
! 2339: * @SystemID: the system identifier or NULL
! 2340: *
! 2341: * Register a new notation declaration
! 2342: *
! 2343: * Returns NULL if not, otherwise the entity
! 2344: */
! 2345: xmlNotationPtr
! 2346: xmlAddNotationDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd,
! 2347: const xmlChar *name,
! 2348: const xmlChar *PublicID, const xmlChar *SystemID) {
! 2349: xmlNotationPtr ret;
! 2350: xmlNotationTablePtr table;
! 2351:
! 2352: if (dtd == NULL) {
! 2353: return(NULL);
! 2354: }
! 2355: if (name == NULL) {
! 2356: return(NULL);
! 2357: }
! 2358: if ((PublicID == NULL) && (SystemID == NULL)) {
! 2359: return(NULL);
! 2360: }
! 2361:
! 2362: /*
! 2363: * Create the Notation table if needed.
! 2364: */
! 2365: table = (xmlNotationTablePtr) dtd->notations;
! 2366: if (table == NULL) {
! 2367: xmlDictPtr dict = NULL;
! 2368: if (dtd->doc != NULL)
! 2369: dict = dtd->doc->dict;
! 2370:
! 2371: dtd->notations = table = xmlHashCreateDict(0, dict);
! 2372: }
! 2373: if (table == NULL) {
! 2374: xmlVErrMemory(ctxt,
! 2375: "xmlAddNotationDecl: Table creation failed!\n");
! 2376: return(NULL);
! 2377: }
! 2378:
! 2379: ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
! 2380: if (ret == NULL) {
! 2381: xmlVErrMemory(ctxt, "malloc failed");
! 2382: return(NULL);
! 2383: }
! 2384: memset(ret, 0, sizeof(xmlNotation));
! 2385:
! 2386: /*
! 2387: * fill the structure.
! 2388: */
! 2389: ret->name = xmlStrdup(name);
! 2390: if (SystemID != NULL)
! 2391: ret->SystemID = xmlStrdup(SystemID);
! 2392: if (PublicID != NULL)
! 2393: ret->PublicID = xmlStrdup(PublicID);
! 2394:
! 2395: /*
! 2396: * Validity Check:
! 2397: * Check the DTD for previous declarations of the ATTLIST
! 2398: */
! 2399: if (xmlHashAddEntry(table, name, ret)) {
! 2400: #ifdef LIBXML_VALID_ENABLED
! 2401: xmlErrValid(NULL, XML_DTD_NOTATION_REDEFINED,
! 2402: "xmlAddNotationDecl: %s already defined\n",
! 2403: (const char *) name);
! 2404: #endif /* LIBXML_VALID_ENABLED */
! 2405: xmlFreeNotation(ret);
! 2406: return(NULL);
! 2407: }
! 2408: return(ret);
! 2409: }
! 2410:
! 2411: /**
! 2412: * xmlFreeNotationTable:
! 2413: * @table: An notation table
! 2414: *
! 2415: * Deallocate the memory used by an entities hash table.
! 2416: */
! 2417: void
! 2418: xmlFreeNotationTable(xmlNotationTablePtr table) {
! 2419: xmlHashFree(table, (xmlHashDeallocator) xmlFreeNotation);
! 2420: }
! 2421:
! 2422: #ifdef LIBXML_TREE_ENABLED
! 2423: /**
! 2424: * xmlCopyNotation:
! 2425: * @nota: A notation
! 2426: *
! 2427: * Build a copy of a notation.
! 2428: *
! 2429: * Returns the new xmlNotationPtr or NULL in case of error.
! 2430: */
! 2431: static xmlNotationPtr
! 2432: xmlCopyNotation(xmlNotationPtr nota) {
! 2433: xmlNotationPtr cur;
! 2434:
! 2435: cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
! 2436: if (cur == NULL) {
! 2437: xmlVErrMemory(NULL, "malloc failed");
! 2438: return(NULL);
! 2439: }
! 2440: if (nota->name != NULL)
! 2441: cur->name = xmlStrdup(nota->name);
! 2442: else
! 2443: cur->name = NULL;
! 2444: if (nota->PublicID != NULL)
! 2445: cur->PublicID = xmlStrdup(nota->PublicID);
! 2446: else
! 2447: cur->PublicID = NULL;
! 2448: if (nota->SystemID != NULL)
! 2449: cur->SystemID = xmlStrdup(nota->SystemID);
! 2450: else
! 2451: cur->SystemID = NULL;
! 2452: return(cur);
! 2453: }
! 2454:
! 2455: /**
! 2456: * xmlCopyNotationTable:
! 2457: * @table: A notation table
! 2458: *
! 2459: * Build a copy of a notation table.
! 2460: *
! 2461: * Returns the new xmlNotationTablePtr or NULL in case of error.
! 2462: */
! 2463: xmlNotationTablePtr
! 2464: xmlCopyNotationTable(xmlNotationTablePtr table) {
! 2465: return((xmlNotationTablePtr) xmlHashCopy(table,
! 2466: (xmlHashCopier) xmlCopyNotation));
! 2467: }
! 2468: #endif /* LIBXML_TREE_ENABLED */
! 2469:
! 2470: #ifdef LIBXML_OUTPUT_ENABLED
! 2471: /**
! 2472: * xmlDumpNotationDecl:
! 2473: * @buf: the XML buffer output
! 2474: * @nota: A notation declaration
! 2475: *
! 2476: * This will dump the content the notation declaration as an XML DTD definition
! 2477: */
! 2478: void
! 2479: xmlDumpNotationDecl(xmlBufferPtr buf, xmlNotationPtr nota) {
! 2480: if ((buf == NULL) || (nota == NULL))
! 2481: return;
! 2482: xmlBufferWriteChar(buf, "<!NOTATION ");
! 2483: xmlBufferWriteCHAR(buf, nota->name);
! 2484: if (nota->PublicID != NULL) {
! 2485: xmlBufferWriteChar(buf, " PUBLIC ");
! 2486: xmlBufferWriteQuotedString(buf, nota->PublicID);
! 2487: if (nota->SystemID != NULL) {
! 2488: xmlBufferWriteChar(buf, " ");
! 2489: xmlBufferWriteQuotedString(buf, nota->SystemID);
! 2490: }
! 2491: } else {
! 2492: xmlBufferWriteChar(buf, " SYSTEM ");
! 2493: xmlBufferWriteQuotedString(buf, nota->SystemID);
! 2494: }
! 2495: xmlBufferWriteChar(buf, " >\n");
! 2496: }
! 2497:
! 2498: /**
! 2499: * xmlDumpNotationDeclScan:
! 2500: * @nota: A notation declaration
! 2501: * @buf: the XML buffer output
! 2502: *
! 2503: * This is called with the hash scan function, and just reverses args
! 2504: */
! 2505: static void
! 2506: xmlDumpNotationDeclScan(xmlNotationPtr nota, xmlBufferPtr buf) {
! 2507: xmlDumpNotationDecl(buf, nota);
! 2508: }
! 2509:
! 2510: /**
! 2511: * xmlDumpNotationTable:
! 2512: * @buf: the XML buffer output
! 2513: * @table: A notation table
! 2514: *
! 2515: * This will dump the content of the notation table as an XML DTD definition
! 2516: */
! 2517: void
! 2518: xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
! 2519: if ((buf == NULL) || (table == NULL))
! 2520: return;
! 2521: xmlHashScan(table, (xmlHashScanner) xmlDumpNotationDeclScan, buf);
! 2522: }
! 2523: #endif /* LIBXML_OUTPUT_ENABLED */
! 2524:
! 2525: /************************************************************************
! 2526: * *
! 2527: * IDs *
! 2528: * *
! 2529: ************************************************************************/
! 2530: /**
! 2531: * DICT_FREE:
! 2532: * @str: a string
! 2533: *
! 2534: * Free a string if it is not owned by the "dict" dictionnary in the
! 2535: * current scope
! 2536: */
! 2537: #define DICT_FREE(str) \
! 2538: if ((str) && ((!dict) || \
! 2539: (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \
! 2540: xmlFree((char *)(str));
! 2541:
! 2542: /**
! 2543: * xmlFreeID:
! 2544: * @not: A id
! 2545: *
! 2546: * Deallocate the memory used by an id definition
! 2547: */
! 2548: static void
! 2549: xmlFreeID(xmlIDPtr id) {
! 2550: xmlDictPtr dict = NULL;
! 2551:
! 2552: if (id == NULL) return;
! 2553:
! 2554: if (id->doc != NULL)
! 2555: dict = id->doc->dict;
! 2556:
! 2557: if (id->value != NULL)
! 2558: DICT_FREE(id->value)
! 2559: if (id->name != NULL)
! 2560: DICT_FREE(id->name)
! 2561: xmlFree(id);
! 2562: }
! 2563:
! 2564:
! 2565: /**
! 2566: * xmlAddID:
! 2567: * @ctxt: the validation context
! 2568: * @doc: pointer to the document
! 2569: * @value: the value name
! 2570: * @attr: the attribute holding the ID
! 2571: *
! 2572: * Register a new id declaration
! 2573: *
! 2574: * Returns NULL if not, otherwise the new xmlIDPtr
! 2575: */
! 2576: xmlIDPtr
! 2577: xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
! 2578: xmlAttrPtr attr) {
! 2579: xmlIDPtr ret;
! 2580: xmlIDTablePtr table;
! 2581:
! 2582: if (doc == NULL) {
! 2583: return(NULL);
! 2584: }
! 2585: if (value == NULL) {
! 2586: return(NULL);
! 2587: }
! 2588: if (attr == NULL) {
! 2589: return(NULL);
! 2590: }
! 2591:
! 2592: /*
! 2593: * Create the ID table if needed.
! 2594: */
! 2595: table = (xmlIDTablePtr) doc->ids;
! 2596: if (table == NULL) {
! 2597: doc->ids = table = xmlHashCreateDict(0, doc->dict);
! 2598: }
! 2599: if (table == NULL) {
! 2600: xmlVErrMemory(ctxt,
! 2601: "xmlAddID: Table creation failed!\n");
! 2602: return(NULL);
! 2603: }
! 2604:
! 2605: ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
! 2606: if (ret == NULL) {
! 2607: xmlVErrMemory(ctxt, "malloc failed");
! 2608: return(NULL);
! 2609: }
! 2610:
! 2611: /*
! 2612: * fill the structure.
! 2613: */
! 2614: ret->value = xmlStrdup(value);
! 2615: ret->doc = doc;
! 2616: if ((ctxt != NULL) && (ctxt->vstateNr != 0)) {
! 2617: /*
! 2618: * Operating in streaming mode, attr is gonna disapear
! 2619: */
! 2620: if (doc->dict != NULL)
! 2621: ret->name = xmlDictLookup(doc->dict, attr->name, -1);
! 2622: else
! 2623: ret->name = xmlStrdup(attr->name);
! 2624: ret->attr = NULL;
! 2625: } else {
! 2626: ret->attr = attr;
! 2627: ret->name = NULL;
! 2628: }
! 2629: ret->lineno = xmlGetLineNo(attr->parent);
! 2630:
! 2631: if (xmlHashAddEntry(table, value, ret) < 0) {
! 2632: #ifdef LIBXML_VALID_ENABLED
! 2633: /*
! 2634: * The id is already defined in this DTD.
! 2635: */
! 2636: if ((ctxt != NULL) && (ctxt->error != NULL)) {
! 2637: xmlErrValidNode(ctxt, attr->parent, XML_DTD_ID_REDEFINED,
! 2638: "ID %s already defined\n",
! 2639: value, NULL, NULL);
! 2640: }
! 2641: #endif /* LIBXML_VALID_ENABLED */
! 2642: xmlFreeID(ret);
! 2643: return(NULL);
! 2644: }
! 2645: if (attr != NULL)
! 2646: attr->atype = XML_ATTRIBUTE_ID;
! 2647: return(ret);
! 2648: }
! 2649:
! 2650: /**
! 2651: * xmlFreeIDTable:
! 2652: * @table: An id table
! 2653: *
! 2654: * Deallocate the memory used by an ID hash table.
! 2655: */
! 2656: void
! 2657: xmlFreeIDTable(xmlIDTablePtr table) {
! 2658: xmlHashFree(table, (xmlHashDeallocator) xmlFreeID);
! 2659: }
! 2660:
! 2661: /**
! 2662: * xmlIsID:
! 2663: * @doc: the document
! 2664: * @elem: the element carrying the attribute
! 2665: * @attr: the attribute
! 2666: *
! 2667: * Determine whether an attribute is of type ID. In case we have DTD(s)
! 2668: * then this is done if DTD loading has been requested. In the case
! 2669: * of HTML documents parsed with the HTML parser, then ID detection is
! 2670: * done systematically.
! 2671: *
! 2672: * Returns 0 or 1 depending on the lookup result
! 2673: */
! 2674: int
! 2675: xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
! 2676: if ((attr == NULL) || (attr->name == NULL)) return(0);
! 2677: if ((attr->ns != NULL) && (attr->ns->prefix != NULL) &&
! 2678: (!strcmp((char *) attr->name, "id")) &&
! 2679: (!strcmp((char *) attr->ns->prefix, "xml")))
! 2680: return(1);
! 2681: if (doc == NULL) return(0);
! 2682: if ((doc->intSubset == NULL) && (doc->extSubset == NULL) &&
! 2683: (doc->type != XML_HTML_DOCUMENT_NODE)) {
! 2684: return(0);
! 2685: } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
! 2686: if ((xmlStrEqual(BAD_CAST "id", attr->name)) ||
! 2687: ((xmlStrEqual(BAD_CAST "name", attr->name)) &&
! 2688: ((elem == NULL) || (xmlStrEqual(elem->name, BAD_CAST "a")))))
! 2689: return(1);
! 2690: return(0);
! 2691: } else if (elem == NULL) {
! 2692: return(0);
! 2693: } else {
! 2694: xmlAttributePtr attrDecl = NULL;
! 2695:
! 2696: xmlChar felem[50], fattr[50];
! 2697: xmlChar *fullelemname, *fullattrname;
! 2698:
! 2699: fullelemname = (elem->ns != NULL && elem->ns->prefix != NULL) ?
! 2700: xmlBuildQName(elem->name, elem->ns->prefix, felem, 50) :
! 2701: (xmlChar *)elem->name;
! 2702:
! 2703: fullattrname = (attr->ns != NULL && attr->ns->prefix != NULL) ?
! 2704: xmlBuildQName(attr->name, attr->ns->prefix, fattr, 50) :
! 2705: (xmlChar *)attr->name;
! 2706:
! 2707: if (fullelemname != NULL && fullattrname != NULL) {
! 2708: attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullelemname,
! 2709: fullattrname);
! 2710: if ((attrDecl == NULL) && (doc->extSubset != NULL))
! 2711: attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullelemname,
! 2712: fullattrname);
! 2713: }
! 2714:
! 2715: if ((fullattrname != fattr) && (fullattrname != attr->name))
! 2716: xmlFree(fullattrname);
! 2717: if ((fullelemname != felem) && (fullelemname != elem->name))
! 2718: xmlFree(fullelemname);
! 2719:
! 2720: if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_ID))
! 2721: return(1);
! 2722: }
! 2723: return(0);
! 2724: }
! 2725:
! 2726: /**
! 2727: * xmlRemoveID:
! 2728: * @doc: the document
! 2729: * @attr: the attribute
! 2730: *
! 2731: * Remove the given attribute from the ID table maintained internally.
! 2732: *
! 2733: * Returns -1 if the lookup failed and 0 otherwise
! 2734: */
! 2735: int
! 2736: xmlRemoveID(xmlDocPtr doc, xmlAttrPtr attr) {
! 2737: xmlIDTablePtr table;
! 2738: xmlIDPtr id;
! 2739: xmlChar *ID;
! 2740:
! 2741: if (doc == NULL) return(-1);
! 2742: if (attr == NULL) return(-1);
! 2743: table = (xmlIDTablePtr) doc->ids;
! 2744: if (table == NULL)
! 2745: return(-1);
! 2746:
! 2747: if (attr == NULL)
! 2748: return(-1);
! 2749: ID = xmlNodeListGetString(doc, attr->children, 1);
! 2750: if (ID == NULL)
! 2751: return(-1);
! 2752: id = xmlHashLookup(table, ID);
! 2753: if (id == NULL || id->attr != attr) {
! 2754: xmlFree(ID);
! 2755: return(-1);
! 2756: }
! 2757: xmlHashRemoveEntry(table, ID, (xmlHashDeallocator) xmlFreeID);
! 2758: xmlFree(ID);
! 2759: attr->atype = 0;
! 2760: return(0);
! 2761: }
! 2762:
! 2763: /**
! 2764: * xmlGetID:
! 2765: * @doc: pointer to the document
! 2766: * @ID: the ID value
! 2767: *
! 2768: * Search the attribute declaring the given ID
! 2769: *
! 2770: * Returns NULL if not found, otherwise the xmlAttrPtr defining the ID
! 2771: */
! 2772: xmlAttrPtr
! 2773: xmlGetID(xmlDocPtr doc, const xmlChar *ID) {
! 2774: xmlIDTablePtr table;
! 2775: xmlIDPtr id;
! 2776:
! 2777: if (doc == NULL) {
! 2778: return(NULL);
! 2779: }
! 2780:
! 2781: if (ID == NULL) {
! 2782: return(NULL);
! 2783: }
! 2784:
! 2785: table = (xmlIDTablePtr) doc->ids;
! 2786: if (table == NULL)
! 2787: return(NULL);
! 2788:
! 2789: id = xmlHashLookup(table, ID);
! 2790: if (id == NULL)
! 2791: return(NULL);
! 2792: if (id->attr == NULL) {
! 2793: /*
! 2794: * We are operating on a stream, return a well known reference
! 2795: * since the attribute node doesn't exist anymore
! 2796: */
! 2797: return((xmlAttrPtr) doc);
! 2798: }
! 2799: return(id->attr);
! 2800: }
! 2801:
! 2802: /************************************************************************
! 2803: * *
! 2804: * Refs *
! 2805: * *
! 2806: ************************************************************************/
! 2807: typedef struct xmlRemoveMemo_t
! 2808: {
! 2809: xmlListPtr l;
! 2810: xmlAttrPtr ap;
! 2811: } xmlRemoveMemo;
! 2812:
! 2813: typedef xmlRemoveMemo *xmlRemoveMemoPtr;
! 2814:
! 2815: typedef struct xmlValidateMemo_t
! 2816: {
! 2817: xmlValidCtxtPtr ctxt;
! 2818: const xmlChar *name;
! 2819: } xmlValidateMemo;
! 2820:
! 2821: typedef xmlValidateMemo *xmlValidateMemoPtr;
! 2822:
! 2823: /**
! 2824: * xmlFreeRef:
! 2825: * @lk: A list link
! 2826: *
! 2827: * Deallocate the memory used by a ref definition
! 2828: */
! 2829: static void
! 2830: xmlFreeRef(xmlLinkPtr lk) {
! 2831: xmlRefPtr ref = (xmlRefPtr)xmlLinkGetData(lk);
! 2832: if (ref == NULL) return;
! 2833: if (ref->value != NULL)
! 2834: xmlFree((xmlChar *)ref->value);
! 2835: if (ref->name != NULL)
! 2836: xmlFree((xmlChar *)ref->name);
! 2837: xmlFree(ref);
! 2838: }
! 2839:
! 2840: /**
! 2841: * xmlFreeRefList:
! 2842: * @list_ref: A list of references.
! 2843: *
! 2844: * Deallocate the memory used by a list of references
! 2845: */
! 2846: static void
! 2847: xmlFreeRefList(xmlListPtr list_ref) {
! 2848: if (list_ref == NULL) return;
! 2849: xmlListDelete(list_ref);
! 2850: }
! 2851:
! 2852: /**
! 2853: * xmlWalkRemoveRef:
! 2854: * @data: Contents of current link
! 2855: * @user: Value supplied by the user
! 2856: *
! 2857: * Returns 0 to abort the walk or 1 to continue
! 2858: */
! 2859: static int
! 2860: xmlWalkRemoveRef(const void *data, const void *user)
! 2861: {
! 2862: xmlAttrPtr attr0 = ((xmlRefPtr)data)->attr;
! 2863: xmlAttrPtr attr1 = ((xmlRemoveMemoPtr)user)->ap;
! 2864: xmlListPtr ref_list = ((xmlRemoveMemoPtr)user)->l;
! 2865:
! 2866: if (attr0 == attr1) { /* Matched: remove and terminate walk */
! 2867: xmlListRemoveFirst(ref_list, (void *)data);
! 2868: return 0;
! 2869: }
! 2870: return 1;
! 2871: }
! 2872:
! 2873: /**
! 2874: * xmlDummyCompare
! 2875: * @data0: Value supplied by the user
! 2876: * @data1: Value supplied by the user
! 2877: *
! 2878: * Do nothing, return 0. Used to create unordered lists.
! 2879: */
! 2880: static int
! 2881: xmlDummyCompare(const void *data0 ATTRIBUTE_UNUSED,
! 2882: const void *data1 ATTRIBUTE_UNUSED)
! 2883: {
! 2884: return (0);
! 2885: }
! 2886:
! 2887: /**
! 2888: * xmlAddRef:
! 2889: * @ctxt: the validation context
! 2890: * @doc: pointer to the document
! 2891: * @value: the value name
! 2892: * @attr: the attribute holding the Ref
! 2893: *
! 2894: * Register a new ref declaration
! 2895: *
! 2896: * Returns NULL if not, otherwise the new xmlRefPtr
! 2897: */
! 2898: xmlRefPtr
! 2899: xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
! 2900: xmlAttrPtr attr) {
! 2901: xmlRefPtr ret;
! 2902: xmlRefTablePtr table;
! 2903: xmlListPtr ref_list;
! 2904:
! 2905: if (doc == NULL) {
! 2906: return(NULL);
! 2907: }
! 2908: if (value == NULL) {
! 2909: return(NULL);
! 2910: }
! 2911: if (attr == NULL) {
! 2912: return(NULL);
! 2913: }
! 2914:
! 2915: /*
! 2916: * Create the Ref table if needed.
! 2917: */
! 2918: table = (xmlRefTablePtr) doc->refs;
! 2919: if (table == NULL) {
! 2920: doc->refs = table = xmlHashCreateDict(0, doc->dict);
! 2921: }
! 2922: if (table == NULL) {
! 2923: xmlVErrMemory(ctxt,
! 2924: "xmlAddRef: Table creation failed!\n");
! 2925: return(NULL);
! 2926: }
! 2927:
! 2928: ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
! 2929: if (ret == NULL) {
! 2930: xmlVErrMemory(ctxt, "malloc failed");
! 2931: return(NULL);
! 2932: }
! 2933:
! 2934: /*
! 2935: * fill the structure.
! 2936: */
! 2937: ret->value = xmlStrdup(value);
! 2938: if ((ctxt != NULL) && (ctxt->vstateNr != 0)) {
! 2939: /*
! 2940: * Operating in streaming mode, attr is gonna disapear
! 2941: */
! 2942: ret->name = xmlStrdup(attr->name);
! 2943: ret->attr = NULL;
! 2944: } else {
! 2945: ret->name = NULL;
! 2946: ret->attr = attr;
! 2947: }
! 2948: ret->lineno = xmlGetLineNo(attr->parent);
! 2949:
! 2950: /* To add a reference :-
! 2951: * References are maintained as a list of references,
! 2952: * Lookup the entry, if no entry create new nodelist
! 2953: * Add the owning node to the NodeList
! 2954: * Return the ref
! 2955: */
! 2956:
! 2957: if (NULL == (ref_list = xmlHashLookup(table, value))) {
! 2958: if (NULL == (ref_list = xmlListCreate(xmlFreeRef, xmlDummyCompare))) {
! 2959: xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
! 2960: "xmlAddRef: Reference list creation failed!\n",
! 2961: NULL);
! 2962: goto failed;
! 2963: }
! 2964: if (xmlHashAddEntry(table, value, ref_list) < 0) {
! 2965: xmlListDelete(ref_list);
! 2966: xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
! 2967: "xmlAddRef: Reference list insertion failed!\n",
! 2968: NULL);
! 2969: goto failed;
! 2970: }
! 2971: }
! 2972: if (xmlListAppend(ref_list, ret) != 0) {
! 2973: xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
! 2974: "xmlAddRef: Reference list insertion failed!\n",
! 2975: NULL);
! 2976: goto failed;
! 2977: }
! 2978: return(ret);
! 2979: failed:
! 2980: if (ret != NULL) {
! 2981: if (ret->value != NULL)
! 2982: xmlFree((char *)ret->value);
! 2983: if (ret->name != NULL)
! 2984: xmlFree((char *)ret->name);
! 2985: xmlFree(ret);
! 2986: }
! 2987: return(NULL);
! 2988: }
! 2989:
! 2990: /**
! 2991: * xmlFreeRefTable:
! 2992: * @table: An ref table
! 2993: *
! 2994: * Deallocate the memory used by an Ref hash table.
! 2995: */
! 2996: void
! 2997: xmlFreeRefTable(xmlRefTablePtr table) {
! 2998: xmlHashFree(table, (xmlHashDeallocator) xmlFreeRefList);
! 2999: }
! 3000:
! 3001: /**
! 3002: * xmlIsRef:
! 3003: * @doc: the document
! 3004: * @elem: the element carrying the attribute
! 3005: * @attr: the attribute
! 3006: *
! 3007: * Determine whether an attribute is of type Ref. In case we have DTD(s)
! 3008: * then this is simple, otherwise we use an heuristic: name Ref (upper
! 3009: * or lowercase).
! 3010: *
! 3011: * Returns 0 or 1 depending on the lookup result
! 3012: */
! 3013: int
! 3014: xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
! 3015: if (attr == NULL)
! 3016: return(0);
! 3017: if (doc == NULL) {
! 3018: doc = attr->doc;
! 3019: if (doc == NULL) return(0);
! 3020: }
! 3021:
! 3022: if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
! 3023: return(0);
! 3024: } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
! 3025: /* TODO @@@ */
! 3026: return(0);
! 3027: } else {
! 3028: xmlAttributePtr attrDecl;
! 3029:
! 3030: if (elem == NULL) return(0);
! 3031: attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
! 3032: if ((attrDecl == NULL) && (doc->extSubset != NULL))
! 3033: attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
! 3034: elem->name, attr->name);
! 3035:
! 3036: if ((attrDecl != NULL) &&
! 3037: (attrDecl->atype == XML_ATTRIBUTE_IDREF ||
! 3038: attrDecl->atype == XML_ATTRIBUTE_IDREFS))
! 3039: return(1);
! 3040: }
! 3041: return(0);
! 3042: }
! 3043:
! 3044: /**
! 3045: * xmlRemoveRef:
! 3046: * @doc: the document
! 3047: * @attr: the attribute
! 3048: *
! 3049: * Remove the given attribute from the Ref table maintained internally.
! 3050: *
! 3051: * Returns -1 if the lookup failed and 0 otherwise
! 3052: */
! 3053: int
! 3054: xmlRemoveRef(xmlDocPtr doc, xmlAttrPtr attr) {
! 3055: xmlListPtr ref_list;
! 3056: xmlRefTablePtr table;
! 3057: xmlChar *ID;
! 3058: xmlRemoveMemo target;
! 3059:
! 3060: if (doc == NULL) return(-1);
! 3061: if (attr == NULL) return(-1);
! 3062: table = (xmlRefTablePtr) doc->refs;
! 3063: if (table == NULL)
! 3064: return(-1);
! 3065:
! 3066: if (attr == NULL)
! 3067: return(-1);
! 3068: ID = xmlNodeListGetString(doc, attr->children, 1);
! 3069: if (ID == NULL)
! 3070: return(-1);
! 3071: ref_list = xmlHashLookup(table, ID);
! 3072:
! 3073: if(ref_list == NULL) {
! 3074: xmlFree(ID);
! 3075: return (-1);
! 3076: }
! 3077: /* At this point, ref_list refers to a list of references which
! 3078: * have the same key as the supplied attr. Our list of references
! 3079: * is ordered by reference address and we don't have that information
! 3080: * here to use when removing. We'll have to walk the list and
! 3081: * check for a matching attribute, when we find one stop the walk
! 3082: * and remove the entry.
! 3083: * The list is ordered by reference, so that means we don't have the
! 3084: * key. Passing the list and the reference to the walker means we
! 3085: * will have enough data to be able to remove the entry.
! 3086: */
! 3087: target.l = ref_list;
! 3088: target.ap = attr;
! 3089:
! 3090: /* Remove the supplied attr from our list */
! 3091: xmlListWalk(ref_list, xmlWalkRemoveRef, &target);
! 3092:
! 3093: /*If the list is empty then remove the list entry in the hash */
! 3094: if (xmlListEmpty(ref_list))
! 3095: xmlHashUpdateEntry(table, ID, NULL, (xmlHashDeallocator)
! 3096: xmlFreeRefList);
! 3097: xmlFree(ID);
! 3098: return(0);
! 3099: }
! 3100:
! 3101: /**
! 3102: * xmlGetRefs:
! 3103: * @doc: pointer to the document
! 3104: * @ID: the ID value
! 3105: *
! 3106: * Find the set of references for the supplied ID.
! 3107: *
! 3108: * Returns NULL if not found, otherwise node set for the ID.
! 3109: */
! 3110: xmlListPtr
! 3111: xmlGetRefs(xmlDocPtr doc, const xmlChar *ID) {
! 3112: xmlRefTablePtr table;
! 3113:
! 3114: if (doc == NULL) {
! 3115: return(NULL);
! 3116: }
! 3117:
! 3118: if (ID == NULL) {
! 3119: return(NULL);
! 3120: }
! 3121:
! 3122: table = (xmlRefTablePtr) doc->refs;
! 3123: if (table == NULL)
! 3124: return(NULL);
! 3125:
! 3126: return (xmlHashLookup(table, ID));
! 3127: }
! 3128:
! 3129: /************************************************************************
! 3130: * *
! 3131: * Routines for validity checking *
! 3132: * *
! 3133: ************************************************************************/
! 3134:
! 3135: /**
! 3136: * xmlGetDtdElementDesc:
! 3137: * @dtd: a pointer to the DtD to search
! 3138: * @name: the element name
! 3139: *
! 3140: * Search the DTD for the description of this element
! 3141: *
! 3142: * returns the xmlElementPtr if found or NULL
! 3143: */
! 3144:
! 3145: xmlElementPtr
! 3146: xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) {
! 3147: xmlElementTablePtr table;
! 3148: xmlElementPtr cur;
! 3149: xmlChar *uqname = NULL, *prefix = NULL;
! 3150:
! 3151: if ((dtd == NULL) || (name == NULL)) return(NULL);
! 3152: if (dtd->elements == NULL)
! 3153: return(NULL);
! 3154: table = (xmlElementTablePtr) dtd->elements;
! 3155:
! 3156: uqname = xmlSplitQName2(name, &prefix);
! 3157: if (uqname != NULL)
! 3158: name = uqname;
! 3159: cur = xmlHashLookup2(table, name, prefix);
! 3160: if (prefix != NULL) xmlFree(prefix);
! 3161: if (uqname != NULL) xmlFree(uqname);
! 3162: return(cur);
! 3163: }
! 3164: /**
! 3165: * xmlGetDtdElementDesc2:
! 3166: * @dtd: a pointer to the DtD to search
! 3167: * @name: the element name
! 3168: * @create: create an empty description if not found
! 3169: *
! 3170: * Search the DTD for the description of this element
! 3171: *
! 3172: * returns the xmlElementPtr if found or NULL
! 3173: */
! 3174:
! 3175: static xmlElementPtr
! 3176: xmlGetDtdElementDesc2(xmlDtdPtr dtd, const xmlChar *name, int create) {
! 3177: xmlElementTablePtr table;
! 3178: xmlElementPtr cur;
! 3179: xmlChar *uqname = NULL, *prefix = NULL;
! 3180:
! 3181: if (dtd == NULL) return(NULL);
! 3182: if (dtd->elements == NULL) {
! 3183: xmlDictPtr dict = NULL;
! 3184:
! 3185: if (dtd->doc != NULL)
! 3186: dict = dtd->doc->dict;
! 3187:
! 3188: if (!create)
! 3189: return(NULL);
! 3190: /*
! 3191: * Create the Element table if needed.
! 3192: */
! 3193: table = (xmlElementTablePtr) dtd->elements;
! 3194: if (table == NULL) {
! 3195: table = xmlHashCreateDict(0, dict);
! 3196: dtd->elements = (void *) table;
! 3197: }
! 3198: if (table == NULL) {
! 3199: xmlVErrMemory(NULL, "element table allocation failed");
! 3200: return(NULL);
! 3201: }
! 3202: }
! 3203: table = (xmlElementTablePtr) dtd->elements;
! 3204:
! 3205: uqname = xmlSplitQName2(name, &prefix);
! 3206: if (uqname != NULL)
! 3207: name = uqname;
! 3208: cur = xmlHashLookup2(table, name, prefix);
! 3209: if ((cur == NULL) && (create)) {
! 3210: cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
! 3211: if (cur == NULL) {
! 3212: xmlVErrMemory(NULL, "malloc failed");
! 3213: return(NULL);
! 3214: }
! 3215: memset(cur, 0, sizeof(xmlElement));
! 3216: cur->type = XML_ELEMENT_DECL;
! 3217:
! 3218: /*
! 3219: * fill the structure.
! 3220: */
! 3221: cur->name = xmlStrdup(name);
! 3222: cur->prefix = xmlStrdup(prefix);
! 3223: cur->etype = XML_ELEMENT_TYPE_UNDEFINED;
! 3224:
! 3225: xmlHashAddEntry2(table, name, prefix, cur);
! 3226: }
! 3227: if (prefix != NULL) xmlFree(prefix);
! 3228: if (uqname != NULL) xmlFree(uqname);
! 3229: return(cur);
! 3230: }
! 3231:
! 3232: /**
! 3233: * xmlGetDtdQElementDesc:
! 3234: * @dtd: a pointer to the DtD to search
! 3235: * @name: the element name
! 3236: * @prefix: the element namespace prefix
! 3237: *
! 3238: * Search the DTD for the description of this element
! 3239: *
! 3240: * returns the xmlElementPtr if found or NULL
! 3241: */
! 3242:
! 3243: xmlElementPtr
! 3244: xmlGetDtdQElementDesc(xmlDtdPtr dtd, const xmlChar *name,
! 3245: const xmlChar *prefix) {
! 3246: xmlElementTablePtr table;
! 3247:
! 3248: if (dtd == NULL) return(NULL);
! 3249: if (dtd->elements == NULL) return(NULL);
! 3250: table = (xmlElementTablePtr) dtd->elements;
! 3251:
! 3252: return(xmlHashLookup2(table, name, prefix));
! 3253: }
! 3254:
! 3255: /**
! 3256: * xmlGetDtdAttrDesc:
! 3257: * @dtd: a pointer to the DtD to search
! 3258: * @elem: the element name
! 3259: * @name: the attribute name
! 3260: *
! 3261: * Search the DTD for the description of this attribute on
! 3262: * this element.
! 3263: *
! 3264: * returns the xmlAttributePtr if found or NULL
! 3265: */
! 3266:
! 3267: xmlAttributePtr
! 3268: xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) {
! 3269: xmlAttributeTablePtr table;
! 3270: xmlAttributePtr cur;
! 3271: xmlChar *uqname = NULL, *prefix = NULL;
! 3272:
! 3273: if (dtd == NULL) return(NULL);
! 3274: if (dtd->attributes == NULL) return(NULL);
! 3275:
! 3276: table = (xmlAttributeTablePtr) dtd->attributes;
! 3277: if (table == NULL)
! 3278: return(NULL);
! 3279:
! 3280: uqname = xmlSplitQName2(name, &prefix);
! 3281:
! 3282: if (uqname != NULL) {
! 3283: cur = xmlHashLookup3(table, uqname, prefix, elem);
! 3284: if (prefix != NULL) xmlFree(prefix);
! 3285: if (uqname != NULL) xmlFree(uqname);
! 3286: } else
! 3287: cur = xmlHashLookup3(table, name, NULL, elem);
! 3288: return(cur);
! 3289: }
! 3290:
! 3291: /**
! 3292: * xmlGetDtdQAttrDesc:
! 3293: * @dtd: a pointer to the DtD to search
! 3294: * @elem: the element name
! 3295: * @name: the attribute name
! 3296: * @prefix: the attribute namespace prefix
! 3297: *
! 3298: * Search the DTD for the description of this qualified attribute on
! 3299: * this element.
! 3300: *
! 3301: * returns the xmlAttributePtr if found or NULL
! 3302: */
! 3303:
! 3304: xmlAttributePtr
! 3305: xmlGetDtdQAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name,
! 3306: const xmlChar *prefix) {
! 3307: xmlAttributeTablePtr table;
! 3308:
! 3309: if (dtd == NULL) return(NULL);
! 3310: if (dtd->attributes == NULL) return(NULL);
! 3311: table = (xmlAttributeTablePtr) dtd->attributes;
! 3312:
! 3313: return(xmlHashLookup3(table, name, prefix, elem));
! 3314: }
! 3315:
! 3316: /**
! 3317: * xmlGetDtdNotationDesc:
! 3318: * @dtd: a pointer to the DtD to search
! 3319: * @name: the notation name
! 3320: *
! 3321: * Search the DTD for the description of this notation
! 3322: *
! 3323: * returns the xmlNotationPtr if found or NULL
! 3324: */
! 3325:
! 3326: xmlNotationPtr
! 3327: xmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) {
! 3328: xmlNotationTablePtr table;
! 3329:
! 3330: if (dtd == NULL) return(NULL);
! 3331: if (dtd->notations == NULL) return(NULL);
! 3332: table = (xmlNotationTablePtr) dtd->notations;
! 3333:
! 3334: return(xmlHashLookup(table, name));
! 3335: }
! 3336:
! 3337: #if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
! 3338: /**
! 3339: * xmlValidateNotationUse:
! 3340: * @ctxt: the validation context
! 3341: * @doc: the document
! 3342: * @notationName: the notation name to check
! 3343: *
! 3344: * Validate that the given name match a notation declaration.
! 3345: * - [ VC: Notation Declared ]
! 3346: *
! 3347: * returns 1 if valid or 0 otherwise
! 3348: */
! 3349:
! 3350: int
! 3351: xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
! 3352: const xmlChar *notationName) {
! 3353: xmlNotationPtr notaDecl;
! 3354: if ((doc == NULL) || (doc->intSubset == NULL) ||
! 3355: (notationName == NULL)) return(-1);
! 3356:
! 3357: notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
! 3358: if ((notaDecl == NULL) && (doc->extSubset != NULL))
! 3359: notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
! 3360:
! 3361: if ((notaDecl == NULL) && (ctxt != NULL)) {
! 3362: xmlErrValidNode(ctxt, (xmlNodePtr) doc, XML_DTD_UNKNOWN_NOTATION,
! 3363: "NOTATION %s is not declared\n",
! 3364: notationName, NULL, NULL);
! 3365: return(0);
! 3366: }
! 3367: return(1);
! 3368: }
! 3369: #endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */
! 3370:
! 3371: /**
! 3372: * xmlIsMixedElement:
! 3373: * @doc: the document
! 3374: * @name: the element name
! 3375: *
! 3376: * Search in the DtDs whether an element accept Mixed content (or ANY)
! 3377: * basically if it is supposed to accept text childs
! 3378: *
! 3379: * returns 0 if no, 1 if yes, and -1 if no element description is available
! 3380: */
! 3381:
! 3382: int
! 3383: xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) {
! 3384: xmlElementPtr elemDecl;
! 3385:
! 3386: if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
! 3387:
! 3388: elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
! 3389: if ((elemDecl == NULL) && (doc->extSubset != NULL))
! 3390: elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
! 3391: if (elemDecl == NULL) return(-1);
! 3392: switch (elemDecl->etype) {
! 3393: case XML_ELEMENT_TYPE_UNDEFINED:
! 3394: return(-1);
! 3395: case XML_ELEMENT_TYPE_ELEMENT:
! 3396: return(0);
! 3397: case XML_ELEMENT_TYPE_EMPTY:
! 3398: /*
! 3399: * return 1 for EMPTY since we want VC error to pop up
! 3400: * on <empty> </empty> for example
! 3401: */
! 3402: case XML_ELEMENT_TYPE_ANY:
! 3403: case XML_ELEMENT_TYPE_MIXED:
! 3404: return(1);
! 3405: }
! 3406: return(1);
! 3407: }
! 3408:
! 3409: #ifdef LIBXML_VALID_ENABLED
! 3410:
! 3411: static int
! 3412: xmlIsDocNameStartChar(xmlDocPtr doc, int c) {
! 3413: if ((doc == NULL) || (doc->properties & XML_DOC_OLD10) == 0) {
! 3414: /*
! 3415: * Use the new checks of production [4] [4a] amd [5] of the
! 3416: * Update 5 of XML-1.0
! 3417: */
! 3418: if (((c >= 'a') && (c <= 'z')) ||
! 3419: ((c >= 'A') && (c <= 'Z')) ||
! 3420: (c == '_') || (c == ':') ||
! 3421: ((c >= 0xC0) && (c <= 0xD6)) ||
! 3422: ((c >= 0xD8) && (c <= 0xF6)) ||
! 3423: ((c >= 0xF8) && (c <= 0x2FF)) ||
! 3424: ((c >= 0x370) && (c <= 0x37D)) ||
! 3425: ((c >= 0x37F) && (c <= 0x1FFF)) ||
! 3426: ((c >= 0x200C) && (c <= 0x200D)) ||
! 3427: ((c >= 0x2070) && (c <= 0x218F)) ||
! 3428: ((c >= 0x2C00) && (c <= 0x2FEF)) ||
! 3429: ((c >= 0x3001) && (c <= 0xD7FF)) ||
! 3430: ((c >= 0xF900) && (c <= 0xFDCF)) ||
! 3431: ((c >= 0xFDF0) && (c <= 0xFFFD)) ||
! 3432: ((c >= 0x10000) && (c <= 0xEFFFF)))
! 3433: return(1);
! 3434: } else {
! 3435: if (IS_LETTER(c) || (c == '_') || (c == ':'))
! 3436: return(1);
! 3437: }
! 3438: return(0);
! 3439: }
! 3440:
! 3441: static int
! 3442: xmlIsDocNameChar(xmlDocPtr doc, int c) {
! 3443: if ((doc == NULL) || (doc->properties & XML_DOC_OLD10) == 0) {
! 3444: /*
! 3445: * Use the new checks of production [4] [4a] amd [5] of the
! 3446: * Update 5 of XML-1.0
! 3447: */
! 3448: if (((c >= 'a') && (c <= 'z')) ||
! 3449: ((c >= 'A') && (c <= 'Z')) ||
! 3450: ((c >= '0') && (c <= '9')) || /* !start */
! 3451: (c == '_') || (c == ':') ||
! 3452: (c == '-') || (c == '.') || (c == 0xB7) || /* !start */
! 3453: ((c >= 0xC0) && (c <= 0xD6)) ||
! 3454: ((c >= 0xD8) && (c <= 0xF6)) ||
! 3455: ((c >= 0xF8) && (c <= 0x2FF)) ||
! 3456: ((c >= 0x300) && (c <= 0x36F)) || /* !start */
! 3457: ((c >= 0x370) && (c <= 0x37D)) ||
! 3458: ((c >= 0x37F) && (c <= 0x1FFF)) ||
! 3459: ((c >= 0x200C) && (c <= 0x200D)) ||
! 3460: ((c >= 0x203F) && (c <= 0x2040)) || /* !start */
! 3461: ((c >= 0x2070) && (c <= 0x218F)) ||
! 3462: ((c >= 0x2C00) && (c <= 0x2FEF)) ||
! 3463: ((c >= 0x3001) && (c <= 0xD7FF)) ||
! 3464: ((c >= 0xF900) && (c <= 0xFDCF)) ||
! 3465: ((c >= 0xFDF0) && (c <= 0xFFFD)) ||
! 3466: ((c >= 0x10000) && (c <= 0xEFFFF)))
! 3467: return(1);
! 3468: } else {
! 3469: if ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
! 3470: (c == '.') || (c == '-') ||
! 3471: (c == '_') || (c == ':') ||
! 3472: (IS_COMBINING(c)) ||
! 3473: (IS_EXTENDER(c)))
! 3474: return(1);
! 3475: }
! 3476: return(0);
! 3477: }
! 3478:
! 3479: /**
! 3480: * xmlValidateNameValue:
! 3481: * @doc: pointer to the document or NULL
! 3482: * @value: an Name value
! 3483: *
! 3484: * Validate that the given value match Name production
! 3485: *
! 3486: * returns 1 if valid or 0 otherwise
! 3487: */
! 3488:
! 3489: static int
! 3490: xmlValidateNameValueInternal(xmlDocPtr doc, const xmlChar *value) {
! 3491: const xmlChar *cur;
! 3492: int val, len;
! 3493:
! 3494: if (value == NULL) return(0);
! 3495: cur = value;
! 3496: val = xmlStringCurrentChar(NULL, cur, &len);
! 3497: cur += len;
! 3498: if (!xmlIsDocNameStartChar(doc, val))
! 3499: return(0);
! 3500:
! 3501: val = xmlStringCurrentChar(NULL, cur, &len);
! 3502: cur += len;
! 3503: while (xmlIsDocNameChar(doc, val)) {
! 3504: val = xmlStringCurrentChar(NULL, cur, &len);
! 3505: cur += len;
! 3506: }
! 3507:
! 3508: if (val != 0) return(0);
! 3509:
! 3510: return(1);
! 3511: }
! 3512:
! 3513: /**
! 3514: * xmlValidateNameValue:
! 3515: * @value: an Name value
! 3516: *
! 3517: * Validate that the given value match Name production
! 3518: *
! 3519: * returns 1 if valid or 0 otherwise
! 3520: */
! 3521:
! 3522: int
! 3523: xmlValidateNameValue(const xmlChar *value) {
! 3524: return(xmlValidateNameValueInternal(NULL, value));
! 3525: }
! 3526:
! 3527: /**
! 3528: * xmlValidateNamesValueInternal:
! 3529: * @doc: pointer to the document or NULL
! 3530: * @value: an Names value
! 3531: *
! 3532: * Validate that the given value match Names production
! 3533: *
! 3534: * returns 1 if valid or 0 otherwise
! 3535: */
! 3536:
! 3537: static int
! 3538: xmlValidateNamesValueInternal(xmlDocPtr doc, const xmlChar *value) {
! 3539: const xmlChar *cur;
! 3540: int val, len;
! 3541:
! 3542: if (value == NULL) return(0);
! 3543: cur = value;
! 3544: val = xmlStringCurrentChar(NULL, cur, &len);
! 3545: cur += len;
! 3546:
! 3547: if (!xmlIsDocNameStartChar(doc, val))
! 3548: return(0);
! 3549:
! 3550: val = xmlStringCurrentChar(NULL, cur, &len);
! 3551: cur += len;
! 3552: while (xmlIsDocNameChar(doc, val)) {
! 3553: val = xmlStringCurrentChar(NULL, cur, &len);
! 3554: cur += len;
! 3555: }
! 3556:
! 3557: /* Should not test IS_BLANK(val) here -- see erratum E20*/
! 3558: while (val == 0x20) {
! 3559: while (val == 0x20) {
! 3560: val = xmlStringCurrentChar(NULL, cur, &len);
! 3561: cur += len;
! 3562: }
! 3563:
! 3564: if (!xmlIsDocNameStartChar(doc, val))
! 3565: return(0);
! 3566:
! 3567: val = xmlStringCurrentChar(NULL, cur, &len);
! 3568: cur += len;
! 3569:
! 3570: while (xmlIsDocNameChar(doc, val)) {
! 3571: val = xmlStringCurrentChar(NULL, cur, &len);
! 3572: cur += len;
! 3573: }
! 3574: }
! 3575:
! 3576: if (val != 0) return(0);
! 3577:
! 3578: return(1);
! 3579: }
! 3580:
! 3581: /**
! 3582: * xmlValidateNamesValue:
! 3583: * @value: an Names value
! 3584: *
! 3585: * Validate that the given value match Names production
! 3586: *
! 3587: * returns 1 if valid or 0 otherwise
! 3588: */
! 3589:
! 3590: int
! 3591: xmlValidateNamesValue(const xmlChar *value) {
! 3592: return(xmlValidateNamesValueInternal(NULL, value));
! 3593: }
! 3594:
! 3595: /**
! 3596: * xmlValidateNmtokenValueInternal:
! 3597: * @doc: pointer to the document or NULL
! 3598: * @value: an Nmtoken value
! 3599: *
! 3600: * Validate that the given value match Nmtoken production
! 3601: *
! 3602: * [ VC: Name Token ]
! 3603: *
! 3604: * returns 1 if valid or 0 otherwise
! 3605: */
! 3606:
! 3607: static int
! 3608: xmlValidateNmtokenValueInternal(xmlDocPtr doc, const xmlChar *value) {
! 3609: const xmlChar *cur;
! 3610: int val, len;
! 3611:
! 3612: if (value == NULL) return(0);
! 3613: cur = value;
! 3614: val = xmlStringCurrentChar(NULL, cur, &len);
! 3615: cur += len;
! 3616:
! 3617: if (!xmlIsDocNameChar(doc, val))
! 3618: return(0);
! 3619:
! 3620: val = xmlStringCurrentChar(NULL, cur, &len);
! 3621: cur += len;
! 3622: while (xmlIsDocNameChar(doc, val)) {
! 3623: val = xmlStringCurrentChar(NULL, cur, &len);
! 3624: cur += len;
! 3625: }
! 3626:
! 3627: if (val != 0) return(0);
! 3628:
! 3629: return(1);
! 3630: }
! 3631:
! 3632: /**
! 3633: * xmlValidateNmtokenValue:
! 3634: * @value: an Nmtoken value
! 3635: *
! 3636: * Validate that the given value match Nmtoken production
! 3637: *
! 3638: * [ VC: Name Token ]
! 3639: *
! 3640: * returns 1 if valid or 0 otherwise
! 3641: */
! 3642:
! 3643: int
! 3644: xmlValidateNmtokenValue(const xmlChar *value) {
! 3645: return(xmlValidateNmtokenValueInternal(NULL, value));
! 3646: }
! 3647:
! 3648: /**
! 3649: * xmlValidateNmtokensValueInternal:
! 3650: * @doc: pointer to the document or NULL
! 3651: * @value: an Nmtokens value
! 3652: *
! 3653: * Validate that the given value match Nmtokens production
! 3654: *
! 3655: * [ VC: Name Token ]
! 3656: *
! 3657: * returns 1 if valid or 0 otherwise
! 3658: */
! 3659:
! 3660: static int
! 3661: xmlValidateNmtokensValueInternal(xmlDocPtr doc, const xmlChar *value) {
! 3662: const xmlChar *cur;
! 3663: int val, len;
! 3664:
! 3665: if (value == NULL) return(0);
! 3666: cur = value;
! 3667: val = xmlStringCurrentChar(NULL, cur, &len);
! 3668: cur += len;
! 3669:
! 3670: while (IS_BLANK(val)) {
! 3671: val = xmlStringCurrentChar(NULL, cur, &len);
! 3672: cur += len;
! 3673: }
! 3674:
! 3675: if (!xmlIsDocNameChar(doc, val))
! 3676: return(0);
! 3677:
! 3678: while (xmlIsDocNameChar(doc, val)) {
! 3679: val = xmlStringCurrentChar(NULL, cur, &len);
! 3680: cur += len;
! 3681: }
! 3682:
! 3683: /* Should not test IS_BLANK(val) here -- see erratum E20*/
! 3684: while (val == 0x20) {
! 3685: while (val == 0x20) {
! 3686: val = xmlStringCurrentChar(NULL, cur, &len);
! 3687: cur += len;
! 3688: }
! 3689: if (val == 0) return(1);
! 3690:
! 3691: if (!xmlIsDocNameChar(doc, val))
! 3692: return(0);
! 3693:
! 3694: val = xmlStringCurrentChar(NULL, cur, &len);
! 3695: cur += len;
! 3696:
! 3697: while (xmlIsDocNameChar(doc, val)) {
! 3698: val = xmlStringCurrentChar(NULL, cur, &len);
! 3699: cur += len;
! 3700: }
! 3701: }
! 3702:
! 3703: if (val != 0) return(0);
! 3704:
! 3705: return(1);
! 3706: }
! 3707:
! 3708: /**
! 3709: * xmlValidateNmtokensValue:
! 3710: * @value: an Nmtokens value
! 3711: *
! 3712: * Validate that the given value match Nmtokens production
! 3713: *
! 3714: * [ VC: Name Token ]
! 3715: *
! 3716: * returns 1 if valid or 0 otherwise
! 3717: */
! 3718:
! 3719: int
! 3720: xmlValidateNmtokensValue(const xmlChar *value) {
! 3721: return(xmlValidateNmtokensValueInternal(NULL, value));
! 3722: }
! 3723:
! 3724: /**
! 3725: * xmlValidateNotationDecl:
! 3726: * @ctxt: the validation context
! 3727: * @doc: a document instance
! 3728: * @nota: a notation definition
! 3729: *
! 3730: * Try to validate a single notation definition
! 3731: * basically it does the following checks as described by the
! 3732: * XML-1.0 recommendation:
! 3733: * - it seems that no validity constraint exists on notation declarations
! 3734: * But this function get called anyway ...
! 3735: *
! 3736: * returns 1 if valid or 0 otherwise
! 3737: */
! 3738:
! 3739: int
! 3740: xmlValidateNotationDecl(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED, xmlDocPtr doc ATTRIBUTE_UNUSED,
! 3741: xmlNotationPtr nota ATTRIBUTE_UNUSED) {
! 3742: int ret = 1;
! 3743:
! 3744: return(ret);
! 3745: }
! 3746:
! 3747: /**
! 3748: * xmlValidateAttributeValueInternal:
! 3749: * @doc: the document
! 3750: * @type: an attribute type
! 3751: * @value: an attribute value
! 3752: *
! 3753: * Validate that the given attribute value match the proper production
! 3754: *
! 3755: * returns 1 if valid or 0 otherwise
! 3756: */
! 3757:
! 3758: static int
! 3759: xmlValidateAttributeValueInternal(xmlDocPtr doc, xmlAttributeType type,
! 3760: const xmlChar *value) {
! 3761: switch (type) {
! 3762: case XML_ATTRIBUTE_ENTITIES:
! 3763: case XML_ATTRIBUTE_IDREFS:
! 3764: return(xmlValidateNamesValueInternal(doc, value));
! 3765: case XML_ATTRIBUTE_ENTITY:
! 3766: case XML_ATTRIBUTE_IDREF:
! 3767: case XML_ATTRIBUTE_ID:
! 3768: case XML_ATTRIBUTE_NOTATION:
! 3769: return(xmlValidateNameValueInternal(doc, value));
! 3770: case XML_ATTRIBUTE_NMTOKENS:
! 3771: case XML_ATTRIBUTE_ENUMERATION:
! 3772: return(xmlValidateNmtokensValueInternal(doc, value));
! 3773: case XML_ATTRIBUTE_NMTOKEN:
! 3774: return(xmlValidateNmtokenValueInternal(doc, value));
! 3775: case XML_ATTRIBUTE_CDATA:
! 3776: break;
! 3777: }
! 3778: return(1);
! 3779: }
! 3780:
! 3781: /**
! 3782: * xmlValidateAttributeValue:
! 3783: * @type: an attribute type
! 3784: * @value: an attribute value
! 3785: *
! 3786: * Validate that the given attribute value match the proper production
! 3787: *
! 3788: * [ VC: ID ]
! 3789: * Values of type ID must match the Name production....
! 3790: *
! 3791: * [ VC: IDREF ]
! 3792: * Values of type IDREF must match the Name production, and values
! 3793: * of type IDREFS must match Names ...
! 3794: *
! 3795: * [ VC: Entity Name ]
! 3796: * Values of type ENTITY must match the Name production, values
! 3797: * of type ENTITIES must match Names ...
! 3798: *
! 3799: * [ VC: Name Token ]
! 3800: * Values of type NMTOKEN must match the Nmtoken production; values
! 3801: * of type NMTOKENS must match Nmtokens.
! 3802: *
! 3803: * returns 1 if valid or 0 otherwise
! 3804: */
! 3805: int
! 3806: xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) {
! 3807: return(xmlValidateAttributeValueInternal(NULL, type, value));
! 3808: }
! 3809:
! 3810: /**
! 3811: * xmlValidateAttributeValue2:
! 3812: * @ctxt: the validation context
! 3813: * @doc: the document
! 3814: * @name: the attribute name (used for error reporting only)
! 3815: * @type: the attribute type
! 3816: * @value: the attribute value
! 3817: *
! 3818: * Validate that the given attribute value match a given type.
! 3819: * This typically cannot be done before having finished parsing
! 3820: * the subsets.
! 3821: *
! 3822: * [ VC: IDREF ]
! 3823: * Values of type IDREF must match one of the declared IDs
! 3824: * Values of type IDREFS must match a sequence of the declared IDs
! 3825: * each Name must match the value of an ID attribute on some element
! 3826: * in the XML document; i.e. IDREF values must match the value of
! 3827: * some ID attribute
! 3828: *
! 3829: * [ VC: Entity Name ]
! 3830: * Values of type ENTITY must match one declared entity
! 3831: * Values of type ENTITIES must match a sequence of declared entities
! 3832: *
! 3833: * [ VC: Notation Attributes ]
! 3834: * all notation names in the declaration must be declared.
! 3835: *
! 3836: * returns 1 if valid or 0 otherwise
! 3837: */
! 3838:
! 3839: static int
! 3840: xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
! 3841: const xmlChar *name, xmlAttributeType type, const xmlChar *value) {
! 3842: int ret = 1;
! 3843: switch (type) {
! 3844: case XML_ATTRIBUTE_IDREFS:
! 3845: case XML_ATTRIBUTE_IDREF:
! 3846: case XML_ATTRIBUTE_ID:
! 3847: case XML_ATTRIBUTE_NMTOKENS:
! 3848: case XML_ATTRIBUTE_ENUMERATION:
! 3849: case XML_ATTRIBUTE_NMTOKEN:
! 3850: case XML_ATTRIBUTE_CDATA:
! 3851: break;
! 3852: case XML_ATTRIBUTE_ENTITY: {
! 3853: xmlEntityPtr ent;
! 3854:
! 3855: ent = xmlGetDocEntity(doc, value);
! 3856: /* yeah it's a bit messy... */
! 3857: if ((ent == NULL) && (doc->standalone == 1)) {
! 3858: doc->standalone = 0;
! 3859: ent = xmlGetDocEntity(doc, value);
! 3860: }
! 3861: if (ent == NULL) {
! 3862: xmlErrValidNode(ctxt, (xmlNodePtr) doc,
! 3863: XML_DTD_UNKNOWN_ENTITY,
! 3864: "ENTITY attribute %s reference an unknown entity \"%s\"\n",
! 3865: name, value, NULL);
! 3866: ret = 0;
! 3867: } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
! 3868: xmlErrValidNode(ctxt, (xmlNodePtr) doc,
! 3869: XML_DTD_ENTITY_TYPE,
! 3870: "ENTITY attribute %s reference an entity \"%s\" of wrong type\n",
! 3871: name, value, NULL);
! 3872: ret = 0;
! 3873: }
! 3874: break;
! 3875: }
! 3876: case XML_ATTRIBUTE_ENTITIES: {
! 3877: xmlChar *dup, *nam = NULL, *cur, save;
! 3878: xmlEntityPtr ent;
! 3879:
! 3880: dup = xmlStrdup(value);
! 3881: if (dup == NULL)
! 3882: return(0);
! 3883: cur = dup;
! 3884: while (*cur != 0) {
! 3885: nam = cur;
! 3886: while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
! 3887: save = *cur;
! 3888: *cur = 0;
! 3889: ent = xmlGetDocEntity(doc, nam);
! 3890: if (ent == NULL) {
! 3891: xmlErrValidNode(ctxt, (xmlNodePtr) doc,
! 3892: XML_DTD_UNKNOWN_ENTITY,
! 3893: "ENTITIES attribute %s reference an unknown entity \"%s\"\n",
! 3894: name, nam, NULL);
! 3895: ret = 0;
! 3896: } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
! 3897: xmlErrValidNode(ctxt, (xmlNodePtr) doc,
! 3898: XML_DTD_ENTITY_TYPE,
! 3899: "ENTITIES attribute %s reference an entity \"%s\" of wrong type\n",
! 3900: name, nam, NULL);
! 3901: ret = 0;
! 3902: }
! 3903: if (save == 0)
! 3904: break;
! 3905: *cur = save;
! 3906: while (IS_BLANK_CH(*cur)) cur++;
! 3907: }
! 3908: xmlFree(dup);
! 3909: break;
! 3910: }
! 3911: case XML_ATTRIBUTE_NOTATION: {
! 3912: xmlNotationPtr nota;
! 3913:
! 3914: nota = xmlGetDtdNotationDesc(doc->intSubset, value);
! 3915: if ((nota == NULL) && (doc->extSubset != NULL))
! 3916: nota = xmlGetDtdNotationDesc(doc->extSubset, value);
! 3917:
! 3918: if (nota == NULL) {
! 3919: xmlErrValidNode(ctxt, (xmlNodePtr) doc,
! 3920: XML_DTD_UNKNOWN_NOTATION,
! 3921: "NOTATION attribute %s reference an unknown notation \"%s\"\n",
! 3922: name, value, NULL);
! 3923: ret = 0;
! 3924: }
! 3925: break;
! 3926: }
! 3927: }
! 3928: return(ret);
! 3929: }
! 3930:
! 3931: /**
! 3932: * xmlValidCtxtNormalizeAttributeValue:
! 3933: * @ctxt: the validation context
! 3934: * @doc: the document
! 3935: * @elem: the parent
! 3936: * @name: the attribute name
! 3937: * @value: the attribute value
! 3938: * @ctxt: the validation context or NULL
! 3939: *
! 3940: * Does the validation related extra step of the normalization of attribute
! 3941: * values:
! 3942: *
! 3943: * If the declared value is not CDATA, then the XML processor must further
! 3944: * process the normalized attribute value by discarding any leading and
! 3945: * trailing space (#x20) characters, and by replacing sequences of space
! 3946: * (#x20) characters by single space (#x20) character.
! 3947: *
! 3948: * Also check VC: Standalone Document Declaration in P32, and update
! 3949: * ctxt->valid accordingly
! 3950: *
! 3951: * returns a new normalized string if normalization is needed, NULL otherwise
! 3952: * the caller must free the returned value.
! 3953: */
! 3954:
! 3955: xmlChar *
! 3956: xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
! 3957: xmlNodePtr elem, const xmlChar *name, const xmlChar *value) {
! 3958: xmlChar *ret, *dst;
! 3959: const xmlChar *src;
! 3960: xmlAttributePtr attrDecl = NULL;
! 3961: int extsubset = 0;
! 3962:
! 3963: if (doc == NULL) return(NULL);
! 3964: if (elem == NULL) return(NULL);
! 3965: if (name == NULL) return(NULL);
! 3966: if (value == NULL) return(NULL);
! 3967:
! 3968: if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
! 3969: xmlChar fn[50];
! 3970: xmlChar *fullname;
! 3971:
! 3972: fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
! 3973: if (fullname == NULL)
! 3974: return(NULL);
! 3975: attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name);
! 3976: if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
! 3977: attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name);
! 3978: if (attrDecl != NULL)
! 3979: extsubset = 1;
! 3980: }
! 3981: if ((fullname != fn) && (fullname != elem->name))
! 3982: xmlFree(fullname);
! 3983: }
! 3984: if ((attrDecl == NULL) && (doc->intSubset != NULL))
! 3985: attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
! 3986: if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
! 3987: attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
! 3988: if (attrDecl != NULL)
! 3989: extsubset = 1;
! 3990: }
! 3991:
! 3992: if (attrDecl == NULL)
! 3993: return(NULL);
! 3994: if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
! 3995: return(NULL);
! 3996:
! 3997: ret = xmlStrdup(value);
! 3998: if (ret == NULL)
! 3999: return(NULL);
! 4000: src = value;
! 4001: dst = ret;
! 4002: while (*src == 0x20) src++;
! 4003: while (*src != 0) {
! 4004: if (*src == 0x20) {
! 4005: while (*src == 0x20) src++;
! 4006: if (*src != 0)
! 4007: *dst++ = 0x20;
! 4008: } else {
! 4009: *dst++ = *src++;
! 4010: }
! 4011: }
! 4012: *dst = 0;
! 4013: if ((doc->standalone) && (extsubset == 1) && (!xmlStrEqual(value, ret))) {
! 4014: xmlErrValidNode(ctxt, elem, XML_DTD_NOT_STANDALONE,
! 4015: "standalone: %s on %s value had to be normalized based on external subset declaration\n",
! 4016: name, elem->name, NULL);
! 4017: ctxt->valid = 0;
! 4018: }
! 4019: return(ret);
! 4020: }
! 4021:
! 4022: /**
! 4023: * xmlValidNormalizeAttributeValue:
! 4024: * @doc: the document
! 4025: * @elem: the parent
! 4026: * @name: the attribute name
! 4027: * @value: the attribute value
! 4028: *
! 4029: * Does the validation related extra step of the normalization of attribute
! 4030: * values:
! 4031: *
! 4032: * If the declared value is not CDATA, then the XML processor must further
! 4033: * process the normalized attribute value by discarding any leading and
! 4034: * trailing space (#x20) characters, and by replacing sequences of space
! 4035: * (#x20) characters by single space (#x20) character.
! 4036: *
! 4037: * Returns a new normalized string if normalization is needed, NULL otherwise
! 4038: * the caller must free the returned value.
! 4039: */
! 4040:
! 4041: xmlChar *
! 4042: xmlValidNormalizeAttributeValue(xmlDocPtr doc, xmlNodePtr elem,
! 4043: const xmlChar *name, const xmlChar *value) {
! 4044: xmlChar *ret, *dst;
! 4045: const xmlChar *src;
! 4046: xmlAttributePtr attrDecl = NULL;
! 4047:
! 4048: if (doc == NULL) return(NULL);
! 4049: if (elem == NULL) return(NULL);
! 4050: if (name == NULL) return(NULL);
! 4051: if (value == NULL) return(NULL);
! 4052:
! 4053: if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
! 4054: xmlChar fn[50];
! 4055: xmlChar *fullname;
! 4056:
! 4057: fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
! 4058: if (fullname == NULL)
! 4059: return(NULL);
! 4060: if ((fullname != fn) && (fullname != elem->name))
! 4061: xmlFree(fullname);
! 4062: }
! 4063: attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
! 4064: if ((attrDecl == NULL) && (doc->extSubset != NULL))
! 4065: attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
! 4066:
! 4067: if (attrDecl == NULL)
! 4068: return(NULL);
! 4069: if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
! 4070: return(NULL);
! 4071:
! 4072: ret = xmlStrdup(value);
! 4073: if (ret == NULL)
! 4074: return(NULL);
! 4075: src = value;
! 4076: dst = ret;
! 4077: while (*src == 0x20) src++;
! 4078: while (*src != 0) {
! 4079: if (*src == 0x20) {
! 4080: while (*src == 0x20) src++;
! 4081: if (*src != 0)
! 4082: *dst++ = 0x20;
! 4083: } else {
! 4084: *dst++ = *src++;
! 4085: }
! 4086: }
! 4087: *dst = 0;
! 4088: return(ret);
! 4089: }
! 4090:
! 4091: static void
! 4092: xmlValidateAttributeIdCallback(xmlAttributePtr attr, int *count,
! 4093: const xmlChar* name ATTRIBUTE_UNUSED) {
! 4094: if (attr->atype == XML_ATTRIBUTE_ID) (*count)++;
! 4095: }
! 4096:
! 4097: /**
! 4098: * xmlValidateAttributeDecl:
! 4099: * @ctxt: the validation context
! 4100: * @doc: a document instance
! 4101: * @attr: an attribute definition
! 4102: *
! 4103: * Try to validate a single attribute definition
! 4104: * basically it does the following checks as described by the
! 4105: * XML-1.0 recommendation:
! 4106: * - [ VC: Attribute Default Legal ]
! 4107: * - [ VC: Enumeration ]
! 4108: * - [ VC: ID Attribute Default ]
! 4109: *
! 4110: * The ID/IDREF uniqueness and matching are done separately
! 4111: *
! 4112: * returns 1 if valid or 0 otherwise
! 4113: */
! 4114:
! 4115: int
! 4116: xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
! 4117: xmlAttributePtr attr) {
! 4118: int ret = 1;
! 4119: int val;
! 4120: CHECK_DTD;
! 4121: if(attr == NULL) return(1);
! 4122:
! 4123: /* Attribute Default Legal */
! 4124: /* Enumeration */
! 4125: if (attr->defaultValue != NULL) {
! 4126: val = xmlValidateAttributeValueInternal(doc, attr->atype,
! 4127: attr->defaultValue);
! 4128: if (val == 0) {
! 4129: xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_DEFAULT,
! 4130: "Syntax of default value for attribute %s of %s is not valid\n",
! 4131: attr->name, attr->elem, NULL);
! 4132: }
! 4133: ret &= val;
! 4134: }
! 4135:
! 4136: /* ID Attribute Default */
! 4137: if ((attr->atype == XML_ATTRIBUTE_ID)&&
! 4138: (attr->def != XML_ATTRIBUTE_IMPLIED) &&
! 4139: (attr->def != XML_ATTRIBUTE_REQUIRED)) {
! 4140: xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_FIXED,
! 4141: "ID attribute %s of %s is not valid must be #IMPLIED or #REQUIRED\n",
! 4142: attr->name, attr->elem, NULL);
! 4143: ret = 0;
! 4144: }
! 4145:
! 4146: /* One ID per Element Type */
! 4147: if (attr->atype == XML_ATTRIBUTE_ID) {
! 4148: int nbId;
! 4149:
! 4150: /* the trick is that we parse DtD as their own internal subset */
! 4151: xmlElementPtr elem = xmlGetDtdElementDesc(doc->intSubset,
! 4152: attr->elem);
! 4153: if (elem != NULL) {
! 4154: nbId = xmlScanIDAttributeDecl(NULL, elem, 0);
! 4155: } else {
! 4156: xmlAttributeTablePtr table;
! 4157:
! 4158: /*
! 4159: * The attribute may be declared in the internal subset and the
! 4160: * element in the external subset.
! 4161: */
! 4162: nbId = 0;
! 4163: if (doc->intSubset != NULL) {
! 4164: table = (xmlAttributeTablePtr) doc->intSubset->attributes;
! 4165: xmlHashScan3(table, NULL, NULL, attr->elem, (xmlHashScanner)
! 4166: xmlValidateAttributeIdCallback, &nbId);
! 4167: }
! 4168: }
! 4169: if (nbId > 1) {
! 4170:
! 4171: xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
! 4172: "Element %s has %d ID attribute defined in the internal subset : %s\n",
! 4173: attr->elem, nbId, attr->name);
! 4174: } else if (doc->extSubset != NULL) {
! 4175: int extId = 0;
! 4176: elem = xmlGetDtdElementDesc(doc->extSubset, attr->elem);
! 4177: if (elem != NULL) {
! 4178: extId = xmlScanIDAttributeDecl(NULL, elem, 0);
! 4179: }
! 4180: if (extId > 1) {
! 4181: xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
! 4182: "Element %s has %d ID attribute defined in the external subset : %s\n",
! 4183: attr->elem, extId, attr->name);
! 4184: } else if (extId + nbId > 1) {
! 4185: xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
! 4186: "Element %s has ID attributes defined in the internal and external subset : %s\n",
! 4187: attr->elem, attr->name, NULL);
! 4188: }
! 4189: }
! 4190: }
! 4191:
! 4192: /* Validity Constraint: Enumeration */
! 4193: if ((attr->defaultValue != NULL) && (attr->tree != NULL)) {
! 4194: xmlEnumerationPtr tree = attr->tree;
! 4195: while (tree != NULL) {
! 4196: if (xmlStrEqual(tree->name, attr->defaultValue)) break;
! 4197: tree = tree->next;
! 4198: }
! 4199: if (tree == NULL) {
! 4200: xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_VALUE,
! 4201: "Default value \"%s\" for attribute %s of %s is not among the enumerated set\n",
! 4202: attr->defaultValue, attr->name, attr->elem);
! 4203: ret = 0;
! 4204: }
! 4205: }
! 4206:
! 4207: return(ret);
! 4208: }
! 4209:
! 4210: /**
! 4211: * xmlValidateElementDecl:
! 4212: * @ctxt: the validation context
! 4213: * @doc: a document instance
! 4214: * @elem: an element definition
! 4215: *
! 4216: * Try to validate a single element definition
! 4217: * basically it does the following checks as described by the
! 4218: * XML-1.0 recommendation:
! 4219: * - [ VC: One ID per Element Type ]
! 4220: * - [ VC: No Duplicate Types ]
! 4221: * - [ VC: Unique Element Type Declaration ]
! 4222: *
! 4223: * returns 1 if valid or 0 otherwise
! 4224: */
! 4225:
! 4226: int
! 4227: xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
! 4228: xmlElementPtr elem) {
! 4229: int ret = 1;
! 4230: xmlElementPtr tst;
! 4231:
! 4232: CHECK_DTD;
! 4233:
! 4234: if (elem == NULL) return(1);
! 4235:
! 4236: #if 0
! 4237: #ifdef LIBXML_REGEXP_ENABLED
! 4238: /* Build the regexp associated to the content model */
! 4239: ret = xmlValidBuildContentModel(ctxt, elem);
! 4240: #endif
! 4241: #endif
! 4242:
! 4243: /* No Duplicate Types */
! 4244: if (elem->etype == XML_ELEMENT_TYPE_MIXED) {
! 4245: xmlElementContentPtr cur, next;
! 4246: const xmlChar *name;
! 4247:
! 4248: cur = elem->content;
! 4249: while (cur != NULL) {
! 4250: if (cur->type != XML_ELEMENT_CONTENT_OR) break;
! 4251: if (cur->c1 == NULL) break;
! 4252: if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
! 4253: name = cur->c1->name;
! 4254: next = cur->c2;
! 4255: while (next != NULL) {
! 4256: if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
! 4257: if ((xmlStrEqual(next->name, name)) &&
! 4258: (xmlStrEqual(next->prefix, cur->c1->prefix))) {
! 4259: if (cur->c1->prefix == NULL) {
! 4260: xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
! 4261: "Definition of %s has duplicate references of %s\n",
! 4262: elem->name, name, NULL);
! 4263: } else {
! 4264: xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
! 4265: "Definition of %s has duplicate references of %s:%s\n",
! 4266: elem->name, cur->c1->prefix, name);
! 4267: }
! 4268: ret = 0;
! 4269: }
! 4270: break;
! 4271: }
! 4272: if (next->c1 == NULL) break;
! 4273: if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
! 4274: if ((xmlStrEqual(next->c1->name, name)) &&
! 4275: (xmlStrEqual(next->c1->prefix, cur->c1->prefix))) {
! 4276: if (cur->c1->prefix == NULL) {
! 4277: xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
! 4278: "Definition of %s has duplicate references to %s\n",
! 4279: elem->name, name, NULL);
! 4280: } else {
! 4281: xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
! 4282: "Definition of %s has duplicate references to %s:%s\n",
! 4283: elem->name, cur->c1->prefix, name);
! 4284: }
! 4285: ret = 0;
! 4286: }
! 4287: next = next->c2;
! 4288: }
! 4289: }
! 4290: cur = cur->c2;
! 4291: }
! 4292: }
! 4293:
! 4294: /* VC: Unique Element Type Declaration */
! 4295: tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
! 4296: if ((tst != NULL ) && (tst != elem) &&
! 4297: ((tst->prefix == elem->prefix) ||
! 4298: (xmlStrEqual(tst->prefix, elem->prefix))) &&
! 4299: (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
! 4300: xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
! 4301: "Redefinition of element %s\n",
! 4302: elem->name, NULL, NULL);
! 4303: ret = 0;
! 4304: }
! 4305: tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
! 4306: if ((tst != NULL ) && (tst != elem) &&
! 4307: ((tst->prefix == elem->prefix) ||
! 4308: (xmlStrEqual(tst->prefix, elem->prefix))) &&
! 4309: (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
! 4310: xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
! 4311: "Redefinition of element %s\n",
! 4312: elem->name, NULL, NULL);
! 4313: ret = 0;
! 4314: }
! 4315: /* One ID per Element Type
! 4316: * already done when registering the attribute
! 4317: if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
! 4318: ret = 0;
! 4319: } */
! 4320: return(ret);
! 4321: }
! 4322:
! 4323: /**
! 4324: * xmlValidateOneAttribute:
! 4325: * @ctxt: the validation context
! 4326: * @doc: a document instance
! 4327: * @elem: an element instance
! 4328: * @attr: an attribute instance
! 4329: * @value: the attribute value (without entities processing)
! 4330: *
! 4331: * Try to validate a single attribute for an element
! 4332: * basically it does the following checks as described by the
! 4333: * XML-1.0 recommendation:
! 4334: * - [ VC: Attribute Value Type ]
! 4335: * - [ VC: Fixed Attribute Default ]
! 4336: * - [ VC: Entity Name ]
! 4337: * - [ VC: Name Token ]
! 4338: * - [ VC: ID ]
! 4339: * - [ VC: IDREF ]
! 4340: * - [ VC: Entity Name ]
! 4341: * - [ VC: Notation Attributes ]
! 4342: *
! 4343: * The ID/IDREF uniqueness and matching are done separately
! 4344: *
! 4345: * returns 1 if valid or 0 otherwise
! 4346: */
! 4347:
! 4348: int
! 4349: xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
! 4350: xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value)
! 4351: {
! 4352: xmlAttributePtr attrDecl = NULL;
! 4353: int val;
! 4354: int ret = 1;
! 4355:
! 4356: CHECK_DTD;
! 4357: if ((elem == NULL) || (elem->name == NULL)) return(0);
! 4358: if ((attr == NULL) || (attr->name == NULL)) return(0);
! 4359:
! 4360: if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
! 4361: xmlChar fn[50];
! 4362: xmlChar *fullname;
! 4363:
! 4364: fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
! 4365: if (fullname == NULL)
! 4366: return(0);
! 4367: if (attr->ns != NULL) {
! 4368: attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
! 4369: attr->name, attr->ns->prefix);
! 4370: if ((attrDecl == NULL) && (doc->extSubset != NULL))
! 4371: attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
! 4372: attr->name, attr->ns->prefix);
! 4373: } else {
! 4374: attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, attr->name);
! 4375: if ((attrDecl == NULL) && (doc->extSubset != NULL))
! 4376: attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
! 4377: fullname, attr->name);
! 4378: }
! 4379: if ((fullname != fn) && (fullname != elem->name))
! 4380: xmlFree(fullname);
! 4381: }
! 4382: if (attrDecl == NULL) {
! 4383: if (attr->ns != NULL) {
! 4384: attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
! 4385: attr->name, attr->ns->prefix);
! 4386: if ((attrDecl == NULL) && (doc->extSubset != NULL))
! 4387: attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
! 4388: attr->name, attr->ns->prefix);
! 4389: } else {
! 4390: attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
! 4391: elem->name, attr->name);
! 4392: if ((attrDecl == NULL) && (doc->extSubset != NULL))
! 4393: attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
! 4394: elem->name, attr->name);
! 4395: }
! 4396: }
! 4397:
! 4398:
! 4399: /* Validity Constraint: Attribute Value Type */
! 4400: if (attrDecl == NULL) {
! 4401: xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
! 4402: "No declaration for attribute %s of element %s\n",
! 4403: attr->name, elem->name, NULL);
! 4404: return(0);
! 4405: }
! 4406: attr->atype = attrDecl->atype;
! 4407:
! 4408: val = xmlValidateAttributeValueInternal(doc, attrDecl->atype, value);
! 4409: if (val == 0) {
! 4410: xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
! 4411: "Syntax of value for attribute %s of %s is not valid\n",
! 4412: attr->name, elem->name, NULL);
! 4413: ret = 0;
! 4414: }
! 4415:
! 4416: /* Validity constraint: Fixed Attribute Default */
! 4417: if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
! 4418: if (!xmlStrEqual(value, attrDecl->defaultValue)) {
! 4419: xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
! 4420: "Value for attribute %s of %s is different from default \"%s\"\n",
! 4421: attr->name, elem->name, attrDecl->defaultValue);
! 4422: ret = 0;
! 4423: }
! 4424: }
! 4425:
! 4426: /* Validity Constraint: ID uniqueness */
! 4427: if (attrDecl->atype == XML_ATTRIBUTE_ID) {
! 4428: if (xmlAddID(ctxt, doc, value, attr) == NULL)
! 4429: ret = 0;
! 4430: }
! 4431:
! 4432: if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
! 4433: (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
! 4434: if (xmlAddRef(ctxt, doc, value, attr) == NULL)
! 4435: ret = 0;
! 4436: }
! 4437:
! 4438: /* Validity Constraint: Notation Attributes */
! 4439: if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
! 4440: xmlEnumerationPtr tree = attrDecl->tree;
! 4441: xmlNotationPtr nota;
! 4442:
! 4443: /* First check that the given NOTATION was declared */
! 4444: nota = xmlGetDtdNotationDesc(doc->intSubset, value);
! 4445: if (nota == NULL)
! 4446: nota = xmlGetDtdNotationDesc(doc->extSubset, value);
! 4447:
! 4448: if (nota == NULL) {
! 4449: xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
! 4450: "Value \"%s\" for attribute %s of %s is not a declared Notation\n",
! 4451: value, attr->name, elem->name);
! 4452: ret = 0;
! 4453: }
! 4454:
! 4455: /* Second, verify that it's among the list */
! 4456: while (tree != NULL) {
! 4457: if (xmlStrEqual(tree->name, value)) break;
! 4458: tree = tree->next;
! 4459: }
! 4460: if (tree == NULL) {
! 4461: xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
! 4462: "Value \"%s\" for attribute %s of %s is not among the enumerated notations\n",
! 4463: value, attr->name, elem->name);
! 4464: ret = 0;
! 4465: }
! 4466: }
! 4467:
! 4468: /* Validity Constraint: Enumeration */
! 4469: if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
! 4470: xmlEnumerationPtr tree = attrDecl->tree;
! 4471: while (tree != NULL) {
! 4472: if (xmlStrEqual(tree->name, value)) break;
! 4473: tree = tree->next;
! 4474: }
! 4475: if (tree == NULL) {
! 4476: xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
! 4477: "Value \"%s\" for attribute %s of %s is not among the enumerated set\n",
! 4478: value, attr->name, elem->name);
! 4479: ret = 0;
! 4480: }
! 4481: }
! 4482:
! 4483: /* Fixed Attribute Default */
! 4484: if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
! 4485: (!xmlStrEqual(attrDecl->defaultValue, value))) {
! 4486: xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
! 4487: "Value for attribute %s of %s must be \"%s\"\n",
! 4488: attr->name, elem->name, attrDecl->defaultValue);
! 4489: ret = 0;
! 4490: }
! 4491:
! 4492: /* Extra check for the attribute value */
! 4493: ret &= xmlValidateAttributeValue2(ctxt, doc, attr->name,
! 4494: attrDecl->atype, value);
! 4495:
! 4496: return(ret);
! 4497: }
! 4498:
! 4499: /**
! 4500: * xmlValidateOneNamespace:
! 4501: * @ctxt: the validation context
! 4502: * @doc: a document instance
! 4503: * @elem: an element instance
! 4504: * @prefix: the namespace prefix
! 4505: * @ns: an namespace declaration instance
! 4506: * @value: the attribute value (without entities processing)
! 4507: *
! 4508: * Try to validate a single namespace declaration for an element
! 4509: * basically it does the following checks as described by the
! 4510: * XML-1.0 recommendation:
! 4511: * - [ VC: Attribute Value Type ]
! 4512: * - [ VC: Fixed Attribute Default ]
! 4513: * - [ VC: Entity Name ]
! 4514: * - [ VC: Name Token ]
! 4515: * - [ VC: ID ]
! 4516: * - [ VC: IDREF ]
! 4517: * - [ VC: Entity Name ]
! 4518: * - [ VC: Notation Attributes ]
! 4519: *
! 4520: * The ID/IDREF uniqueness and matching are done separately
! 4521: *
! 4522: * returns 1 if valid or 0 otherwise
! 4523: */
! 4524:
! 4525: int
! 4526: xmlValidateOneNamespace(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
! 4527: xmlNodePtr elem, const xmlChar *prefix, xmlNsPtr ns, const xmlChar *value) {
! 4528: /* xmlElementPtr elemDecl; */
! 4529: xmlAttributePtr attrDecl = NULL;
! 4530: int val;
! 4531: int ret = 1;
! 4532:
! 4533: CHECK_DTD;
! 4534: if ((elem == NULL) || (elem->name == NULL)) return(0);
! 4535: if ((ns == NULL) || (ns->href == NULL)) return(0);
! 4536:
! 4537: if (prefix != NULL) {
! 4538: xmlChar fn[50];
! 4539: xmlChar *fullname;
! 4540:
! 4541: fullname = xmlBuildQName(elem->name, prefix, fn, 50);
! 4542: if (fullname == NULL) {
! 4543: xmlVErrMemory(ctxt, "Validating namespace");
! 4544: return(0);
! 4545: }
! 4546: if (ns->prefix != NULL) {
! 4547: attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
! 4548: ns->prefix, BAD_CAST "xmlns");
! 4549: if ((attrDecl == NULL) && (doc->extSubset != NULL))
! 4550: attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
! 4551: ns->prefix, BAD_CAST "xmlns");
! 4552: } else {
! 4553: attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname,
! 4554: BAD_CAST "xmlns");
! 4555: if ((attrDecl == NULL) && (doc->extSubset != NULL))
! 4556: attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname,
! 4557: BAD_CAST "xmlns");
! 4558: }
! 4559: if ((fullname != fn) && (fullname != elem->name))
! 4560: xmlFree(fullname);
! 4561: }
! 4562: if (attrDecl == NULL) {
! 4563: if (ns->prefix != NULL) {
! 4564: attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
! 4565: ns->prefix, BAD_CAST "xmlns");
! 4566: if ((attrDecl == NULL) && (doc->extSubset != NULL))
! 4567: attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
! 4568: ns->prefix, BAD_CAST "xmlns");
! 4569: } else {
! 4570: attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
! 4571: elem->name, BAD_CAST "xmlns");
! 4572: if ((attrDecl == NULL) && (doc->extSubset != NULL))
! 4573: attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
! 4574: elem->name, BAD_CAST "xmlns");
! 4575: }
! 4576: }
! 4577:
! 4578:
! 4579: /* Validity Constraint: Attribute Value Type */
! 4580: if (attrDecl == NULL) {
! 4581: if (ns->prefix != NULL) {
! 4582: xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
! 4583: "No declaration for attribute xmlns:%s of element %s\n",
! 4584: ns->prefix, elem->name, NULL);
! 4585: } else {
! 4586: xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
! 4587: "No declaration for attribute xmlns of element %s\n",
! 4588: elem->name, NULL, NULL);
! 4589: }
! 4590: return(0);
! 4591: }
! 4592:
! 4593: val = xmlValidateAttributeValueInternal(doc, attrDecl->atype, value);
! 4594: if (val == 0) {
! 4595: if (ns->prefix != NULL) {
! 4596: xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
! 4597: "Syntax of value for attribute xmlns:%s of %s is not valid\n",
! 4598: ns->prefix, elem->name, NULL);
! 4599: } else {
! 4600: xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
! 4601: "Syntax of value for attribute xmlns of %s is not valid\n",
! 4602: elem->name, NULL, NULL);
! 4603: }
! 4604: ret = 0;
! 4605: }
! 4606:
! 4607: /* Validity constraint: Fixed Attribute Default */
! 4608: if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
! 4609: if (!xmlStrEqual(value, attrDecl->defaultValue)) {
! 4610: if (ns->prefix != NULL) {
! 4611: xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
! 4612: "Value for attribute xmlns:%s of %s is different from default \"%s\"\n",
! 4613: ns->prefix, elem->name, attrDecl->defaultValue);
! 4614: } else {
! 4615: xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
! 4616: "Value for attribute xmlns of %s is different from default \"%s\"\n",
! 4617: elem->name, attrDecl->defaultValue, NULL);
! 4618: }
! 4619: ret = 0;
! 4620: }
! 4621: }
! 4622:
! 4623: /* Validity Constraint: ID uniqueness */
! 4624: if (attrDecl->atype == XML_ATTRIBUTE_ID) {
! 4625: if (xmlAddID(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
! 4626: ret = 0;
! 4627: }
! 4628:
! 4629: if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
! 4630: (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
! 4631: if (xmlAddRef(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
! 4632: ret = 0;
! 4633: }
! 4634:
! 4635: /* Validity Constraint: Notation Attributes */
! 4636: if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
! 4637: xmlEnumerationPtr tree = attrDecl->tree;
! 4638: xmlNotationPtr nota;
! 4639:
! 4640: /* First check that the given NOTATION was declared */
! 4641: nota = xmlGetDtdNotationDesc(doc->intSubset, value);
! 4642: if (nota == NULL)
! 4643: nota = xmlGetDtdNotationDesc(doc->extSubset, value);
! 4644:
! 4645: if (nota == NULL) {
! 4646: if (ns->prefix != NULL) {
! 4647: xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
! 4648: "Value \"%s\" for attribute xmlns:%s of %s is not a declared Notation\n",
! 4649: value, ns->prefix, elem->name);
! 4650: } else {
! 4651: xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
! 4652: "Value \"%s\" for attribute xmlns of %s is not a declared Notation\n",
! 4653: value, elem->name, NULL);
! 4654: }
! 4655: ret = 0;
! 4656: }
! 4657:
! 4658: /* Second, verify that it's among the list */
! 4659: while (tree != NULL) {
! 4660: if (xmlStrEqual(tree->name, value)) break;
! 4661: tree = tree->next;
! 4662: }
! 4663: if (tree == NULL) {
! 4664: if (ns->prefix != NULL) {
! 4665: xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
! 4666: "Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated notations\n",
! 4667: value, ns->prefix, elem->name);
! 4668: } else {
! 4669: xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
! 4670: "Value \"%s\" for attribute xmlns of %s is not among the enumerated notations\n",
! 4671: value, elem->name, NULL);
! 4672: }
! 4673: ret = 0;
! 4674: }
! 4675: }
! 4676:
! 4677: /* Validity Constraint: Enumeration */
! 4678: if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
! 4679: xmlEnumerationPtr tree = attrDecl->tree;
! 4680: while (tree != NULL) {
! 4681: if (xmlStrEqual(tree->name, value)) break;
! 4682: tree = tree->next;
! 4683: }
! 4684: if (tree == NULL) {
! 4685: if (ns->prefix != NULL) {
! 4686: xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
! 4687: "Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated set\n",
! 4688: value, ns->prefix, elem->name);
! 4689: } else {
! 4690: xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
! 4691: "Value \"%s\" for attribute xmlns of %s is not among the enumerated set\n",
! 4692: value, elem->name, NULL);
! 4693: }
! 4694: ret = 0;
! 4695: }
! 4696: }
! 4697:
! 4698: /* Fixed Attribute Default */
! 4699: if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
! 4700: (!xmlStrEqual(attrDecl->defaultValue, value))) {
! 4701: if (ns->prefix != NULL) {
! 4702: xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
! 4703: "Value for attribute xmlns:%s of %s must be \"%s\"\n",
! 4704: ns->prefix, elem->name, attrDecl->defaultValue);
! 4705: } else {
! 4706: xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
! 4707: "Value for attribute xmlns of %s must be \"%s\"\n",
! 4708: elem->name, attrDecl->defaultValue, NULL);
! 4709: }
! 4710: ret = 0;
! 4711: }
! 4712:
! 4713: /* Extra check for the attribute value */
! 4714: if (ns->prefix != NULL) {
! 4715: ret &= xmlValidateAttributeValue2(ctxt, doc, ns->prefix,
! 4716: attrDecl->atype, value);
! 4717: } else {
! 4718: ret &= xmlValidateAttributeValue2(ctxt, doc, BAD_CAST "xmlns",
! 4719: attrDecl->atype, value);
! 4720: }
! 4721:
! 4722: return(ret);
! 4723: }
! 4724:
! 4725: #ifndef LIBXML_REGEXP_ENABLED
! 4726: /**
! 4727: * xmlValidateSkipIgnorable:
! 4728: * @ctxt: the validation context
! 4729: * @child: the child list
! 4730: *
! 4731: * Skip ignorable elements w.r.t. the validation process
! 4732: *
! 4733: * returns the first element to consider for validation of the content model
! 4734: */
! 4735:
! 4736: static xmlNodePtr
! 4737: xmlValidateSkipIgnorable(xmlNodePtr child) {
! 4738: while (child != NULL) {
! 4739: switch (child->type) {
! 4740: /* These things are ignored (skipped) during validation. */
! 4741: case XML_PI_NODE:
! 4742: case XML_COMMENT_NODE:
! 4743: case XML_XINCLUDE_START:
! 4744: case XML_XINCLUDE_END:
! 4745: child = child->next;
! 4746: break;
! 4747: case XML_TEXT_NODE:
! 4748: if (xmlIsBlankNode(child))
! 4749: child = child->next;
! 4750: else
! 4751: return(child);
! 4752: break;
! 4753: /* keep current node */
! 4754: default:
! 4755: return(child);
! 4756: }
! 4757: }
! 4758: return(child);
! 4759: }
! 4760:
! 4761: /**
! 4762: * xmlValidateElementType:
! 4763: * @ctxt: the validation context
! 4764: *
! 4765: * Try to validate the content model of an element internal function
! 4766: *
! 4767: * returns 1 if valid or 0 ,-1 in case of error, -2 if an entity
! 4768: * reference is found and -3 if the validation succeeded but
! 4769: * the content model is not determinist.
! 4770: */
! 4771:
! 4772: static int
! 4773: xmlValidateElementType(xmlValidCtxtPtr ctxt) {
! 4774: int ret = -1;
! 4775: int determinist = 1;
! 4776:
! 4777: NODE = xmlValidateSkipIgnorable(NODE);
! 4778: if ((NODE == NULL) && (CONT == NULL))
! 4779: return(1);
! 4780: if ((NODE == NULL) &&
! 4781: ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
! 4782: (CONT->ocur == XML_ELEMENT_CONTENT_OPT))) {
! 4783: return(1);
! 4784: }
! 4785: if (CONT == NULL) return(-1);
! 4786: if ((NODE != NULL) && (NODE->type == XML_ENTITY_REF_NODE))
! 4787: return(-2);
! 4788:
! 4789: /*
! 4790: * We arrive here when more states need to be examined
! 4791: */
! 4792: cont:
! 4793:
! 4794: /*
! 4795: * We just recovered from a rollback generated by a possible
! 4796: * epsilon transition, go directly to the analysis phase
! 4797: */
! 4798: if (STATE == ROLLBACK_PARENT) {
! 4799: DEBUG_VALID_MSG("restored parent branch");
! 4800: DEBUG_VALID_STATE(NODE, CONT)
! 4801: ret = 1;
! 4802: goto analyze;
! 4803: }
! 4804:
! 4805: DEBUG_VALID_STATE(NODE, CONT)
! 4806: /*
! 4807: * we may have to save a backup state here. This is the equivalent
! 4808: * of handling epsilon transition in NFAs.
! 4809: */
! 4810: if ((CONT != NULL) &&
! 4811: ((CONT->parent == NULL) ||
! 4812: (CONT->parent->type != XML_ELEMENT_CONTENT_OR)) &&
! 4813: ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
! 4814: (CONT->ocur == XML_ELEMENT_CONTENT_OPT) ||
! 4815: ((CONT->ocur == XML_ELEMENT_CONTENT_PLUS) && (OCCURRENCE)))) {
! 4816: DEBUG_VALID_MSG("saving parent branch");
! 4817: if (vstateVPush(ctxt, CONT, NODE, DEPTH, OCCURS, ROLLBACK_PARENT) < 0)
! 4818: return(0);
! 4819: }
! 4820:
! 4821:
! 4822: /*
! 4823: * Check first if the content matches
! 4824: */
! 4825: switch (CONT->type) {
! 4826: case XML_ELEMENT_CONTENT_PCDATA:
! 4827: if (NODE == NULL) {
! 4828: DEBUG_VALID_MSG("pcdata failed no node");
! 4829: ret = 0;
! 4830: break;
! 4831: }
! 4832: if (NODE->type == XML_TEXT_NODE) {
! 4833: DEBUG_VALID_MSG("pcdata found, skip to next");
! 4834: /*
! 4835: * go to next element in the content model
! 4836: * skipping ignorable elems
! 4837: */
! 4838: do {
! 4839: NODE = NODE->next;
! 4840: NODE = xmlValidateSkipIgnorable(NODE);
! 4841: if ((NODE != NULL) &&
! 4842: (NODE->type == XML_ENTITY_REF_NODE))
! 4843: return(-2);
! 4844: } while ((NODE != NULL) &&
! 4845: ((NODE->type != XML_ELEMENT_NODE) &&
! 4846: (NODE->type != XML_TEXT_NODE) &&
! 4847: (NODE->type != XML_CDATA_SECTION_NODE)));
! 4848: ret = 1;
! 4849: break;
! 4850: } else {
! 4851: DEBUG_VALID_MSG("pcdata failed");
! 4852: ret = 0;
! 4853: break;
! 4854: }
! 4855: break;
! 4856: case XML_ELEMENT_CONTENT_ELEMENT:
! 4857: if (NODE == NULL) {
! 4858: DEBUG_VALID_MSG("element failed no node");
! 4859: ret = 0;
! 4860: break;
! 4861: }
! 4862: ret = ((NODE->type == XML_ELEMENT_NODE) &&
! 4863: (xmlStrEqual(NODE->name, CONT->name)));
! 4864: if (ret == 1) {
! 4865: if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
! 4866: ret = (CONT->prefix == NULL);
! 4867: } else if (CONT->prefix == NULL) {
! 4868: ret = 0;
! 4869: } else {
! 4870: ret = xmlStrEqual(NODE->ns->prefix, CONT->prefix);
! 4871: }
! 4872: }
! 4873: if (ret == 1) {
! 4874: DEBUG_VALID_MSG("element found, skip to next");
! 4875: /*
! 4876: * go to next element in the content model
! 4877: * skipping ignorable elems
! 4878: */
! 4879: do {
! 4880: NODE = NODE->next;
! 4881: NODE = xmlValidateSkipIgnorable(NODE);
! 4882: if ((NODE != NULL) &&
! 4883: (NODE->type == XML_ENTITY_REF_NODE))
! 4884: return(-2);
! 4885: } while ((NODE != NULL) &&
! 4886: ((NODE->type != XML_ELEMENT_NODE) &&
! 4887: (NODE->type != XML_TEXT_NODE) &&
! 4888: (NODE->type != XML_CDATA_SECTION_NODE)));
! 4889: } else {
! 4890: DEBUG_VALID_MSG("element failed");
! 4891: ret = 0;
! 4892: break;
! 4893: }
! 4894: break;
! 4895: case XML_ELEMENT_CONTENT_OR:
! 4896: /*
! 4897: * Small optimization.
! 4898: */
! 4899: if (CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
! 4900: if ((NODE == NULL) ||
! 4901: (!xmlStrEqual(NODE->name, CONT->c1->name))) {
! 4902: DEPTH++;
! 4903: CONT = CONT->c2;
! 4904: goto cont;
! 4905: }
! 4906: if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
! 4907: ret = (CONT->c1->prefix == NULL);
! 4908: } else if (CONT->c1->prefix == NULL) {
! 4909: ret = 0;
! 4910: } else {
! 4911: ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
! 4912: }
! 4913: if (ret == 0) {
! 4914: DEPTH++;
! 4915: CONT = CONT->c2;
! 4916: goto cont;
! 4917: }
! 4918: }
! 4919:
! 4920: /*
! 4921: * save the second branch 'or' branch
! 4922: */
! 4923: DEBUG_VALID_MSG("saving 'or' branch");
! 4924: if (vstateVPush(ctxt, CONT->c2, NODE, (unsigned char)(DEPTH + 1),
! 4925: OCCURS, ROLLBACK_OR) < 0)
! 4926: return(-1);
! 4927: DEPTH++;
! 4928: CONT = CONT->c1;
! 4929: goto cont;
! 4930: case XML_ELEMENT_CONTENT_SEQ:
! 4931: /*
! 4932: * Small optimization.
! 4933: */
! 4934: if ((CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) &&
! 4935: ((CONT->c1->ocur == XML_ELEMENT_CONTENT_OPT) ||
! 4936: (CONT->c1->ocur == XML_ELEMENT_CONTENT_MULT))) {
! 4937: if ((NODE == NULL) ||
! 4938: (!xmlStrEqual(NODE->name, CONT->c1->name))) {
! 4939: DEPTH++;
! 4940: CONT = CONT->c2;
! 4941: goto cont;
! 4942: }
! 4943: if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
! 4944: ret = (CONT->c1->prefix == NULL);
! 4945: } else if (CONT->c1->prefix == NULL) {
! 4946: ret = 0;
! 4947: } else {
! 4948: ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
! 4949: }
! 4950: if (ret == 0) {
! 4951: DEPTH++;
! 4952: CONT = CONT->c2;
! 4953: goto cont;
! 4954: }
! 4955: }
! 4956: DEPTH++;
! 4957: CONT = CONT->c1;
! 4958: goto cont;
! 4959: }
! 4960:
! 4961: /*
! 4962: * At this point handle going up in the tree
! 4963: */
! 4964: if (ret == -1) {
! 4965: DEBUG_VALID_MSG("error found returning");
! 4966: return(ret);
! 4967: }
! 4968: analyze:
! 4969: while (CONT != NULL) {
! 4970: /*
! 4971: * First do the analysis depending on the occurrence model at
! 4972: * this level.
! 4973: */
! 4974: if (ret == 0) {
! 4975: switch (CONT->ocur) {
! 4976: xmlNodePtr cur;
! 4977:
! 4978: case XML_ELEMENT_CONTENT_ONCE:
! 4979: cur = ctxt->vstate->node;
! 4980: DEBUG_VALID_MSG("Once branch failed, rollback");
! 4981: if (vstateVPop(ctxt) < 0 ) {
! 4982: DEBUG_VALID_MSG("exhaustion, failed");
! 4983: return(0);
! 4984: }
! 4985: if (cur != ctxt->vstate->node)
! 4986: determinist = -3;
! 4987: goto cont;
! 4988: case XML_ELEMENT_CONTENT_PLUS:
! 4989: if (OCCURRENCE == 0) {
! 4990: cur = ctxt->vstate->node;
! 4991: DEBUG_VALID_MSG("Plus branch failed, rollback");
! 4992: if (vstateVPop(ctxt) < 0 ) {
! 4993: DEBUG_VALID_MSG("exhaustion, failed");
! 4994: return(0);
! 4995: }
! 4996: if (cur != ctxt->vstate->node)
! 4997: determinist = -3;
! 4998: goto cont;
! 4999: }
! 5000: DEBUG_VALID_MSG("Plus branch found");
! 5001: ret = 1;
! 5002: break;
! 5003: case XML_ELEMENT_CONTENT_MULT:
! 5004: #ifdef DEBUG_VALID_ALGO
! 5005: if (OCCURRENCE == 0) {
! 5006: DEBUG_VALID_MSG("Mult branch failed");
! 5007: } else {
! 5008: DEBUG_VALID_MSG("Mult branch found");
! 5009: }
! 5010: #endif
! 5011: ret = 1;
! 5012: break;
! 5013: case XML_ELEMENT_CONTENT_OPT:
! 5014: DEBUG_VALID_MSG("Option branch failed");
! 5015: ret = 1;
! 5016: break;
! 5017: }
! 5018: } else {
! 5019: switch (CONT->ocur) {
! 5020: case XML_ELEMENT_CONTENT_OPT:
! 5021: DEBUG_VALID_MSG("Option branch succeeded");
! 5022: ret = 1;
! 5023: break;
! 5024: case XML_ELEMENT_CONTENT_ONCE:
! 5025: DEBUG_VALID_MSG("Once branch succeeded");
! 5026: ret = 1;
! 5027: break;
! 5028: case XML_ELEMENT_CONTENT_PLUS:
! 5029: if (STATE == ROLLBACK_PARENT) {
! 5030: DEBUG_VALID_MSG("Plus branch rollback");
! 5031: ret = 1;
! 5032: break;
! 5033: }
! 5034: if (NODE == NULL) {
! 5035: DEBUG_VALID_MSG("Plus branch exhausted");
! 5036: ret = 1;
! 5037: break;
! 5038: }
! 5039: DEBUG_VALID_MSG("Plus branch succeeded, continuing");
! 5040: SET_OCCURRENCE;
! 5041: goto cont;
! 5042: case XML_ELEMENT_CONTENT_MULT:
! 5043: if (STATE == ROLLBACK_PARENT) {
! 5044: DEBUG_VALID_MSG("Mult branch rollback");
! 5045: ret = 1;
! 5046: break;
! 5047: }
! 5048: if (NODE == NULL) {
! 5049: DEBUG_VALID_MSG("Mult branch exhausted");
! 5050: ret = 1;
! 5051: break;
! 5052: }
! 5053: DEBUG_VALID_MSG("Mult branch succeeded, continuing");
! 5054: /* SET_OCCURRENCE; */
! 5055: goto cont;
! 5056: }
! 5057: }
! 5058: STATE = 0;
! 5059:
! 5060: /*
! 5061: * Then act accordingly at the parent level
! 5062: */
! 5063: RESET_OCCURRENCE;
! 5064: if (CONT->parent == NULL)
! 5065: break;
! 5066:
! 5067: switch (CONT->parent->type) {
! 5068: case XML_ELEMENT_CONTENT_PCDATA:
! 5069: DEBUG_VALID_MSG("Error: parent pcdata");
! 5070: return(-1);
! 5071: case XML_ELEMENT_CONTENT_ELEMENT:
! 5072: DEBUG_VALID_MSG("Error: parent element");
! 5073: return(-1);
! 5074: case XML_ELEMENT_CONTENT_OR:
! 5075: if (ret == 1) {
! 5076: DEBUG_VALID_MSG("Or succeeded");
! 5077: CONT = CONT->parent;
! 5078: DEPTH--;
! 5079: } else {
! 5080: DEBUG_VALID_MSG("Or failed");
! 5081: CONT = CONT->parent;
! 5082: DEPTH--;
! 5083: }
! 5084: break;
! 5085: case XML_ELEMENT_CONTENT_SEQ:
! 5086: if (ret == 0) {
! 5087: DEBUG_VALID_MSG("Sequence failed");
! 5088: CONT = CONT->parent;
! 5089: DEPTH--;
! 5090: } else if (CONT == CONT->parent->c1) {
! 5091: DEBUG_VALID_MSG("Sequence testing 2nd branch");
! 5092: CONT = CONT->parent->c2;
! 5093: goto cont;
! 5094: } else {
! 5095: DEBUG_VALID_MSG("Sequence succeeded");
! 5096: CONT = CONT->parent;
! 5097: DEPTH--;
! 5098: }
! 5099: }
! 5100: }
! 5101: if (NODE != NULL) {
! 5102: xmlNodePtr cur;
! 5103:
! 5104: cur = ctxt->vstate->node;
! 5105: DEBUG_VALID_MSG("Failed, remaining input, rollback");
! 5106: if (vstateVPop(ctxt) < 0 ) {
! 5107: DEBUG_VALID_MSG("exhaustion, failed");
! 5108: return(0);
! 5109: }
! 5110: if (cur != ctxt->vstate->node)
! 5111: determinist = -3;
! 5112: goto cont;
! 5113: }
! 5114: if (ret == 0) {
! 5115: xmlNodePtr cur;
! 5116:
! 5117: cur = ctxt->vstate->node;
! 5118: DEBUG_VALID_MSG("Failure, rollback");
! 5119: if (vstateVPop(ctxt) < 0 ) {
! 5120: DEBUG_VALID_MSG("exhaustion, failed");
! 5121: return(0);
! 5122: }
! 5123: if (cur != ctxt->vstate->node)
! 5124: determinist = -3;
! 5125: goto cont;
! 5126: }
! 5127: return(determinist);
! 5128: }
! 5129: #endif
! 5130:
! 5131: /**
! 5132: * xmlSnprintfElements:
! 5133: * @buf: an output buffer
! 5134: * @size: the size of the buffer
! 5135: * @content: An element
! 5136: * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
! 5137: *
! 5138: * This will dump the list of elements to the buffer
! 5139: * Intended just for the debug routine
! 5140: */
! 5141: static void
! 5142: xmlSnprintfElements(char *buf, int size, xmlNodePtr node, int glob) {
! 5143: xmlNodePtr cur;
! 5144: int len;
! 5145:
! 5146: if (node == NULL) return;
! 5147: if (glob) strcat(buf, "(");
! 5148: cur = node;
! 5149: while (cur != NULL) {
! 5150: len = strlen(buf);
! 5151: if (size - len < 50) {
! 5152: if ((size - len > 4) && (buf[len - 1] != '.'))
! 5153: strcat(buf, " ...");
! 5154: return;
! 5155: }
! 5156: switch (cur->type) {
! 5157: case XML_ELEMENT_NODE:
! 5158: if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
! 5159: if (size - len < xmlStrlen(cur->ns->prefix) + 10) {
! 5160: if ((size - len > 4) && (buf[len - 1] != '.'))
! 5161: strcat(buf, " ...");
! 5162: return;
! 5163: }
! 5164: strcat(buf, (char *) cur->ns->prefix);
! 5165: strcat(buf, ":");
! 5166: }
! 5167: if (size - len < xmlStrlen(cur->name) + 10) {
! 5168: if ((size - len > 4) && (buf[len - 1] != '.'))
! 5169: strcat(buf, " ...");
! 5170: return;
! 5171: }
! 5172: strcat(buf, (char *) cur->name);
! 5173: if (cur->next != NULL)
! 5174: strcat(buf, " ");
! 5175: break;
! 5176: case XML_TEXT_NODE:
! 5177: if (xmlIsBlankNode(cur))
! 5178: break;
! 5179: case XML_CDATA_SECTION_NODE:
! 5180: case XML_ENTITY_REF_NODE:
! 5181: strcat(buf, "CDATA");
! 5182: if (cur->next != NULL)
! 5183: strcat(buf, " ");
! 5184: break;
! 5185: case XML_ATTRIBUTE_NODE:
! 5186: case XML_DOCUMENT_NODE:
! 5187: #ifdef LIBXML_DOCB_ENABLED
! 5188: case XML_DOCB_DOCUMENT_NODE:
! 5189: #endif
! 5190: case XML_HTML_DOCUMENT_NODE:
! 5191: case XML_DOCUMENT_TYPE_NODE:
! 5192: case XML_DOCUMENT_FRAG_NODE:
! 5193: case XML_NOTATION_NODE:
! 5194: case XML_NAMESPACE_DECL:
! 5195: strcat(buf, "???");
! 5196: if (cur->next != NULL)
! 5197: strcat(buf, " ");
! 5198: break;
! 5199: case XML_ENTITY_NODE:
! 5200: case XML_PI_NODE:
! 5201: case XML_DTD_NODE:
! 5202: case XML_COMMENT_NODE:
! 5203: case XML_ELEMENT_DECL:
! 5204: case XML_ATTRIBUTE_DECL:
! 5205: case XML_ENTITY_DECL:
! 5206: case XML_XINCLUDE_START:
! 5207: case XML_XINCLUDE_END:
! 5208: break;
! 5209: }
! 5210: cur = cur->next;
! 5211: }
! 5212: if (glob) strcat(buf, ")");
! 5213: }
! 5214:
! 5215: /**
! 5216: * xmlValidateElementContent:
! 5217: * @ctxt: the validation context
! 5218: * @child: the child list
! 5219: * @elemDecl: pointer to the element declaration
! 5220: * @warn: emit the error message
! 5221: * @parent: the parent element (for error reporting)
! 5222: *
! 5223: * Try to validate the content model of an element
! 5224: *
! 5225: * returns 1 if valid or 0 if not and -1 in case of error
! 5226: */
! 5227:
! 5228: static int
! 5229: xmlValidateElementContent(xmlValidCtxtPtr ctxt, xmlNodePtr child,
! 5230: xmlElementPtr elemDecl, int warn, xmlNodePtr parent) {
! 5231: int ret = 1;
! 5232: #ifndef LIBXML_REGEXP_ENABLED
! 5233: xmlNodePtr repl = NULL, last = NULL, tmp;
! 5234: #endif
! 5235: xmlNodePtr cur;
! 5236: xmlElementContentPtr cont;
! 5237: const xmlChar *name;
! 5238:
! 5239: if (elemDecl == NULL)
! 5240: return(-1);
! 5241: cont = elemDecl->content;
! 5242: name = elemDecl->name;
! 5243:
! 5244: #ifdef LIBXML_REGEXP_ENABLED
! 5245: /* Build the regexp associated to the content model */
! 5246: if (elemDecl->contModel == NULL)
! 5247: ret = xmlValidBuildContentModel(ctxt, elemDecl);
! 5248: if (elemDecl->contModel == NULL) {
! 5249: return(-1);
! 5250: } else {
! 5251: xmlRegExecCtxtPtr exec;
! 5252:
! 5253: if (!xmlRegexpIsDeterminist(elemDecl->contModel)) {
! 5254: return(-1);
! 5255: }
! 5256: ctxt->nodeMax = 0;
! 5257: ctxt->nodeNr = 0;
! 5258: ctxt->nodeTab = NULL;
! 5259: exec = xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
! 5260: if (exec != NULL) {
! 5261: cur = child;
! 5262: while (cur != NULL) {
! 5263: switch (cur->type) {
! 5264: case XML_ENTITY_REF_NODE:
! 5265: /*
! 5266: * Push the current node to be able to roll back
! 5267: * and process within the entity
! 5268: */
! 5269: if ((cur->children != NULL) &&
! 5270: (cur->children->children != NULL)) {
! 5271: nodeVPush(ctxt, cur);
! 5272: cur = cur->children->children;
! 5273: continue;
! 5274: }
! 5275: break;
! 5276: case XML_TEXT_NODE:
! 5277: if (xmlIsBlankNode(cur))
! 5278: break;
! 5279: ret = 0;
! 5280: goto fail;
! 5281: case XML_CDATA_SECTION_NODE:
! 5282: /* TODO */
! 5283: ret = 0;
! 5284: goto fail;
! 5285: case XML_ELEMENT_NODE:
! 5286: if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
! 5287: xmlChar fn[50];
! 5288: xmlChar *fullname;
! 5289:
! 5290: fullname = xmlBuildQName(cur->name,
! 5291: cur->ns->prefix, fn, 50);
! 5292: if (fullname == NULL) {
! 5293: ret = -1;
! 5294: goto fail;
! 5295: }
! 5296: ret = xmlRegExecPushString(exec, fullname, NULL);
! 5297: if ((fullname != fn) && (fullname != cur->name))
! 5298: xmlFree(fullname);
! 5299: } else {
! 5300: ret = xmlRegExecPushString(exec, cur->name, NULL);
! 5301: }
! 5302: break;
! 5303: default:
! 5304: break;
! 5305: }
! 5306: /*
! 5307: * Switch to next element
! 5308: */
! 5309: cur = cur->next;
! 5310: while (cur == NULL) {
! 5311: cur = nodeVPop(ctxt);
! 5312: if (cur == NULL)
! 5313: break;
! 5314: cur = cur->next;
! 5315: }
! 5316: }
! 5317: ret = xmlRegExecPushString(exec, NULL, NULL);
! 5318: fail:
! 5319: xmlRegFreeExecCtxt(exec);
! 5320: }
! 5321: }
! 5322: #else /* LIBXML_REGEXP_ENABLED */
! 5323: /*
! 5324: * Allocate the stack
! 5325: */
! 5326: ctxt->vstateMax = 8;
! 5327: ctxt->vstateTab = (xmlValidState *) xmlMalloc(
! 5328: ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
! 5329: if (ctxt->vstateTab == NULL) {
! 5330: xmlVErrMemory(ctxt, "malloc failed");
! 5331: return(-1);
! 5332: }
! 5333: /*
! 5334: * The first entry in the stack is reserved to the current state
! 5335: */
! 5336: ctxt->nodeMax = 0;
! 5337: ctxt->nodeNr = 0;
! 5338: ctxt->nodeTab = NULL;
! 5339: ctxt->vstate = &ctxt->vstateTab[0];
! 5340: ctxt->vstateNr = 1;
! 5341: CONT = cont;
! 5342: NODE = child;
! 5343: DEPTH = 0;
! 5344: OCCURS = 0;
! 5345: STATE = 0;
! 5346: ret = xmlValidateElementType(ctxt);
! 5347: if ((ret == -3) && (warn)) {
! 5348: xmlErrValidWarning(ctxt, child, XML_DTD_CONTENT_NOT_DETERMINIST,
! 5349: "Content model for Element %s is ambiguous\n",
! 5350: name, NULL, NULL);
! 5351: } else if (ret == -2) {
! 5352: /*
! 5353: * An entities reference appeared at this level.
! 5354: * Buid a minimal representation of this node content
! 5355: * sufficient to run the validation process on it
! 5356: */
! 5357: DEBUG_VALID_MSG("Found an entity reference, linearizing");
! 5358: cur = child;
! 5359: while (cur != NULL) {
! 5360: switch (cur->type) {
! 5361: case XML_ENTITY_REF_NODE:
! 5362: /*
! 5363: * Push the current node to be able to roll back
! 5364: * and process within the entity
! 5365: */
! 5366: if ((cur->children != NULL) &&
! 5367: (cur->children->children != NULL)) {
! 5368: nodeVPush(ctxt, cur);
! 5369: cur = cur->children->children;
! 5370: continue;
! 5371: }
! 5372: break;
! 5373: case XML_TEXT_NODE:
! 5374: if (xmlIsBlankNode(cur))
! 5375: break;
! 5376: /* no break on purpose */
! 5377: case XML_CDATA_SECTION_NODE:
! 5378: /* no break on purpose */
! 5379: case XML_ELEMENT_NODE:
! 5380: /*
! 5381: * Allocate a new node and minimally fills in
! 5382: * what's required
! 5383: */
! 5384: tmp = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
! 5385: if (tmp == NULL) {
! 5386: xmlVErrMemory(ctxt, "malloc failed");
! 5387: xmlFreeNodeList(repl);
! 5388: ret = -1;
! 5389: goto done;
! 5390: }
! 5391: tmp->type = cur->type;
! 5392: tmp->name = cur->name;
! 5393: tmp->ns = cur->ns;
! 5394: tmp->next = NULL;
! 5395: tmp->content = NULL;
! 5396: if (repl == NULL)
! 5397: repl = last = tmp;
! 5398: else {
! 5399: last->next = tmp;
! 5400: last = tmp;
! 5401: }
! 5402: if (cur->type == XML_CDATA_SECTION_NODE) {
! 5403: /*
! 5404: * E59 spaces in CDATA does not match the
! 5405: * nonterminal S
! 5406: */
! 5407: tmp->content = xmlStrdup(BAD_CAST "CDATA");
! 5408: }
! 5409: break;
! 5410: default:
! 5411: break;
! 5412: }
! 5413: /*
! 5414: * Switch to next element
! 5415: */
! 5416: cur = cur->next;
! 5417: while (cur == NULL) {
! 5418: cur = nodeVPop(ctxt);
! 5419: if (cur == NULL)
! 5420: break;
! 5421: cur = cur->next;
! 5422: }
! 5423: }
! 5424:
! 5425: /*
! 5426: * Relaunch the validation
! 5427: */
! 5428: ctxt->vstate = &ctxt->vstateTab[0];
! 5429: ctxt->vstateNr = 1;
! 5430: CONT = cont;
! 5431: NODE = repl;
! 5432: DEPTH = 0;
! 5433: OCCURS = 0;
! 5434: STATE = 0;
! 5435: ret = xmlValidateElementType(ctxt);
! 5436: }
! 5437: #endif /* LIBXML_REGEXP_ENABLED */
! 5438: if ((warn) && ((ret != 1) && (ret != -3))) {
! 5439: if (ctxt != NULL) {
! 5440: char expr[5000];
! 5441: char list[5000];
! 5442:
! 5443: expr[0] = 0;
! 5444: xmlSnprintfElementContent(&expr[0], 5000, cont, 1);
! 5445: list[0] = 0;
! 5446: #ifndef LIBXML_REGEXP_ENABLED
! 5447: if (repl != NULL)
! 5448: xmlSnprintfElements(&list[0], 5000, repl, 1);
! 5449: else
! 5450: #endif /* LIBXML_REGEXP_ENABLED */
! 5451: xmlSnprintfElements(&list[0], 5000, child, 1);
! 5452:
! 5453: if (name != NULL) {
! 5454: xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
! 5455: "Element %s content does not follow the DTD, expecting %s, got %s\n",
! 5456: name, BAD_CAST expr, BAD_CAST list);
! 5457: } else {
! 5458: xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
! 5459: "Element content does not follow the DTD, expecting %s, got %s\n",
! 5460: BAD_CAST expr, BAD_CAST list, NULL);
! 5461: }
! 5462: } else {
! 5463: if (name != NULL) {
! 5464: xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
! 5465: "Element %s content does not follow the DTD\n",
! 5466: name, NULL, NULL);
! 5467: } else {
! 5468: xmlErrValidNode(ctxt, parent, XML_DTD_CONTENT_MODEL,
! 5469: "Element content does not follow the DTD\n",
! 5470: NULL, NULL, NULL);
! 5471: }
! 5472: }
! 5473: ret = 0;
! 5474: }
! 5475: if (ret == -3)
! 5476: ret = 1;
! 5477:
! 5478: #ifndef LIBXML_REGEXP_ENABLED
! 5479: done:
! 5480: /*
! 5481: * Deallocate the copy if done, and free up the validation stack
! 5482: */
! 5483: while (repl != NULL) {
! 5484: tmp = repl->next;
! 5485: xmlFree(repl);
! 5486: repl = tmp;
! 5487: }
! 5488: ctxt->vstateMax = 0;
! 5489: if (ctxt->vstateTab != NULL) {
! 5490: xmlFree(ctxt->vstateTab);
! 5491: ctxt->vstateTab = NULL;
! 5492: }
! 5493: #endif
! 5494: ctxt->nodeMax = 0;
! 5495: ctxt->nodeNr = 0;
! 5496: if (ctxt->nodeTab != NULL) {
! 5497: xmlFree(ctxt->nodeTab);
! 5498: ctxt->nodeTab = NULL;
! 5499: }
! 5500: return(ret);
! 5501:
! 5502: }
! 5503:
! 5504: /**
! 5505: * xmlValidateCdataElement:
! 5506: * @ctxt: the validation context
! 5507: * @doc: a document instance
! 5508: * @elem: an element instance
! 5509: *
! 5510: * Check that an element follows #CDATA
! 5511: *
! 5512: * returns 1 if valid or 0 otherwise
! 5513: */
! 5514: static int
! 5515: xmlValidateOneCdataElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
! 5516: xmlNodePtr elem) {
! 5517: int ret = 1;
! 5518: xmlNodePtr cur, child;
! 5519:
! 5520: if ((ctxt == NULL) || (doc == NULL) || (elem == NULL))
! 5521: return(0);
! 5522:
! 5523: child = elem->children;
! 5524:
! 5525: cur = child;
! 5526: while (cur != NULL) {
! 5527: switch (cur->type) {
! 5528: case XML_ENTITY_REF_NODE:
! 5529: /*
! 5530: * Push the current node to be able to roll back
! 5531: * and process within the entity
! 5532: */
! 5533: if ((cur->children != NULL) &&
! 5534: (cur->children->children != NULL)) {
! 5535: nodeVPush(ctxt, cur);
! 5536: cur = cur->children->children;
! 5537: continue;
! 5538: }
! 5539: break;
! 5540: case XML_COMMENT_NODE:
! 5541: case XML_PI_NODE:
! 5542: case XML_TEXT_NODE:
! 5543: case XML_CDATA_SECTION_NODE:
! 5544: break;
! 5545: default:
! 5546: ret = 0;
! 5547: goto done;
! 5548: }
! 5549: /*
! 5550: * Switch to next element
! 5551: */
! 5552: cur = cur->next;
! 5553: while (cur == NULL) {
! 5554: cur = nodeVPop(ctxt);
! 5555: if (cur == NULL)
! 5556: break;
! 5557: cur = cur->next;
! 5558: }
! 5559: }
! 5560: done:
! 5561: ctxt->nodeMax = 0;
! 5562: ctxt->nodeNr = 0;
! 5563: if (ctxt->nodeTab != NULL) {
! 5564: xmlFree(ctxt->nodeTab);
! 5565: ctxt->nodeTab = NULL;
! 5566: }
! 5567: return(ret);
! 5568: }
! 5569:
! 5570: /**
! 5571: * xmlValidateCheckMixed:
! 5572: * @ctxt: the validation context
! 5573: * @cont: the mixed content model
! 5574: * @qname: the qualified name as appearing in the serialization
! 5575: *
! 5576: * Check if the given node is part of the content model.
! 5577: *
! 5578: * Returns 1 if yes, 0 if no, -1 in case of error
! 5579: */
! 5580: static int
! 5581: xmlValidateCheckMixed(xmlValidCtxtPtr ctxt,
! 5582: xmlElementContentPtr cont, const xmlChar *qname) {
! 5583: const xmlChar *name;
! 5584: int plen;
! 5585: name = xmlSplitQName3(qname, &plen);
! 5586:
! 5587: if (name == NULL) {
! 5588: while (cont != NULL) {
! 5589: if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
! 5590: if ((cont->prefix == NULL) && (xmlStrEqual(cont->name, qname)))
! 5591: return(1);
! 5592: } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
! 5593: (cont->c1 != NULL) &&
! 5594: (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
! 5595: if ((cont->c1->prefix == NULL) &&
! 5596: (xmlStrEqual(cont->c1->name, qname)))
! 5597: return(1);
! 5598: } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
! 5599: (cont->c1 == NULL) ||
! 5600: (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
! 5601: xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT,
! 5602: "Internal: MIXED struct corrupted\n",
! 5603: NULL);
! 5604: break;
! 5605: }
! 5606: cont = cont->c2;
! 5607: }
! 5608: } else {
! 5609: while (cont != NULL) {
! 5610: if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
! 5611: if ((cont->prefix != NULL) &&
! 5612: (xmlStrncmp(cont->prefix, qname, plen) == 0) &&
! 5613: (xmlStrEqual(cont->name, name)))
! 5614: return(1);
! 5615: } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
! 5616: (cont->c1 != NULL) &&
! 5617: (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
! 5618: if ((cont->c1->prefix != NULL) &&
! 5619: (xmlStrncmp(cont->c1->prefix, qname, plen) == 0) &&
! 5620: (xmlStrEqual(cont->c1->name, name)))
! 5621: return(1);
! 5622: } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
! 5623: (cont->c1 == NULL) ||
! 5624: (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
! 5625: xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT,
! 5626: "Internal: MIXED struct corrupted\n",
! 5627: NULL);
! 5628: break;
! 5629: }
! 5630: cont = cont->c2;
! 5631: }
! 5632: }
! 5633: return(0);
! 5634: }
! 5635:
! 5636: /**
! 5637: * xmlValidGetElemDecl:
! 5638: * @ctxt: the validation context
! 5639: * @doc: a document instance
! 5640: * @elem: an element instance
! 5641: * @extsubset: pointer, (out) indicate if the declaration was found
! 5642: * in the external subset.
! 5643: *
! 5644: * Finds a declaration associated to an element in the document.
! 5645: *
! 5646: * returns the pointer to the declaration or NULL if not found.
! 5647: */
! 5648: static xmlElementPtr
! 5649: xmlValidGetElemDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
! 5650: xmlNodePtr elem, int *extsubset) {
! 5651: xmlElementPtr elemDecl = NULL;
! 5652: const xmlChar *prefix = NULL;
! 5653:
! 5654: if ((ctxt == NULL) || (doc == NULL) ||
! 5655: (elem == NULL) || (elem->name == NULL))
! 5656: return(NULL);
! 5657: if (extsubset != NULL)
! 5658: *extsubset = 0;
! 5659:
! 5660: /*
! 5661: * Fetch the declaration for the qualified name
! 5662: */
! 5663: if ((elem->ns != NULL) && (elem->ns->prefix != NULL))
! 5664: prefix = elem->ns->prefix;
! 5665:
! 5666: if (prefix != NULL) {
! 5667: elemDecl = xmlGetDtdQElementDesc(doc->intSubset,
! 5668: elem->name, prefix);
! 5669: if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
! 5670: elemDecl = xmlGetDtdQElementDesc(doc->extSubset,
! 5671: elem->name, prefix);
! 5672: if ((elemDecl != NULL) && (extsubset != NULL))
! 5673: *extsubset = 1;
! 5674: }
! 5675: }
! 5676:
! 5677: /*
! 5678: * Fetch the declaration for the non qualified name
! 5679: * This is "non-strict" validation should be done on the
! 5680: * full QName but in that case being flexible makes sense.
! 5681: */
! 5682: if (elemDecl == NULL) {
! 5683: elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
! 5684: if ((elemDecl == NULL) && (doc->extSubset != NULL)) {
! 5685: elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
! 5686: if ((elemDecl != NULL) && (extsubset != NULL))
! 5687: *extsubset = 1;
! 5688: }
! 5689: }
! 5690: if (elemDecl == NULL) {
! 5691: xmlErrValidNode(ctxt, elem,
! 5692: XML_DTD_UNKNOWN_ELEM,
! 5693: "No declaration for element %s\n",
! 5694: elem->name, NULL, NULL);
! 5695: }
! 5696: return(elemDecl);
! 5697: }
! 5698:
! 5699: #ifdef LIBXML_REGEXP_ENABLED
! 5700: /**
! 5701: * xmlValidatePushElement:
! 5702: * @ctxt: the validation context
! 5703: * @doc: a document instance
! 5704: * @elem: an element instance
! 5705: * @qname: the qualified name as appearing in the serialization
! 5706: *
! 5707: * Push a new element start on the validation stack.
! 5708: *
! 5709: * returns 1 if no validation problem was found or 0 otherwise
! 5710: */
! 5711: int
! 5712: xmlValidatePushElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
! 5713: xmlNodePtr elem, const xmlChar *qname) {
! 5714: int ret = 1;
! 5715: xmlElementPtr eDecl;
! 5716: int extsubset = 0;
! 5717:
! 5718: if (ctxt == NULL)
! 5719: return(0);
! 5720: /* printf("PushElem %s\n", qname); */
! 5721: if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
! 5722: xmlValidStatePtr state = ctxt->vstate;
! 5723: xmlElementPtr elemDecl;
! 5724:
! 5725: /*
! 5726: * Check the new element agaisnt the content model of the new elem.
! 5727: */
! 5728: if (state->elemDecl != NULL) {
! 5729: elemDecl = state->elemDecl;
! 5730:
! 5731: switch(elemDecl->etype) {
! 5732: case XML_ELEMENT_TYPE_UNDEFINED:
! 5733: ret = 0;
! 5734: break;
! 5735: case XML_ELEMENT_TYPE_EMPTY:
! 5736: xmlErrValidNode(ctxt, state->node,
! 5737: XML_DTD_NOT_EMPTY,
! 5738: "Element %s was declared EMPTY this one has content\n",
! 5739: state->node->name, NULL, NULL);
! 5740: ret = 0;
! 5741: break;
! 5742: case XML_ELEMENT_TYPE_ANY:
! 5743: /* I don't think anything is required then */
! 5744: break;
! 5745: case XML_ELEMENT_TYPE_MIXED:
! 5746: /* simple case of declared as #PCDATA */
! 5747: if ((elemDecl->content != NULL) &&
! 5748: (elemDecl->content->type ==
! 5749: XML_ELEMENT_CONTENT_PCDATA)) {
! 5750: xmlErrValidNode(ctxt, state->node,
! 5751: XML_DTD_NOT_PCDATA,
! 5752: "Element %s was declared #PCDATA but contains non text nodes\n",
! 5753: state->node->name, NULL, NULL);
! 5754: ret = 0;
! 5755: } else {
! 5756: ret = xmlValidateCheckMixed(ctxt, elemDecl->content,
! 5757: qname);
! 5758: if (ret != 1) {
! 5759: xmlErrValidNode(ctxt, state->node,
! 5760: XML_DTD_INVALID_CHILD,
! 5761: "Element %s is not declared in %s list of possible children\n",
! 5762: qname, state->node->name, NULL);
! 5763: }
! 5764: }
! 5765: break;
! 5766: case XML_ELEMENT_TYPE_ELEMENT:
! 5767: /*
! 5768: * TODO:
! 5769: * VC: Standalone Document Declaration
! 5770: * - element types with element content, if white space
! 5771: * occurs directly within any instance of those types.
! 5772: */
! 5773: if (state->exec != NULL) {
! 5774: ret = xmlRegExecPushString(state->exec, qname, NULL);
! 5775: if (ret < 0) {
! 5776: xmlErrValidNode(ctxt, state->node,
! 5777: XML_DTD_CONTENT_MODEL,
! 5778: "Element %s content does not follow the DTD, Misplaced %s\n",
! 5779: state->node->name, qname, NULL);
! 5780: ret = 0;
! 5781: } else {
! 5782: ret = 1;
! 5783: }
! 5784: }
! 5785: break;
! 5786: }
! 5787: }
! 5788: }
! 5789: eDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
! 5790: vstateVPush(ctxt, eDecl, elem);
! 5791: return(ret);
! 5792: }
! 5793:
! 5794: /**
! 5795: * xmlValidatePushCData:
! 5796: * @ctxt: the validation context
! 5797: * @data: some character data read
! 5798: * @len: the lenght of the data
! 5799: *
! 5800: * check the CData parsed for validation in the current stack
! 5801: *
! 5802: * returns 1 if no validation problem was found or 0 otherwise
! 5803: */
! 5804: int
! 5805: xmlValidatePushCData(xmlValidCtxtPtr ctxt, const xmlChar *data, int len) {
! 5806: int ret = 1;
! 5807:
! 5808: /* printf("CDATA %s %d\n", data, len); */
! 5809: if (ctxt == NULL)
! 5810: return(0);
! 5811: if (len <= 0)
! 5812: return(ret);
! 5813: if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
! 5814: xmlValidStatePtr state = ctxt->vstate;
! 5815: xmlElementPtr elemDecl;
! 5816:
! 5817: /*
! 5818: * Check the new element agaisnt the content model of the new elem.
! 5819: */
! 5820: if (state->elemDecl != NULL) {
! 5821: elemDecl = state->elemDecl;
! 5822:
! 5823: switch(elemDecl->etype) {
! 5824: case XML_ELEMENT_TYPE_UNDEFINED:
! 5825: ret = 0;
! 5826: break;
! 5827: case XML_ELEMENT_TYPE_EMPTY:
! 5828: xmlErrValidNode(ctxt, state->node,
! 5829: XML_DTD_NOT_EMPTY,
! 5830: "Element %s was declared EMPTY this one has content\n",
! 5831: state->node->name, NULL, NULL);
! 5832: ret = 0;
! 5833: break;
! 5834: case XML_ELEMENT_TYPE_ANY:
! 5835: break;
! 5836: case XML_ELEMENT_TYPE_MIXED:
! 5837: break;
! 5838: case XML_ELEMENT_TYPE_ELEMENT:
! 5839: if (len > 0) {
! 5840: int i;
! 5841:
! 5842: for (i = 0;i < len;i++) {
! 5843: if (!IS_BLANK_CH(data[i])) {
! 5844: xmlErrValidNode(ctxt, state->node,
! 5845: XML_DTD_CONTENT_MODEL,
! 5846: "Element %s content does not follow the DTD, Text not allowed\n",
! 5847: state->node->name, NULL, NULL);
! 5848: ret = 0;
! 5849: goto done;
! 5850: }
! 5851: }
! 5852: /*
! 5853: * TODO:
! 5854: * VC: Standalone Document Declaration
! 5855: * element types with element content, if white space
! 5856: * occurs directly within any instance of those types.
! 5857: */
! 5858: }
! 5859: break;
! 5860: }
! 5861: }
! 5862: }
! 5863: done:
! 5864: return(ret);
! 5865: }
! 5866:
! 5867: /**
! 5868: * xmlValidatePopElement:
! 5869: * @ctxt: the validation context
! 5870: * @doc: a document instance
! 5871: * @elem: an element instance
! 5872: * @qname: the qualified name as appearing in the serialization
! 5873: *
! 5874: * Pop the element end from the validation stack.
! 5875: *
! 5876: * returns 1 if no validation problem was found or 0 otherwise
! 5877: */
! 5878: int
! 5879: xmlValidatePopElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc ATTRIBUTE_UNUSED,
! 5880: xmlNodePtr elem ATTRIBUTE_UNUSED,
! 5881: const xmlChar *qname ATTRIBUTE_UNUSED) {
! 5882: int ret = 1;
! 5883:
! 5884: if (ctxt == NULL)
! 5885: return(0);
! 5886: /* printf("PopElem %s\n", qname); */
! 5887: if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) {
! 5888: xmlValidStatePtr state = ctxt->vstate;
! 5889: xmlElementPtr elemDecl;
! 5890:
! 5891: /*
! 5892: * Check the new element agaisnt the content model of the new elem.
! 5893: */
! 5894: if (state->elemDecl != NULL) {
! 5895: elemDecl = state->elemDecl;
! 5896:
! 5897: if (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT) {
! 5898: if (state->exec != NULL) {
! 5899: ret = xmlRegExecPushString(state->exec, NULL, NULL);
! 5900: if (ret == 0) {
! 5901: xmlErrValidNode(ctxt, state->node,
! 5902: XML_DTD_CONTENT_MODEL,
! 5903: "Element %s content does not follow the DTD, Expecting more child\n",
! 5904: state->node->name, NULL,NULL);
! 5905: } else {
! 5906: /*
! 5907: * previous validation errors should not generate
! 5908: * a new one here
! 5909: */
! 5910: ret = 1;
! 5911: }
! 5912: }
! 5913: }
! 5914: }
! 5915: vstateVPop(ctxt);
! 5916: }
! 5917: return(ret);
! 5918: }
! 5919: #endif /* LIBXML_REGEXP_ENABLED */
! 5920:
! 5921: /**
! 5922: * xmlValidateOneElement:
! 5923: * @ctxt: the validation context
! 5924: * @doc: a document instance
! 5925: * @elem: an element instance
! 5926: *
! 5927: * Try to validate a single element and it's attributes,
! 5928: * basically it does the following checks as described by the
! 5929: * XML-1.0 recommendation:
! 5930: * - [ VC: Element Valid ]
! 5931: * - [ VC: Required Attribute ]
! 5932: * Then call xmlValidateOneAttribute() for each attribute present.
! 5933: *
! 5934: * The ID/IDREF checkings are done separately
! 5935: *
! 5936: * returns 1 if valid or 0 otherwise
! 5937: */
! 5938:
! 5939: int
! 5940: xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
! 5941: xmlNodePtr elem) {
! 5942: xmlElementPtr elemDecl = NULL;
! 5943: xmlElementContentPtr cont;
! 5944: xmlAttributePtr attr;
! 5945: xmlNodePtr child;
! 5946: int ret = 1, tmp;
! 5947: const xmlChar *name;
! 5948: int extsubset = 0;
! 5949:
! 5950: CHECK_DTD;
! 5951:
! 5952: if (elem == NULL) return(0);
! 5953: switch (elem->type) {
! 5954: case XML_ATTRIBUTE_NODE:
! 5955: xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
! 5956: "Attribute element not expected\n", NULL, NULL ,NULL);
! 5957: return(0);
! 5958: case XML_TEXT_NODE:
! 5959: if (elem->children != NULL) {
! 5960: xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
! 5961: "Text element has children !\n",
! 5962: NULL,NULL,NULL);
! 5963: return(0);
! 5964: }
! 5965: if (elem->ns != NULL) {
! 5966: xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
! 5967: "Text element has namespace !\n",
! 5968: NULL,NULL,NULL);
! 5969: return(0);
! 5970: }
! 5971: if (elem->content == NULL) {
! 5972: xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
! 5973: "Text element has no content !\n",
! 5974: NULL,NULL,NULL);
! 5975: return(0);
! 5976: }
! 5977: return(1);
! 5978: case XML_XINCLUDE_START:
! 5979: case XML_XINCLUDE_END:
! 5980: return(1);
! 5981: case XML_CDATA_SECTION_NODE:
! 5982: case XML_ENTITY_REF_NODE:
! 5983: case XML_PI_NODE:
! 5984: case XML_COMMENT_NODE:
! 5985: return(1);
! 5986: case XML_ENTITY_NODE:
! 5987: xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
! 5988: "Entity element not expected\n", NULL, NULL ,NULL);
! 5989: return(0);
! 5990: case XML_NOTATION_NODE:
! 5991: xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
! 5992: "Notation element not expected\n", NULL, NULL ,NULL);
! 5993: return(0);
! 5994: case XML_DOCUMENT_NODE:
! 5995: case XML_DOCUMENT_TYPE_NODE:
! 5996: case XML_DOCUMENT_FRAG_NODE:
! 5997: xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
! 5998: "Document element not expected\n", NULL, NULL ,NULL);
! 5999: return(0);
! 6000: case XML_HTML_DOCUMENT_NODE:
! 6001: xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
! 6002: "HTML Document not expected\n", NULL, NULL ,NULL);
! 6003: return(0);
! 6004: case XML_ELEMENT_NODE:
! 6005: break;
! 6006: default:
! 6007: xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR,
! 6008: "unknown element type\n", NULL, NULL ,NULL);
! 6009: return(0);
! 6010: }
! 6011:
! 6012: /*
! 6013: * Fetch the declaration
! 6014: */
! 6015: elemDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset);
! 6016: if (elemDecl == NULL)
! 6017: return(0);
! 6018:
! 6019: /*
! 6020: * If vstateNr is not zero that means continuous validation is
! 6021: * activated, do not try to check the content model at that level.
! 6022: */
! 6023: if (ctxt->vstateNr == 0) {
! 6024: /* Check that the element content matches the definition */
! 6025: switch (elemDecl->etype) {
! 6026: case XML_ELEMENT_TYPE_UNDEFINED:
! 6027: xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ELEM,
! 6028: "No declaration for element %s\n",
! 6029: elem->name, NULL, NULL);
! 6030: return(0);
! 6031: case XML_ELEMENT_TYPE_EMPTY:
! 6032: if (elem->children != NULL) {
! 6033: xmlErrValidNode(ctxt, elem, XML_DTD_NOT_EMPTY,
! 6034: "Element %s was declared EMPTY this one has content\n",
! 6035: elem->name, NULL, NULL);
! 6036: ret = 0;
! 6037: }
! 6038: break;
! 6039: case XML_ELEMENT_TYPE_ANY:
! 6040: /* I don't think anything is required then */
! 6041: break;
! 6042: case XML_ELEMENT_TYPE_MIXED:
! 6043:
! 6044: /* simple case of declared as #PCDATA */
! 6045: if ((elemDecl->content != NULL) &&
! 6046: (elemDecl->content->type == XML_ELEMENT_CONTENT_PCDATA)) {
! 6047: ret = xmlValidateOneCdataElement(ctxt, doc, elem);
! 6048: if (!ret) {
! 6049: xmlErrValidNode(ctxt, elem, XML_DTD_NOT_PCDATA,
! 6050: "Element %s was declared #PCDATA but contains non text nodes\n",
! 6051: elem->name, NULL, NULL);
! 6052: }
! 6053: break;
! 6054: }
! 6055: child = elem->children;
! 6056: /* Hum, this start to get messy */
! 6057: while (child != NULL) {
! 6058: if (child->type == XML_ELEMENT_NODE) {
! 6059: name = child->name;
! 6060: if ((child->ns != NULL) && (child->ns->prefix != NULL)) {
! 6061: xmlChar fn[50];
! 6062: xmlChar *fullname;
! 6063:
! 6064: fullname = xmlBuildQName(child->name, child->ns->prefix,
! 6065: fn, 50);
! 6066: if (fullname == NULL)
! 6067: return(0);
! 6068: cont = elemDecl->content;
! 6069: while (cont != NULL) {
! 6070: if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
! 6071: if (xmlStrEqual(cont->name, fullname))
! 6072: break;
! 6073: } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
! 6074: (cont->c1 != NULL) &&
! 6075: (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
! 6076: if (xmlStrEqual(cont->c1->name, fullname))
! 6077: break;
! 6078: } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
! 6079: (cont->c1 == NULL) ||
! 6080: (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
! 6081: xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT,
! 6082: "Internal: MIXED struct corrupted\n",
! 6083: NULL);
! 6084: break;
! 6085: }
! 6086: cont = cont->c2;
! 6087: }
! 6088: if ((fullname != fn) && (fullname != child->name))
! 6089: xmlFree(fullname);
! 6090: if (cont != NULL)
! 6091: goto child_ok;
! 6092: }
! 6093: cont = elemDecl->content;
! 6094: while (cont != NULL) {
! 6095: if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
! 6096: if (xmlStrEqual(cont->name, name)) break;
! 6097: } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
! 6098: (cont->c1 != NULL) &&
! 6099: (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
! 6100: if (xmlStrEqual(cont->c1->name, name)) break;
! 6101: } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
! 6102: (cont->c1 == NULL) ||
! 6103: (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
! 6104: xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT,
! 6105: "Internal: MIXED struct corrupted\n",
! 6106: NULL);
! 6107: break;
! 6108: }
! 6109: cont = cont->c2;
! 6110: }
! 6111: if (cont == NULL) {
! 6112: xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_CHILD,
! 6113: "Element %s is not declared in %s list of possible children\n",
! 6114: name, elem->name, NULL);
! 6115: ret = 0;
! 6116: }
! 6117: }
! 6118: child_ok:
! 6119: child = child->next;
! 6120: }
! 6121: break;
! 6122: case XML_ELEMENT_TYPE_ELEMENT:
! 6123: if ((doc->standalone == 1) && (extsubset == 1)) {
! 6124: /*
! 6125: * VC: Standalone Document Declaration
! 6126: * - element types with element content, if white space
! 6127: * occurs directly within any instance of those types.
! 6128: */
! 6129: child = elem->children;
! 6130: while (child != NULL) {
! 6131: if (child->type == XML_TEXT_NODE) {
! 6132: const xmlChar *content = child->content;
! 6133:
! 6134: while (IS_BLANK_CH(*content))
! 6135: content++;
! 6136: if (*content == 0) {
! 6137: xmlErrValidNode(ctxt, elem,
! 6138: XML_DTD_STANDALONE_WHITE_SPACE,
! 6139: "standalone: %s declared in the external subset contains white spaces nodes\n",
! 6140: elem->name, NULL, NULL);
! 6141: ret = 0;
! 6142: break;
! 6143: }
! 6144: }
! 6145: child =child->next;
! 6146: }
! 6147: }
! 6148: child = elem->children;
! 6149: cont = elemDecl->content;
! 6150: tmp = xmlValidateElementContent(ctxt, child, elemDecl, 1, elem);
! 6151: if (tmp <= 0)
! 6152: ret = tmp;
! 6153: break;
! 6154: }
! 6155: } /* not continuous */
! 6156:
! 6157: /* [ VC: Required Attribute ] */
! 6158: attr = elemDecl->attributes;
! 6159: while (attr != NULL) {
! 6160: if (attr->def == XML_ATTRIBUTE_REQUIRED) {
! 6161: int qualified = -1;
! 6162:
! 6163: if ((attr->prefix == NULL) &&
! 6164: (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
! 6165: xmlNsPtr ns;
! 6166:
! 6167: ns = elem->nsDef;
! 6168: while (ns != NULL) {
! 6169: if (ns->prefix == NULL)
! 6170: goto found;
! 6171: ns = ns->next;
! 6172: }
! 6173: } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
! 6174: xmlNsPtr ns;
! 6175:
! 6176: ns = elem->nsDef;
! 6177: while (ns != NULL) {
! 6178: if (xmlStrEqual(attr->name, ns->prefix))
! 6179: goto found;
! 6180: ns = ns->next;
! 6181: }
! 6182: } else {
! 6183: xmlAttrPtr attrib;
! 6184:
! 6185: attrib = elem->properties;
! 6186: while (attrib != NULL) {
! 6187: if (xmlStrEqual(attrib->name, attr->name)) {
! 6188: if (attr->prefix != NULL) {
! 6189: xmlNsPtr nameSpace = attrib->ns;
! 6190:
! 6191: if (nameSpace == NULL)
! 6192: nameSpace = elem->ns;
! 6193: /*
! 6194: * qualified names handling is problematic, having a
! 6195: * different prefix should be possible but DTDs don't
! 6196: * allow to define the URI instead of the prefix :-(
! 6197: */
! 6198: if (nameSpace == NULL) {
! 6199: if (qualified < 0)
! 6200: qualified = 0;
! 6201: } else if (!xmlStrEqual(nameSpace->prefix,
! 6202: attr->prefix)) {
! 6203: if (qualified < 1)
! 6204: qualified = 1;
! 6205: } else
! 6206: goto found;
! 6207: } else {
! 6208: /*
! 6209: * We should allow applications to define namespaces
! 6210: * for their application even if the DTD doesn't
! 6211: * carry one, otherwise, basically we would always
! 6212: * break.
! 6213: */
! 6214: goto found;
! 6215: }
! 6216: }
! 6217: attrib = attrib->next;
! 6218: }
! 6219: }
! 6220: if (qualified == -1) {
! 6221: if (attr->prefix == NULL) {
! 6222: xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
! 6223: "Element %s does not carry attribute %s\n",
! 6224: elem->name, attr->name, NULL);
! 6225: ret = 0;
! 6226: } else {
! 6227: xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE,
! 6228: "Element %s does not carry attribute %s:%s\n",
! 6229: elem->name, attr->prefix,attr->name);
! 6230: ret = 0;
! 6231: }
! 6232: } else if (qualified == 0) {
! 6233: xmlErrValidWarning(ctxt, elem, XML_DTD_NO_PREFIX,
! 6234: "Element %s required attribute %s:%s has no prefix\n",
! 6235: elem->name, attr->prefix, attr->name);
! 6236: } else if (qualified == 1) {
! 6237: xmlErrValidWarning(ctxt, elem, XML_DTD_DIFFERENT_PREFIX,
! 6238: "Element %s required attribute %s:%s has different prefix\n",
! 6239: elem->name, attr->prefix, attr->name);
! 6240: }
! 6241: } else if (attr->def == XML_ATTRIBUTE_FIXED) {
! 6242: /*
! 6243: * Special tests checking #FIXED namespace declarations
! 6244: * have the right value since this is not done as an
! 6245: * attribute checking
! 6246: */
! 6247: if ((attr->prefix == NULL) &&
! 6248: (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) {
! 6249: xmlNsPtr ns;
! 6250:
! 6251: ns = elem->nsDef;
! 6252: while (ns != NULL) {
! 6253: if (ns->prefix == NULL) {
! 6254: if (!xmlStrEqual(attr->defaultValue, ns->href)) {
! 6255: xmlErrValidNode(ctxt, elem,
! 6256: XML_DTD_ELEM_DEFAULT_NAMESPACE,
! 6257: "Element %s namespace name for default namespace does not match the DTD\n",
! 6258: elem->name, NULL, NULL);
! 6259: ret = 0;
! 6260: }
! 6261: goto found;
! 6262: }
! 6263: ns = ns->next;
! 6264: }
! 6265: } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) {
! 6266: xmlNsPtr ns;
! 6267:
! 6268: ns = elem->nsDef;
! 6269: while (ns != NULL) {
! 6270: if (xmlStrEqual(attr->name, ns->prefix)) {
! 6271: if (!xmlStrEqual(attr->defaultValue, ns->href)) {
! 6272: xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
! 6273: "Element %s namespace name for %s does not match the DTD\n",
! 6274: elem->name, ns->prefix, NULL);
! 6275: ret = 0;
! 6276: }
! 6277: goto found;
! 6278: }
! 6279: ns = ns->next;
! 6280: }
! 6281: }
! 6282: }
! 6283: found:
! 6284: attr = attr->nexth;
! 6285: }
! 6286: return(ret);
! 6287: }
! 6288:
! 6289: /**
! 6290: * xmlValidateRoot:
! 6291: * @ctxt: the validation context
! 6292: * @doc: a document instance
! 6293: *
! 6294: * Try to validate a the root element
! 6295: * basically it does the following check as described by the
! 6296: * XML-1.0 recommendation:
! 6297: * - [ VC: Root Element Type ]
! 6298: * it doesn't try to recurse or apply other check to the element
! 6299: *
! 6300: * returns 1 if valid or 0 otherwise
! 6301: */
! 6302:
! 6303: int
! 6304: xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
! 6305: xmlNodePtr root;
! 6306: int ret;
! 6307:
! 6308: if (doc == NULL) return(0);
! 6309:
! 6310: root = xmlDocGetRootElement(doc);
! 6311: if ((root == NULL) || (root->name == NULL)) {
! 6312: xmlErrValid(ctxt, XML_DTD_NO_ROOT,
! 6313: "no root element\n", NULL);
! 6314: return(0);
! 6315: }
! 6316:
! 6317: /*
! 6318: * When doing post validation against a separate DTD, those may
! 6319: * no internal subset has been generated
! 6320: */
! 6321: if ((doc->intSubset != NULL) &&
! 6322: (doc->intSubset->name != NULL)) {
! 6323: /*
! 6324: * Check first the document root against the NQName
! 6325: */
! 6326: if (!xmlStrEqual(doc->intSubset->name, root->name)) {
! 6327: if ((root->ns != NULL) && (root->ns->prefix != NULL)) {
! 6328: xmlChar fn[50];
! 6329: xmlChar *fullname;
! 6330:
! 6331: fullname = xmlBuildQName(root->name, root->ns->prefix, fn, 50);
! 6332: if (fullname == NULL) {
! 6333: xmlVErrMemory(ctxt, NULL);
! 6334: return(0);
! 6335: }
! 6336: ret = xmlStrEqual(doc->intSubset->name, fullname);
! 6337: if ((fullname != fn) && (fullname != root->name))
! 6338: xmlFree(fullname);
! 6339: if (ret == 1)
! 6340: goto name_ok;
! 6341: }
! 6342: if ((xmlStrEqual(doc->intSubset->name, BAD_CAST "HTML")) &&
! 6343: (xmlStrEqual(root->name, BAD_CAST "html")))
! 6344: goto name_ok;
! 6345: xmlErrValidNode(ctxt, root, XML_DTD_ROOT_NAME,
! 6346: "root and DTD name do not match '%s' and '%s'\n",
! 6347: root->name, doc->intSubset->name, NULL);
! 6348: return(0);
! 6349: }
! 6350: }
! 6351: name_ok:
! 6352: return(1);
! 6353: }
! 6354:
! 6355:
! 6356: /**
! 6357: * xmlValidateElement:
! 6358: * @ctxt: the validation context
! 6359: * @doc: a document instance
! 6360: * @elem: an element instance
! 6361: *
! 6362: * Try to validate the subtree under an element
! 6363: *
! 6364: * returns 1 if valid or 0 otherwise
! 6365: */
! 6366:
! 6367: int
! 6368: xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
! 6369: xmlNodePtr child;
! 6370: xmlAttrPtr attr;
! 6371: xmlNsPtr ns;
! 6372: const xmlChar *value;
! 6373: int ret = 1;
! 6374:
! 6375: if (elem == NULL) return(0);
! 6376:
! 6377: /*
! 6378: * XInclude elements were added after parsing in the infoset,
! 6379: * they don't really mean anything validation wise.
! 6380: */
! 6381: if ((elem->type == XML_XINCLUDE_START) ||
! 6382: (elem->type == XML_XINCLUDE_END))
! 6383: return(1);
! 6384:
! 6385: CHECK_DTD;
! 6386:
! 6387: /*
! 6388: * Entities references have to be handled separately
! 6389: */
! 6390: if (elem->type == XML_ENTITY_REF_NODE) {
! 6391: return(1);
! 6392: }
! 6393:
! 6394: ret &= xmlValidateOneElement(ctxt, doc, elem);
! 6395: if (elem->type == XML_ELEMENT_NODE) {
! 6396: attr = elem->properties;
! 6397: while (attr != NULL) {
! 6398: value = xmlNodeListGetString(doc, attr->children, 0);
! 6399: ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
! 6400: if (value != NULL)
! 6401: xmlFree((char *)value);
! 6402: attr= attr->next;
! 6403: }
! 6404: ns = elem->nsDef;
! 6405: while (ns != NULL) {
! 6406: if (elem->ns == NULL)
! 6407: ret &= xmlValidateOneNamespace(ctxt, doc, elem, NULL,
! 6408: ns, ns->href);
! 6409: else
! 6410: ret &= xmlValidateOneNamespace(ctxt, doc, elem,
! 6411: elem->ns->prefix, ns, ns->href);
! 6412: ns = ns->next;
! 6413: }
! 6414: }
! 6415: child = elem->children;
! 6416: while (child != NULL) {
! 6417: ret &= xmlValidateElement(ctxt, doc, child);
! 6418: child = child->next;
! 6419: }
! 6420:
! 6421: return(ret);
! 6422: }
! 6423:
! 6424: /**
! 6425: * xmlValidateRef:
! 6426: * @ref: A reference to be validated
! 6427: * @ctxt: Validation context
! 6428: * @name: Name of ID we are searching for
! 6429: *
! 6430: */
! 6431: static void
! 6432: xmlValidateRef(xmlRefPtr ref, xmlValidCtxtPtr ctxt,
! 6433: const xmlChar *name) {
! 6434: xmlAttrPtr id;
! 6435: xmlAttrPtr attr;
! 6436:
! 6437: if (ref == NULL)
! 6438: return;
! 6439: if ((ref->attr == NULL) && (ref->name == NULL))
! 6440: return;
! 6441: attr = ref->attr;
! 6442: if (attr == NULL) {
! 6443: xmlChar *dup, *str = NULL, *cur, save;
! 6444:
! 6445: dup = xmlStrdup(name);
! 6446: if (dup == NULL) {
! 6447: ctxt->valid = 0;
! 6448: return;
! 6449: }
! 6450: cur = dup;
! 6451: while (*cur != 0) {
! 6452: str = cur;
! 6453: while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
! 6454: save = *cur;
! 6455: *cur = 0;
! 6456: id = xmlGetID(ctxt->doc, str);
! 6457: if (id == NULL) {
! 6458: xmlErrValidNodeNr(ctxt, NULL, XML_DTD_UNKNOWN_ID,
! 6459: "attribute %s line %d references an unknown ID \"%s\"\n",
! 6460: ref->name, ref->lineno, str);
! 6461: ctxt->valid = 0;
! 6462: }
! 6463: if (save == 0)
! 6464: break;
! 6465: *cur = save;
! 6466: while (IS_BLANK_CH(*cur)) cur++;
! 6467: }
! 6468: xmlFree(dup);
! 6469: } else if (attr->atype == XML_ATTRIBUTE_IDREF) {
! 6470: id = xmlGetID(ctxt->doc, name);
! 6471: if (id == NULL) {
! 6472: xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
! 6473: "IDREF attribute %s references an unknown ID \"%s\"\n",
! 6474: attr->name, name, NULL);
! 6475: ctxt->valid = 0;
! 6476: }
! 6477: } else if (attr->atype == XML_ATTRIBUTE_IDREFS) {
! 6478: xmlChar *dup, *str = NULL, *cur, save;
! 6479:
! 6480: dup = xmlStrdup(name);
! 6481: if (dup == NULL) {
! 6482: xmlVErrMemory(ctxt, "IDREFS split");
! 6483: ctxt->valid = 0;
! 6484: return;
! 6485: }
! 6486: cur = dup;
! 6487: while (*cur != 0) {
! 6488: str = cur;
! 6489: while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
! 6490: save = *cur;
! 6491: *cur = 0;
! 6492: id = xmlGetID(ctxt->doc, str);
! 6493: if (id == NULL) {
! 6494: xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID,
! 6495: "IDREFS attribute %s references an unknown ID \"%s\"\n",
! 6496: attr->name, str, NULL);
! 6497: ctxt->valid = 0;
! 6498: }
! 6499: if (save == 0)
! 6500: break;
! 6501: *cur = save;
! 6502: while (IS_BLANK_CH(*cur)) cur++;
! 6503: }
! 6504: xmlFree(dup);
! 6505: }
! 6506: }
! 6507:
! 6508: /**
! 6509: * xmlWalkValidateList:
! 6510: * @data: Contents of current link
! 6511: * @user: Value supplied by the user
! 6512: *
! 6513: * Returns 0 to abort the walk or 1 to continue
! 6514: */
! 6515: static int
! 6516: xmlWalkValidateList(const void *data, const void *user)
! 6517: {
! 6518: xmlValidateMemoPtr memo = (xmlValidateMemoPtr)user;
! 6519: xmlValidateRef((xmlRefPtr)data, memo->ctxt, memo->name);
! 6520: return 1;
! 6521: }
! 6522:
! 6523: /**
! 6524: * xmlValidateCheckRefCallback:
! 6525: * @ref_list: List of references
! 6526: * @ctxt: Validation context
! 6527: * @name: Name of ID we are searching for
! 6528: *
! 6529: */
! 6530: static void
! 6531: xmlValidateCheckRefCallback(xmlListPtr ref_list, xmlValidCtxtPtr ctxt,
! 6532: const xmlChar *name) {
! 6533: xmlValidateMemo memo;
! 6534:
! 6535: if (ref_list == NULL)
! 6536: return;
! 6537: memo.ctxt = ctxt;
! 6538: memo.name = name;
! 6539:
! 6540: xmlListWalk(ref_list, xmlWalkValidateList, &memo);
! 6541:
! 6542: }
! 6543:
! 6544: /**
! 6545: * xmlValidateDocumentFinal:
! 6546: * @ctxt: the validation context
! 6547: * @doc: a document instance
! 6548: *
! 6549: * Does the final step for the document validation once all the
! 6550: * incremental validation steps have been completed
! 6551: *
! 6552: * basically it does the following checks described by the XML Rec
! 6553: *
! 6554: * Check all the IDREF/IDREFS attributes definition for validity
! 6555: *
! 6556: * returns 1 if valid or 0 otherwise
! 6557: */
! 6558:
! 6559: int
! 6560: xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
! 6561: xmlRefTablePtr table;
! 6562:
! 6563: if (ctxt == NULL)
! 6564: return(0);
! 6565: if (doc == NULL) {
! 6566: xmlErrValid(ctxt, XML_DTD_NO_DOC,
! 6567: "xmlValidateDocumentFinal: doc == NULL\n", NULL);
! 6568: return(0);
! 6569: }
! 6570:
! 6571: /*
! 6572: * Check all the NOTATION/NOTATIONS attributes
! 6573: */
! 6574: /*
! 6575: * Check all the ENTITY/ENTITIES attributes definition for validity
! 6576: */
! 6577: /*
! 6578: * Check all the IDREF/IDREFS attributes definition for validity
! 6579: */
! 6580: table = (xmlRefTablePtr) doc->refs;
! 6581: ctxt->doc = doc;
! 6582: ctxt->valid = 1;
! 6583: xmlHashScan(table, (xmlHashScanner) xmlValidateCheckRefCallback, ctxt);
! 6584: return(ctxt->valid);
! 6585: }
! 6586:
! 6587: /**
! 6588: * xmlValidateDtd:
! 6589: * @ctxt: the validation context
! 6590: * @doc: a document instance
! 6591: * @dtd: a dtd instance
! 6592: *
! 6593: * Try to validate the document against the dtd instance
! 6594: *
! 6595: * Basically it does check all the definitions in the DtD.
! 6596: * Note the the internal subset (if present) is de-coupled
! 6597: * (i.e. not used), which could give problems if ID or IDREF
! 6598: * is present.
! 6599: *
! 6600: * returns 1 if valid or 0 otherwise
! 6601: */
! 6602:
! 6603: int
! 6604: xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
! 6605: int ret;
! 6606: xmlDtdPtr oldExt, oldInt;
! 6607: xmlNodePtr root;
! 6608:
! 6609: if (dtd == NULL) return(0);
! 6610: if (doc == NULL) return(0);
! 6611: oldExt = doc->extSubset;
! 6612: oldInt = doc->intSubset;
! 6613: doc->extSubset = dtd;
! 6614: doc->intSubset = NULL;
! 6615: ret = xmlValidateRoot(ctxt, doc);
! 6616: if (ret == 0) {
! 6617: doc->extSubset = oldExt;
! 6618: doc->intSubset = oldInt;
! 6619: return(ret);
! 6620: }
! 6621: if (doc->ids != NULL) {
! 6622: xmlFreeIDTable(doc->ids);
! 6623: doc->ids = NULL;
! 6624: }
! 6625: if (doc->refs != NULL) {
! 6626: xmlFreeRefTable(doc->refs);
! 6627: doc->refs = NULL;
! 6628: }
! 6629: root = xmlDocGetRootElement(doc);
! 6630: ret = xmlValidateElement(ctxt, doc, root);
! 6631: ret &= xmlValidateDocumentFinal(ctxt, doc);
! 6632: doc->extSubset = oldExt;
! 6633: doc->intSubset = oldInt;
! 6634: return(ret);
! 6635: }
! 6636:
! 6637: static void
! 6638: xmlValidateNotationCallback(xmlEntityPtr cur, xmlValidCtxtPtr ctxt,
! 6639: const xmlChar *name ATTRIBUTE_UNUSED) {
! 6640: if (cur == NULL)
! 6641: return;
! 6642: if (cur->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
! 6643: xmlChar *notation = cur->content;
! 6644:
! 6645: if (notation != NULL) {
! 6646: int ret;
! 6647:
! 6648: ret = xmlValidateNotationUse(ctxt, cur->doc, notation);
! 6649: if (ret != 1) {
! 6650: ctxt->valid = 0;
! 6651: }
! 6652: }
! 6653: }
! 6654: }
! 6655:
! 6656: static void
! 6657: xmlValidateAttributeCallback(xmlAttributePtr cur, xmlValidCtxtPtr ctxt,
! 6658: const xmlChar *name ATTRIBUTE_UNUSED) {
! 6659: int ret;
! 6660: xmlDocPtr doc;
! 6661: xmlElementPtr elem = NULL;
! 6662:
! 6663: if (cur == NULL)
! 6664: return;
! 6665: switch (cur->atype) {
! 6666: case XML_ATTRIBUTE_CDATA:
! 6667: case XML_ATTRIBUTE_ID:
! 6668: case XML_ATTRIBUTE_IDREF :
! 6669: case XML_ATTRIBUTE_IDREFS:
! 6670: case XML_ATTRIBUTE_NMTOKEN:
! 6671: case XML_ATTRIBUTE_NMTOKENS:
! 6672: case XML_ATTRIBUTE_ENUMERATION:
! 6673: break;
! 6674: case XML_ATTRIBUTE_ENTITY:
! 6675: case XML_ATTRIBUTE_ENTITIES:
! 6676: case XML_ATTRIBUTE_NOTATION:
! 6677: if (cur->defaultValue != NULL) {
! 6678:
! 6679: ret = xmlValidateAttributeValue2(ctxt, ctxt->doc, cur->name,
! 6680: cur->atype, cur->defaultValue);
! 6681: if ((ret == 0) && (ctxt->valid == 1))
! 6682: ctxt->valid = 0;
! 6683: }
! 6684: if (cur->tree != NULL) {
! 6685: xmlEnumerationPtr tree = cur->tree;
! 6686: while (tree != NULL) {
! 6687: ret = xmlValidateAttributeValue2(ctxt, ctxt->doc,
! 6688: cur->name, cur->atype, tree->name);
! 6689: if ((ret == 0) && (ctxt->valid == 1))
! 6690: ctxt->valid = 0;
! 6691: tree = tree->next;
! 6692: }
! 6693: }
! 6694: }
! 6695: if (cur->atype == XML_ATTRIBUTE_NOTATION) {
! 6696: doc = cur->doc;
! 6697: if (cur->elem == NULL) {
! 6698: xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
! 6699: "xmlValidateAttributeCallback(%s): internal error\n",
! 6700: (const char *) cur->name);
! 6701: return;
! 6702: }
! 6703:
! 6704: if (doc != NULL)
! 6705: elem = xmlGetDtdElementDesc(doc->intSubset, cur->elem);
! 6706: if ((elem == NULL) && (doc != NULL))
! 6707: elem = xmlGetDtdElementDesc(doc->extSubset, cur->elem);
! 6708: if ((elem == NULL) && (cur->parent != NULL) &&
! 6709: (cur->parent->type == XML_DTD_NODE))
! 6710: elem = xmlGetDtdElementDesc((xmlDtdPtr) cur->parent, cur->elem);
! 6711: if (elem == NULL) {
! 6712: xmlErrValidNode(ctxt, NULL, XML_DTD_UNKNOWN_ELEM,
! 6713: "attribute %s: could not find decl for element %s\n",
! 6714: cur->name, cur->elem, NULL);
! 6715: return;
! 6716: }
! 6717: if (elem->etype == XML_ELEMENT_TYPE_EMPTY) {
! 6718: xmlErrValidNode(ctxt, NULL, XML_DTD_EMPTY_NOTATION,
! 6719: "NOTATION attribute %s declared for EMPTY element %s\n",
! 6720: cur->name, cur->elem, NULL);
! 6721: ctxt->valid = 0;
! 6722: }
! 6723: }
! 6724: }
! 6725:
! 6726: /**
! 6727: * xmlValidateDtdFinal:
! 6728: * @ctxt: the validation context
! 6729: * @doc: a document instance
! 6730: *
! 6731: * Does the final step for the dtds validation once all the
! 6732: * subsets have been parsed
! 6733: *
! 6734: * basically it does the following checks described by the XML Rec
! 6735: * - check that ENTITY and ENTITIES type attributes default or
! 6736: * possible values matches one of the defined entities.
! 6737: * - check that NOTATION type attributes default or
! 6738: * possible values matches one of the defined notations.
! 6739: *
! 6740: * returns 1 if valid or 0 if invalid and -1 if not well-formed
! 6741: */
! 6742:
! 6743: int
! 6744: xmlValidateDtdFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
! 6745: xmlDtdPtr dtd;
! 6746: xmlAttributeTablePtr table;
! 6747: xmlEntitiesTablePtr entities;
! 6748:
! 6749: if ((doc == NULL) || (ctxt == NULL)) return(0);
! 6750: if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
! 6751: return(0);
! 6752: ctxt->doc = doc;
! 6753: ctxt->valid = 1;
! 6754: dtd = doc->intSubset;
! 6755: if ((dtd != NULL) && (dtd->attributes != NULL)) {
! 6756: table = (xmlAttributeTablePtr) dtd->attributes;
! 6757: xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt);
! 6758: }
! 6759: if ((dtd != NULL) && (dtd->entities != NULL)) {
! 6760: entities = (xmlEntitiesTablePtr) dtd->entities;
! 6761: xmlHashScan(entities, (xmlHashScanner) xmlValidateNotationCallback,
! 6762: ctxt);
! 6763: }
! 6764: dtd = doc->extSubset;
! 6765: if ((dtd != NULL) && (dtd->attributes != NULL)) {
! 6766: table = (xmlAttributeTablePtr) dtd->attributes;
! 6767: xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt);
! 6768: }
! 6769: if ((dtd != NULL) && (dtd->entities != NULL)) {
! 6770: entities = (xmlEntitiesTablePtr) dtd->entities;
! 6771: xmlHashScan(entities, (xmlHashScanner) xmlValidateNotationCallback,
! 6772: ctxt);
! 6773: }
! 6774: return(ctxt->valid);
! 6775: }
! 6776:
! 6777: /**
! 6778: * xmlValidateDocument:
! 6779: * @ctxt: the validation context
! 6780: * @doc: a document instance
! 6781: *
! 6782: * Try to validate the document instance
! 6783: *
! 6784: * basically it does the all the checks described by the XML Rec
! 6785: * i.e. validates the internal and external subset (if present)
! 6786: * and validate the document tree.
! 6787: *
! 6788: * returns 1 if valid or 0 otherwise
! 6789: */
! 6790:
! 6791: int
! 6792: xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
! 6793: int ret;
! 6794: xmlNodePtr root;
! 6795:
! 6796: if (doc == NULL)
! 6797: return(0);
! 6798: if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
! 6799: xmlErrValid(ctxt, XML_DTD_NO_DTD,
! 6800: "no DTD found!\n", NULL);
! 6801: return(0);
! 6802: }
! 6803: if ((doc->intSubset != NULL) && ((doc->intSubset->SystemID != NULL) ||
! 6804: (doc->intSubset->ExternalID != NULL)) && (doc->extSubset == NULL)) {
! 6805: xmlChar *sysID;
! 6806: if (doc->intSubset->SystemID != NULL) {
! 6807: sysID = xmlBuildURI(doc->intSubset->SystemID,
! 6808: doc->URL);
! 6809: if (sysID == NULL) {
! 6810: xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
! 6811: "Could not build URI for external subset \"%s\"\n",
! 6812: (const char *) doc->intSubset->SystemID);
! 6813: return 0;
! 6814: }
! 6815: } else
! 6816: sysID = NULL;
! 6817: doc->extSubset = xmlParseDTD(doc->intSubset->ExternalID,
! 6818: (const xmlChar *)sysID);
! 6819: if (sysID != NULL)
! 6820: xmlFree(sysID);
! 6821: if (doc->extSubset == NULL) {
! 6822: if (doc->intSubset->SystemID != NULL) {
! 6823: xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
! 6824: "Could not load the external subset \"%s\"\n",
! 6825: (const char *) doc->intSubset->SystemID);
! 6826: } else {
! 6827: xmlErrValid(ctxt, XML_DTD_LOAD_ERROR,
! 6828: "Could not load the external subset \"%s\"\n",
! 6829: (const char *) doc->intSubset->ExternalID);
! 6830: }
! 6831: return(0);
! 6832: }
! 6833: }
! 6834:
! 6835: if (doc->ids != NULL) {
! 6836: xmlFreeIDTable(doc->ids);
! 6837: doc->ids = NULL;
! 6838: }
! 6839: if (doc->refs != NULL) {
! 6840: xmlFreeRefTable(doc->refs);
! 6841: doc->refs = NULL;
! 6842: }
! 6843: ret = xmlValidateDtdFinal(ctxt, doc);
! 6844: if (!xmlValidateRoot(ctxt, doc)) return(0);
! 6845:
! 6846: root = xmlDocGetRootElement(doc);
! 6847: ret &= xmlValidateElement(ctxt, doc, root);
! 6848: ret &= xmlValidateDocumentFinal(ctxt, doc);
! 6849: return(ret);
! 6850: }
! 6851:
! 6852: /************************************************************************
! 6853: * *
! 6854: * Routines for dynamic validation editing *
! 6855: * *
! 6856: ************************************************************************/
! 6857:
! 6858: /**
! 6859: * xmlValidGetPotentialChildren:
! 6860: * @ctree: an element content tree
! 6861: * @names: an array to store the list of child names
! 6862: * @len: a pointer to the number of element in the list
! 6863: * @max: the size of the array
! 6864: *
! 6865: * Build/extend a list of potential children allowed by the content tree
! 6866: *
! 6867: * returns the number of element in the list, or -1 in case of error.
! 6868: */
! 6869:
! 6870: int
! 6871: xmlValidGetPotentialChildren(xmlElementContent *ctree,
! 6872: const xmlChar **names,
! 6873: int *len, int max) {
! 6874: int i;
! 6875:
! 6876: if ((ctree == NULL) || (names == NULL) || (len == NULL))
! 6877: return(-1);
! 6878: if (*len >= max) return(*len);
! 6879:
! 6880: switch (ctree->type) {
! 6881: case XML_ELEMENT_CONTENT_PCDATA:
! 6882: for (i = 0; i < *len;i++)
! 6883: if (xmlStrEqual(BAD_CAST "#PCDATA", names[i])) return(*len);
! 6884: names[(*len)++] = BAD_CAST "#PCDATA";
! 6885: break;
! 6886: case XML_ELEMENT_CONTENT_ELEMENT:
! 6887: for (i = 0; i < *len;i++)
! 6888: if (xmlStrEqual(ctree->name, names[i])) return(*len);
! 6889: names[(*len)++] = ctree->name;
! 6890: break;
! 6891: case XML_ELEMENT_CONTENT_SEQ:
! 6892: xmlValidGetPotentialChildren(ctree->c1, names, len, max);
! 6893: xmlValidGetPotentialChildren(ctree->c2, names, len, max);
! 6894: break;
! 6895: case XML_ELEMENT_CONTENT_OR:
! 6896: xmlValidGetPotentialChildren(ctree->c1, names, len, max);
! 6897: xmlValidGetPotentialChildren(ctree->c2, names, len, max);
! 6898: break;
! 6899: }
! 6900:
! 6901: return(*len);
! 6902: }
! 6903:
! 6904: /*
! 6905: * Dummy function to suppress messages while we try out valid elements
! 6906: */
! 6907: static void XMLCDECL xmlNoValidityErr(void *ctx ATTRIBUTE_UNUSED,
! 6908: const char *msg ATTRIBUTE_UNUSED, ...) {
! 6909: return;
! 6910: }
! 6911:
! 6912: /**
! 6913: * xmlValidGetValidElements:
! 6914: * @prev: an element to insert after
! 6915: * @next: an element to insert next
! 6916: * @names: an array to store the list of child names
! 6917: * @max: the size of the array
! 6918: *
! 6919: * This function returns the list of authorized children to insert
! 6920: * within an existing tree while respecting the validity constraints
! 6921: * forced by the Dtd. The insertion point is defined using @prev and
! 6922: * @next in the following ways:
! 6923: * to insert before 'node': xmlValidGetValidElements(node->prev, node, ...
! 6924: * to insert next 'node': xmlValidGetValidElements(node, node->next, ...
! 6925: * to replace 'node': xmlValidGetValidElements(node->prev, node->next, ...
! 6926: * to prepend a child to 'node': xmlValidGetValidElements(NULL, node->childs,
! 6927: * to append a child to 'node': xmlValidGetValidElements(node->last, NULL, ...
! 6928: *
! 6929: * pointers to the element names are inserted at the beginning of the array
! 6930: * and do not need to be freed.
! 6931: *
! 6932: * returns the number of element in the list, or -1 in case of error. If
! 6933: * the function returns the value @max the caller is invited to grow the
! 6934: * receiving array and retry.
! 6935: */
! 6936:
! 6937: int
! 6938: xmlValidGetValidElements(xmlNode *prev, xmlNode *next, const xmlChar **names,
! 6939: int max) {
! 6940: xmlValidCtxt vctxt;
! 6941: int nb_valid_elements = 0;
! 6942: const xmlChar *elements[256];
! 6943: int nb_elements = 0, i;
! 6944: const xmlChar *name;
! 6945:
! 6946: xmlNode *ref_node;
! 6947: xmlNode *parent;
! 6948: xmlNode *test_node;
! 6949:
! 6950: xmlNode *prev_next;
! 6951: xmlNode *next_prev;
! 6952: xmlNode *parent_childs;
! 6953: xmlNode *parent_last;
! 6954:
! 6955: xmlElement *element_desc;
! 6956:
! 6957: if (prev == NULL && next == NULL)
! 6958: return(-1);
! 6959:
! 6960: if (names == NULL) return(-1);
! 6961: if (max <= 0) return(-1);
! 6962:
! 6963: memset(&vctxt, 0, sizeof (xmlValidCtxt));
! 6964: vctxt.error = xmlNoValidityErr; /* this suppresses err/warn output */
! 6965:
! 6966: nb_valid_elements = 0;
! 6967: ref_node = prev ? prev : next;
! 6968: parent = ref_node->parent;
! 6969:
! 6970: /*
! 6971: * Retrieves the parent element declaration
! 6972: */
! 6973: element_desc = xmlGetDtdElementDesc(parent->doc->intSubset,
! 6974: parent->name);
! 6975: if ((element_desc == NULL) && (parent->doc->extSubset != NULL))
! 6976: element_desc = xmlGetDtdElementDesc(parent->doc->extSubset,
! 6977: parent->name);
! 6978: if (element_desc == NULL) return(-1);
! 6979:
! 6980: /*
! 6981: * Do a backup of the current tree structure
! 6982: */
! 6983: prev_next = prev ? prev->next : NULL;
! 6984: next_prev = next ? next->prev : NULL;
! 6985: parent_childs = parent->children;
! 6986: parent_last = parent->last;
! 6987:
! 6988: /*
! 6989: * Creates a dummy node and insert it into the tree
! 6990: */
! 6991: test_node = xmlNewDocNode (ref_node->doc, NULL, BAD_CAST "<!dummy?>", NULL);
! 6992: test_node->parent = parent;
! 6993: test_node->prev = prev;
! 6994: test_node->next = next;
! 6995: name = test_node->name;
! 6996:
! 6997: if (prev) prev->next = test_node;
! 6998: else parent->children = test_node;
! 6999:
! 7000: if (next) next->prev = test_node;
! 7001: else parent->last = test_node;
! 7002:
! 7003: /*
! 7004: * Insert each potential child node and check if the parent is
! 7005: * still valid
! 7006: */
! 7007: nb_elements = xmlValidGetPotentialChildren(element_desc->content,
! 7008: elements, &nb_elements, 256);
! 7009:
! 7010: for (i = 0;i < nb_elements;i++) {
! 7011: test_node->name = elements[i];
! 7012: if (xmlValidateOneElement(&vctxt, parent->doc, parent)) {
! 7013: int j;
! 7014:
! 7015: for (j = 0; j < nb_valid_elements;j++)
! 7016: if (xmlStrEqual(elements[i], names[j])) break;
! 7017: names[nb_valid_elements++] = elements[i];
! 7018: if (nb_valid_elements >= max) break;
! 7019: }
! 7020: }
! 7021:
! 7022: /*
! 7023: * Restore the tree structure
! 7024: */
! 7025: if (prev) prev->next = prev_next;
! 7026: if (next) next->prev = next_prev;
! 7027: parent->children = parent_childs;
! 7028: parent->last = parent_last;
! 7029:
! 7030: /*
! 7031: * Free up the dummy node
! 7032: */
! 7033: test_node->name = name;
! 7034: xmlFreeNode(test_node);
! 7035:
! 7036: return(nb_valid_elements);
! 7037: }
! 7038: #endif /* LIBXML_VALID_ENABLED */
! 7039:
! 7040: #define bottom_valid
! 7041: #include "elfgcchack.h"
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>