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