xinclude.c
1 /* 2 * xinclude.c : Code to implement XInclude processing 3 * 4 * World Wide Web Consortium W3C Last Call Working Draft 10 November 2003 5 * http://www.w3.org/TR/2003/WD-xinclude-20031110 6 * 7 * See Copyright for the status of this software. 8 * 9 * daniel@veillard.com 10 */ 11 12 #define IN_LIBXML 13 #include "libxml.h" 14 15 #include <string.h> 16 #include <libxml/xmlmemory.h> 17 #include <libxml/tree.h> 18 #include <libxml/parser.h> 19 #include <libxml/uri.h> 20 #include <libxml/xpath.h> 21 #include <libxml/xpointer.h> 22 #include <libxml/parserInternals.h> 23 #include <libxml/xmlerror.h> 24 #include <libxml/encoding.h> 25 #include <libxml/globals.h> 26 27 #ifdef LIBXML_XINCLUDE_ENABLED 28 #include <libxml/xinclude.h> 29 30 #include "buf.h" 31 32 #define XINCLUDE_MAX_DEPTH 40 33 34 /* #define DEBUG_XINCLUDE */ 35 #ifdef DEBUG_XINCLUDE 36 #ifdef LIBXML_DEBUG_ENABLED 37 #include <libxml/debugXML.h> 38 #endif 39 #endif 40 41 /************************************************************************ 42 * * 43 * XInclude context handling * 44 * * 45 ************************************************************************/ 46 47 /* 48 * An XInclude context 49 */ 50 typedef xmlChar *xmlURL; 51 52 typedef struct _xmlXIncludeRef xmlXIncludeRef; 53 typedef xmlXIncludeRef *xmlXIncludeRefPtr; 54 struct _xmlXIncludeRef { 55 xmlChar *URI; /* the fully resolved resource URL */ 56 xmlChar *fragment; /* the fragment in the URI */ 57 xmlDocPtr doc; /* the parsed document */ 58 xmlNodePtr ref; /* the node making the reference in the source */ 59 xmlNodePtr inc; /* the included copy */ 60 int xml; /* xml or txt */ 61 int count; /* how many refs use that specific doc */ 62 xmlXPathObjectPtr xptr; /* the xpointer if needed */ 63 int emptyFb; /* flag to show fallback empty */ 64 }; 65 66 struct _xmlXIncludeCtxt { 67 xmlDocPtr doc; /* the source document */ 68 int incBase; /* the first include for this document */ 69 int incNr; /* number of includes */ 70 int incMax; /* size of includes tab */ 71 xmlXIncludeRefPtr *incTab; /* array of included references */ 72 73 int txtNr; /* number of unparsed documents */ 74 int txtMax; /* size of unparsed documents tab */ 75 xmlChar * *txtTab; /* array of unparsed text strings */ 76 xmlURL *txturlTab; /* array of unparsed text URLs */ 77 78 xmlChar * url; /* the current URL processed */ 79 int urlNr; /* number of URLs stacked */ 80 int urlMax; /* size of URL stack */ 81 xmlChar * *urlTab; /* URL stack */ 82 83 int nbErrors; /* the number of errors detected */ 84 int legacy; /* using XINCLUDE_OLD_NS */ 85 int parseFlags; /* the flags used for parsing XML documents */ 86 xmlChar * base; /* the current xml:base */ 87 88 void *_private; /* application data */ 89 }; 90 91 static int 92 xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr tree); 93 94 95 /************************************************************************ 96 * * 97 * XInclude error handler * 98 * * 99 ************************************************************************/ 100 101 /** 102 * xmlXIncludeErrMemory: 103 * @extra: extra information 104 * 105 * Handle an out of memory condition 106 */ 107 static void 108 xmlXIncludeErrMemory(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node, 109 const char *extra) 110 { 111 if (ctxt != NULL) 112 ctxt->nbErrors++; 113 __xmlRaiseError(NULL, NULL, NULL, ctxt, node, XML_FROM_XINCLUDE, 114 XML_ERR_NO_MEMORY, XML_ERR_ERROR, NULL, 0, 115 extra, NULL, NULL, 0, 0, 116 "Memory allocation failed : %s\n", extra); 117 } 118 119 /** 120 * xmlXIncludeErr: 121 * @ctxt: the XInclude context 122 * @node: the context node 123 * @msg: the error message 124 * @extra: extra information 125 * 126 * Handle an XInclude error 127 */ 128 static void LIBXML_ATTR_FORMAT(4,0) 129 xmlXIncludeErr(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node, int error, 130 const char *msg, const xmlChar *extra) 131 { 132 if (ctxt != NULL) 133 ctxt->nbErrors++; 134 #pragma clang diagnostic push 135 #pragma clang diagnostic ignored "-Wformat-nonliteral" 136 __xmlRaiseError(NULL, NULL, NULL, ctxt, node, XML_FROM_XINCLUDE, 137 error, XML_ERR_ERROR, NULL, 0, 138 (const char *) extra, NULL, NULL, 0, 0, 139 msg, (const char *) extra); 140 #pragma clang diagnostic pop 141 } 142 143 #if 0 144 /** 145 * xmlXIncludeWarn: 146 * @ctxt: the XInclude context 147 * @node: the context node 148 * @msg: the error message 149 * @extra: extra information 150 * 151 * Emit an XInclude warning. 152 */ 153 static void LIBXML_ATTR_FORMAT(4,0) 154 xmlXIncludeWarn(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node, int error, 155 const char *msg, const xmlChar *extra) 156 { 157 __xmlRaiseError(NULL, NULL, NULL, ctxt, node, XML_FROM_XINCLUDE, 158 error, XML_ERR_WARNING, NULL, 0, 159 (const char *) extra, NULL, NULL, 0, 0, 160 msg, (const char *) extra); 161 } 162 #endif 163 164 /** 165 * xmlXIncludeGetProp: 166 * @ctxt: the XInclude context 167 * @cur: the node 168 * @name: the attribute name 169 * 170 * Get an XInclude attribute 171 * 172 * Returns the value (to be freed) or NULL if not found 173 */ 174 static xmlChar * 175 xmlXIncludeGetProp(xmlXIncludeCtxtPtr ctxt, xmlNodePtr cur, 176 const xmlChar *name) { 177 xmlChar *ret; 178 179 ret = xmlGetNsProp(cur, XINCLUDE_NS, name); 180 if (ret != NULL) 181 return(ret); 182 if (ctxt->legacy != 0) { 183 ret = xmlGetNsProp(cur, XINCLUDE_OLD_NS, name); 184 if (ret != NULL) 185 return(ret); 186 } 187 ret = xmlGetProp(cur, name); 188 return(ret); 189 } 190 /** 191 * xmlXIncludeFreeRef: 192 * @ref: the XInclude reference 193 * 194 * Free an XInclude reference 195 */ 196 static void 197 xmlXIncludeFreeRef(xmlXIncludeRefPtr ref) { 198 if (ref == NULL) 199 return; 200 #ifdef DEBUG_XINCLUDE 201 xmlGenericError(xmlGenericErrorContext, "Freeing ref\n"); 202 #endif 203 if (ref->doc != NULL) { 204 #ifdef DEBUG_XINCLUDE 205 xmlGenericError(xmlGenericErrorContext, "Freeing doc %s\n", ref->URI); 206 #endif 207 xmlFreeDoc(ref->doc); 208 } 209 if (ref->URI != NULL) 210 xmlFree(ref->URI); 211 if (ref->fragment != NULL) 212 xmlFree(ref->fragment); 213 if (ref->xptr != NULL) 214 xmlXPathFreeObject(ref->xptr); 215 xmlFree(ref); 216 } 217 218 /** 219 * xmlXIncludeNewRef: 220 * @ctxt: the XInclude context 221 * @URI: the resource URI 222 * 223 * Creates a new reference within an XInclude context 224 * 225 * Returns the new set 226 */ 227 static xmlXIncludeRefPtr 228 xmlXIncludeNewRef(xmlXIncludeCtxtPtr ctxt, const xmlChar *URI, 229 xmlNodePtr ref) { 230 xmlXIncludeRefPtr ret; 231 232 #ifdef DEBUG_XINCLUDE 233 xmlGenericError(xmlGenericErrorContext, "New ref %s\n", URI); 234 #endif 235 ret = (xmlXIncludeRefPtr) xmlMalloc(sizeof(xmlXIncludeRef)); 236 if (ret == NULL) { 237 xmlXIncludeErrMemory(ctxt, ref, "growing XInclude context"); 238 return(NULL); 239 } 240 memset(ret, 0, sizeof(xmlXIncludeRef)); 241 if (URI == NULL) 242 ret->URI = NULL; 243 else 244 ret->URI = xmlStrdup(URI); 245 ret->fragment = NULL; 246 ret->ref = ref; 247 ret->doc = NULL; 248 ret->count = 0; 249 ret->xml = 0; 250 ret->inc = NULL; 251 if (ctxt->incMax == 0) { 252 ctxt->incMax = 4; 253 ctxt->incTab = (xmlXIncludeRefPtr *) xmlMalloc(ctxt->incMax * 254 sizeof(ctxt->incTab[0])); 255 if (ctxt->incTab == NULL) { 256 xmlXIncludeErrMemory(ctxt, ref, "growing XInclude context"); 257 xmlXIncludeFreeRef(ret); 258 return(NULL); 259 } 260 } 261 if (ctxt->incNr >= ctxt->incMax) { 262 ctxt->incMax *= 2; 263 ctxt->incTab = (xmlXIncludeRefPtr *) xmlRealloc(ctxt->incTab, 264 ctxt->incMax * sizeof(ctxt->incTab[0])); 265 if (ctxt->incTab == NULL) { 266 xmlXIncludeErrMemory(ctxt, ref, "growing XInclude context"); 267 xmlXIncludeFreeRef(ret); 268 return(NULL); 269 } 270 } 271 ctxt->incTab[ctxt->incNr++] = ret; 272 return(ret); 273 } 274 275 /** 276 * xmlXIncludeNewContext: 277 * @doc: an XML Document 278 * 279 * Creates a new XInclude context 280 * 281 * Returns the new set 282 */ 283 xmlXIncludeCtxtPtr 284 xmlXIncludeNewContext(xmlDocPtr doc) { 285 xmlXIncludeCtxtPtr ret; 286 287 #ifdef DEBUG_XINCLUDE 288 xmlGenericError(xmlGenericErrorContext, "New context\n"); 289 #endif 290 if (doc == NULL) 291 return(NULL); 292 ret = (xmlXIncludeCtxtPtr) xmlMalloc(sizeof(xmlXIncludeCtxt)); 293 if (ret == NULL) { 294 xmlXIncludeErrMemory(NULL, (xmlNodePtr) doc, 295 "creating XInclude context"); 296 return(NULL); 297 } 298 memset(ret, 0, sizeof(xmlXIncludeCtxt)); 299 ret->doc = doc; 300 ret->incNr = 0; 301 ret->incBase = 0; 302 ret->incMax = 0; 303 ret->incTab = NULL; 304 ret->nbErrors = 0; 305 return(ret); 306 } 307 308 /** 309 * xmlXIncludeURLPush: 310 * @ctxt: the parser context 311 * @value: the url 312 * 313 * Pushes a new url on top of the url stack 314 * 315 * Returns -1 in case of error, the index in the stack otherwise 316 */ 317 static int 318 xmlXIncludeURLPush(xmlXIncludeCtxtPtr ctxt, 319 const xmlChar *value) 320 { 321 if (ctxt->urlNr > XINCLUDE_MAX_DEPTH) { 322 xmlXIncludeErr(ctxt, NULL, XML_XINCLUDE_RECURSION, 323 "detected a recursion in %s\n", value); 324 return(-1); 325 } 326 if (ctxt->urlTab == NULL) { 327 ctxt->urlMax = 4; 328 ctxt->urlNr = 0; 329 ctxt->urlTab = (xmlChar * *) xmlMalloc( 330 ctxt->urlMax * sizeof(ctxt->urlTab[0])); 331 if (ctxt->urlTab == NULL) { 332 xmlXIncludeErrMemory(ctxt, NULL, "adding URL"); 333 return (-1); 334 } 335 } 336 if (ctxt->urlNr >= ctxt->urlMax) { 337 ctxt->urlMax *= 2; 338 ctxt->urlTab = 339 (xmlChar * *) xmlRealloc(ctxt->urlTab, 340 ctxt->urlMax * 341 sizeof(ctxt->urlTab[0])); 342 if (ctxt->urlTab == NULL) { 343 xmlXIncludeErrMemory(ctxt, NULL, "adding URL"); 344 return (-1); 345 } 346 } 347 ctxt->url = ctxt->urlTab[ctxt->urlNr] = xmlStrdup(value); 348 return (ctxt->urlNr++); 349 } 350 351 /** 352 * xmlXIncludeURLPop: 353 * @ctxt: the parser context 354 * 355 * Pops the top URL from the URL stack 356 */ 357 static void 358 xmlXIncludeURLPop(xmlXIncludeCtxtPtr ctxt) 359 { 360 xmlChar * ret; 361 362 if (ctxt->urlNr <= 0) 363 return; 364 ctxt->urlNr--; 365 if (ctxt->urlNr > 0) 366 ctxt->url = ctxt->urlTab[ctxt->urlNr - 1]; 367 else 368 ctxt->url = NULL; 369 ret = ctxt->urlTab[ctxt->urlNr]; 370 ctxt->urlTab[ctxt->urlNr] = NULL; 371 if (ret != NULL) 372 xmlFree(ret); 373 } 374 375 /** 376 * xmlXIncludeFreeContext: 377 * @ctxt: the XInclude context 378 * 379 * Free an XInclude context 380 */ 381 void 382 xmlXIncludeFreeContext(xmlXIncludeCtxtPtr ctxt) { 383 int i; 384 385 #ifdef DEBUG_XINCLUDE 386 xmlGenericError(xmlGenericErrorContext, "Freeing context\n"); 387 #endif 388 if (ctxt == NULL) 389 return; 390 while (ctxt->urlNr > 0) 391 xmlXIncludeURLPop(ctxt); 392 if (ctxt->urlTab != NULL) 393 xmlFree(ctxt->urlTab); 394 for (i = 0;i < ctxt->incNr;i++) { 395 if (ctxt->incTab[i] != NULL) 396 xmlXIncludeFreeRef(ctxt->incTab[i]); 397 } 398 if (ctxt->incTab != NULL) 399 xmlFree(ctxt->incTab); 400 if (ctxt->txtTab != NULL) { 401 for (i = 0;i < ctxt->txtNr;i++) { 402 if (ctxt->txtTab[i] != NULL) 403 xmlFree(ctxt->txtTab[i]); 404 } 405 xmlFree(ctxt->txtTab); 406 } 407 if (ctxt->txturlTab != NULL) { 408 for (i = 0;i < ctxt->txtNr;i++) { 409 if (ctxt->txturlTab[i] != NULL) 410 xmlFree(ctxt->txturlTab[i]); 411 } 412 xmlFree(ctxt->txturlTab); 413 } 414 if (ctxt->base != NULL) { 415 xmlFree(ctxt->base); 416 } 417 xmlFree(ctxt); 418 } 419 420 /** 421 * xmlXIncludeParseFile: 422 * @ctxt: the XInclude context 423 * @URL: the URL or file path 424 * 425 * parse a document for XInclude 426 */ 427 static xmlDocPtr 428 xmlXIncludeParseFile(xmlXIncludeCtxtPtr ctxt, const char *URL) { 429 xmlDocPtr ret; 430 xmlParserCtxtPtr pctxt; 431 xmlParserInputPtr inputStream; 432 433 xmlInitParser(); 434 435 pctxt = xmlNewParserCtxt(); 436 if (pctxt == NULL) { 437 xmlXIncludeErrMemory(ctxt, NULL, "cannot allocate parser context"); 438 return(NULL); 439 } 440 441 /* 442 * pass in the application data to the parser context. 443 */ 444 pctxt->_private = ctxt->_private; 445 446 /* 447 * try to ensure that new documents included are actually 448 * built with the same dictionary as the including document. 449 */ 450 if ((ctxt->doc != NULL) && (ctxt->doc->dict != NULL)) { 451 if (pctxt->dict != NULL) 452 xmlDictFree(pctxt->dict); 453 pctxt->dict = ctxt->doc->dict; 454 xmlDictReference(pctxt->dict); 455 } 456 457 xmlCtxtUseOptions(pctxt, ctxt->parseFlags | XML_PARSE_DTDLOAD); 458 459 inputStream = xmlLoadExternalEntity(URL, NULL, pctxt); 460 if (inputStream == NULL) { 461 xmlFreeParserCtxt(pctxt); 462 return(NULL); 463 } 464 465 inputPush(pctxt, inputStream); 466 467 if (pctxt->directory == NULL) 468 pctxt->directory = xmlParserGetDirectory(URL); 469 470 pctxt->loadsubset |= XML_DETECT_IDS; 471 472 xmlParseDocument(pctxt); 473 474 if (pctxt->wellFormed) { 475 ret = pctxt->myDoc; 476 } 477 else { 478 ret = NULL; 479 if (pctxt->myDoc != NULL) 480 xmlFreeDoc(pctxt->myDoc); 481 pctxt->myDoc = NULL; 482 } 483 xmlFreeParserCtxt(pctxt); 484 485 return(ret); 486 } 487 488 /** 489 * xmlXIncludeAddNode: 490 * @ctxt: the XInclude context 491 * @cur: the new node 492 * 493 * Add a new node to process to an XInclude context 494 */ 495 static int 496 xmlXIncludeAddNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr cur) { 497 xmlXIncludeRefPtr ref; 498 xmlURIPtr uri; 499 xmlChar *URL; 500 xmlChar *fragment = NULL; 501 xmlChar *href; 502 xmlChar *parse; 503 xmlChar *base; 504 xmlChar *URI; 505 int xml = 1, i; /* default Issue 64 */ 506 int local = 0; 507 508 509 if (ctxt == NULL) 510 return(-1); 511 if (cur == NULL) 512 return(-1); 513 514 #ifdef DEBUG_XINCLUDE 515 xmlGenericError(xmlGenericErrorContext, "Add node\n"); 516 #endif 517 /* 518 * read the attributes 519 */ 520 href = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_HREF); 521 if (href == NULL) { 522 href = xmlStrdup(BAD_CAST ""); /* @@@@ href is now optional */ 523 if (href == NULL) 524 return(-1); 525 } 526 if ((href[0] == '#') || (href[0] == 0)) 527 local = 1; 528 parse = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_PARSE); 529 if (parse != NULL) { 530 if (xmlStrEqual(parse, XINCLUDE_PARSE_XML)) 531 xml = 1; 532 else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT)) 533 xml = 0; 534 else { 535 xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_PARSE_VALUE, 536 "invalid value %s for 'parse'\n", parse); 537 if (href != NULL) 538 xmlFree(href); 539 if (parse != NULL) 540 xmlFree(parse); 541 return(-1); 542 } 543 } 544 545 /* 546 * compute the URI 547 */ 548 base = xmlNodeGetBase(ctxt->doc, cur); 549 if (base == NULL) { 550 URI = xmlBuildURI(href, ctxt->doc->URL); 551 } else { 552 URI = xmlBuildURI(href, base); 553 } 554 if (URI == NULL) { 555 xmlChar *escbase; 556 xmlChar *eschref; 557 /* 558 * Some escaping may be needed 559 */ 560 escbase = xmlURIEscape(base); 561 eschref = xmlURIEscape(href); 562 URI = xmlBuildURI(eschref, escbase); 563 if (escbase != NULL) 564 xmlFree(escbase); 565 if (eschref != NULL) 566 xmlFree(eschref); 567 } 568 if (parse != NULL) 569 xmlFree(parse); 570 if (href != NULL) 571 xmlFree(href); 572 if (base != NULL) 573 xmlFree(base); 574 if (URI == NULL) { 575 xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_HREF_URI, 576 "failed build URL\n", NULL); 577 return(-1); 578 } 579 fragment = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_PARSE_XPOINTER); 580 581 /* 582 * Check the URL and remove any fragment identifier 583 */ 584 uri = xmlParseURI((const char *)URI); 585 if (uri == NULL) { 586 xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_HREF_URI, 587 "invalid value URI %s\n", URI); 588 if (fragment != NULL) 589 xmlFree(fragment); 590 xmlFree(URI); 591 return(-1); 592 } 593 594 if (uri->fragment != NULL) { 595 if (ctxt->legacy != 0) { 596 if (fragment == NULL) { 597 fragment = (xmlChar *) uri->fragment; 598 } else { 599 xmlFree(uri->fragment); 600 } 601 } else { 602 xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_FRAGMENT_ID, 603 "Invalid fragment identifier in URI %s use the xpointer attribute\n", 604 URI); 605 if (fragment != NULL) 606 xmlFree(fragment); 607 xmlFreeURI(uri); 608 xmlFree(URI); 609 return(-1); 610 } 611 uri->fragment = NULL; 612 } 613 URL = xmlSaveUri(uri); 614 xmlFreeURI(uri); 615 xmlFree(URI); 616 if (URL == NULL) { 617 xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_HREF_URI, 618 "invalid value URI %s\n", URI); 619 if (fragment != NULL) 620 xmlFree(fragment); 621 return(-1); 622 } 623 624 /* 625 * If local and xml then we need a fragment 626 */ 627 if ((local == 1) && (xml == 1) && 628 ((fragment == NULL) || (fragment[0] == 0))) { 629 xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_RECURSION, 630 "detected a local recursion with no xpointer in %s\n", 631 URL); 632 if (fragment != NULL) 633 xmlFree(fragment); 634 return(-1); 635 } 636 637 /* 638 * Check the URL against the stack for recursions 639 */ 640 if ((!local) && (xml == 1)) { 641 for (i = 0;i < ctxt->urlNr;i++) { 642 if (xmlStrEqual(URL, ctxt->urlTab[i])) { 643 xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_RECURSION, 644 "detected a recursion in %s\n", URL); 645 return(-1); 646 } 647 } 648 } 649 650 ref = xmlXIncludeNewRef(ctxt, URL, cur); 651 if (ref == NULL) { 652 return(-1); 653 } 654 ref->fragment = fragment; 655 ref->doc = NULL; 656 ref->xml = xml; 657 ref->count = 1; 658 xmlFree(URL); 659 return(0); 660 } 661 662 /** 663 * xmlXIncludeRecurseDoc: 664 * @ctxt: the XInclude context 665 * @doc: the new document 666 * @url: the associated URL 667 * 668 * The XInclude recursive nature is handled at this point. 669 */ 670 static void 671 xmlXIncludeRecurseDoc(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, 672 const xmlURL url ATTRIBUTE_UNUSED) { 673 xmlXIncludeCtxtPtr newctxt; 674 int i; 675 676 /* 677 * Avoid recursion in already substitued resources 678 for (i = 0;i < ctxt->urlNr;i++) { 679 if (xmlStrEqual(doc->URL, ctxt->urlTab[i])) 680 return; 681 } 682 */ 683 684 #ifdef DEBUG_XINCLUDE 685 xmlGenericError(xmlGenericErrorContext, "Recursing in doc %s\n", doc->URL); 686 #endif 687 /* 688 * Handle recursion here. 689 */ 690 691 newctxt = xmlXIncludeNewContext(doc); 692 if (newctxt != NULL) { 693 /* 694 * Copy the private user data 695 */ 696 newctxt->_private = ctxt->_private; 697 /* 698 * Copy the existing document set 699 */ 700 newctxt->incMax = ctxt->incMax; 701 newctxt->incNr = ctxt->incNr; 702 newctxt->incTab = (xmlXIncludeRefPtr *) xmlMalloc(newctxt->incMax * 703 sizeof(newctxt->incTab[0])); 704 if (newctxt->incTab == NULL) { 705 xmlXIncludeErrMemory(ctxt, (xmlNodePtr) doc, "processing doc"); 706 xmlFree(newctxt); 707 return; 708 } 709 /* 710 * copy the urlTab 711 */ 712 newctxt->urlMax = ctxt->urlMax; 713 newctxt->urlNr = ctxt->urlNr; 714 newctxt->urlTab = ctxt->urlTab; 715 716 /* 717 * Inherit the existing base 718 */ 719 newctxt->base = xmlStrdup(ctxt->base); 720 721 /* 722 * Inherit the documents already in use by other includes 723 */ 724 newctxt->incBase = ctxt->incNr; 725 for (i = 0;i < ctxt->incNr;i++) { 726 newctxt->incTab[i] = ctxt->incTab[i]; 727 newctxt->incTab[i]->count++; /* prevent the recursion from 728 freeing it */ 729 } 730 /* 731 * The new context should also inherit the Parse Flags 732 * (bug 132597) 733 */ 734 newctxt->parseFlags = ctxt->parseFlags; 735 xmlXIncludeDoProcess(newctxt, doc, xmlDocGetRootElement(doc)); 736 for (i = 0;i < ctxt->incNr;i++) { 737 newctxt->incTab[i]->count--; 738 newctxt->incTab[i] = NULL; 739 } 740 741 /* urlTab may have been reallocated */ 742 ctxt->urlTab = newctxt->urlTab; 743 ctxt->urlMax = newctxt->urlMax; 744 745 newctxt->urlMax = 0; 746 newctxt->urlNr = 0; 747 newctxt->urlTab = NULL; 748 749 xmlXIncludeFreeContext(newctxt); 750 } 751 #ifdef DEBUG_XINCLUDE 752 xmlGenericError(xmlGenericErrorContext, "Done recursing in doc %s\n", url); 753 #endif 754 } 755 756 /** 757 * xmlXIncludeAddTxt: 758 * @ctxt: the XInclude context 759 * @txt: the new text node 760 * @url: the associated URL 761 * 762 * Add a new txtument to the list 763 */ 764 static void 765 xmlXIncludeAddTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *txt, 766 const xmlURL url) { 767 #ifdef DEBUG_XINCLUDE 768 xmlGenericError(xmlGenericErrorContext, "Adding text %s\n", url); 769 #endif 770 if (ctxt->txtMax == 0) { 771 ctxt->txtMax = 4; 772 ctxt->txtTab = (xmlChar **) xmlMalloc(ctxt->txtMax * 773 sizeof(ctxt->txtTab[0])); 774 if (ctxt->txtTab == NULL) { 775 xmlXIncludeErrMemory(ctxt, NULL, "processing text"); 776 return; 777 } 778 ctxt->txturlTab = (xmlURL *) xmlMalloc(ctxt->txtMax * 779 sizeof(ctxt->txturlTab[0])); 780 if (ctxt->txturlTab == NULL) { 781 xmlXIncludeErrMemory(ctxt, NULL, "processing text"); 782 return; 783 } 784 } 785 if (ctxt->txtNr >= ctxt->txtMax) { 786 ctxt->txtMax *= 2; 787 ctxt->txtTab = (xmlChar **) xmlRealloc(ctxt->txtTab, 788 ctxt->txtMax * sizeof(ctxt->txtTab[0])); 789 if (ctxt->txtTab == NULL) { 790 xmlXIncludeErrMemory(ctxt, NULL, "processing text"); 791 return; 792 } 793 ctxt->txturlTab = (xmlURL *) xmlRealloc(ctxt->txturlTab, 794 ctxt->txtMax * sizeof(ctxt->txturlTab[0])); 795 if (ctxt->txturlTab == NULL) { 796 xmlXIncludeErrMemory(ctxt, NULL, "processing text"); 797 return; 798 } 799 } 800 ctxt->txtTab[ctxt->txtNr] = xmlStrdup(txt); 801 ctxt->txturlTab[ctxt->txtNr] = xmlStrdup(url); 802 ctxt->txtNr++; 803 } 804 805 /************************************************************************ 806 * * 807 * Node copy with specific semantic * 808 * * 809 ************************************************************************/ 810 811 static xmlNodePtr 812 xmlXIncludeCopyNodeList(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target, 813 xmlDocPtr source, xmlNodePtr elem); 814 815 /** 816 * xmlXIncludeCopyNode: 817 * @ctxt: the XInclude context 818 * @target: the document target 819 * @source: the document source 820 * @elem: the element 821 * 822 * Make a copy of the node while preserving the XInclude semantic 823 * of the Infoset copy 824 */ 825 static xmlNodePtr 826 xmlXIncludeCopyNode(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target, 827 xmlDocPtr source, xmlNodePtr elem) { 828 xmlNodePtr result = NULL; 829 830 if ((ctxt == NULL) || (target == NULL) || (source == NULL) || 831 (elem == NULL)) 832 return(NULL); 833 if (elem->type == XML_DTD_NODE) 834 return(NULL); 835 if (elem->type == XML_DOCUMENT_NODE) 836 result = xmlXIncludeCopyNodeList(ctxt, target, source, elem->children); 837 else 838 result = xmlDocCopyNode(elem, target, 1); 839 return(result); 840 } 841 842 /** 843 * xmlXIncludeCopyNodeList: 844 * @ctxt: the XInclude context 845 * @target: the document target 846 * @source: the document source 847 * @elem: the element list 848 * 849 * Make a copy of the node list while preserving the XInclude semantic 850 * of the Infoset copy 851 */ 852 static xmlNodePtr 853 xmlXIncludeCopyNodeList(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target, 854 xmlDocPtr source, xmlNodePtr elem) { 855 xmlNodePtr cur, res, result = NULL, last = NULL; 856 857 if ((ctxt == NULL) || (target == NULL) || (source == NULL) || 858 (elem == NULL)) 859 return(NULL); 860 cur = elem; 861 while (cur != NULL) { 862 res = xmlXIncludeCopyNode(ctxt, target, source, cur); 863 if (res != NULL) { 864 if (result == NULL) { 865 result = last = res; 866 } else { 867 last->next = res; 868 res->prev = last; 869 last = res; 870 } 871 } 872 cur = cur->next; 873 } 874 return(result); 875 } 876 877 /** 878 * xmlXIncludeGetNthChild: 879 * @cur: the node 880 * @no: the child number 881 * 882 * Returns the @n'th element child of @cur or NULL 883 */ 884 static xmlNodePtr 885 xmlXIncludeGetNthChild(xmlNodePtr cur, int no) { 886 int i; 887 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) 888 return(NULL); 889 cur = cur->children; 890 for (i = 0;i <= no;cur = cur->next) { 891 if (cur == NULL) 892 return(cur); 893 if ((cur->type == XML_ELEMENT_NODE) || 894 (cur->type == XML_DOCUMENT_NODE) || 895 (cur->type == XML_HTML_DOCUMENT_NODE)) { 896 i++; 897 if (i == no) 898 break; 899 } 900 } 901 return(cur); 902 } 903 904 xmlNodePtr xmlXPtrAdvanceNode(xmlNodePtr cur, int *level); /* in xpointer.c */ 905 /** 906 * xmlXIncludeCopyRange: 907 * @ctxt: the XInclude context 908 * @target: the document target 909 * @source: the document source 910 * @obj: the XPointer result from the evaluation. 911 * 912 * Build a node list tree copy of the XPointer result. 913 * 914 * Returns an xmlNodePtr list or NULL. 915 * The caller has to free the node tree. 916 */ 917 static xmlNodePtr 918 xmlXIncludeCopyRange(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target, 919 xmlDocPtr source, xmlXPathObjectPtr range) { 920 /* pointers to generated nodes */ 921 xmlNodePtr list = NULL, last = NULL, listParent = NULL; 922 xmlNodePtr tmp, tmp2; 923 /* pointers to traversal nodes */ 924 xmlNodePtr start, cur, end; 925 int index1, index2; 926 int level = 0, lastLevel = 0, endLevel = 0, endFlag = 0; 927 928 if ((ctxt == NULL) || (target == NULL) || (source == NULL) || 929 (range == NULL)) 930 return(NULL); 931 if (range->type != XPATH_RANGE) 932 return(NULL); 933 start = (xmlNodePtr) range->user; 934 935 if ((start == NULL) || (start->type == XML_NAMESPACE_DECL)) 936 return(NULL); 937 end = range->user2; 938 if (end == NULL) 939 return(xmlDocCopyNode(start, target, 1)); 940 if (end->type == XML_NAMESPACE_DECL) 941 return(NULL); 942 943 cur = start; 944 index1 = range->index; 945 index2 = range->index2; 946 /* 947 * level is depth of the current node under consideration 948 * list is the pointer to the root of the output tree 949 * listParent is a pointer to the parent of output tree (within 950 the included file) in case we need to add another level 951 * last is a pointer to the last node added to the output tree 952 * lastLevel is the depth of last (relative to the root) 953 */ 954 while (cur != NULL) { 955 /* 956 * Check if our output tree needs a parent 957 */ 958 if (level < 0) { 959 while (level < 0) { 960 /* copy must include namespaces and properties */ 961 tmp2 = xmlDocCopyNode(listParent, target, 2); 962 xmlAddChild(tmp2, list); 963 list = tmp2; 964 listParent = listParent->parent; 965 level++; 966 } 967 last = list; 968 lastLevel = 0; 969 } 970 /* 971 * Check whether we need to change our insertion point 972 */ 973 while (level < lastLevel) { 974 last = last->parent; 975 lastLevel --; 976 } 977 if (cur == end) { /* Are we at the end of the range? */ 978 if (cur->type == XML_TEXT_NODE) { 979 const xmlChar *content = cur->content; 980 int len; 981 982 if (content == NULL) { 983 tmp = xmlNewTextLen(NULL, 0); 984 } else { 985 len = index2; 986 if ((cur == start) && (index1 > 1)) { 987 content += (index1 - 1); 988 len -= (index1 - 1); 989 } else { 990 len = index2; 991 } 992 tmp = xmlNewTextLen(content, len); 993 } 994 /* single sub text node selection */ 995 if (list == NULL) 996 return(tmp); 997 /* prune and return full set */ 998 if (level == lastLevel) 999 xmlAddNextSibling(last, tmp); 1000 else 1001 xmlAddChild(last, tmp); 1002 return(list); 1003 } else { /* ending node not a text node */ 1004 endLevel = level; /* remember the level of the end node */ 1005 endFlag = 1; 1006 /* last node - need to take care of properties + namespaces */ 1007 tmp = xmlDocCopyNode(cur, target, 2); 1008 if (list == NULL) { 1009 list = tmp; 1010 listParent = cur->parent; 1011 last = tmp; 1012 } else { 1013 if (level == lastLevel) 1014 last = xmlAddNextSibling(last, tmp); 1015 else { 1016 last = xmlAddChild(last, tmp); 1017 lastLevel = level; 1018 } 1019 } 1020 1021 if (index2 > 1) { 1022 end = xmlXIncludeGetNthChild(cur, index2 - 1); 1023 index2 = 0; 1024 } 1025 if ((cur == start) && (index1 > 1)) { 1026 cur = xmlXIncludeGetNthChild(cur, index1 - 1); 1027 index1 = 0; 1028 } else { 1029 cur = cur->children; 1030 } 1031 level++; /* increment level to show change */ 1032 /* 1033 * Now gather the remaining nodes from cur to end 1034 */ 1035 continue; /* while */ 1036 } 1037 } else if (cur == start) { /* Not at the end, are we at start? */ 1038 if ((cur->type == XML_TEXT_NODE) || 1039 (cur->type == XML_CDATA_SECTION_NODE)) { 1040 const xmlChar *content = cur->content; 1041 1042 if (content == NULL) { 1043 tmp = xmlNewTextLen(NULL, 0); 1044 } else { 1045 if (index1 > 1) { 1046 content += (index1 - 1); 1047 index1 = 0; 1048 } 1049 tmp = xmlNewText(content); 1050 } 1051 last = list = tmp; 1052 listParent = cur->parent; 1053 } else { /* Not text node */ 1054 /* 1055 * start of the range - need to take care of 1056 * properties and namespaces 1057 */ 1058 tmp = xmlDocCopyNode(cur, target, 2); 1059 list = last = tmp; 1060 listParent = cur->parent; 1061 if (index1 > 1) { /* Do we need to position? */ 1062 cur = xmlXIncludeGetNthChild(cur, index1 - 1); 1063 level = lastLevel = 1; 1064 index1 = 0; 1065 /* 1066 * Now gather the remaining nodes from cur to end 1067 */ 1068 continue; /* while */ 1069 } 1070 } 1071 } else { 1072 tmp = NULL; 1073 switch (cur->type) { 1074 case XML_DTD_NODE: 1075 case XML_ELEMENT_DECL: 1076 case XML_ATTRIBUTE_DECL: 1077 case XML_ENTITY_NODE: 1078 /* Do not copy DTD informations */ 1079 break; 1080 case XML_ENTITY_DECL: 1081 /* handle crossing entities -> stack needed */ 1082 break; 1083 case XML_XINCLUDE_START: 1084 case XML_XINCLUDE_END: 1085 /* don't consider it part of the tree content */ 1086 break; 1087 case XML_ATTRIBUTE_NODE: 1088 /* Humm, should not happen ! */ 1089 break; 1090 default: 1091 /* 1092 * Middle of the range - need to take care of 1093 * properties and namespaces 1094 */ 1095 tmp = xmlDocCopyNode(cur, target, 2); 1096 break; 1097 } 1098 if (tmp != NULL) { 1099 if (level == lastLevel) 1100 last = xmlAddNextSibling(last, tmp); 1101 else { 1102 last = xmlAddChild(last, tmp); 1103 lastLevel = level; 1104 } 1105 } 1106 } 1107 /* 1108 * Skip to next node in document order 1109 */ 1110 cur = xmlXPtrAdvanceNode(cur, &level); 1111 if (endFlag && (level >= endLevel)) 1112 break; 1113 } 1114 return(list); 1115 } 1116 1117 /** 1118 * xmlXIncludeBuildNodeList: 1119 * @ctxt: the XInclude context 1120 * @target: the document target 1121 * @source: the document source 1122 * @obj: the XPointer result from the evaluation. 1123 * 1124 * Build a node list tree copy of the XPointer result. 1125 * This will drop Attributes and Namespace declarations. 1126 * 1127 * Returns an xmlNodePtr list or NULL. 1128 * the caller has to free the node tree. 1129 */ 1130 static xmlNodePtr 1131 xmlXIncludeCopyXPointer(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target, 1132 xmlDocPtr source, xmlXPathObjectPtr obj) { 1133 xmlNodePtr list = NULL, last = NULL; 1134 int i; 1135 1136 if (source == NULL) 1137 source = ctxt->doc; 1138 if ((ctxt == NULL) || (target == NULL) || (source == NULL) || 1139 (obj == NULL)) 1140 return(NULL); 1141 switch (obj->type) { 1142 case XPATH_NODESET: { 1143 xmlNodeSetPtr set = obj->nodesetval; 1144 if (set == NULL) 1145 return(NULL); 1146 for (i = 0;i < set->nodeNr;i++) { 1147 if (set->nodeTab[i] == NULL) 1148 continue; 1149 switch (set->nodeTab[i]->type) { 1150 case XML_TEXT_NODE: 1151 case XML_CDATA_SECTION_NODE: 1152 case XML_ELEMENT_NODE: 1153 case XML_ENTITY_REF_NODE: 1154 case XML_ENTITY_NODE: 1155 case XML_PI_NODE: 1156 case XML_COMMENT_NODE: 1157 case XML_DOCUMENT_NODE: 1158 case XML_HTML_DOCUMENT_NODE: 1159 #ifdef LIBXML_DOCB_ENABLED 1160 case XML_DOCB_DOCUMENT_NODE: 1161 #endif 1162 case XML_XINCLUDE_END: 1163 break; 1164 case XML_XINCLUDE_START: { 1165 xmlNodePtr tmp, cur = set->nodeTab[i]; 1166 1167 cur = cur->next; 1168 while (cur != NULL) { 1169 switch(cur->type) { 1170 case XML_TEXT_NODE: 1171 case XML_CDATA_SECTION_NODE: 1172 case XML_ELEMENT_NODE: 1173 case XML_ENTITY_REF_NODE: 1174 case XML_ENTITY_NODE: 1175 case XML_PI_NODE: 1176 case XML_COMMENT_NODE: 1177 tmp = xmlXIncludeCopyNode(ctxt, target, 1178 source, cur); 1179 if (last == NULL) { 1180 list = last = tmp; 1181 } else { 1182 last = xmlAddNextSibling(last, tmp); 1183 } 1184 cur = cur->next; 1185 continue; 1186 default: 1187 break; 1188 } 1189 break; 1190 } 1191 continue; 1192 } 1193 case XML_ATTRIBUTE_NODE: 1194 case XML_NAMESPACE_DECL: 1195 case XML_DOCUMENT_TYPE_NODE: 1196 case XML_DOCUMENT_FRAG_NODE: 1197 case XML_NOTATION_NODE: 1198 case XML_DTD_NODE: 1199 case XML_ELEMENT_DECL: 1200 case XML_ATTRIBUTE_DECL: 1201 case XML_ENTITY_DECL: 1202 continue; /* for */ 1203 } 1204 if (last == NULL) 1205 list = last = xmlXIncludeCopyNode(ctxt, target, source, 1206 set->nodeTab[i]); 1207 else { 1208 xmlAddNextSibling(last, 1209 xmlXIncludeCopyNode(ctxt, target, source, 1210 set->nodeTab[i])); 1211 if (last->next != NULL) 1212 last = last->next; 1213 } 1214 } 1215 break; 1216 } 1217 #ifdef LIBXML_XPTR_ENABLED 1218 case XPATH_LOCATIONSET: { 1219 xmlLocationSetPtr set = (xmlLocationSetPtr) obj->user; 1220 if (set == NULL) 1221 return(NULL); 1222 for (i = 0;i < set->locNr;i++) { 1223 if (last == NULL) 1224 list = last = xmlXIncludeCopyXPointer(ctxt, target, source, 1225 set->locTab[i]); 1226 else 1227 xmlAddNextSibling(last, 1228 xmlXIncludeCopyXPointer(ctxt, target, source, 1229 set->locTab[i])); 1230 if (last != NULL) { 1231 while (last->next != NULL) 1232 last = last->next; 1233 } 1234 } 1235 break; 1236 } 1237 case XPATH_RANGE: 1238 return(xmlXIncludeCopyRange(ctxt, target, source, obj)); 1239 #endif 1240 case XPATH_POINT: 1241 /* points are ignored in XInclude */ 1242 break; 1243 default: 1244 break; 1245 } 1246 return(list); 1247 } 1248 /************************************************************************ 1249 * * 1250 * XInclude I/O handling * 1251 * * 1252 ************************************************************************/ 1253 1254 typedef struct _xmlXIncludeMergeData xmlXIncludeMergeData; 1255 typedef xmlXIncludeMergeData *xmlXIncludeMergeDataPtr; 1256 struct _xmlXIncludeMergeData { 1257 xmlDocPtr doc; 1258 xmlXIncludeCtxtPtr ctxt; 1259 }; 1260 1261 /** 1262 * xmlXIncludeMergeOneEntity: 1263 * @ent: the entity 1264 * @doc: the including doc 1265 * @nr: the entity name 1266 * 1267 * Inplements the merge of one entity 1268 */ 1269 static void 1270 xmlXIncludeMergeEntity(xmlEntityPtr ent, xmlXIncludeMergeDataPtr data, 1271 xmlChar *name ATTRIBUTE_UNUSED) { 1272 xmlEntityPtr ret, prev; 1273 xmlDocPtr doc; 1274 xmlXIncludeCtxtPtr ctxt; 1275 1276 if ((ent == NULL) || (data == NULL)) 1277 return; 1278 ctxt = data->ctxt; 1279 doc = data->doc; 1280 if ((ctxt == NULL) || (doc == NULL)) 1281 return; 1282 switch (ent->etype) { 1283 case XML_INTERNAL_PARAMETER_ENTITY: 1284 case XML_EXTERNAL_PARAMETER_ENTITY: 1285 case XML_INTERNAL_PREDEFINED_ENTITY: 1286 return; 1287 case XML_INTERNAL_GENERAL_ENTITY: 1288 case XML_EXTERNAL_GENERAL_PARSED_ENTITY: 1289 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY: 1290 break; 1291 } 1292 ret = xmlAddDocEntity(doc, ent->name, ent->etype, ent->ExternalID, 1293 ent->SystemID, ent->content); 1294 if (ret != NULL) { 1295 if (ent->URI != NULL) 1296 ret->URI = xmlStrdup(ent->URI); 1297 } else { 1298 prev = xmlGetDocEntity(doc, ent->name); 1299 if (prev != NULL) { 1300 if (ent->etype != prev->etype) 1301 goto error; 1302 1303 if ((ent->SystemID != NULL) && (prev->SystemID != NULL)) { 1304 if (!xmlStrEqual(ent->SystemID, prev->SystemID)) 1305 goto error; 1306 } else if ((ent->ExternalID != NULL) && 1307 (prev->ExternalID != NULL)) { 1308 if (!xmlStrEqual(ent->ExternalID, prev->ExternalID)) 1309 goto error; 1310 } else if ((ent->content != NULL) && (prev->content != NULL)) { 1311 if (!xmlStrEqual(ent->content, prev->content)) 1312 goto error; 1313 } else { 1314 goto error; 1315 } 1316 1317 } 1318 } 1319 return; 1320 error: 1321 switch (ent->etype) { 1322 case XML_INTERNAL_PARAMETER_ENTITY: 1323 case XML_EXTERNAL_PARAMETER_ENTITY: 1324 case XML_INTERNAL_PREDEFINED_ENTITY: 1325 case XML_INTERNAL_GENERAL_ENTITY: 1326 case XML_EXTERNAL_GENERAL_PARSED_ENTITY: 1327 return; 1328 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY: 1329 break; 1330 } 1331 xmlXIncludeErr(ctxt, (xmlNodePtr) ent, XML_XINCLUDE_ENTITY_DEF_MISMATCH, 1332 "mismatch in redefinition of entity %s\n", 1333 ent->name); 1334 } 1335 1336 /** 1337 * xmlXIncludeMergeEntities: 1338 * @ctxt: an XInclude context 1339 * @doc: the including doc 1340 * @from: the included doc 1341 * 1342 * Inplements the entity merge 1343 * 1344 * Returns 0 if merge succeeded, -1 if some processing failed 1345 */ 1346 static int 1347 xmlXIncludeMergeEntities(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, 1348 xmlDocPtr from) { 1349 xmlNodePtr cur; 1350 xmlDtdPtr target, source; 1351 1352 if (ctxt == NULL) 1353 return(-1); 1354 1355 if ((from == NULL) || (from->intSubset == NULL)) 1356 return(0); 1357 1358 target = doc->intSubset; 1359 if (target == NULL) { 1360 cur = xmlDocGetRootElement(doc); 1361 if (cur == NULL) 1362 return(-1); 1363 target = xmlCreateIntSubset(doc, cur->name, NULL, NULL); 1364 if (target == NULL) 1365 return(-1); 1366 } 1367 1368 source = from->intSubset; 1369 if ((source != NULL) && (source->entities != NULL)) { 1370 xmlXIncludeMergeData data; 1371 1372 data.ctxt = ctxt; 1373 data.doc = doc; 1374 1375 xmlHashScan((xmlHashTablePtr) source->entities, 1376 (xmlHashScanner) xmlXIncludeMergeEntity, &data); 1377 } 1378 source = from->extSubset; 1379 if ((source != NULL) && (source->entities != NULL)) { 1380 xmlXIncludeMergeData data; 1381 1382 data.ctxt = ctxt; 1383 data.doc = doc; 1384 1385 /* 1386 * don't duplicate existing stuff when external subsets are the same 1387 */ 1388 if ((!xmlStrEqual(target->ExternalID, source->ExternalID)) && 1389 (!xmlStrEqual(target->SystemID, source->SystemID))) { 1390 xmlHashScan((xmlHashTablePtr) source->entities, 1391 (xmlHashScanner) xmlXIncludeMergeEntity, &data); 1392 } 1393 } 1394 return(0); 1395 } 1396 1397 /** 1398 * xmlXIncludeLoadDoc: 1399 * @ctxt: the XInclude context 1400 * @url: the associated URL 1401 * @nr: the xinclude node number 1402 * 1403 * Load the document, and store the result in the XInclude context 1404 * 1405 * Returns 0 in case of success, -1 in case of failure 1406 */ 1407 static int 1408 xmlXIncludeLoadDoc(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) { 1409 xmlDocPtr doc; 1410 xmlURIPtr uri; 1411 xmlChar *URL; 1412 xmlChar *fragment = NULL; 1413 int i = 0; 1414 #ifdef LIBXML_XPTR_ENABLED 1415 int saveFlags; 1416 #endif 1417 1418 #ifdef DEBUG_XINCLUDE 1419 xmlGenericError(xmlGenericErrorContext, "Loading doc %s:%d\n", url, nr); 1420 #endif 1421 /* 1422 * Check the URL and remove any fragment identifier 1423 */ 1424 uri = xmlParseURI((const char *)url); 1425 if (uri == NULL) { 1426 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, 1427 XML_XINCLUDE_HREF_URI, 1428 "invalid value URI %s\n", url); 1429 return(-1); 1430 } 1431 if (uri->fragment != NULL) { 1432 fragment = (xmlChar *) uri->fragment; 1433 uri->fragment = NULL; 1434 } 1435 if ((ctxt->incTab != NULL) && (ctxt->incTab[nr] != NULL) && 1436 (ctxt->incTab[nr]->fragment != NULL)) { 1437 if (fragment != NULL) xmlFree(fragment); 1438 fragment = xmlStrdup(ctxt->incTab[nr]->fragment); 1439 } 1440 URL = xmlSaveUri(uri); 1441 xmlFreeURI(uri); 1442 if (URL == NULL) { 1443 if (ctxt->incTab != NULL) 1444 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, 1445 XML_XINCLUDE_HREF_URI, 1446 "invalid value URI %s\n", url); 1447 else 1448 xmlXIncludeErr(ctxt, NULL, 1449 XML_XINCLUDE_HREF_URI, 1450 "invalid value URI %s\n", url); 1451 if (fragment != NULL) 1452 xmlFree(fragment); 1453 return(-1); 1454 } 1455 1456 /* 1457 * Handling of references to the local document are done 1458 * directly through ctxt->doc. 1459 */ 1460 if ((URL[0] == 0) || (URL[0] == '#') || 1461 ((ctxt->doc != NULL) && (xmlStrEqual(URL, ctxt->doc->URL)))) { 1462 doc = NULL; 1463 goto loaded; 1464 } 1465 1466 /* 1467 * Prevent reloading twice the document. 1468 */ 1469 for (i = 0; i < ctxt->incNr; i++) { 1470 if ((xmlStrEqual(URL, ctxt->incTab[i]->URI)) && 1471 (ctxt->incTab[i]->doc != NULL)) { 1472 doc = ctxt->incTab[i]->doc; 1473 #ifdef DEBUG_XINCLUDE 1474 printf("Already loaded %s\n", URL); 1475 #endif 1476 goto loaded; 1477 } 1478 } 1479 1480 /* 1481 * Load it. 1482 */ 1483 #ifdef DEBUG_XINCLUDE 1484 printf("loading %s\n", URL); 1485 #endif 1486 #ifdef LIBXML_XPTR_ENABLED 1487 /* 1488 * If this is an XPointer evaluation, we want to assure that 1489 * all entities have been resolved prior to processing the 1490 * referenced document 1491 */ 1492 saveFlags = ctxt->parseFlags; 1493 if (fragment != NULL) { /* if this is an XPointer eval */ 1494 ctxt->parseFlags |= XML_PARSE_NOENT; 1495 } 1496 #endif 1497 1498 doc = xmlXIncludeParseFile(ctxt, (const char *)URL); 1499 #ifdef LIBXML_XPTR_ENABLED 1500 ctxt->parseFlags = saveFlags; 1501 #endif 1502 if (doc == NULL) { 1503 xmlFree(URL); 1504 if (fragment != NULL) 1505 xmlFree(fragment); 1506 return(-1); 1507 } 1508 ctxt->incTab[nr]->doc = doc; 1509 /* 1510 * It's possible that the requested URL has been mapped to a 1511 * completely different location (e.g. through a catalog entry). 1512 * To check for this, we compare the URL with that of the doc 1513 * and change it if they disagree (bug 146988). 1514 */ 1515 if (!xmlStrEqual(URL, doc->URL)) { 1516 xmlFree(URL); 1517 URL = xmlStrdup(doc->URL); 1518 } 1519 for (i = nr + 1; i < ctxt->incNr; i++) { 1520 if (xmlStrEqual(URL, ctxt->incTab[i]->URI)) { 1521 ctxt->incTab[nr]->count++; 1522 #ifdef DEBUG_XINCLUDE 1523 printf("Increasing %s count since reused\n", URL); 1524 #endif 1525 break; 1526 } 1527 } 1528 1529 /* 1530 * Make sure we have all entities fixed up 1531 */ 1532 xmlXIncludeMergeEntities(ctxt, ctxt->doc, doc); 1533 1534 /* 1535 * We don't need the DTD anymore, free up space 1536 if (doc->intSubset != NULL) { 1537 xmlUnlinkNode((xmlNodePtr) doc->intSubset); 1538 xmlFreeNode((xmlNodePtr) doc->intSubset); 1539 doc->intSubset = NULL; 1540 } 1541 if (doc->extSubset != NULL) { 1542 xmlUnlinkNode((xmlNodePtr) doc->extSubset); 1543 xmlFreeNode((xmlNodePtr) doc->extSubset); 1544 doc->extSubset = NULL; 1545 } 1546 */ 1547 xmlXIncludeRecurseDoc(ctxt, doc, URL); 1548 1549 loaded: 1550 if (fragment == NULL) { 1551 /* 1552 * Add the top children list as the replacement copy. 1553 */ 1554 if (doc == NULL) 1555 { 1556 /* Hopefully a DTD declaration won't be copied from 1557 * the same document */ 1558 ctxt->incTab[nr]->inc = xmlCopyNodeList(ctxt->doc->children); 1559 } else { 1560 ctxt->incTab[nr]->inc = xmlXIncludeCopyNodeList(ctxt, ctxt->doc, 1561 doc, doc->children); 1562 } 1563 } 1564 #ifdef LIBXML_XPTR_ENABLED 1565 else { 1566 /* 1567 * Computes the XPointer expression and make a copy used 1568 * as the replacement copy. 1569 */ 1570 xmlXPathObjectPtr xptr; 1571 xmlXPathContextPtr xptrctxt; 1572 xmlNodeSetPtr set; 1573 1574 if (doc == NULL) { 1575 xptrctxt = xmlXPtrNewContext(ctxt->doc, ctxt->incTab[nr]->ref, 1576 NULL); 1577 } else { 1578 xptrctxt = xmlXPtrNewContext(doc, NULL, NULL); 1579 } 1580 if (xptrctxt == NULL) { 1581 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, 1582 XML_XINCLUDE_XPTR_FAILED, 1583 "could not create XPointer context\n", NULL); 1584 xmlFree(URL); 1585 xmlFree(fragment); 1586 return(-1); 1587 } 1588 xptr = xmlXPtrEval(fragment, xptrctxt); 1589 if (xptr == NULL) { 1590 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, 1591 XML_XINCLUDE_XPTR_FAILED, 1592 "XPointer evaluation failed: #%s\n", 1593 fragment); 1594 xmlXPathFreeContext(xptrctxt); 1595 xmlFree(URL); 1596 xmlFree(fragment); 1597 return(-1); 1598 } 1599 switch (xptr->type) { 1600 case XPATH_UNDEFINED: 1601 case XPATH_BOOLEAN: 1602 case XPATH_NUMBER: 1603 case XPATH_STRING: 1604 case XPATH_POINT: 1605 case XPATH_USERS: 1606 case XPATH_XSLT_TREE: 1607 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, 1608 XML_XINCLUDE_XPTR_RESULT, 1609 "XPointer is not a range: #%s\n", 1610 fragment); 1611 xmlXPathFreeContext(xptrctxt); 1612 xmlFree(URL); 1613 xmlFree(fragment); 1614 return(-1); 1615 case XPATH_NODESET: 1616 if ((xptr->nodesetval == NULL) || 1617 (xptr->nodesetval->nodeNr <= 0)) { 1618 xmlXPathFreeContext(xptrctxt); 1619 xmlFree(URL); 1620 xmlFree(fragment); 1621 return(-1); 1622 } 1623 1624 case XPATH_RANGE: 1625 case XPATH_LOCATIONSET: 1626 break; 1627 } 1628 set = xptr->nodesetval; 1629 if (set != NULL) { 1630 for (i = 0;i < set->nodeNr;i++) { 1631 if (set->nodeTab[i] == NULL) 1632 continue; 1633 switch (set->nodeTab[i]->type) { 1634 case XML_ELEMENT_NODE: 1635 case XML_TEXT_NODE: 1636 case XML_CDATA_SECTION_NODE: 1637 case XML_ENTITY_REF_NODE: 1638 case XML_ENTITY_NODE: 1639 case XML_PI_NODE: 1640 case XML_COMMENT_NODE: 1641 case XML_DOCUMENT_NODE: 1642 case XML_HTML_DOCUMENT_NODE: 1643 #ifdef LIBXML_DOCB_ENABLED 1644 case XML_DOCB_DOCUMENT_NODE: 1645 #endif 1646 continue; 1647 1648 case XML_ATTRIBUTE_NODE: 1649 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, 1650 XML_XINCLUDE_XPTR_RESULT, 1651 "XPointer selects an attribute: #%s\n", 1652 fragment); 1653 set->nodeTab[i] = NULL; 1654 continue; 1655 case XML_NAMESPACE_DECL: 1656 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, 1657 XML_XINCLUDE_XPTR_RESULT, 1658 "XPointer selects a namespace: #%s\n", 1659 fragment); 1660 set->nodeTab[i] = NULL; 1661 continue; 1662 case XML_DOCUMENT_TYPE_NODE: 1663 case XML_DOCUMENT_FRAG_NODE: 1664 case XML_NOTATION_NODE: 1665 case XML_DTD_NODE: 1666 case XML_ELEMENT_DECL: 1667 case XML_ATTRIBUTE_DECL: 1668 case XML_ENTITY_DECL: 1669 case XML_XINCLUDE_START: 1670 case XML_XINCLUDE_END: 1671 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, 1672 XML_XINCLUDE_XPTR_RESULT, 1673 "XPointer selects unexpected nodes: #%s\n", 1674 fragment); 1675 set->nodeTab[i] = NULL; 1676 set->nodeTab[i] = NULL; 1677 continue; /* for */ 1678 } 1679 } 1680 } 1681 if (doc == NULL) { 1682 ctxt->incTab[nr]->xptr = xptr; 1683 ctxt->incTab[nr]->inc = NULL; 1684 } else { 1685 ctxt->incTab[nr]->inc = 1686 xmlXIncludeCopyXPointer(ctxt, ctxt->doc, doc, xptr); 1687 xmlXPathFreeObject(xptr); 1688 } 1689 xmlXPathFreeContext(xptrctxt); 1690 xmlFree(fragment); 1691 } 1692 #endif 1693 1694 /* 1695 * Do the xml:base fixup if needed 1696 */ 1697 if ((doc != NULL) && (URL != NULL) && 1698 (!(ctxt->parseFlags & XML_PARSE_NOBASEFIX)) && 1699 (!(doc->parseFlags & XML_PARSE_NOBASEFIX))) { 1700 xmlNodePtr node; 1701 xmlChar *base; 1702 xmlChar *curBase; 1703 1704 /* 1705 * The base is only adjusted if "necessary", i.e. if the xinclude node 1706 * has a base specified, or the URL is relative 1707 */ 1708 base = xmlGetNsProp(ctxt->incTab[nr]->ref, BAD_CAST "base", 1709 XML_XML_NAMESPACE); 1710 if (base == NULL) { 1711 /* 1712 * No xml:base on the xinclude node, so we check whether the 1713 * URI base is different than (relative to) the context base 1714 */ 1715 curBase = xmlBuildRelativeURI(URL, ctxt->base); 1716 if (curBase == NULL) { /* Error return */ 1717 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, 1718 XML_XINCLUDE_HREF_URI, 1719 "trying to build relative URI from %s\n", URL); 1720 } else { 1721 /* If the URI doesn't contain a slash, it's not relative */ 1722 if (!xmlStrchr(curBase, (xmlChar) '/')) 1723 xmlFree(curBase); 1724 else 1725 base = curBase; 1726 } 1727 } 1728 if (base != NULL) { /* Adjustment may be needed */ 1729 node = ctxt->incTab[nr]->inc; 1730 while (node != NULL) { 1731 /* Only work on element nodes */ 1732 if (node->type == XML_ELEMENT_NODE) { 1733 curBase = xmlNodeGetBase(node->doc, node); 1734 /* If no current base, set it */ 1735 if (curBase == NULL) { 1736 xmlNodeSetBase(node, base); 1737 } else { 1738 /* 1739 * If the current base is the same as the 1740 * URL of the document, then reset it to be 1741 * the specified xml:base or the relative URI 1742 */ 1743 if (xmlStrEqual(curBase, node->doc->URL)) { 1744 xmlNodeSetBase(node, base); 1745 } else { 1746 /* 1747 * If the element already has an xml:base 1748 * set, then relativise it if necessary 1749 */ 1750 xmlChar *xmlBase; 1751 xmlBase = xmlGetNsProp(node, 1752 BAD_CAST "base", 1753 XML_XML_NAMESPACE); 1754 if (xmlBase != NULL) { 1755 xmlChar *relBase; 1756 relBase = xmlBuildURI(xmlBase, base); 1757 if (relBase == NULL) { /* error */ 1758 xmlXIncludeErr(ctxt, 1759 ctxt->incTab[nr]->ref, 1760 XML_XINCLUDE_HREF_URI, 1761 "trying to rebuild base from %s\n", 1762 xmlBase); 1763 } else { 1764 xmlNodeSetBase(node, relBase); 1765 xmlFree(relBase); 1766 } 1767 xmlFree(xmlBase); 1768 } 1769 } 1770 xmlFree(curBase); 1771 } 1772 } 1773 node = node->next; 1774 } 1775 xmlFree(base); 1776 } 1777 } 1778 if ((nr < ctxt->incNr) && (ctxt->incTab[nr]->doc != NULL) && 1779 (ctxt->incTab[nr]->count <= 1)) { 1780 #ifdef DEBUG_XINCLUDE 1781 printf("freeing %s\n", ctxt->incTab[nr]->doc->URL); 1782 #endif 1783 xmlFreeDoc(ctxt->incTab[nr]->doc); 1784 ctxt->incTab[nr]->doc = NULL; 1785 } 1786 xmlFree(URL); 1787 return(0); 1788 } 1789 1790 /** 1791 * xmlXIncludeLoadTxt: 1792 * @ctxt: the XInclude context 1793 * @url: the associated URL 1794 * @nr: the xinclude node number 1795 * 1796 * Load the content, and store the result in the XInclude context 1797 * 1798 * Returns 0 in case of success, -1 in case of failure 1799 */ 1800 static int 1801 xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) { 1802 xmlParserInputBufferPtr buf; 1803 xmlNodePtr node; 1804 xmlURIPtr uri; 1805 xmlChar *URL; 1806 int i; 1807 xmlChar *encoding = NULL; 1808 xmlCharEncoding enc = (xmlCharEncoding) 0; 1809 xmlParserCtxtPtr pctxt; 1810 xmlParserInputPtr inputStream; 1811 int xinclude_multibyte_fallback_used = 0; 1812 1813 /* 1814 * Check the URL and remove any fragment identifier 1815 */ 1816 uri = xmlParseURI((const char *)url); 1817 if (uri == NULL) { 1818 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_HREF_URI, 1819 "invalid value URI %s\n", url); 1820 return(-1); 1821 } 1822 if (uri->fragment != NULL) { 1823 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_TEXT_FRAGMENT, 1824 "fragment identifier forbidden for text: %s\n", 1825 (const xmlChar *) uri->fragment); 1826 xmlFreeURI(uri); 1827 return(-1); 1828 } 1829 URL = xmlSaveUri(uri); 1830 xmlFreeURI(uri); 1831 if (URL == NULL) { 1832 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_HREF_URI, 1833 "invalid value URI %s\n", url); 1834 return(-1); 1835 } 1836 1837 /* 1838 * Handling of references to the local document are done 1839 * directly through ctxt->doc. 1840 */ 1841 if (URL[0] == 0) { 1842 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, 1843 XML_XINCLUDE_TEXT_DOCUMENT, 1844 "text serialization of document not available\n", NULL); 1845 xmlFree(URL); 1846 return(-1); 1847 } 1848 1849 /* 1850 * Prevent reloading twice the document. 1851 */ 1852 for (i = 0; i < ctxt->txtNr; i++) { 1853 if (xmlStrEqual(URL, ctxt->txturlTab[i])) { 1854 node = xmlNewText(ctxt->txtTab[i]); 1855 goto loaded; 1856 } 1857 } 1858 /* 1859 * Try to get the encoding if available 1860 */ 1861 if ((ctxt->incTab[nr] != NULL) && (ctxt->incTab[nr]->ref != NULL)) { 1862 encoding = xmlGetProp(ctxt->incTab[nr]->ref, XINCLUDE_PARSE_ENCODING); 1863 } 1864 if (encoding != NULL) { 1865 /* 1866 * TODO: we should not have to remap to the xmlCharEncoding 1867 * predefined set, a better interface than 1868 * xmlParserInputBufferCreateFilename should allow any 1869 * encoding supported by iconv 1870 */ 1871 enc = xmlParseCharEncoding((const char *) encoding); 1872 if (enc == XML_CHAR_ENCODING_ERROR) { 1873 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, 1874 XML_XINCLUDE_UNKNOWN_ENCODING, 1875 "encoding %s not supported\n", encoding); 1876 xmlFree(encoding); 1877 xmlFree(URL); 1878 return(-1); 1879 } 1880 xmlFree(encoding); 1881 } 1882 1883 /* 1884 * Load it. 1885 */ 1886 pctxt = xmlNewParserCtxt(); 1887 inputStream = xmlLoadExternalEntity((const char*)URL, NULL, pctxt); 1888 if(inputStream == NULL) { 1889 xmlFreeParserCtxt(pctxt); 1890 xmlFree(URL); 1891 return(-1); 1892 } 1893 buf = inputStream->buf; 1894 if (buf == NULL) { 1895 xmlFreeInputStream (inputStream); 1896 xmlFreeParserCtxt(pctxt); 1897 xmlFree(URL); 1898 return(-1); 1899 } 1900 if (buf->encoder) 1901 xmlCharEncCloseFunc(buf->encoder); 1902 buf->encoder = xmlGetCharEncodingHandler(enc); 1903 node = xmlNewText(NULL); 1904 1905 /* 1906 * Scan all chars from the resource and add the to the node 1907 */ 1908 xinclude_multibyte_fallback: 1909 while (xmlParserInputBufferRead(buf, 128) > 0) { 1910 int len; 1911 const xmlChar *content; 1912 1913 content = xmlBufContent(buf->buffer); 1914 len = xmlBufLength(buf->buffer); 1915 for (i = 0;i < len;) { 1916 int cur; 1917 int l; 1918 1919 cur = xmlStringCurrentChar(NULL, &content[i], &l); 1920 if (!IS_CHAR(cur)) { 1921 /* Handle splitted multibyte char at buffer boundary */ 1922 if (((len - i) < 4) && (!xinclude_multibyte_fallback_used)) { 1923 xinclude_multibyte_fallback_used = 1; 1924 xmlBufShrink(buf->buffer, i); 1925 goto xinclude_multibyte_fallback; 1926 } else { 1927 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, 1928 XML_XINCLUDE_INVALID_CHAR, 1929 "%s contains invalid char\n", URL); 1930 xmlFreeParserInputBuffer(buf); 1931 xmlFree(URL); 1932 return(-1); 1933 } 1934 } else { 1935 xinclude_multibyte_fallback_used = 0; 1936 xmlNodeAddContentLen(node, &content[i], l); 1937 } 1938 i += l; 1939 } 1940 xmlBufShrink(buf->buffer, len); 1941 } 1942 xmlFreeParserCtxt(pctxt); 1943 xmlXIncludeAddTxt(ctxt, node->content, URL); 1944 xmlFreeInputStream(inputStream); 1945 1946 loaded: 1947 /* 1948 * Add the element as the replacement copy. 1949 */ 1950 ctxt->incTab[nr]->inc = node; 1951 xmlFree(URL); 1952 return(0); 1953 } 1954 1955 /** 1956 * xmlXIncludeLoadFallback: 1957 * @ctxt: the XInclude context 1958 * @fallback: the fallback node 1959 * @nr: the xinclude node number 1960 * 1961 * Load the content of the fallback node, and store the result 1962 * in the XInclude context 1963 * 1964 * Returns 0 in case of success, -1 in case of failure 1965 */ 1966 static int 1967 xmlXIncludeLoadFallback(xmlXIncludeCtxtPtr ctxt, xmlNodePtr fallback, int nr) { 1968 xmlXIncludeCtxtPtr newctxt; 1969 int ret = 0; 1970 1971 if ((fallback == NULL) || (fallback->type == XML_NAMESPACE_DECL) || 1972 (ctxt == NULL)) 1973 return(-1); 1974 if (fallback->children != NULL) { 1975 /* 1976 * It's possible that the fallback also has 'includes' 1977 * (Bug 129969), so we re-process the fallback just in case 1978 */ 1979 newctxt = xmlXIncludeNewContext(ctxt->doc); 1980 if (newctxt == NULL) 1981 return (-1); 1982 newctxt->_private = ctxt->_private; 1983 newctxt->base = xmlStrdup(ctxt->base); /* Inherit the base from the existing context */ 1984 xmlXIncludeSetFlags(newctxt, ctxt->parseFlags); 1985 ret = xmlXIncludeDoProcess(newctxt, ctxt->doc, fallback->children); 1986 if (ctxt->nbErrors > 0) 1987 ret = -1; 1988 else if (ret > 0) 1989 ret = 0; /* xmlXIncludeDoProcess can return +ve number */ 1990 xmlXIncludeFreeContext(newctxt); 1991 1992 ctxt->incTab[nr]->inc = xmlDocCopyNodeList(ctxt->doc, 1993 fallback->children); 1994 } else { 1995 ctxt->incTab[nr]->inc = NULL; 1996 ctxt->incTab[nr]->emptyFb = 1; /* flag empty callback */ 1997 } 1998 return(ret); 1999 } 2000 2001 /************************************************************************ 2002 * * 2003 * XInclude Processing * 2004 * * 2005 ************************************************************************/ 2006 2007 /** 2008 * xmlXIncludePreProcessNode: 2009 * @ctxt: an XInclude context 2010 * @node: an XInclude node 2011 * 2012 * Implement the XInclude preprocessing, currently just adding the element 2013 * for further processing. 2014 * 2015 * Returns the result list or NULL in case of error 2016 */ 2017 static xmlNodePtr 2018 xmlXIncludePreProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) { 2019 xmlXIncludeAddNode(ctxt, node); 2020 return(NULL); 2021 } 2022 2023 /** 2024 * xmlXIncludeLoadNode: 2025 * @ctxt: an XInclude context 2026 * @nr: the node number 2027 * 2028 * Find and load the infoset replacement for the given node. 2029 * 2030 * Returns 0 if substitution succeeded, -1 if some processing failed 2031 */ 2032 static int 2033 xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, int nr) { 2034 xmlNodePtr cur; 2035 xmlChar *href; 2036 xmlChar *parse; 2037 xmlChar *base; 2038 xmlChar *oldBase; 2039 xmlChar *URI; 2040 int xml = 1; /* default Issue 64 */ 2041 int ret; 2042 2043 if (ctxt == NULL) 2044 return(-1); 2045 if ((nr < 0) || (nr >= ctxt->incNr)) 2046 return(-1); 2047 cur = ctxt->incTab[nr]->ref; 2048 if (cur == NULL) 2049 return(-1); 2050 2051 /* 2052 * read the attributes 2053 */ 2054 href = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_HREF); 2055 if (href == NULL) { 2056 href = xmlStrdup(BAD_CAST ""); /* @@@@ href is now optional */ 2057 if (href == NULL) 2058 return(-1); 2059 } 2060 parse = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_PARSE); 2061 if (parse != NULL) { 2062 if (xmlStrEqual(parse, XINCLUDE_PARSE_XML)) 2063 xml = 1; 2064 else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT)) 2065 xml = 0; 2066 else { 2067 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, 2068 XML_XINCLUDE_PARSE_VALUE, 2069 "invalid value %s for 'parse'\n", parse); 2070 if (href != NULL) 2071 xmlFree(href); 2072 if (parse != NULL) 2073 xmlFree(parse); 2074 return(-1); 2075 } 2076 } 2077 2078 /* 2079 * compute the URI 2080 */ 2081 base = xmlNodeGetBase(ctxt->doc, cur); 2082 if (base == NULL) { 2083 URI = xmlBuildURI(href, ctxt->doc->URL); 2084 } else { 2085 URI = xmlBuildURI(href, base); 2086 } 2087 if (URI == NULL) { 2088 xmlChar *escbase; 2089 xmlChar *eschref; 2090 /* 2091 * Some escaping may be needed 2092 */ 2093 escbase = xmlURIEscape(base); 2094 eschref = xmlURIEscape(href); 2095 URI = xmlBuildURI(eschref, escbase); 2096 if (escbase != NULL) 2097 xmlFree(escbase); 2098 if (eschref != NULL) 2099 xmlFree(eschref); 2100 } 2101 if (URI == NULL) { 2102 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, 2103 XML_XINCLUDE_HREF_URI, "failed build URL\n", NULL); 2104 if (parse != NULL) 2105 xmlFree(parse); 2106 if (href != NULL) 2107 xmlFree(href); 2108 if (base != NULL) 2109 xmlFree(base); 2110 return(-1); 2111 } 2112 #ifdef DEBUG_XINCLUDE 2113 xmlGenericError(xmlGenericErrorContext, "parse: %s\n", 2114 xml ? "xml": "text"); 2115 xmlGenericError(xmlGenericErrorContext, "URI: %s\n", URI); 2116 #endif 2117 2118 /* 2119 * Save the base for this include (saving the current one) 2120 */ 2121 oldBase = ctxt->base; 2122 ctxt->base = base; 2123 2124 if (xml) { 2125 ret = xmlXIncludeLoadDoc(ctxt, URI, nr); 2126 /* xmlXIncludeGetFragment(ctxt, cur, URI); */ 2127 } else { 2128 ret = xmlXIncludeLoadTxt(ctxt, URI, nr); 2129 } 2130 2131 /* 2132 * Restore the original base before checking for fallback 2133 */ 2134 ctxt->base = oldBase; 2135 2136 if (ret < 0) { 2137 xmlNodePtr children; 2138 2139 /* 2140 * Time to try a fallback if availble 2141 */ 2142 #ifdef DEBUG_XINCLUDE 2143 xmlGenericError(xmlGenericErrorContext, "error looking for fallback\n"); 2144 #endif 2145 children = cur->children; 2146 while (children != NULL) { 2147 if ((children->type == XML_ELEMENT_NODE) && 2148 (children->ns != NULL) && 2149 (xmlStrEqual(children->name, XINCLUDE_FALLBACK)) && 2150 ((xmlStrEqual(children->ns->href, XINCLUDE_NS)) || 2151 (xmlStrEqual(children->ns->href, XINCLUDE_OLD_NS)))) { 2152 ret = xmlXIncludeLoadFallback(ctxt, children, nr); 2153 if (ret == 0) 2154 break; 2155 } 2156 children = children->next; 2157 } 2158 } 2159 if (ret < 0) { 2160 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, 2161 XML_XINCLUDE_NO_FALLBACK, 2162 "could not load %s, and no fallback was found\n", 2163 URI); 2164 } 2165 2166 /* 2167 * Cleanup 2168 */ 2169 if (URI != NULL) 2170 xmlFree(URI); 2171 if (parse != NULL) 2172 xmlFree(parse); 2173 if (href != NULL) 2174 xmlFree(href); 2175 if (base != NULL) 2176 xmlFree(base); 2177 return(0); 2178 } 2179 2180 /** 2181 * xmlXIncludeIncludeNode: 2182 * @ctxt: an XInclude context 2183 * @nr: the node number 2184 * 2185 * Inplement the infoset replacement for the given node 2186 * 2187 * Returns 0 if substitution succeeded, -1 if some processing failed 2188 */ 2189 static int 2190 xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) { 2191 xmlNodePtr cur, end, list, tmp; 2192 2193 if (ctxt == NULL) 2194 return(-1); 2195 if ((nr < 0) || (nr >= ctxt->incNr)) 2196 return(-1); 2197 cur = ctxt->incTab[nr]->ref; 2198 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL)) 2199 return(-1); 2200 2201 /* 2202 * If we stored an XPointer a late computation may be needed 2203 */ 2204 if ((ctxt->incTab[nr]->inc == NULL) && 2205 (ctxt->incTab[nr]->xptr != NULL)) { 2206 ctxt->incTab[nr]->inc = 2207 xmlXIncludeCopyXPointer(ctxt, ctxt->doc, ctxt->doc, 2208 ctxt->incTab[nr]->xptr); 2209 xmlXPathFreeObject(ctxt->incTab[nr]->xptr); 2210 ctxt->incTab[nr]->xptr = NULL; 2211 } 2212 list = ctxt->incTab[nr]->inc; 2213 ctxt->incTab[nr]->inc = NULL; 2214 2215 /* 2216 * Check against the risk of generating a multi-rooted document 2217 */ 2218 if ((cur->parent != NULL) && 2219 (cur->parent->type != XML_ELEMENT_NODE)) { 2220 int nb_elem = 0; 2221 2222 tmp = list; 2223 while (tmp != NULL) { 2224 if (tmp->type == XML_ELEMENT_NODE) 2225 nb_elem++; 2226 tmp = tmp->next; 2227 } 2228 if (nb_elem > 1) { 2229 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, 2230 XML_XINCLUDE_MULTIPLE_ROOT, 2231 "XInclude error: would result in multiple root nodes\n", 2232 NULL); 2233 return(-1); 2234 } 2235 } 2236 2237 if (ctxt->parseFlags & XML_PARSE_NOXINCNODE) { 2238 /* 2239 * Add the list of nodes 2240 */ 2241 while (list != NULL) { 2242 end = list; 2243 list = list->next; 2244 2245 xmlAddPrevSibling(cur, end); 2246 } 2247 xmlUnlinkNode(cur); 2248 xmlFreeNode(cur); 2249 } else { 2250 /* 2251 * Change the current node as an XInclude start one, and add an 2252 * XInclude end one 2253 */ 2254 cur->type = XML_XINCLUDE_START; 2255 end = xmlNewDocNode(cur->doc, cur->ns, cur->name, NULL); 2256 if (end == NULL) { 2257 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, 2258 XML_XINCLUDE_BUILD_FAILED, 2259 "failed to build node\n", NULL); 2260 return(-1); 2261 } 2262 end->type = XML_XINCLUDE_END; 2263 xmlAddNextSibling(cur, end); 2264 2265 /* 2266 * Add the list of nodes 2267 */ 2268 while (list != NULL) { 2269 cur = list; 2270 list = list->next; 2271 2272 xmlAddPrevSibling(end, cur); 2273 } 2274 } 2275 2276 2277 return(0); 2278 } 2279 2280 /** 2281 * xmlXIncludeTestNode: 2282 * @ctxt: the XInclude processing context 2283 * @node: an XInclude node 2284 * 2285 * test if the node is an XInclude node 2286 * 2287 * Returns 1 true, 0 otherwise 2288 */ 2289 static int 2290 xmlXIncludeTestNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) { 2291 if (node == NULL) 2292 return(0); 2293 if (node->type != XML_ELEMENT_NODE) 2294 return(0); 2295 if (node->ns == NULL) 2296 return(0); 2297 if ((xmlStrEqual(node->ns->href, XINCLUDE_NS)) || 2298 (xmlStrEqual(node->ns->href, XINCLUDE_OLD_NS))) { 2299 if (xmlStrEqual(node->ns->href, XINCLUDE_OLD_NS)) { 2300 if (ctxt->legacy == 0) { 2301 #if 0 /* wait for the XML Core Working Group to get something stable ! */ 2302 xmlXIncludeWarn(ctxt, node, XML_XINCLUDE_DEPRECATED_NS, 2303 "Deprecated XInclude namespace found, use %s", 2304 XINCLUDE_NS); 2305 #endif 2306 ctxt->legacy = 1; 2307 } 2308 } 2309 if (xmlStrEqual(node->name, XINCLUDE_NODE)) { 2310 xmlNodePtr child = node->children; 2311 int nb_fallback = 0; 2312 2313 while (child != NULL) { 2314 if ((child->type == XML_ELEMENT_NODE) && 2315 (child->ns != NULL) && 2316 ((xmlStrEqual(child->ns->href, XINCLUDE_NS)) || 2317 (xmlStrEqual(child->ns->href, XINCLUDE_OLD_NS)))) { 2318 if (xmlStrEqual(child->name, XINCLUDE_NODE)) { 2319 xmlXIncludeErr(ctxt, node, 2320 XML_XINCLUDE_INCLUDE_IN_INCLUDE, 2321 "%s has an 'include' child\n", 2322 XINCLUDE_NODE); 2323 return(0); 2324 } 2325 if (xmlStrEqual(child->name, XINCLUDE_FALLBACK)) { 2326 nb_fallback++; 2327 } 2328 } 2329 child = child->next; 2330 } 2331 if (nb_fallback > 1) { 2332 xmlXIncludeErr(ctxt, node, XML_XINCLUDE_FALLBACKS_IN_INCLUDE, 2333 "%s has multiple fallback children\n", 2334 XINCLUDE_NODE); 2335 return(0); 2336 } 2337 return(1); 2338 } 2339 if (xmlStrEqual(node->name, XINCLUDE_FALLBACK)) { 2340 if ((node->parent == NULL) || 2341 (node->parent->type != XML_ELEMENT_NODE) || 2342 (node->parent->ns == NULL) || 2343 ((!xmlStrEqual(node->parent->ns->href, XINCLUDE_NS)) && 2344 (!xmlStrEqual(node->parent->ns->href, XINCLUDE_OLD_NS))) || 2345 (!xmlStrEqual(node->parent->name, XINCLUDE_NODE))) { 2346 xmlXIncludeErr(ctxt, node, 2347 XML_XINCLUDE_FALLBACK_NOT_IN_INCLUDE, 2348 "%s is not the child of an 'include'\n", 2349 XINCLUDE_FALLBACK); 2350 } 2351 } 2352 } 2353 return(0); 2354 } 2355 2356 /** 2357 * xmlXIncludeDoProcess: 2358 * @ctxt: the XInclude processing context 2359 * @doc: an XML document 2360 * @tree: the top of the tree to process 2361 * 2362 * Implement the XInclude substitution on the XML document @doc 2363 * 2364 * Returns 0 if no substitution were done, -1 if some processing failed 2365 * or the number of substitutions done. 2366 */ 2367 static int 2368 xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr tree) { 2369 xmlNodePtr cur; 2370 int ret = 0; 2371 int i, start; 2372 2373 if ((doc == NULL) || (tree == NULL) || (tree->type == XML_NAMESPACE_DECL)) 2374 return(-1); 2375 if (ctxt == NULL) 2376 return(-1); 2377 2378 if (doc->URL != NULL) { 2379 ret = xmlXIncludeURLPush(ctxt, doc->URL); 2380 if (ret < 0) 2381 return(-1); 2382 } 2383 start = ctxt->incNr; 2384 2385 /* 2386 * First phase: lookup the elements in the document 2387 */ 2388 cur = tree; 2389 while ((cur != NULL) && (cur != tree->parent)) { 2390 /* TODO: need to work on entities -> stack */ 2391 if (xmlXIncludeTestNode(ctxt, cur) == 1) { 2392 xmlXIncludePreProcessNode(ctxt, cur); 2393 } else if ((cur->children != NULL) && 2394 ((cur->type == XML_DOCUMENT_NODE) || 2395 (cur->type == XML_ELEMENT_NODE))) { 2396 cur = cur->children; 2397 continue; 2398 } 2399 if (cur->next != NULL) { 2400 cur = cur->next; 2401 } else { 2402 if (cur == tree) 2403 break; 2404 do { 2405 cur = cur->parent; 2406 if ((cur == NULL) || (cur == tree->parent)) 2407 break; /* do */ 2408 if (cur->next != NULL) { 2409 cur = cur->next; 2410 break; /* do */ 2411 } 2412 } while (cur != NULL); 2413 } 2414 } 2415 2416 /* 2417 * Second Phase : collect the infosets fragments 2418 */ 2419 for (i = start;i < ctxt->incNr; i++) { 2420 xmlXIncludeLoadNode(ctxt, i); 2421 ret++; 2422 } 2423 2424 /* 2425 * Third phase: extend the original document infoset. 2426 * 2427 * Originally we bypassed the inclusion if there were any errors 2428 * encountered on any of the XIncludes. A bug was raised (bug 2429 * 132588) requesting that we output the XIncludes without error, 2430 * so the check for inc!=NULL || xptr!=NULL was put in. This may 2431 * give some other problems in the future, but for now it seems to 2432 * work ok. 2433 * 2434 */ 2435 for (i = ctxt->incBase;i < ctxt->incNr; i++) { 2436 if ((ctxt->incTab[i]->inc != NULL) || 2437 (ctxt->incTab[i]->xptr != NULL) || 2438 (ctxt->incTab[i]->emptyFb != 0)) /* (empty fallback) */ 2439 xmlXIncludeIncludeNode(ctxt, i); 2440 } 2441 2442 if (doc->URL != NULL) 2443 xmlXIncludeURLPop(ctxt); 2444 return(ret); 2445 } 2446 2447 /** 2448 * xmlXIncludeSetFlags: 2449 * @ctxt: an XInclude processing context 2450 * @flags: a set of xmlParserOption used for parsing XML includes 2451 * 2452 * Set the flags used for further processing of XML resources. 2453 * 2454 * Returns 0 in case of success and -1 in case of error. 2455 */ 2456 int 2457 xmlXIncludeSetFlags(xmlXIncludeCtxtPtr ctxt, int flags) { 2458 if (ctxt == NULL) 2459 return(-1); 2460 ctxt->parseFlags = flags; 2461 return(0); 2462 } 2463 2464 /** 2465 * xmlXIncludeProcessTreeFlagsData: 2466 * @tree: an XML node 2467 * @flags: a set of xmlParserOption used for parsing XML includes 2468 * @data: application data that will be passed to the parser context 2469 * in the _private field of the parser context(s) 2470 * 2471 * Implement the XInclude substitution on the XML node @tree 2472 * 2473 * Returns 0 if no substitution were done, -1 if some processing failed 2474 * or the number of substitutions done. 2475 */ 2476 2477 int 2478 xmlXIncludeProcessTreeFlagsData(xmlNodePtr tree, int flags, void *data) { 2479 xmlXIncludeCtxtPtr ctxt; 2480 int ret = 0; 2481 2482 if ((tree == NULL) || (tree->type == XML_NAMESPACE_DECL) || 2483 (tree->doc == NULL)) 2484 return(-1); 2485 2486 ctxt = xmlXIncludeNewContext(tree->doc); 2487 if (ctxt == NULL) 2488 return(-1); 2489 ctxt->_private = data; 2490 ctxt->base = xmlStrdup((xmlChar *)tree->doc->URL); 2491 xmlXIncludeSetFlags(ctxt, flags); 2492 ret = xmlXIncludeDoProcess(ctxt, tree->doc, tree); 2493 if ((ret >= 0) && (ctxt->nbErrors > 0)) 2494 ret = -1; 2495 2496 xmlXIncludeFreeContext(ctxt); 2497 return(ret); 2498 } 2499 2500 /** 2501 * xmlXIncludeProcessFlagsData: 2502 * @doc: an XML document 2503 * @flags: a set of xmlParserOption used for parsing XML includes 2504 * @data: application data that will be passed to the parser context 2505 * in the _private field of the parser context(s) 2506 * 2507 * Implement the XInclude substitution on the XML document @doc 2508 * 2509 * Returns 0 if no substitution were done, -1 if some processing failed 2510 * or the number of substitutions done. 2511 */ 2512 int 2513 xmlXIncludeProcessFlagsData(xmlDocPtr doc, int flags, void *data) { 2514 xmlNodePtr tree; 2515 2516 if (doc == NULL) 2517 return(-1); 2518 tree = xmlDocGetRootElement(doc); 2519 if (tree == NULL) 2520 return(-1); 2521 return(xmlXIncludeProcessTreeFlagsData(tree, flags, data)); 2522 } 2523 2524 /** 2525 * xmlXIncludeProcessFlags: 2526 * @doc: an XML document 2527 * @flags: a set of xmlParserOption used for parsing XML includes 2528 * 2529 * Implement the XInclude substitution on the XML document @doc 2530 * 2531 * Returns 0 if no substitution were done, -1 if some processing failed 2532 * or the number of substitutions done. 2533 */ 2534 int 2535 xmlXIncludeProcessFlags(xmlDocPtr doc, int flags) { 2536 return xmlXIncludeProcessFlagsData(doc, flags, NULL); 2537 } 2538 2539 /** 2540 * xmlXIncludeProcess: 2541 * @doc: an XML document 2542 * 2543 * Implement the XInclude substitution on the XML document @doc 2544 * 2545 * Returns 0 if no substitution were done, -1 if some processing failed 2546 * or the number of substitutions done. 2547 */ 2548 int 2549 xmlXIncludeProcess(xmlDocPtr doc) { 2550 return(xmlXIncludeProcessFlags(doc, 0)); 2551 } 2552 2553 /** 2554 * xmlXIncludeProcessTreeFlags: 2555 * @tree: a node in an XML document 2556 * @flags: a set of xmlParserOption used for parsing XML includes 2557 * 2558 * Implement the XInclude substitution for the given subtree 2559 * 2560 * Returns 0 if no substitution were done, -1 if some processing failed 2561 * or the number of substitutions done. 2562 */ 2563 int 2564 xmlXIncludeProcessTreeFlags(xmlNodePtr tree, int flags) { 2565 xmlXIncludeCtxtPtr ctxt; 2566 int ret = 0; 2567 2568 if ((tree == NULL) || (tree->type == XML_NAMESPACE_DECL) || 2569 (tree->doc == NULL)) 2570 return(-1); 2571 ctxt = xmlXIncludeNewContext(tree->doc); 2572 if (ctxt == NULL) 2573 return(-1); 2574 ctxt->base = xmlNodeGetBase(tree->doc, tree); 2575 xmlXIncludeSetFlags(ctxt, flags); 2576 ret = xmlXIncludeDoProcess(ctxt, tree->doc, tree); 2577 if ((ret >= 0) && (ctxt->nbErrors > 0)) 2578 ret = -1; 2579 2580 xmlXIncludeFreeContext(ctxt); 2581 return(ret); 2582 } 2583 2584 /** 2585 * xmlXIncludeProcessTree: 2586 * @tree: a node in an XML document 2587 * 2588 * Implement the XInclude substitution for the given subtree 2589 * 2590 * Returns 0 if no substitution were done, -1 if some processing failed 2591 * or the number of substitutions done. 2592 */ 2593 int 2594 xmlXIncludeProcessTree(xmlNodePtr tree) { 2595 return(xmlXIncludeProcessTreeFlags(tree, 0)); 2596 } 2597 2598 /** 2599 * xmlXIncludeProcessNode: 2600 * @ctxt: an existing XInclude context 2601 * @node: a node in an XML document 2602 * 2603 * Implement the XInclude substitution for the given subtree reusing 2604 * the informations and data coming from the given context. 2605 * 2606 * Returns 0 if no substitution were done, -1 if some processing failed 2607 * or the number of substitutions done. 2608 */ 2609 int 2610 xmlXIncludeProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) { 2611 int ret = 0; 2612 2613 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL) || 2614 (node->doc == NULL) || (ctxt == NULL)) 2615 return(-1); 2616 ret = xmlXIncludeDoProcess(ctxt, node->doc, node); 2617 if ((ret >= 0) && (ctxt->nbErrors > 0)) 2618 ret = -1; 2619 return(ret); 2620 } 2621 2622 #else /* !LIBXML_XINCLUDE_ENABLED */ 2623 #endif 2624 #define bottom_xinclude 2625 #include "elfgcchack.h"