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