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) || (parent == 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 (elem->type != XML_ELEMENT_NODE)) 5522 return(0); 5523 5524 child = elem->children; 5525 5526 cur = child; 5527 while (cur != NULL) { 5528 switch (cur->type) { 5529 case XML_ENTITY_REF_NODE: 5530 /* 5531 * Push the current node to be able to roll back 5532 * and process within the entity 5533 */ 5534 if ((cur->children != NULL) && 5535 (cur->children->children != NULL)) { 5536 nodeVPush(ctxt, cur); 5537 cur = cur->children->children; 5538 continue; 5539 } 5540 break; 5541 case XML_COMMENT_NODE: 5542 case XML_PI_NODE: 5543 case XML_TEXT_NODE: 5544 case XML_CDATA_SECTION_NODE: 5545 break; 5546 default: 5547 ret = 0; 5548 goto done; 5549 } 5550 /* 5551 * Switch to next element 5552 */ 5553 cur = cur->next; 5554 while (cur == NULL) { 5555 cur = nodeVPop(ctxt); 5556 if (cur == NULL) 5557 break; 5558 cur = cur->next; 5559 } 5560 } 5561 done: 5562 ctxt->nodeMax = 0; 5563 ctxt->nodeNr = 0; 5564 if (ctxt->nodeTab != NULL) { 5565 xmlFree(ctxt->nodeTab); 5566 ctxt->nodeTab = NULL; 5567 } 5568 return(ret); 5569 } 5570 5571 /** 5572 * xmlValidateCheckMixed: 5573 * @ctxt: the validation context 5574 * @cont: the mixed content model 5575 * @qname: the qualified name as appearing in the serialization 5576 * 5577 * Check if the given node is part of the content model. 5578 * 5579 * Returns 1 if yes, 0 if no, -1 in case of error 5580 */ 5581 static int 5582 xmlValidateCheckMixed(xmlValidCtxtPtr ctxt, 5583 xmlElementContentPtr cont, const xmlChar *qname) { 5584 const xmlChar *name; 5585 int plen; 5586 name = xmlSplitQName3(qname, &plen); 5587 5588 if (name == NULL) { 5589 while (cont != NULL) { 5590 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) { 5591 if ((cont->prefix == NULL) && (xmlStrEqual(cont->name, qname))) 5592 return(1); 5593 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) && 5594 (cont->c1 != NULL) && 5595 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){ 5596 if ((cont->c1->prefix == NULL) && 5597 (xmlStrEqual(cont->c1->name, qname))) 5598 return(1); 5599 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) || 5600 (cont->c1 == NULL) || 5601 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){ 5602 xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT, 5603 "Internal: MIXED struct corrupted\n", 5604 NULL); 5605 break; 5606 } 5607 cont = cont->c2; 5608 } 5609 } else { 5610 while (cont != NULL) { 5611 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) { 5612 if ((cont->prefix != NULL) && 5613 (xmlStrncmp(cont->prefix, qname, plen) == 0) && 5614 (xmlStrEqual(cont->name, name))) 5615 return(1); 5616 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) && 5617 (cont->c1 != NULL) && 5618 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){ 5619 if ((cont->c1->prefix != NULL) && 5620 (xmlStrncmp(cont->c1->prefix, qname, plen) == 0) && 5621 (xmlStrEqual(cont->c1->name, name))) 5622 return(1); 5623 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) || 5624 (cont->c1 == NULL) || 5625 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){ 5626 xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT, 5627 "Internal: MIXED struct corrupted\n", 5628 NULL); 5629 break; 5630 } 5631 cont = cont->c2; 5632 } 5633 } 5634 return(0); 5635 } 5636 5637 /** 5638 * xmlValidGetElemDecl: 5639 * @ctxt: the validation context 5640 * @doc: a document instance 5641 * @elem: an element instance 5642 * @extsubset: pointer, (out) indicate if the declaration was found 5643 * in the external subset. 5644 * 5645 * Finds a declaration associated to an element in the document. 5646 * 5647 * returns the pointer to the declaration or NULL if not found. 5648 */ 5649 static xmlElementPtr 5650 xmlValidGetElemDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc, 5651 xmlNodePtr elem, int *extsubset) { 5652 xmlElementPtr elemDecl = NULL; 5653 const xmlChar *prefix = NULL; 5654 5655 if ((ctxt == NULL) || (doc == NULL) || 5656 (elem == NULL) || (elem->name == NULL)) 5657 return(NULL); 5658 if (extsubset != NULL) 5659 *extsubset = 0; 5660 5661 /* 5662 * Fetch the declaration for the qualified name 5663 */ 5664 if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) 5665 prefix = elem->ns->prefix; 5666 5667 if (prefix != NULL) { 5668 elemDecl = xmlGetDtdQElementDesc(doc->intSubset, 5669 elem->name, prefix); 5670 if ((elemDecl == NULL) && (doc->extSubset != NULL)) { 5671 elemDecl = xmlGetDtdQElementDesc(doc->extSubset, 5672 elem->name, prefix); 5673 if ((elemDecl != NULL) && (extsubset != NULL)) 5674 *extsubset = 1; 5675 } 5676 } 5677 5678 /* 5679 * Fetch the declaration for the non qualified name 5680 * This is "non-strict" validation should be done on the 5681 * full QName but in that case being flexible makes sense. 5682 */ 5683 if (elemDecl == NULL) { 5684 elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name); 5685 if ((elemDecl == NULL) && (doc->extSubset != NULL)) { 5686 elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name); 5687 if ((elemDecl != NULL) && (extsubset != NULL)) 5688 *extsubset = 1; 5689 } 5690 } 5691 if (elemDecl == NULL) { 5692 xmlErrValidNode(ctxt, elem, 5693 XML_DTD_UNKNOWN_ELEM, 5694 "No declaration for element %s\n", 5695 elem->name, NULL, NULL); 5696 } 5697 return(elemDecl); 5698 } 5699 5700 #ifdef LIBXML_REGEXP_ENABLED 5701 /** 5702 * xmlValidatePushElement: 5703 * @ctxt: the validation context 5704 * @doc: a document instance 5705 * @elem: an element instance 5706 * @qname: the qualified name as appearing in the serialization 5707 * 5708 * Push a new element start on the validation stack. 5709 * 5710 * returns 1 if no validation problem was found or 0 otherwise 5711 */ 5712 int 5713 xmlValidatePushElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, 5714 xmlNodePtr elem, const xmlChar *qname) { 5715 int ret = 1; 5716 xmlElementPtr eDecl; 5717 int extsubset = 0; 5718 5719 if (ctxt == NULL) 5720 return(0); 5721 /* printf("PushElem %s\n", qname); */ 5722 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) { 5723 xmlValidStatePtr state = ctxt->vstate; 5724 xmlElementPtr elemDecl; 5725 5726 /* 5727 * Check the new element agaisnt the content model of the new elem. 5728 */ 5729 if (state->elemDecl != NULL) { 5730 elemDecl = state->elemDecl; 5731 5732 switch(elemDecl->etype) { 5733 case XML_ELEMENT_TYPE_UNDEFINED: 5734 ret = 0; 5735 break; 5736 case XML_ELEMENT_TYPE_EMPTY: 5737 xmlErrValidNode(ctxt, state->node, 5738 XML_DTD_NOT_EMPTY, 5739 "Element %s was declared EMPTY this one has content\n", 5740 state->node->name, NULL, NULL); 5741 ret = 0; 5742 break; 5743 case XML_ELEMENT_TYPE_ANY: 5744 /* I don't think anything is required then */ 5745 break; 5746 case XML_ELEMENT_TYPE_MIXED: 5747 /* simple case of declared as #PCDATA */ 5748 if ((elemDecl->content != NULL) && 5749 (elemDecl->content->type == 5750 XML_ELEMENT_CONTENT_PCDATA)) { 5751 xmlErrValidNode(ctxt, state->node, 5752 XML_DTD_NOT_PCDATA, 5753 "Element %s was declared #PCDATA but contains non text nodes\n", 5754 state->node->name, NULL, NULL); 5755 ret = 0; 5756 } else { 5757 ret = xmlValidateCheckMixed(ctxt, elemDecl->content, 5758 qname); 5759 if (ret != 1) { 5760 xmlErrValidNode(ctxt, state->node, 5761 XML_DTD_INVALID_CHILD, 5762 "Element %s is not declared in %s list of possible children\n", 5763 qname, state->node->name, NULL); 5764 } 5765 } 5766 break; 5767 case XML_ELEMENT_TYPE_ELEMENT: 5768 /* 5769 * TODO: 5770 * VC: Standalone Document Declaration 5771 * - element types with element content, if white space 5772 * occurs directly within any instance of those types. 5773 */ 5774 if (state->exec != NULL) { 5775 ret = xmlRegExecPushString(state->exec, qname, NULL); 5776 if (ret < 0) { 5777 xmlErrValidNode(ctxt, state->node, 5778 XML_DTD_CONTENT_MODEL, 5779 "Element %s content does not follow the DTD, Misplaced %s\n", 5780 state->node->name, qname, NULL); 5781 ret = 0; 5782 } else { 5783 ret = 1; 5784 } 5785 } 5786 break; 5787 } 5788 } 5789 } 5790 eDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset); 5791 vstateVPush(ctxt, eDecl, elem); 5792 return(ret); 5793 } 5794 5795 /** 5796 * xmlValidatePushCData: 5797 * @ctxt: the validation context 5798 * @data: some character data read 5799 * @len: the length of the data 5800 * 5801 * check the CData parsed for validation in the current stack 5802 * 5803 * returns 1 if no validation problem was found or 0 otherwise 5804 */ 5805 int 5806 xmlValidatePushCData(xmlValidCtxtPtr ctxt, const xmlChar *data, int len) { 5807 int ret = 1; 5808 5809 /* printf("CDATA %s %d\n", data, len); */ 5810 if (ctxt == NULL) 5811 return(0); 5812 if (len <= 0) 5813 return(ret); 5814 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) { 5815 xmlValidStatePtr state = ctxt->vstate; 5816 xmlElementPtr elemDecl; 5817 5818 /* 5819 * Check the new element agaisnt the content model of the new elem. 5820 */ 5821 if (state->elemDecl != NULL) { 5822 elemDecl = state->elemDecl; 5823 5824 switch(elemDecl->etype) { 5825 case XML_ELEMENT_TYPE_UNDEFINED: 5826 ret = 0; 5827 break; 5828 case XML_ELEMENT_TYPE_EMPTY: 5829 xmlErrValidNode(ctxt, state->node, 5830 XML_DTD_NOT_EMPTY, 5831 "Element %s was declared EMPTY this one has content\n", 5832 state->node->name, NULL, NULL); 5833 ret = 0; 5834 break; 5835 case XML_ELEMENT_TYPE_ANY: 5836 break; 5837 case XML_ELEMENT_TYPE_MIXED: 5838 break; 5839 case XML_ELEMENT_TYPE_ELEMENT: 5840 if (len > 0) { 5841 int i; 5842 5843 for (i = 0;i < len;i++) { 5844 if (!IS_BLANK_CH(data[i])) { 5845 xmlErrValidNode(ctxt, state->node, 5846 XML_DTD_CONTENT_MODEL, 5847 "Element %s content does not follow the DTD, Text not allowed\n", 5848 state->node->name, NULL, NULL); 5849 ret = 0; 5850 goto done; 5851 } 5852 } 5853 /* 5854 * TODO: 5855 * VC: Standalone Document Declaration 5856 * element types with element content, if white space 5857 * occurs directly within any instance of those types. 5858 */ 5859 } 5860 break; 5861 } 5862 } 5863 } 5864 done: 5865 return(ret); 5866 } 5867 5868 /** 5869 * xmlValidatePopElement: 5870 * @ctxt: the validation context 5871 * @doc: a document instance 5872 * @elem: an element instance 5873 * @qname: the qualified name as appearing in the serialization 5874 * 5875 * Pop the element end from the validation stack. 5876 * 5877 * returns 1 if no validation problem was found or 0 otherwise 5878 */ 5879 int 5880 xmlValidatePopElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc ATTRIBUTE_UNUSED, 5881 xmlNodePtr elem ATTRIBUTE_UNUSED, 5882 const xmlChar *qname ATTRIBUTE_UNUSED) { 5883 int ret = 1; 5884 5885 if (ctxt == NULL) 5886 return(0); 5887 /* printf("PopElem %s\n", qname); */ 5888 if ((ctxt->vstateNr > 0) && (ctxt->vstate != NULL)) { 5889 xmlValidStatePtr state = ctxt->vstate; 5890 xmlElementPtr elemDecl; 5891 5892 /* 5893 * Check the new element agaisnt the content model of the new elem. 5894 */ 5895 if (state->elemDecl != NULL) { 5896 elemDecl = state->elemDecl; 5897 5898 if (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT) { 5899 if (state->exec != NULL) { 5900 ret = xmlRegExecPushString(state->exec, NULL, NULL); 5901 if (ret == 0) { 5902 xmlErrValidNode(ctxt, state->node, 5903 XML_DTD_CONTENT_MODEL, 5904 "Element %s content does not follow the DTD, Expecting more child\n", 5905 state->node->name, NULL,NULL); 5906 } else { 5907 /* 5908 * previous validation errors should not generate 5909 * a new one here 5910 */ 5911 ret = 1; 5912 } 5913 } 5914 } 5915 } 5916 vstateVPop(ctxt); 5917 } 5918 return(ret); 5919 } 5920 #endif /* LIBXML_REGEXP_ENABLED */ 5921 5922 /** 5923 * xmlValidateOneElement: 5924 * @ctxt: the validation context 5925 * @doc: a document instance 5926 * @elem: an element instance 5927 * 5928 * Try to validate a single element and it's attributes, 5929 * basically it does the following checks as described by the 5930 * XML-1.0 recommendation: 5931 * - [ VC: Element Valid ] 5932 * - [ VC: Required Attribute ] 5933 * Then call xmlValidateOneAttribute() for each attribute present. 5934 * 5935 * The ID/IDREF checkings are done separately 5936 * 5937 * returns 1 if valid or 0 otherwise 5938 */ 5939 5940 int 5941 xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, 5942 xmlNodePtr elem) { 5943 xmlElementPtr elemDecl = NULL; 5944 xmlElementContentPtr cont; 5945 xmlAttributePtr attr; 5946 xmlNodePtr child; 5947 int ret = 1, tmp; 5948 const xmlChar *name; 5949 int extsubset = 0; 5950 5951 CHECK_DTD; 5952 5953 if (elem == NULL) return(0); 5954 switch (elem->type) { 5955 case XML_ATTRIBUTE_NODE: 5956 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR, 5957 "Attribute element not expected\n", NULL, NULL ,NULL); 5958 return(0); 5959 case XML_TEXT_NODE: 5960 if (elem->children != NULL) { 5961 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR, 5962 "Text element has children !\n", 5963 NULL,NULL,NULL); 5964 return(0); 5965 } 5966 if (elem->ns != NULL) { 5967 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR, 5968 "Text element has namespace !\n", 5969 NULL,NULL,NULL); 5970 return(0); 5971 } 5972 if (elem->content == NULL) { 5973 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR, 5974 "Text element has no content !\n", 5975 NULL,NULL,NULL); 5976 return(0); 5977 } 5978 return(1); 5979 case XML_XINCLUDE_START: 5980 case XML_XINCLUDE_END: 5981 return(1); 5982 case XML_CDATA_SECTION_NODE: 5983 case XML_ENTITY_REF_NODE: 5984 case XML_PI_NODE: 5985 case XML_COMMENT_NODE: 5986 return(1); 5987 case XML_ENTITY_NODE: 5988 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR, 5989 "Entity element not expected\n", NULL, NULL ,NULL); 5990 return(0); 5991 case XML_NOTATION_NODE: 5992 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR, 5993 "Notation element not expected\n", NULL, NULL ,NULL); 5994 return(0); 5995 case XML_DOCUMENT_NODE: 5996 case XML_DOCUMENT_TYPE_NODE: 5997 case XML_DOCUMENT_FRAG_NODE: 5998 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR, 5999 "Document element not expected\n", NULL, NULL ,NULL); 6000 return(0); 6001 case XML_HTML_DOCUMENT_NODE: 6002 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR, 6003 "HTML Document not expected\n", NULL, NULL ,NULL); 6004 return(0); 6005 case XML_ELEMENT_NODE: 6006 break; 6007 default: 6008 xmlErrValidNode(ctxt, elem, XML_ERR_INTERNAL_ERROR, 6009 "unknown element type\n", NULL, NULL ,NULL); 6010 return(0); 6011 } 6012 6013 /* 6014 * Fetch the declaration 6015 */ 6016 elemDecl = xmlValidGetElemDecl(ctxt, doc, elem, &extsubset); 6017 if (elemDecl == NULL) 6018 return(0); 6019 6020 /* 6021 * If vstateNr is not zero that means continuous validation is 6022 * activated, do not try to check the content model at that level. 6023 */ 6024 if (ctxt->vstateNr == 0) { 6025 /* Check that the element content matches the definition */ 6026 switch (elemDecl->etype) { 6027 case XML_ELEMENT_TYPE_UNDEFINED: 6028 xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ELEM, 6029 "No declaration for element %s\n", 6030 elem->name, NULL, NULL); 6031 return(0); 6032 case XML_ELEMENT_TYPE_EMPTY: 6033 if (elem->children != NULL) { 6034 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_EMPTY, 6035 "Element %s was declared EMPTY this one has content\n", 6036 elem->name, NULL, NULL); 6037 ret = 0; 6038 } 6039 break; 6040 case XML_ELEMENT_TYPE_ANY: 6041 /* I don't think anything is required then */ 6042 break; 6043 case XML_ELEMENT_TYPE_MIXED: 6044 6045 /* simple case of declared as #PCDATA */ 6046 if ((elemDecl->content != NULL) && 6047 (elemDecl->content->type == XML_ELEMENT_CONTENT_PCDATA)) { 6048 ret = xmlValidateOneCdataElement(ctxt, doc, elem); 6049 if (!ret) { 6050 xmlErrValidNode(ctxt, elem, XML_DTD_NOT_PCDATA, 6051 "Element %s was declared #PCDATA but contains non text nodes\n", 6052 elem->name, NULL, NULL); 6053 } 6054 break; 6055 } 6056 child = elem->children; 6057 /* Hum, this start to get messy */ 6058 while (child != NULL) { 6059 if (child->type == XML_ELEMENT_NODE) { 6060 name = child->name; 6061 if ((child->ns != NULL) && (child->ns->prefix != NULL)) { 6062 xmlChar fn[50]; 6063 xmlChar *fullname; 6064 6065 fullname = xmlBuildQName(child->name, child->ns->prefix, 6066 fn, 50); 6067 if (fullname == NULL) 6068 return(0); 6069 cont = elemDecl->content; 6070 while (cont != NULL) { 6071 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) { 6072 if (xmlStrEqual(cont->name, fullname)) 6073 break; 6074 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) && 6075 (cont->c1 != NULL) && 6076 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){ 6077 if (xmlStrEqual(cont->c1->name, fullname)) 6078 break; 6079 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) || 6080 (cont->c1 == NULL) || 6081 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){ 6082 xmlErrValid(NULL, XML_DTD_MIXED_CORRUPT, 6083 "Internal: MIXED struct corrupted\n", 6084 NULL); 6085 break; 6086 } 6087 cont = cont->c2; 6088 } 6089 if ((fullname != fn) && (fullname != child->name)) 6090 xmlFree(fullname); 6091 if (cont != NULL) 6092 goto child_ok; 6093 } 6094 cont = elemDecl->content; 6095 while (cont != NULL) { 6096 if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) { 6097 if (xmlStrEqual(cont->name, name)) break; 6098 } else if ((cont->type == XML_ELEMENT_CONTENT_OR) && 6099 (cont->c1 != NULL) && 6100 (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) { 6101 if (xmlStrEqual(cont->c1->name, name)) break; 6102 } else if ((cont->type != XML_ELEMENT_CONTENT_OR) || 6103 (cont->c1 == NULL) || 6104 (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) { 6105 xmlErrValid(ctxt, XML_DTD_MIXED_CORRUPT, 6106 "Internal: MIXED struct corrupted\n", 6107 NULL); 6108 break; 6109 } 6110 cont = cont->c2; 6111 } 6112 if (cont == NULL) { 6113 xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_CHILD, 6114 "Element %s is not declared in %s list of possible children\n", 6115 name, elem->name, NULL); 6116 ret = 0; 6117 } 6118 } 6119 child_ok: 6120 child = child->next; 6121 } 6122 break; 6123 case XML_ELEMENT_TYPE_ELEMENT: 6124 if ((doc->standalone == 1) && (extsubset == 1)) { 6125 /* 6126 * VC: Standalone Document Declaration 6127 * - element types with element content, if white space 6128 * occurs directly within any instance of those types. 6129 */ 6130 child = elem->children; 6131 while (child != NULL) { 6132 if (child->type == XML_TEXT_NODE) { 6133 const xmlChar *content = child->content; 6134 6135 while (IS_BLANK_CH(*content)) 6136 content++; 6137 if (*content == 0) { 6138 xmlErrValidNode(ctxt, elem, 6139 XML_DTD_STANDALONE_WHITE_SPACE, 6140 "standalone: %s declared in the external subset contains white spaces nodes\n", 6141 elem->name, NULL, NULL); 6142 ret = 0; 6143 break; 6144 } 6145 } 6146 child =child->next; 6147 } 6148 } 6149 child = elem->children; 6150 cont = elemDecl->content; 6151 tmp = xmlValidateElementContent(ctxt, child, elemDecl, 1, elem); 6152 if (tmp <= 0) 6153 ret = tmp; 6154 break; 6155 } 6156 } /* not continuous */ 6157 6158 /* [ VC: Required Attribute ] */ 6159 attr = elemDecl->attributes; 6160 while (attr != NULL) { 6161 if (attr->def == XML_ATTRIBUTE_REQUIRED) { 6162 int qualified = -1; 6163 6164 if ((attr->prefix == NULL) && 6165 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) { 6166 xmlNsPtr ns; 6167 6168 ns = elem->nsDef; 6169 while (ns != NULL) { 6170 if (ns->prefix == NULL) 6171 goto found; 6172 ns = ns->next; 6173 } 6174 } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) { 6175 xmlNsPtr ns; 6176 6177 ns = elem->nsDef; 6178 while (ns != NULL) { 6179 if (xmlStrEqual(attr->name, ns->prefix)) 6180 goto found; 6181 ns = ns->next; 6182 } 6183 } else { 6184 xmlAttrPtr attrib; 6185 6186 attrib = elem->properties; 6187 while (attrib != NULL) { 6188 if (xmlStrEqual(attrib->name, attr->name)) { 6189 if (attr->prefix != NULL) { 6190 xmlNsPtr nameSpace = attrib->ns; 6191 6192 if (nameSpace == NULL) 6193 nameSpace = elem->ns; 6194 /* 6195 * qualified names handling is problematic, having a 6196 * different prefix should be possible but DTDs don't 6197 * allow to define the URI instead of the prefix :-( 6198 */ 6199 if (nameSpace == NULL) { 6200 if (qualified < 0) 6201 qualified = 0; 6202 } else if (!xmlStrEqual(nameSpace->prefix, 6203 attr->prefix)) { 6204 if (qualified < 1) 6205 qualified = 1; 6206 } else 6207 goto found; 6208 } else { 6209 /* 6210 * We should allow applications to define namespaces 6211 * for their application even if the DTD doesn't 6212 * carry one, otherwise, basically we would always 6213 * break. 6214 */ 6215 goto found; 6216 } 6217 } 6218 attrib = attrib->next; 6219 } 6220 } 6221 if (qualified == -1) { 6222 if (attr->prefix == NULL) { 6223 xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE, 6224 "Element %s does not carry attribute %s\n", 6225 elem->name, attr->name, NULL); 6226 ret = 0; 6227 } else { 6228 xmlErrValidNode(ctxt, elem, XML_DTD_MISSING_ATTRIBUTE, 6229 "Element %s does not carry attribute %s:%s\n", 6230 elem->name, attr->prefix,attr->name); 6231 ret = 0; 6232 } 6233 } else if (qualified == 0) { 6234 xmlErrValidWarning(ctxt, elem, XML_DTD_NO_PREFIX, 6235 "Element %s required attribute %s:%s has no prefix\n", 6236 elem->name, attr->prefix, attr->name); 6237 } else if (qualified == 1) { 6238 xmlErrValidWarning(ctxt, elem, XML_DTD_DIFFERENT_PREFIX, 6239 "Element %s required attribute %s:%s has different prefix\n", 6240 elem->name, attr->prefix, attr->name); 6241 } 6242 } else if (attr->def == XML_ATTRIBUTE_FIXED) { 6243 /* 6244 * Special tests checking #FIXED namespace declarations 6245 * have the right value since this is not done as an 6246 * attribute checking 6247 */ 6248 if ((attr->prefix == NULL) && 6249 (xmlStrEqual(attr->name, BAD_CAST "xmlns"))) { 6250 xmlNsPtr ns; 6251 6252 ns = elem->nsDef; 6253 while (ns != NULL) { 6254 if (ns->prefix == NULL) { 6255 if (!xmlStrEqual(attr->defaultValue, ns->href)) { 6256 xmlErrValidNode(ctxt, elem, 6257 XML_DTD_ELEM_DEFAULT_NAMESPACE, 6258 "Element %s namespace name for default namespace does not match the DTD\n", 6259 elem->name, NULL, NULL); 6260 ret = 0; 6261 } 6262 goto found; 6263 } 6264 ns = ns->next; 6265 } 6266 } else if (xmlStrEqual(attr->prefix, BAD_CAST "xmlns")) { 6267 xmlNsPtr ns; 6268 6269 ns = elem->nsDef; 6270 while (ns != NULL) { 6271 if (xmlStrEqual(attr->name, ns->prefix)) { 6272 if (!xmlStrEqual(attr->defaultValue, ns->href)) { 6273 xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE, 6274 "Element %s namespace name for %s does not match the DTD\n", 6275 elem->name, ns->prefix, NULL); 6276 ret = 0; 6277 } 6278 goto found; 6279 } 6280 ns = ns->next; 6281 } 6282 } 6283 } 6284 found: 6285 attr = attr->nexth; 6286 } 6287 return(ret); 6288 } 6289 6290 /** 6291 * xmlValidateRoot: 6292 * @ctxt: the validation context 6293 * @doc: a document instance 6294 * 6295 * Try to validate a the root element 6296 * basically it does the following check as described by the 6297 * XML-1.0 recommendation: 6298 * - [ VC: Root Element Type ] 6299 * it doesn't try to recurse or apply other check to the element 6300 * 6301 * returns 1 if valid or 0 otherwise 6302 */ 6303 6304 int 6305 xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) { 6306 xmlNodePtr root; 6307 int ret; 6308 6309 if (doc == NULL) return(0); 6310 6311 root = xmlDocGetRootElement(doc); 6312 if ((root == NULL) || (root->name == NULL)) { 6313 xmlErrValid(ctxt, XML_DTD_NO_ROOT, 6314 "no root element\n", NULL); 6315 return(0); 6316 } 6317 6318 /* 6319 * When doing post validation against a separate DTD, those may 6320 * no internal subset has been generated 6321 */ 6322 if ((doc->intSubset != NULL) && 6323 (doc->intSubset->name != NULL)) { 6324 /* 6325 * Check first the document root against the NQName 6326 */ 6327 if (!xmlStrEqual(doc->intSubset->name, root->name)) { 6328 if ((root->ns != NULL) && (root->ns->prefix != NULL)) { 6329 xmlChar fn[50]; 6330 xmlChar *fullname; 6331 6332 fullname = xmlBuildQName(root->name, root->ns->prefix, fn, 50); 6333 if (fullname == NULL) { 6334 xmlVErrMemory(ctxt, NULL); 6335 return(0); 6336 } 6337 ret = xmlStrEqual(doc->intSubset->name, fullname); 6338 if ((fullname != fn) && (fullname != root->name)) 6339 xmlFree(fullname); 6340 if (ret == 1) 6341 goto name_ok; 6342 } 6343 if ((xmlStrEqual(doc->intSubset->name, BAD_CAST "HTML")) && 6344 (xmlStrEqual(root->name, BAD_CAST "html"))) 6345 goto name_ok; 6346 xmlErrValidNode(ctxt, root, XML_DTD_ROOT_NAME, 6347 "root and DTD name do not match '%s' and '%s'\n", 6348 root->name, doc->intSubset->name, NULL); 6349 return(0); 6350 } 6351 } 6352 name_ok: 6353 return(1); 6354 } 6355 6356 6357 /** 6358 * xmlValidateElement: 6359 * @ctxt: the validation context 6360 * @doc: a document instance 6361 * @elem: an element instance 6362 * 6363 * Try to validate the subtree under an element 6364 * 6365 * returns 1 if valid or 0 otherwise 6366 */ 6367 6368 int 6369 xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) { 6370 xmlNodePtr child; 6371 xmlAttrPtr attr; 6372 xmlNsPtr ns; 6373 const xmlChar *value; 6374 int ret = 1; 6375 6376 if (elem == NULL) return(0); 6377 6378 /* 6379 * XInclude elements were added after parsing in the infoset, 6380 * they don't really mean anything validation wise. 6381 */ 6382 if ((elem->type == XML_XINCLUDE_START) || 6383 (elem->type == XML_XINCLUDE_END) || 6384 (elem->type == XML_NAMESPACE_DECL)) 6385 return(1); 6386 6387 CHECK_DTD; 6388 6389 /* 6390 * Entities references have to be handled separately 6391 */ 6392 if (elem->type == XML_ENTITY_REF_NODE) { 6393 return(1); 6394 } 6395 6396 ret &= xmlValidateOneElement(ctxt, doc, elem); 6397 if (elem->type == XML_ELEMENT_NODE) { 6398 attr = elem->properties; 6399 while (attr != NULL) { 6400 value = xmlNodeListGetString(doc, attr->children, 0); 6401 ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value); 6402 if (value != NULL) 6403 xmlFree((char *)value); 6404 attr= attr->next; 6405 } 6406 ns = elem->nsDef; 6407 while (ns != NULL) { 6408 if (elem->ns == NULL) 6409 ret &= xmlValidateOneNamespace(ctxt, doc, elem, NULL, 6410 ns, ns->href); 6411 else 6412 ret &= xmlValidateOneNamespace(ctxt, doc, elem, 6413 elem->ns->prefix, ns, ns->href); 6414 ns = ns->next; 6415 } 6416 } 6417 child = elem->children; 6418 while (child != NULL) { 6419 ret &= xmlValidateElement(ctxt, doc, child); 6420 child = child->next; 6421 } 6422 6423 return(ret); 6424 } 6425 6426 /** 6427 * xmlValidateRef: 6428 * @ref: A reference to be validated 6429 * @ctxt: Validation context 6430 * @name: Name of ID we are searching for 6431 * 6432 */ 6433 static void 6434 xmlValidateRef(xmlRefPtr ref, xmlValidCtxtPtr ctxt, 6435 const xmlChar *name) { 6436 xmlAttrPtr id; 6437 xmlAttrPtr attr; 6438 6439 if (ref == NULL) 6440 return; 6441 if ((ref->attr == NULL) && (ref->name == NULL)) 6442 return; 6443 attr = ref->attr; 6444 if (attr == NULL) { 6445 xmlChar *dup, *str = NULL, *cur, save; 6446 6447 dup = xmlStrdup(name); 6448 if (dup == NULL) { 6449 ctxt->valid = 0; 6450 return; 6451 } 6452 cur = dup; 6453 while (*cur != 0) { 6454 str = cur; 6455 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++; 6456 save = *cur; 6457 *cur = 0; 6458 id = xmlGetID(ctxt->doc, str); 6459 if (id == NULL) { 6460 xmlErrValidNodeNr(ctxt, NULL, XML_DTD_UNKNOWN_ID, 6461 "attribute %s line %d references an unknown ID \"%s\"\n", 6462 ref->name, ref->lineno, str); 6463 ctxt->valid = 0; 6464 } 6465 if (save == 0) 6466 break; 6467 *cur = save; 6468 while (IS_BLANK_CH(*cur)) cur++; 6469 } 6470 xmlFree(dup); 6471 } else if (attr->atype == XML_ATTRIBUTE_IDREF) { 6472 id = xmlGetID(ctxt->doc, name); 6473 if (id == NULL) { 6474 xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID, 6475 "IDREF attribute %s references an unknown ID \"%s\"\n", 6476 attr->name, name, NULL); 6477 ctxt->valid = 0; 6478 } 6479 } else if (attr->atype == XML_ATTRIBUTE_IDREFS) { 6480 xmlChar *dup, *str = NULL, *cur, save; 6481 6482 dup = xmlStrdup(name); 6483 if (dup == NULL) { 6484 xmlVErrMemory(ctxt, "IDREFS split"); 6485 ctxt->valid = 0; 6486 return; 6487 } 6488 cur = dup; 6489 while (*cur != 0) { 6490 str = cur; 6491 while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++; 6492 save = *cur; 6493 *cur = 0; 6494 id = xmlGetID(ctxt->doc, str); 6495 if (id == NULL) { 6496 xmlErrValidNode(ctxt, attr->parent, XML_DTD_UNKNOWN_ID, 6497 "IDREFS attribute %s references an unknown ID \"%s\"\n", 6498 attr->name, str, NULL); 6499 ctxt->valid = 0; 6500 } 6501 if (save == 0) 6502 break; 6503 *cur = save; 6504 while (IS_BLANK_CH(*cur)) cur++; 6505 } 6506 xmlFree(dup); 6507 } 6508 } 6509 6510 /** 6511 * xmlWalkValidateList: 6512 * @data: Contents of current link 6513 * @user: Value supplied by the user 6514 * 6515 * Returns 0 to abort the walk or 1 to continue 6516 */ 6517 static int 6518 xmlWalkValidateList(const void *data, const void *user) 6519 { 6520 xmlValidateMemoPtr memo = (xmlValidateMemoPtr)user; 6521 xmlValidateRef((xmlRefPtr)data, memo->ctxt, memo->name); 6522 return 1; 6523 } 6524 6525 /** 6526 * xmlValidateCheckRefCallback: 6527 * @ref_list: List of references 6528 * @ctxt: Validation context 6529 * @name: Name of ID we are searching for 6530 * 6531 */ 6532 static void 6533 xmlValidateCheckRefCallback(xmlListPtr ref_list, xmlValidCtxtPtr ctxt, 6534 const xmlChar *name) { 6535 xmlValidateMemo memo; 6536 6537 if (ref_list == NULL) 6538 return; 6539 memo.ctxt = ctxt; 6540 memo.name = name; 6541 6542 xmlListWalk(ref_list, xmlWalkValidateList, &memo); 6543 6544 } 6545 6546 /** 6547 * xmlValidateDocumentFinal: 6548 * @ctxt: the validation context 6549 * @doc: a document instance 6550 * 6551 * Does the final step for the document validation once all the 6552 * incremental validation steps have been completed 6553 * 6554 * basically it does the following checks described by the XML Rec 6555 * 6556 * Check all the IDREF/IDREFS attributes definition for validity 6557 * 6558 * returns 1 if valid or 0 otherwise 6559 */ 6560 6561 int 6562 xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) { 6563 xmlRefTablePtr table; 6564 unsigned int save; 6565 6566 if (ctxt == NULL) 6567 return(0); 6568 if (doc == NULL) { 6569 xmlErrValid(ctxt, XML_DTD_NO_DOC, 6570 "xmlValidateDocumentFinal: doc == NULL\n", NULL); 6571 return(0); 6572 } 6573 6574 /* trick to get correct line id report */ 6575 save = ctxt->finishDtd; 6576 ctxt->finishDtd = 0; 6577 6578 /* 6579 * Check all the NOTATION/NOTATIONS attributes 6580 */ 6581 /* 6582 * Check all the ENTITY/ENTITIES attributes definition for validity 6583 */ 6584 /* 6585 * Check all the IDREF/IDREFS attributes definition for validity 6586 */ 6587 table = (xmlRefTablePtr) doc->refs; 6588 ctxt->doc = doc; 6589 ctxt->valid = 1; 6590 xmlHashScan(table, (xmlHashScanner) xmlValidateCheckRefCallback, ctxt); 6591 6592 ctxt->finishDtd = save; 6593 return(ctxt->valid); 6594 } 6595 6596 /** 6597 * xmlValidateDtd: 6598 * @ctxt: the validation context 6599 * @doc: a document instance 6600 * @dtd: a dtd instance 6601 * 6602 * Try to validate the document against the dtd instance 6603 * 6604 * Basically it does check all the definitions in the DtD. 6605 * Note the the internal subset (if present) is de-coupled 6606 * (i.e. not used), which could give problems if ID or IDREF 6607 * is present. 6608 * 6609 * returns 1 if valid or 0 otherwise 6610 */ 6611 6612 int 6613 xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) { 6614 int ret; 6615 xmlDtdPtr oldExt, oldInt; 6616 xmlNodePtr root; 6617 6618 if (dtd == NULL) return(0); 6619 if (doc == NULL) return(0); 6620 oldExt = doc->extSubset; 6621 oldInt = doc->intSubset; 6622 doc->extSubset = dtd; 6623 doc->intSubset = NULL; 6624 ret = xmlValidateRoot(ctxt, doc); 6625 if (ret == 0) { 6626 doc->extSubset = oldExt; 6627 doc->intSubset = oldInt; 6628 return(ret); 6629 } 6630 if (doc->ids != NULL) { 6631 xmlFreeIDTable(doc->ids); 6632 doc->ids = NULL; 6633 } 6634 if (doc->refs != NULL) { 6635 xmlFreeRefTable(doc->refs); 6636 doc->refs = NULL; 6637 } 6638 root = xmlDocGetRootElement(doc); 6639 ret = xmlValidateElement(ctxt, doc, root); 6640 ret &= xmlValidateDocumentFinal(ctxt, doc); 6641 doc->extSubset = oldExt; 6642 doc->intSubset = oldInt; 6643 return(ret); 6644 } 6645 6646 static void 6647 xmlValidateNotationCallback(xmlEntityPtr cur, xmlValidCtxtPtr ctxt, 6648 const xmlChar *name ATTRIBUTE_UNUSED) { 6649 if (cur == NULL) 6650 return; 6651 if (cur->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) { 6652 xmlChar *notation = cur->content; 6653 6654 if (notation != NULL) { 6655 int ret; 6656 6657 ret = xmlValidateNotationUse(ctxt, cur->doc, notation); 6658 if (ret != 1) { 6659 ctxt->valid = 0; 6660 } 6661 } 6662 } 6663 } 6664 6665 static void 6666 xmlValidateAttributeCallback(xmlAttributePtr cur, xmlValidCtxtPtr ctxt, 6667 const xmlChar *name ATTRIBUTE_UNUSED) { 6668 int ret; 6669 xmlDocPtr doc; 6670 xmlElementPtr elem = NULL; 6671 6672 if (cur == NULL) 6673 return; 6674 switch (cur->atype) { 6675 case XML_ATTRIBUTE_CDATA: 6676 case XML_ATTRIBUTE_ID: 6677 case XML_ATTRIBUTE_IDREF : 6678 case XML_ATTRIBUTE_IDREFS: 6679 case XML_ATTRIBUTE_NMTOKEN: 6680 case XML_ATTRIBUTE_NMTOKENS: 6681 case XML_ATTRIBUTE_ENUMERATION: 6682 break; 6683 case XML_ATTRIBUTE_ENTITY: 6684 case XML_ATTRIBUTE_ENTITIES: 6685 case XML_ATTRIBUTE_NOTATION: 6686 if (cur->defaultValue != NULL) { 6687 6688 ret = xmlValidateAttributeValue2(ctxt, ctxt->doc, cur->name, 6689 cur->atype, cur->defaultValue); 6690 if ((ret == 0) && (ctxt->valid == 1)) 6691 ctxt->valid = 0; 6692 } 6693 if (cur->tree != NULL) { 6694 xmlEnumerationPtr tree = cur->tree; 6695 while (tree != NULL) { 6696 ret = xmlValidateAttributeValue2(ctxt, ctxt->doc, 6697 cur->name, cur->atype, tree->name); 6698 if ((ret == 0) && (ctxt->valid == 1)) 6699 ctxt->valid = 0; 6700 tree = tree->next; 6701 } 6702 } 6703 } 6704 if (cur->atype == XML_ATTRIBUTE_NOTATION) { 6705 doc = cur->doc; 6706 if (cur->elem == NULL) { 6707 xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR, 6708 "xmlValidateAttributeCallback(%s): internal error\n", 6709 (const char *) cur->name); 6710 return; 6711 } 6712 6713 if (doc != NULL) 6714 elem = xmlGetDtdElementDesc(doc->intSubset, cur->elem); 6715 if ((elem == NULL) && (doc != NULL)) 6716 elem = xmlGetDtdElementDesc(doc->extSubset, cur->elem); 6717 if ((elem == NULL) && (cur->parent != NULL) && 6718 (cur->parent->type == XML_DTD_NODE)) 6719 elem = xmlGetDtdElementDesc((xmlDtdPtr) cur->parent, cur->elem); 6720 if (elem == NULL) { 6721 xmlErrValidNode(ctxt, NULL, XML_DTD_UNKNOWN_ELEM, 6722 "attribute %s: could not find decl for element %s\n", 6723 cur->name, cur->elem, NULL); 6724 return; 6725 } 6726 if (elem->etype == XML_ELEMENT_TYPE_EMPTY) { 6727 xmlErrValidNode(ctxt, NULL, XML_DTD_EMPTY_NOTATION, 6728 "NOTATION attribute %s declared for EMPTY element %s\n", 6729 cur->name, cur->elem, NULL); 6730 ctxt->valid = 0; 6731 } 6732 } 6733 } 6734 6735 /** 6736 * xmlValidateDtdFinal: 6737 * @ctxt: the validation context 6738 * @doc: a document instance 6739 * 6740 * Does the final step for the dtds validation once all the 6741 * subsets have been parsed 6742 * 6743 * basically it does the following checks described by the XML Rec 6744 * - check that ENTITY and ENTITIES type attributes default or 6745 * possible values matches one of the defined entities. 6746 * - check that NOTATION type attributes default or 6747 * possible values matches one of the defined notations. 6748 * 6749 * returns 1 if valid or 0 if invalid and -1 if not well-formed 6750 */ 6751 6752 int 6753 xmlValidateDtdFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) { 6754 xmlDtdPtr dtd; 6755 xmlAttributeTablePtr table; 6756 xmlEntitiesTablePtr entities; 6757 6758 if ((doc == NULL) || (ctxt == NULL)) return(0); 6759 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) 6760 return(0); 6761 ctxt->doc = doc; 6762 ctxt->valid = 1; 6763 dtd = doc->intSubset; 6764 if ((dtd != NULL) && (dtd->attributes != NULL)) { 6765 table = (xmlAttributeTablePtr) dtd->attributes; 6766 xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt); 6767 } 6768 if ((dtd != NULL) && (dtd->entities != NULL)) { 6769 entities = (xmlEntitiesTablePtr) dtd->entities; 6770 xmlHashScan(entities, (xmlHashScanner) xmlValidateNotationCallback, 6771 ctxt); 6772 } 6773 dtd = doc->extSubset; 6774 if ((dtd != NULL) && (dtd->attributes != NULL)) { 6775 table = (xmlAttributeTablePtr) dtd->attributes; 6776 xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt); 6777 } 6778 if ((dtd != NULL) && (dtd->entities != NULL)) { 6779 entities = (xmlEntitiesTablePtr) dtd->entities; 6780 xmlHashScan(entities, (xmlHashScanner) xmlValidateNotationCallback, 6781 ctxt); 6782 } 6783 return(ctxt->valid); 6784 } 6785 6786 /** 6787 * xmlValidateDocument: 6788 * @ctxt: the validation context 6789 * @doc: a document instance 6790 * 6791 * Try to validate the document instance 6792 * 6793 * basically it does the all the checks described by the XML Rec 6794 * i.e. validates the internal and external subset (if present) 6795 * and validate the document tree. 6796 * 6797 * returns 1 if valid or 0 otherwise 6798 */ 6799 6800 int 6801 xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) { 6802 int ret; 6803 xmlNodePtr root; 6804 6805 if (doc == NULL) 6806 return(0); 6807 if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) { 6808 xmlErrValid(ctxt, XML_DTD_NO_DTD, 6809 "no DTD found!\n", NULL); 6810 return(0); 6811 } 6812 if ((doc->intSubset != NULL) && ((doc->intSubset->SystemID != NULL) || 6813 (doc->intSubset->ExternalID != NULL)) && (doc->extSubset == NULL)) { 6814 xmlChar *sysID; 6815 if (doc->intSubset->SystemID != NULL) { 6816 sysID = xmlBuildURI(doc->intSubset->SystemID, 6817 doc->URL); 6818 if (sysID == NULL) { 6819 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR, 6820 "Could not build URI for external subset \"%s\"\n", 6821 (const char *) doc->intSubset->SystemID); 6822 return 0; 6823 } 6824 } else 6825 sysID = NULL; 6826 doc->extSubset = xmlParseDTD(doc->intSubset->ExternalID, 6827 (const xmlChar *)sysID); 6828 if (sysID != NULL) 6829 xmlFree(sysID); 6830 if (doc->extSubset == NULL) { 6831 if (doc->intSubset->SystemID != NULL) { 6832 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR, 6833 "Could not load the external subset \"%s\"\n", 6834 (const char *) doc->intSubset->SystemID); 6835 } else { 6836 xmlErrValid(ctxt, XML_DTD_LOAD_ERROR, 6837 "Could not load the external subset \"%s\"\n", 6838 (const char *) doc->intSubset->ExternalID); 6839 } 6840 return(0); 6841 } 6842 } 6843 6844 if (doc->ids != NULL) { 6845 xmlFreeIDTable(doc->ids); 6846 doc->ids = NULL; 6847 } 6848 if (doc->refs != NULL) { 6849 xmlFreeRefTable(doc->refs); 6850 doc->refs = NULL; 6851 } 6852 ret = xmlValidateDtdFinal(ctxt, doc); 6853 if (!xmlValidateRoot(ctxt, doc)) return(0); 6854 6855 root = xmlDocGetRootElement(doc); 6856 ret &= xmlValidateElement(ctxt, doc, root); 6857 ret &= xmlValidateDocumentFinal(ctxt, doc); 6858 return(ret); 6859 } 6860 6861 /************************************************************************ 6862 * * 6863 * Routines for dynamic validation editing * 6864 * * 6865 ************************************************************************/ 6866 6867 /** 6868 * xmlValidGetPotentialChildren: 6869 * @ctree: an element content tree 6870 * @names: an array to store the list of child names 6871 * @len: a pointer to the number of element in the list 6872 * @max: the size of the array 6873 * 6874 * Build/extend a list of potential children allowed by the content tree 6875 * 6876 * returns the number of element in the list, or -1 in case of error. 6877 */ 6878 6879 int 6880 xmlValidGetPotentialChildren(xmlElementContent *ctree, 6881 const xmlChar **names, 6882 int *len, int max) { 6883 int i; 6884 6885 if ((ctree == NULL) || (names == NULL) || (len == NULL)) 6886 return(-1); 6887 if (*len >= max) return(*len); 6888 6889 switch (ctree->type) { 6890 case XML_ELEMENT_CONTENT_PCDATA: 6891 for (i = 0; i < *len;i++) 6892 if (xmlStrEqual(BAD_CAST "#PCDATA", names[i])) return(*len); 6893 names[(*len)++] = BAD_CAST "#PCDATA"; 6894 break; 6895 case XML_ELEMENT_CONTENT_ELEMENT: 6896 for (i = 0; i < *len;i++) 6897 if (xmlStrEqual(ctree->name, names[i])) return(*len); 6898 names[(*len)++] = ctree->name; 6899 break; 6900 case XML_ELEMENT_CONTENT_SEQ: 6901 xmlValidGetPotentialChildren(ctree->c1, names, len, max); 6902 xmlValidGetPotentialChildren(ctree->c2, names, len, max); 6903 break; 6904 case XML_ELEMENT_CONTENT_OR: 6905 xmlValidGetPotentialChildren(ctree->c1, names, len, max); 6906 xmlValidGetPotentialChildren(ctree->c2, names, len, max); 6907 break; 6908 } 6909 6910 return(*len); 6911 } 6912 6913 /* 6914 * Dummy function to suppress messages while we try out valid elements 6915 */ 6916 static void XMLCDECL xmlNoValidityErr(void *ctx ATTRIBUTE_UNUSED, 6917 const char *msg ATTRIBUTE_UNUSED, ...) { 6918 return; 6919 } 6920 6921 /** 6922 * xmlValidGetValidElements: 6923 * @prev: an element to insert after 6924 * @next: an element to insert next 6925 * @names: an array to store the list of child names 6926 * @max: the size of the array 6927 * 6928 * This function returns the list of authorized children to insert 6929 * within an existing tree while respecting the validity constraints 6930 * forced by the Dtd. The insertion point is defined using @prev and 6931 * @next in the following ways: 6932 * to insert before 'node': xmlValidGetValidElements(node->prev, node, ... 6933 * to insert next 'node': xmlValidGetValidElements(node, node->next, ... 6934 * to replace 'node': xmlValidGetValidElements(node->prev, node->next, ... 6935 * to prepend a child to 'node': xmlValidGetValidElements(NULL, node->childs, 6936 * to append a child to 'node': xmlValidGetValidElements(node->last, NULL, ... 6937 * 6938 * pointers to the element names are inserted at the beginning of the array 6939 * and do not need to be freed. 6940 * 6941 * returns the number of element in the list, or -1 in case of error. If 6942 * the function returns the value @max the caller is invited to grow the 6943 * receiving array and retry. 6944 */ 6945 6946 int 6947 xmlValidGetValidElements(xmlNode *prev, xmlNode *next, const xmlChar **names, 6948 int max) { 6949 xmlValidCtxt vctxt; 6950 int nb_valid_elements = 0; 6951 const xmlChar *elements[256]; 6952 int nb_elements = 0, i; 6953 const xmlChar *name; 6954 6955 xmlNode *ref_node; 6956 xmlNode *parent; 6957 xmlNode *test_node; 6958 6959 xmlNode *prev_next; 6960 xmlNode *next_prev; 6961 xmlNode *parent_childs; 6962 xmlNode *parent_last; 6963 6964 xmlElement *element_desc; 6965 6966 if (prev == NULL && next == NULL) 6967 return(-1); 6968 6969 if (names == NULL) return(-1); 6970 if (max <= 0) return(-1); 6971 6972 memset(&vctxt, 0, sizeof (xmlValidCtxt)); 6973 vctxt.error = xmlNoValidityErr; /* this suppresses err/warn output */ 6974 6975 nb_valid_elements = 0; 6976 ref_node = prev ? prev : next; 6977 parent = ref_node->parent; 6978 6979 /* 6980 * Retrieves the parent element declaration 6981 */ 6982 element_desc = xmlGetDtdElementDesc(parent->doc->intSubset, 6983 parent->name); 6984 if ((element_desc == NULL) && (parent->doc->extSubset != NULL)) 6985 element_desc = xmlGetDtdElementDesc(parent->doc->extSubset, 6986 parent->name); 6987 if (element_desc == NULL) return(-1); 6988 6989 /* 6990 * Do a backup of the current tree structure 6991 */ 6992 prev_next = prev ? prev->next : NULL; 6993 next_prev = next ? next->prev : NULL; 6994 parent_childs = parent->children; 6995 parent_last = parent->last; 6996 6997 /* 6998 * Creates a dummy node and insert it into the tree 6999 */ 7000 test_node = xmlNewDocNode (ref_node->doc, NULL, BAD_CAST "<!dummy?>", NULL); 7001 test_node->parent = parent; 7002 test_node->prev = prev; 7003 test_node->next = next; 7004 name = test_node->name; 7005 7006 if (prev) prev->next = test_node; 7007 else parent->children = test_node; 7008 7009 if (next) next->prev = test_node; 7010 else parent->last = test_node; 7011 7012 /* 7013 * Insert each potential child node and check if the parent is 7014 * still valid 7015 */ 7016 nb_elements = xmlValidGetPotentialChildren(element_desc->content, 7017 elements, &nb_elements, 256); 7018 7019 for (i = 0;i < nb_elements;i++) { 7020 test_node->name = elements[i]; 7021 if (xmlValidateOneElement(&vctxt, parent->doc, parent)) { 7022 int j; 7023 7024 for (j = 0; j < nb_valid_elements;j++) 7025 if (xmlStrEqual(elements[i], names[j])) break; 7026 names[nb_valid_elements++] = elements[i]; 7027 if (nb_valid_elements >= max) break; 7028 } 7029 } 7030 7031 /* 7032 * Restore the tree structure 7033 */ 7034 if (prev) prev->next = prev_next; 7035 if (next) next->prev = next_prev; 7036 parent->children = parent_childs; 7037 parent->last = parent_last; 7038 7039 /* 7040 * Free up the dummy node 7041 */ 7042 test_node->name = name; 7043 xmlFreeNode(test_node); 7044 7045 return(nb_valid_elements); 7046 } 7047 #endif /* LIBXML_VALID_ENABLED */ 7048 7049 #define bottom_valid 7050 #include "elfgcchack.h" 7051