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