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