Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenxinclude.c
Go to the documentation of this file.
00001 /* 00002 * xinclude.c : Code to implement XInclude processing 00003 * 00004 * World Wide Web Consortium W3C Last Call Working Draft 10 November 2003 00005 * http://www.w3.org/TR/2003/WD-xinclude-20031110 00006 * 00007 * See Copyright for the status of this software. 00008 * 00009 * daniel@veillard.com 00010 */ 00011 00012 #define IN_LIBXML 00013 #include "libxml.h" 00014 00015 #include <string.h> 00016 #include <libxml/xmlmemory.h> 00017 #include <libxml/tree.h> 00018 #include <libxml/parser.h> 00019 #include <libxml/uri.h> 00020 #include <libxml/xpointer.h> 00021 #include <libxml/parserInternals.h> 00022 #include <libxml/xmlerror.h> 00023 #include <libxml/encoding.h> 00024 #include <libxml/globals.h> 00025 00026 #ifdef LIBXML_XINCLUDE_ENABLED 00027 #include <libxml/xinclude.h> 00028 00029 00030 #define XINCLUDE_MAX_DEPTH 40 00031 00032 /* #define DEBUG_XINCLUDE */ 00033 #ifdef DEBUG_XINCLUDE 00034 #ifdef LIBXML_DEBUG_ENABLED 00035 #include <libxml/debugXML.h> 00036 #endif 00037 #endif 00038 00039 /************************************************************************ 00040 * * 00041 * XInclude context handling * 00042 * * 00043 ************************************************************************/ 00044 00045 /* 00046 * An XInclude context 00047 */ 00048 typedef xmlChar *xmlURL; 00049 00050 typedef struct _xmlXIncludeRef xmlXIncludeRef; 00051 typedef xmlXIncludeRef *xmlXIncludeRefPtr; 00052 struct _xmlXIncludeRef { 00053 xmlChar *URI; /* the fully resolved resource URL */ 00054 xmlChar *fragment; /* the fragment in the URI */ 00055 xmlDocPtr doc; /* the parsed document */ 00056 xmlNodePtr ref; /* the node making the reference in the source */ 00057 xmlNodePtr inc; /* the included copy */ 00058 int xml; /* xml or txt */ 00059 int count; /* how many refs use that specific doc */ 00060 xmlXPathObjectPtr xptr; /* the xpointer if needed */ 00061 int emptyFb; /* flag to show fallback empty */ 00062 }; 00063 00064 struct _xmlXIncludeCtxt { 00065 xmlDocPtr doc; /* the source document */ 00066 int incBase; /* the first include for this document */ 00067 int incNr; /* number of includes */ 00068 int incMax; /* size of includes tab */ 00069 xmlXIncludeRefPtr *incTab; /* array of included references */ 00070 00071 int txtNr; /* number of unparsed documents */ 00072 int txtMax; /* size of unparsed documents tab */ 00073 xmlNodePtr *txtTab; /* array of unparsed text nodes */ 00074 xmlURL *txturlTab; /* array of unparsed text URLs */ 00075 00076 xmlChar * url; /* the current URL processed */ 00077 int urlNr; /* number of URLs stacked */ 00078 int urlMax; /* size of URL stack */ 00079 xmlChar * *urlTab; /* URL stack */ 00080 00081 int nbErrors; /* the number of errors detected */ 00082 int legacy; /* using XINCLUDE_OLD_NS */ 00083 int parseFlags; /* the flags used for parsing XML documents */ 00084 xmlChar * base; /* the current xml:base */ 00085 00086 void *_private; /* application data */ 00087 }; 00088 00089 static int 00090 xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr tree); 00091 00092 00093 /************************************************************************ 00094 * * 00095 * XInclude error handler * 00096 * * 00097 ************************************************************************/ 00098 00105 static void 00106 xmlXIncludeErrMemory(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node, 00107 const char *extra) 00108 { 00109 if (ctxt != NULL) 00110 ctxt->nbErrors++; 00111 __xmlRaiseError(NULL, NULL, NULL, ctxt, node, XML_FROM_XINCLUDE, 00112 XML_ERR_NO_MEMORY, XML_ERR_ERROR, NULL, 0, 00113 extra, NULL, NULL, 0, 0, 00114 "Memory allocation failed : %s\n", extra); 00115 } 00116 00126 static void 00127 xmlXIncludeErr(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node, int error, 00128 const char *msg, const xmlChar *extra) 00129 { 00130 if (ctxt != NULL) 00131 ctxt->nbErrors++; 00132 __xmlRaiseError(NULL, NULL, NULL, ctxt, node, XML_FROM_XINCLUDE, 00133 error, XML_ERR_ERROR, NULL, 0, 00134 (const char *) extra, NULL, NULL, 0, 0, 00135 msg, (const char *) extra); 00136 } 00137 00138 #if 0 00139 00148 static void 00149 xmlXIncludeWarn(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node, int error, 00150 const char *msg, const xmlChar *extra) 00151 { 00152 __xmlRaiseError(NULL, NULL, NULL, ctxt, node, XML_FROM_XINCLUDE, 00153 error, XML_ERR_WARNING, NULL, 0, 00154 (const char *) extra, NULL, NULL, 0, 0, 00155 msg, (const char *) extra); 00156 } 00157 #endif 00158 00169 static xmlChar * 00170 xmlXIncludeGetProp(xmlXIncludeCtxtPtr ctxt, xmlNodePtr cur, 00171 const xmlChar *name) { 00172 xmlChar *ret; 00173 00174 ret = xmlGetNsProp(cur, XINCLUDE_NS, name); 00175 if (ret != NULL) 00176 return(ret); 00177 if (ctxt->legacy != 0) { 00178 ret = xmlGetNsProp(cur, XINCLUDE_OLD_NS, name); 00179 if (ret != NULL) 00180 return(ret); 00181 } 00182 ret = xmlGetProp(cur, name); 00183 return(ret); 00184 } 00191 static void 00192 xmlXIncludeFreeRef(xmlXIncludeRefPtr ref) { 00193 if (ref == NULL) 00194 return; 00195 #ifdef DEBUG_XINCLUDE 00196 xmlGenericError(xmlGenericErrorContext, "Freeing ref\n"); 00197 #endif 00198 if (ref->doc != NULL) { 00199 #ifdef DEBUG_XINCLUDE 00200 xmlGenericError(xmlGenericErrorContext, "Freeing doc %s\n", ref->URI); 00201 #endif 00202 xmlFreeDoc(ref->doc); 00203 } 00204 if (ref->URI != NULL) 00205 xmlFree(ref->URI); 00206 if (ref->fragment != NULL) 00207 xmlFree(ref->fragment); 00208 if (ref->xptr != NULL) 00209 xmlXPathFreeObject(ref->xptr); 00210 xmlFree(ref); 00211 } 00212 00222 static xmlXIncludeRefPtr 00223 xmlXIncludeNewRef(xmlXIncludeCtxtPtr ctxt, const xmlChar *URI, 00224 xmlNodePtr ref) { 00225 xmlXIncludeRefPtr ret; 00226 00227 #ifdef DEBUG_XINCLUDE 00228 xmlGenericError(xmlGenericErrorContext, "New ref %s\n", URI); 00229 #endif 00230 ret = (xmlXIncludeRefPtr) xmlMalloc(sizeof(xmlXIncludeRef)); 00231 if (ret == NULL) { 00232 xmlXIncludeErrMemory(ctxt, ref, "growing XInclude context"); 00233 return(NULL); 00234 } 00235 memset(ret, 0, sizeof(xmlXIncludeRef)); 00236 if (URI == NULL) 00237 ret->URI = NULL; 00238 else 00239 ret->URI = xmlStrdup(URI); 00240 ret->fragment = NULL; 00241 ret->ref = ref; 00242 ret->doc = NULL; 00243 ret->count = 0; 00244 ret->xml = 0; 00245 ret->inc = NULL; 00246 if (ctxt->incMax == 0) { 00247 ctxt->incMax = 4; 00248 ctxt->incTab = (xmlXIncludeRefPtr *) xmlMalloc(ctxt->incMax * 00249 sizeof(ctxt->incTab[0])); 00250 if (ctxt->incTab == NULL) { 00251 xmlXIncludeErrMemory(ctxt, ref, "growing XInclude context"); 00252 xmlXIncludeFreeRef(ret); 00253 return(NULL); 00254 } 00255 } 00256 if (ctxt->incNr >= ctxt->incMax) { 00257 ctxt->incMax *= 2; 00258 ctxt->incTab = (xmlXIncludeRefPtr *) xmlRealloc(ctxt->incTab, 00259 ctxt->incMax * sizeof(ctxt->incTab[0])); 00260 if (ctxt->incTab == NULL) { 00261 xmlXIncludeErrMemory(ctxt, ref, "growing XInclude context"); 00262 xmlXIncludeFreeRef(ret); 00263 return(NULL); 00264 } 00265 } 00266 ctxt->incTab[ctxt->incNr++] = ret; 00267 return(ret); 00268 } 00269 00278 xmlXIncludeCtxtPtr 00279 xmlXIncludeNewContext(xmlDocPtr doc) { 00280 xmlXIncludeCtxtPtr ret; 00281 00282 #ifdef DEBUG_XINCLUDE 00283 xmlGenericError(xmlGenericErrorContext, "New context\n"); 00284 #endif 00285 if (doc == NULL) 00286 return(NULL); 00287 ret = (xmlXIncludeCtxtPtr) xmlMalloc(sizeof(xmlXIncludeCtxt)); 00288 if (ret == NULL) { 00289 xmlXIncludeErrMemory(NULL, (xmlNodePtr) doc, 00290 "creating XInclude context"); 00291 return(NULL); 00292 } 00293 memset(ret, 0, sizeof(xmlXIncludeCtxt)); 00294 ret->doc = doc; 00295 ret->incNr = 0; 00296 ret->incBase = 0; 00297 ret->incMax = 0; 00298 ret->incTab = NULL; 00299 ret->nbErrors = 0; 00300 return(ret); 00301 } 00302 00312 static int 00313 xmlXIncludeURLPush(xmlXIncludeCtxtPtr ctxt, 00314 const xmlChar *value) 00315 { 00316 if (ctxt->urlNr > XINCLUDE_MAX_DEPTH) { 00317 xmlXIncludeErr(ctxt, NULL, XML_XINCLUDE_RECURSION, 00318 "detected a recursion in %s\n", value); 00319 return(-1); 00320 } 00321 if (ctxt->urlTab == NULL) { 00322 ctxt->urlMax = 4; 00323 ctxt->urlNr = 0; 00324 ctxt->urlTab = (xmlChar * *) xmlMalloc( 00325 ctxt->urlMax * sizeof(ctxt->urlTab[0])); 00326 if (ctxt->urlTab == NULL) { 00327 xmlXIncludeErrMemory(ctxt, NULL, "adding URL"); 00328 return (-1); 00329 } 00330 } 00331 if (ctxt->urlNr >= ctxt->urlMax) { 00332 ctxt->urlMax *= 2; 00333 ctxt->urlTab = 00334 (xmlChar * *) xmlRealloc(ctxt->urlTab, 00335 ctxt->urlMax * 00336 sizeof(ctxt->urlTab[0])); 00337 if (ctxt->urlTab == NULL) { 00338 xmlXIncludeErrMemory(ctxt, NULL, "adding URL"); 00339 return (-1); 00340 } 00341 } 00342 ctxt->url = ctxt->urlTab[ctxt->urlNr] = xmlStrdup(value); 00343 return (ctxt->urlNr++); 00344 } 00345 00352 static void 00353 xmlXIncludeURLPop(xmlXIncludeCtxtPtr ctxt) 00354 { 00355 xmlChar * ret; 00356 00357 if (ctxt->urlNr <= 0) 00358 return; 00359 ctxt->urlNr--; 00360 if (ctxt->urlNr > 0) 00361 ctxt->url = ctxt->urlTab[ctxt->urlNr - 1]; 00362 else 00363 ctxt->url = NULL; 00364 ret = ctxt->urlTab[ctxt->urlNr]; 00365 ctxt->urlTab[ctxt->urlNr] = NULL; 00366 if (ret != NULL) 00367 xmlFree(ret); 00368 } 00369 00376 void 00377 xmlXIncludeFreeContext(xmlXIncludeCtxtPtr ctxt) { 00378 int i; 00379 00380 #ifdef DEBUG_XINCLUDE 00381 xmlGenericError(xmlGenericErrorContext, "Freeing context\n"); 00382 #endif 00383 if (ctxt == NULL) 00384 return; 00385 while (ctxt->urlNr > 0) 00386 xmlXIncludeURLPop(ctxt); 00387 if (ctxt->urlTab != NULL) 00388 xmlFree(ctxt->urlTab); 00389 for (i = 0;i < ctxt->incNr;i++) { 00390 if (ctxt->incTab[i] != NULL) 00391 xmlXIncludeFreeRef(ctxt->incTab[i]); 00392 } 00393 if (ctxt->txturlTab != NULL) { 00394 for (i = 0;i < ctxt->txtNr;i++) { 00395 if (ctxt->txturlTab[i] != NULL) 00396 xmlFree(ctxt->txturlTab[i]); 00397 } 00398 } 00399 if (ctxt->incTab != NULL) 00400 xmlFree(ctxt->incTab); 00401 if (ctxt->txtTab != NULL) 00402 xmlFree(ctxt->txtTab); 00403 if (ctxt->txturlTab != NULL) 00404 xmlFree(ctxt->txturlTab); 00405 if (ctxt->base != NULL) { 00406 xmlFree(ctxt->base); 00407 } 00408 xmlFree(ctxt); 00409 } 00410 00418 static xmlDocPtr 00419 xmlXIncludeParseFile(xmlXIncludeCtxtPtr ctxt, const char *URL) { 00420 xmlDocPtr ret; 00421 xmlParserCtxtPtr pctxt; 00422 xmlParserInputPtr inputStream; 00423 00424 xmlInitParser(); 00425 00426 pctxt = xmlNewParserCtxt(); 00427 if (pctxt == NULL) { 00428 xmlXIncludeErrMemory(ctxt, NULL, "cannot allocate parser context"); 00429 return(NULL); 00430 } 00431 00432 /* 00433 * pass in the application data to the parser context. 00434 */ 00435 pctxt->_private = ctxt->_private; 00436 00437 /* 00438 * try to ensure that new documents included are actually 00439 * built with the same dictionary as the including document. 00440 */ 00441 if ((ctxt->doc != NULL) && (ctxt->doc->dict != NULL)) { 00442 if (pctxt->dict != NULL) 00443 xmlDictFree(pctxt->dict); 00444 pctxt->dict = ctxt->doc->dict; 00445 xmlDictReference(pctxt->dict); 00446 } 00447 00448 xmlCtxtUseOptions(pctxt, ctxt->parseFlags | XML_PARSE_DTDLOAD); 00449 00450 inputStream = xmlLoadExternalEntity(URL, NULL, pctxt); 00451 if (inputStream == NULL) { 00452 xmlFreeParserCtxt(pctxt); 00453 return(NULL); 00454 } 00455 00456 inputPush(pctxt, inputStream); 00457 00458 if (pctxt->directory == NULL) 00459 pctxt->directory = xmlParserGetDirectory(URL); 00460 00461 pctxt->loadsubset |= XML_DETECT_IDS; 00462 00463 xmlParseDocument(pctxt); 00464 00465 if (pctxt->wellFormed) { 00466 ret = pctxt->myDoc; 00467 } 00468 else { 00469 ret = NULL; 00470 if (pctxt->myDoc != NULL) 00471 xmlFreeDoc(pctxt->myDoc); 00472 pctxt->myDoc = NULL; 00473 } 00474 xmlFreeParserCtxt(pctxt); 00475 00476 return(ret); 00477 } 00478 00486 static int 00487 xmlXIncludeAddNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr cur) { 00488 xmlXIncludeRefPtr ref; 00489 xmlURIPtr uri; 00490 xmlChar *URL; 00491 xmlChar *fragment = NULL; 00492 xmlChar *href; 00493 xmlChar *parse; 00494 xmlChar *base; 00495 xmlChar *URI; 00496 int xml = 1, i; /* default Issue 64 */ 00497 int local = 0; 00498 00499 00500 if (ctxt == NULL) 00501 return(-1); 00502 if (cur == NULL) 00503 return(-1); 00504 00505 #ifdef DEBUG_XINCLUDE 00506 xmlGenericError(xmlGenericErrorContext, "Add node\n"); 00507 #endif 00508 /* 00509 * read the attributes 00510 */ 00511 href = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_HREF); 00512 if (href == NULL) { 00513 href = xmlStrdup(BAD_CAST ""); /* @@@@ href is now optional */ 00514 if (href == NULL) 00515 return(-1); 00516 } 00517 if ((href[0] == '#') || (href[0] == 0)) 00518 local = 1; 00519 parse = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_PARSE); 00520 if (parse != NULL) { 00521 if (xmlStrEqual(parse, XINCLUDE_PARSE_XML)) 00522 xml = 1; 00523 else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT)) 00524 xml = 0; 00525 else { 00526 xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_PARSE_VALUE, 00527 "invalid value %s for 'parse'\n", parse); 00528 if (href != NULL) 00529 xmlFree(href); 00530 if (parse != NULL) 00531 xmlFree(parse); 00532 return(-1); 00533 } 00534 } 00535 00536 /* 00537 * compute the URI 00538 */ 00539 base = xmlNodeGetBase(ctxt->doc, cur); 00540 if (base == NULL) { 00541 URI = xmlBuildURI(href, ctxt->doc->URL); 00542 } else { 00543 URI = xmlBuildURI(href, base); 00544 } 00545 if (URI == NULL) { 00546 xmlChar *escbase; 00547 xmlChar *eschref; 00548 /* 00549 * Some escaping may be needed 00550 */ 00551 escbase = xmlURIEscape(base); 00552 eschref = xmlURIEscape(href); 00553 URI = xmlBuildURI(eschref, escbase); 00554 if (escbase != NULL) 00555 xmlFree(escbase); 00556 if (eschref != NULL) 00557 xmlFree(eschref); 00558 } 00559 if (parse != NULL) 00560 xmlFree(parse); 00561 if (href != NULL) 00562 xmlFree(href); 00563 if (base != NULL) 00564 xmlFree(base); 00565 if (URI == NULL) { 00566 xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_HREF_URI, 00567 "failed build URL\n", NULL); 00568 return(-1); 00569 } 00570 fragment = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_PARSE_XPOINTER); 00571 00572 /* 00573 * Check the URL and remove any fragment identifier 00574 */ 00575 uri = xmlParseURI((const char *)URI); 00576 if (uri == NULL) { 00577 xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_HREF_URI, 00578 "invalid value URI %s\n", URI); 00579 if (fragment != NULL) 00580 xmlFree(fragment); 00581 xmlFree(URI); 00582 return(-1); 00583 } 00584 00585 if (uri->fragment != NULL) { 00586 if (ctxt->legacy != 0) { 00587 if (fragment == NULL) { 00588 fragment = (xmlChar *) uri->fragment; 00589 } else { 00590 xmlFree(uri->fragment); 00591 } 00592 } else { 00593 xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_FRAGMENT_ID, 00594 "Invalid fragment identifier in URI %s use the xpointer attribute\n", 00595 URI); 00596 if (fragment != NULL) 00597 xmlFree(fragment); 00598 xmlFreeURI(uri); 00599 xmlFree(URI); 00600 return(-1); 00601 } 00602 uri->fragment = NULL; 00603 } 00604 URL = xmlSaveUri(uri); 00605 xmlFreeURI(uri); 00606 xmlFree(URI); 00607 if (URL == NULL) { 00608 xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_HREF_URI, 00609 "invalid value URI %s\n", URI); 00610 if (fragment != NULL) 00611 xmlFree(fragment); 00612 return(-1); 00613 } 00614 00615 /* 00616 * If local and xml then we need a fragment 00617 */ 00618 if ((local == 1) && (xml == 1) && 00619 ((fragment == NULL) || (fragment[0] == 0))) { 00620 xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_RECURSION, 00621 "detected a local recursion with no xpointer in %s\n", 00622 URL); 00623 if (fragment != NULL) 00624 xmlFree(fragment); 00625 return(-1); 00626 } 00627 00628 /* 00629 * Check the URL against the stack for recursions 00630 */ 00631 if ((!local) && (xml == 1)) { 00632 for (i = 0;i < ctxt->urlNr;i++) { 00633 if (xmlStrEqual(URL, ctxt->urlTab[i])) { 00634 xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_RECURSION, 00635 "detected a recursion in %s\n", URL); 00636 return(-1); 00637 } 00638 } 00639 } 00640 00641 ref = xmlXIncludeNewRef(ctxt, URL, cur); 00642 if (ref == NULL) { 00643 return(-1); 00644 } 00645 ref->fragment = fragment; 00646 ref->doc = NULL; 00647 ref->xml = xml; 00648 ref->count = 1; 00649 xmlFree(URL); 00650 return(0); 00651 } 00652 00661 static void 00662 xmlXIncludeRecurseDoc(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, 00663 const xmlURL url ATTRIBUTE_UNUSED) { 00664 xmlXIncludeCtxtPtr newctxt; 00665 int i; 00666 00667 /* 00668 * Avoid recursion in already substitued resources 00669 for (i = 0;i < ctxt->urlNr;i++) { 00670 if (xmlStrEqual(doc->URL, ctxt->urlTab[i])) 00671 return; 00672 } 00673 */ 00674 00675 #ifdef DEBUG_XINCLUDE 00676 xmlGenericError(xmlGenericErrorContext, "Recursing in doc %s\n", doc->URL); 00677 #endif 00678 /* 00679 * Handle recursion here. 00680 */ 00681 00682 newctxt = xmlXIncludeNewContext(doc); 00683 if (newctxt != NULL) { 00684 /* 00685 * Copy the private user data 00686 */ 00687 newctxt->_private = ctxt->_private; 00688 /* 00689 * Copy the existing document set 00690 */ 00691 newctxt->incMax = ctxt->incMax; 00692 newctxt->incNr = ctxt->incNr; 00693 newctxt->incTab = (xmlXIncludeRefPtr *) xmlMalloc(newctxt->incMax * 00694 sizeof(newctxt->incTab[0])); 00695 if (newctxt->incTab == NULL) { 00696 xmlXIncludeErrMemory(ctxt, (xmlNodePtr) doc, "processing doc"); 00697 xmlFree(newctxt); 00698 return; 00699 } 00700 /* 00701 * copy the urlTab 00702 */ 00703 newctxt->urlMax = ctxt->urlMax; 00704 newctxt->urlNr = ctxt->urlNr; 00705 newctxt->urlTab = ctxt->urlTab; 00706 00707 /* 00708 * Inherit the existing base 00709 */ 00710 newctxt->base = xmlStrdup(ctxt->base); 00711 00712 /* 00713 * Inherit the documents already in use by other includes 00714 */ 00715 newctxt->incBase = ctxt->incNr; 00716 for (i = 0;i < ctxt->incNr;i++) { 00717 newctxt->incTab[i] = ctxt->incTab[i]; 00718 newctxt->incTab[i]->count++; /* prevent the recursion from 00719 freeing it */ 00720 } 00721 /* 00722 * The new context should also inherit the Parse Flags 00723 * (bug 132597) 00724 */ 00725 newctxt->parseFlags = ctxt->parseFlags; 00726 xmlXIncludeDoProcess(newctxt, doc, xmlDocGetRootElement(doc)); 00727 for (i = 0;i < ctxt->incNr;i++) { 00728 newctxt->incTab[i]->count--; 00729 newctxt->incTab[i] = NULL; 00730 } 00731 00732 /* urlTab may have been reallocated */ 00733 ctxt->urlTab = newctxt->urlTab; 00734 ctxt->urlMax = newctxt->urlMax; 00735 00736 newctxt->urlMax = 0; 00737 newctxt->urlNr = 0; 00738 newctxt->urlTab = NULL; 00739 00740 xmlXIncludeFreeContext(newctxt); 00741 } 00742 #ifdef DEBUG_XINCLUDE 00743 xmlGenericError(xmlGenericErrorContext, "Done recursing in doc %s\n", url); 00744 #endif 00745 } 00746 00755 static void 00756 xmlXIncludeAddTxt(xmlXIncludeCtxtPtr ctxt, xmlNodePtr txt, const xmlURL url) { 00757 #ifdef DEBUG_XINCLUDE 00758 xmlGenericError(xmlGenericErrorContext, "Adding text %s\n", url); 00759 #endif 00760 if (ctxt->txtMax == 0) { 00761 ctxt->txtMax = 4; 00762 ctxt->txtTab = (xmlNodePtr *) xmlMalloc(ctxt->txtMax * 00763 sizeof(ctxt->txtTab[0])); 00764 if (ctxt->txtTab == NULL) { 00765 xmlXIncludeErrMemory(ctxt, NULL, "processing text"); 00766 return; 00767 } 00768 ctxt->txturlTab = (xmlURL *) xmlMalloc(ctxt->txtMax * 00769 sizeof(ctxt->txturlTab[0])); 00770 if (ctxt->txturlTab == NULL) { 00771 xmlXIncludeErrMemory(ctxt, NULL, "processing text"); 00772 return; 00773 } 00774 } 00775 if (ctxt->txtNr >= ctxt->txtMax) { 00776 ctxt->txtMax *= 2; 00777 ctxt->txtTab = (xmlNodePtr *) xmlRealloc(ctxt->txtTab, 00778 ctxt->txtMax * sizeof(ctxt->txtTab[0])); 00779 if (ctxt->txtTab == NULL) { 00780 xmlXIncludeErrMemory(ctxt, NULL, "processing text"); 00781 return; 00782 } 00783 ctxt->txturlTab = (xmlURL *) xmlRealloc(ctxt->txturlTab, 00784 ctxt->txtMax * sizeof(ctxt->txturlTab[0])); 00785 if (ctxt->txturlTab == NULL) { 00786 xmlXIncludeErrMemory(ctxt, NULL, "processing text"); 00787 return; 00788 } 00789 } 00790 ctxt->txtTab[ctxt->txtNr] = txt; 00791 ctxt->txturlTab[ctxt->txtNr] = xmlStrdup(url); 00792 ctxt->txtNr++; 00793 } 00794 00795 /************************************************************************ 00796 * * 00797 * Node copy with specific semantic * 00798 * * 00799 ************************************************************************/ 00800 00801 static xmlNodePtr 00802 xmlXIncludeCopyNodeList(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target, 00803 xmlDocPtr source, xmlNodePtr elem); 00804 00815 static xmlNodePtr 00816 xmlXIncludeCopyNode(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target, 00817 xmlDocPtr source, xmlNodePtr elem) { 00818 xmlNodePtr result = NULL; 00819 00820 if ((ctxt == NULL) || (target == NULL) || (source == NULL) || 00821 (elem == NULL)) 00822 return(NULL); 00823 if (elem->type == XML_DTD_NODE) 00824 return(NULL); 00825 if (elem->type == XML_DOCUMENT_NODE) 00826 result = xmlXIncludeCopyNodeList(ctxt, target, source, elem->children); 00827 else 00828 result = xmlDocCopyNode(elem, target, 1); 00829 return(result); 00830 } 00831 00842 static xmlNodePtr 00843 xmlXIncludeCopyNodeList(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target, 00844 xmlDocPtr source, xmlNodePtr elem) { 00845 xmlNodePtr cur, res, result = NULL, last = NULL; 00846 00847 if ((ctxt == NULL) || (target == NULL) || (source == NULL) || 00848 (elem == NULL)) 00849 return(NULL); 00850 cur = elem; 00851 while (cur != NULL) { 00852 res = xmlXIncludeCopyNode(ctxt, target, source, cur); 00853 if (res != NULL) { 00854 if (result == NULL) { 00855 result = last = res; 00856 } else { 00857 last->next = res; 00858 res->prev = last; 00859 last = res; 00860 } 00861 } 00862 cur = cur->next; 00863 } 00864 return(result); 00865 } 00866 00874 static xmlNodePtr 00875 xmlXIncludeGetNthChild(xmlNodePtr cur, int no) { 00876 int i; 00877 if (cur == NULL) 00878 return(cur); 00879 cur = cur->children; 00880 for (i = 0;i <= no;cur = cur->next) { 00881 if (cur == NULL) 00882 return(cur); 00883 if ((cur->type == XML_ELEMENT_NODE) || 00884 (cur->type == XML_DOCUMENT_NODE) || 00885 (cur->type == XML_HTML_DOCUMENT_NODE)) { 00886 i++; 00887 if (i == no) 00888 break; 00889 } 00890 } 00891 return(cur); 00892 } 00893 00894 xmlNodePtr xmlXPtrAdvanceNode(xmlNodePtr cur, int *level); /* in xpointer.c */ 00907 static xmlNodePtr 00908 xmlXIncludeCopyRange(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target, 00909 xmlDocPtr source, xmlXPathObjectPtr range) { 00910 /* pointers to generated nodes */ 00911 xmlNodePtr list = NULL, last = NULL, listParent = NULL; 00912 xmlNodePtr tmp, tmp2; 00913 /* pointers to traversal nodes */ 00914 xmlNodePtr start, cur, end; 00915 int index1, index2; 00916 int level = 0, lastLevel = 0, endLevel = 0, endFlag = 0; 00917 00918 if ((ctxt == NULL) || (target == NULL) || (source == NULL) || 00919 (range == NULL)) 00920 return(NULL); 00921 if (range->type != XPATH_RANGE) 00922 return(NULL); 00923 start = (xmlNodePtr) range->user; 00924 00925 if (start == NULL) 00926 return(NULL); 00927 end = range->user2; 00928 if (end == NULL) 00929 return(xmlDocCopyNode(start, target, 1)); 00930 00931 cur = start; 00932 index1 = range->index; 00933 index2 = range->index2; 00934 /* 00935 * level is depth of the current node under consideration 00936 * list is the pointer to the root of the output tree 00937 * listParent is a pointer to the parent of output tree (within 00938 the included file) in case we need to add another level 00939 * last is a pointer to the last node added to the output tree 00940 * lastLevel is the depth of last (relative to the root) 00941 */ 00942 while (cur != NULL) { 00943 /* 00944 * Check if our output tree needs a parent 00945 */ 00946 if (level < 0) { 00947 while (level < 0) { 00948 /* copy must include namespaces and properties */ 00949 tmp2 = xmlDocCopyNode(listParent, target, 2); 00950 xmlAddChild(tmp2, list); 00951 list = tmp2; 00952 listParent = listParent->parent; 00953 level++; 00954 } 00955 last = list; 00956 lastLevel = 0; 00957 } 00958 /* 00959 * Check whether we need to change our insertion point 00960 */ 00961 while (level < lastLevel) { 00962 last = last->parent; 00963 lastLevel --; 00964 } 00965 if (cur == end) { /* Are we at the end of the range? */ 00966 if (cur->type == XML_TEXT_NODE) { 00967 const xmlChar *content = cur->content; 00968 int len; 00969 00970 if (content == NULL) { 00971 tmp = xmlNewTextLen(NULL, 0); 00972 } else { 00973 len = index2; 00974 if ((cur == start) && (index1 > 1)) { 00975 content += (index1 - 1); 00976 len -= (index1 - 1); 00977 } else { 00978 len = index2; 00979 } 00980 tmp = xmlNewTextLen(content, len); 00981 } 00982 /* single sub text node selection */ 00983 if (list == NULL) 00984 return(tmp); 00985 /* prune and return full set */ 00986 if (level == lastLevel) 00987 xmlAddNextSibling(last, tmp); 00988 else 00989 xmlAddChild(last, tmp); 00990 return(list); 00991 } else { /* ending node not a text node */ 00992 endLevel = level; /* remember the level of the end node */ 00993 endFlag = 1; 00994 /* last node - need to take care of properties + namespaces */ 00995 tmp = xmlDocCopyNode(cur, target, 2); 00996 if (list == NULL) { 00997 list = tmp; 00998 listParent = cur->parent; 00999 } else { 01000 if (level == lastLevel) 01001 xmlAddNextSibling(last, tmp); 01002 else { 01003 xmlAddChild(last, tmp); 01004 lastLevel = level; 01005 } 01006 } 01007 last = tmp; 01008 01009 if (index2 > 1) { 01010 end = xmlXIncludeGetNthChild(cur, index2 - 1); 01011 index2 = 0; 01012 } 01013 if ((cur == start) && (index1 > 1)) { 01014 cur = xmlXIncludeGetNthChild(cur, index1 - 1); 01015 index1 = 0; 01016 } else { 01017 cur = cur->children; 01018 } 01019 level++; /* increment level to show change */ 01020 /* 01021 * Now gather the remaining nodes from cur to end 01022 */ 01023 continue; /* while */ 01024 } 01025 } else if (cur == start) { /* Not at the end, are we at start? */ 01026 if ((cur->type == XML_TEXT_NODE) || 01027 (cur->type == XML_CDATA_SECTION_NODE)) { 01028 const xmlChar *content = cur->content; 01029 01030 if (content == NULL) { 01031 tmp = xmlNewTextLen(NULL, 0); 01032 } else { 01033 if (index1 > 1) { 01034 content += (index1 - 1); 01035 index1 = 0; 01036 } 01037 tmp = xmlNewText(content); 01038 } 01039 last = list = tmp; 01040 listParent = cur->parent; 01041 } else { /* Not text node */ 01042 /* 01043 * start of the range - need to take care of 01044 * properties and namespaces 01045 */ 01046 tmp = xmlDocCopyNode(cur, target, 2); 01047 list = last = tmp; 01048 listParent = cur->parent; 01049 if (index1 > 1) { /* Do we need to position? */ 01050 cur = xmlXIncludeGetNthChild(cur, index1 - 1); 01051 level = lastLevel = 1; 01052 index1 = 0; 01053 /* 01054 * Now gather the remaining nodes from cur to end 01055 */ 01056 continue; /* while */ 01057 } 01058 } 01059 } else { 01060 tmp = NULL; 01061 switch (cur->type) { 01062 case XML_DTD_NODE: 01063 case XML_ELEMENT_DECL: 01064 case XML_ATTRIBUTE_DECL: 01065 case XML_ENTITY_NODE: 01066 /* Do not copy DTD informations */ 01067 break; 01068 case XML_ENTITY_DECL: 01069 /* handle crossing entities -> stack needed */ 01070 break; 01071 case XML_XINCLUDE_START: 01072 case XML_XINCLUDE_END: 01073 /* don't consider it part of the tree content */ 01074 break; 01075 case XML_ATTRIBUTE_NODE: 01076 /* Humm, should not happen ! */ 01077 break; 01078 default: 01079 /* 01080 * Middle of the range - need to take care of 01081 * properties and namespaces 01082 */ 01083 tmp = xmlDocCopyNode(cur, target, 2); 01084 break; 01085 } 01086 if (tmp != NULL) { 01087 if (level == lastLevel) 01088 xmlAddNextSibling(last, tmp); 01089 else { 01090 xmlAddChild(last, tmp); 01091 lastLevel = level; 01092 } 01093 last = tmp; 01094 } 01095 } 01096 /* 01097 * Skip to next node in document order 01098 */ 01099 cur = xmlXPtrAdvanceNode(cur, &level); 01100 if (endFlag && (level >= endLevel)) 01101 break; 01102 } 01103 return(list); 01104 } 01105 01119 static xmlNodePtr 01120 xmlXIncludeCopyXPointer(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target, 01121 xmlDocPtr source, xmlXPathObjectPtr obj) { 01122 xmlNodePtr list = NULL, last = NULL; 01123 int i; 01124 01125 if (source == NULL) 01126 source = ctxt->doc; 01127 if ((ctxt == NULL) || (target == NULL) || (source == NULL) || 01128 (obj == NULL)) 01129 return(NULL); 01130 switch (obj->type) { 01131 case XPATH_NODESET: { 01132 xmlNodeSetPtr set = obj->nodesetval; 01133 if (set == NULL) 01134 return(NULL); 01135 for (i = 0;i < set->nodeNr;i++) { 01136 if (set->nodeTab[i] == NULL) 01137 continue; 01138 switch (set->nodeTab[i]->type) { 01139 case XML_TEXT_NODE: 01140 case XML_CDATA_SECTION_NODE: 01141 case XML_ELEMENT_NODE: 01142 case XML_ENTITY_REF_NODE: 01143 case XML_ENTITY_NODE: 01144 case XML_PI_NODE: 01145 case XML_COMMENT_NODE: 01146 case XML_DOCUMENT_NODE: 01147 case XML_HTML_DOCUMENT_NODE: 01148 #ifdef LIBXML_DOCB_ENABLED 01149 case XML_DOCB_DOCUMENT_NODE: 01150 #endif 01151 case XML_XINCLUDE_END: 01152 break; 01153 case XML_XINCLUDE_START: { 01154 xmlNodePtr tmp, cur = set->nodeTab[i]; 01155 01156 cur = cur->next; 01157 while (cur != NULL) { 01158 switch(cur->type) { 01159 case XML_TEXT_NODE: 01160 case XML_CDATA_SECTION_NODE: 01161 case XML_ELEMENT_NODE: 01162 case XML_ENTITY_REF_NODE: 01163 case XML_ENTITY_NODE: 01164 case XML_PI_NODE: 01165 case XML_COMMENT_NODE: 01166 tmp = xmlXIncludeCopyNode(ctxt, target, 01167 source, cur); 01168 if (last == NULL) { 01169 list = last = tmp; 01170 } else { 01171 xmlAddNextSibling(last, tmp); 01172 last = tmp; 01173 } 01174 cur = cur->next; 01175 continue; 01176 default: 01177 break; 01178 } 01179 break; 01180 } 01181 continue; 01182 } 01183 case XML_ATTRIBUTE_NODE: 01184 case XML_NAMESPACE_DECL: 01185 case XML_DOCUMENT_TYPE_NODE: 01186 case XML_DOCUMENT_FRAG_NODE: 01187 case XML_NOTATION_NODE: 01188 case XML_DTD_NODE: 01189 case XML_ELEMENT_DECL: 01190 case XML_ATTRIBUTE_DECL: 01191 case XML_ENTITY_DECL: 01192 continue; /* for */ 01193 } 01194 if (last == NULL) 01195 list = last = xmlXIncludeCopyNode(ctxt, target, source, 01196 set->nodeTab[i]); 01197 else { 01198 xmlAddNextSibling(last, 01199 xmlXIncludeCopyNode(ctxt, target, source, 01200 set->nodeTab[i])); 01201 if (last->next != NULL) 01202 last = last->next; 01203 } 01204 } 01205 break; 01206 } 01207 case XPATH_LOCATIONSET: { 01208 xmlLocationSetPtr set = (xmlLocationSetPtr) obj->user; 01209 if (set == NULL) 01210 return(NULL); 01211 for (i = 0;i < set->locNr;i++) { 01212 if (last == NULL) 01213 list = last = xmlXIncludeCopyXPointer(ctxt, target, source, 01214 set->locTab[i]); 01215 else 01216 xmlAddNextSibling(last, 01217 xmlXIncludeCopyXPointer(ctxt, target, source, 01218 set->locTab[i])); 01219 if (last != NULL) { 01220 while (last->next != NULL) 01221 last = last->next; 01222 } 01223 } 01224 break; 01225 } 01226 #ifdef LIBXML_XPTR_ENABLED 01227 case XPATH_RANGE: 01228 return(xmlXIncludeCopyRange(ctxt, target, source, obj)); 01229 #endif 01230 case XPATH_POINT: 01231 /* points are ignored in XInclude */ 01232 break; 01233 default: 01234 break; 01235 } 01236 return(list); 01237 } 01238 /************************************************************************ 01239 * * 01240 * XInclude I/O handling * 01241 * * 01242 ************************************************************************/ 01243 01244 typedef struct _xmlXIncludeMergeData xmlXIncludeMergeData; 01245 typedef xmlXIncludeMergeData *xmlXIncludeMergeDataPtr; 01246 struct _xmlXIncludeMergeData { 01247 xmlDocPtr doc; 01248 xmlXIncludeCtxtPtr ctxt; 01249 }; 01250 01259 static void 01260 xmlXIncludeMergeEntity(xmlEntityPtr ent, xmlXIncludeMergeDataPtr data, 01261 xmlChar *name ATTRIBUTE_UNUSED) { 01262 xmlEntityPtr ret, prev; 01263 xmlDocPtr doc; 01264 xmlXIncludeCtxtPtr ctxt; 01265 01266 if ((ent == NULL) || (data == NULL)) 01267 return; 01268 ctxt = data->ctxt; 01269 doc = data->doc; 01270 if ((ctxt == NULL) || (doc == NULL)) 01271 return; 01272 switch (ent->etype) { 01273 case XML_INTERNAL_PARAMETER_ENTITY: 01274 case XML_EXTERNAL_PARAMETER_ENTITY: 01275 case XML_INTERNAL_PREDEFINED_ENTITY: 01276 return; 01277 case XML_INTERNAL_GENERAL_ENTITY: 01278 case XML_EXTERNAL_GENERAL_PARSED_ENTITY: 01279 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY: 01280 break; 01281 } 01282 ret = xmlAddDocEntity(doc, ent->name, ent->etype, ent->ExternalID, 01283 ent->SystemID, ent->content); 01284 if (ret != NULL) { 01285 if (ent->URI != NULL) 01286 ret->URI = xmlStrdup(ent->URI); 01287 } else { 01288 prev = xmlGetDocEntity(doc, ent->name); 01289 if (prev != NULL) { 01290 if (ent->etype != prev->etype) 01291 goto error; 01292 01293 if ((ent->SystemID != NULL) && (prev->SystemID != NULL)) { 01294 if (!xmlStrEqual(ent->SystemID, prev->SystemID)) 01295 goto error; 01296 } else if ((ent->ExternalID != NULL) && 01297 (prev->ExternalID != NULL)) { 01298 if (!xmlStrEqual(ent->ExternalID, prev->ExternalID)) 01299 goto error; 01300 } else if ((ent->content != NULL) && (prev->content != NULL)) { 01301 if (!xmlStrEqual(ent->content, prev->content)) 01302 goto error; 01303 } else { 01304 goto error; 01305 } 01306 01307 } 01308 } 01309 return; 01310 error: 01311 switch (ent->etype) { 01312 case XML_INTERNAL_PARAMETER_ENTITY: 01313 case XML_EXTERNAL_PARAMETER_ENTITY: 01314 case XML_INTERNAL_PREDEFINED_ENTITY: 01315 case XML_INTERNAL_GENERAL_ENTITY: 01316 case XML_EXTERNAL_GENERAL_PARSED_ENTITY: 01317 return; 01318 case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY: 01319 break; 01320 } 01321 xmlXIncludeErr(ctxt, (xmlNodePtr) ent, XML_XINCLUDE_ENTITY_DEF_MISMATCH, 01322 "mismatch in redefinition of entity %s\n", 01323 ent->name); 01324 } 01325 01336 static int 01337 xmlXIncludeMergeEntities(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, 01338 xmlDocPtr from) { 01339 xmlNodePtr cur; 01340 xmlDtdPtr target, source; 01341 01342 if (ctxt == NULL) 01343 return(-1); 01344 01345 if ((from == NULL) || (from->intSubset == NULL)) 01346 return(0); 01347 01348 target = doc->intSubset; 01349 if (target == NULL) { 01350 cur = xmlDocGetRootElement(doc); 01351 if (cur == NULL) 01352 return(-1); 01353 target = xmlCreateIntSubset(doc, cur->name, NULL, NULL); 01354 if (target == NULL) 01355 return(-1); 01356 } 01357 01358 source = from->intSubset; 01359 if ((source != NULL) && (source->entities != NULL)) { 01360 xmlXIncludeMergeData data; 01361 01362 data.ctxt = ctxt; 01363 data.doc = doc; 01364 01365 xmlHashScan((xmlHashTablePtr) source->entities, 01366 (xmlHashScanner) xmlXIncludeMergeEntity, &data); 01367 } 01368 source = from->extSubset; 01369 if ((source != NULL) && (source->entities != NULL)) { 01370 xmlXIncludeMergeData data; 01371 01372 data.ctxt = ctxt; 01373 data.doc = doc; 01374 01375 /* 01376 * don't duplicate existing stuff when external subsets are the same 01377 */ 01378 if ((!xmlStrEqual(target->ExternalID, source->ExternalID)) && 01379 (!xmlStrEqual(target->SystemID, source->SystemID))) { 01380 xmlHashScan((xmlHashTablePtr) source->entities, 01381 (xmlHashScanner) xmlXIncludeMergeEntity, &data); 01382 } 01383 } 01384 return(0); 01385 } 01386 01397 static int 01398 xmlXIncludeLoadDoc(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) { 01399 xmlDocPtr doc; 01400 xmlURIPtr uri; 01401 xmlChar *URL; 01402 xmlChar *fragment = NULL; 01403 int i = 0; 01404 #ifdef LIBXML_XPTR_ENABLED 01405 int saveFlags; 01406 #endif 01407 01408 #ifdef DEBUG_XINCLUDE 01409 xmlGenericError(xmlGenericErrorContext, "Loading doc %s:%d\n", url, nr); 01410 #endif 01411 /* 01412 * Check the URL and remove any fragment identifier 01413 */ 01414 uri = xmlParseURI((const char *)url); 01415 if (uri == NULL) { 01416 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, 01417 XML_XINCLUDE_HREF_URI, 01418 "invalid value URI %s\n", url); 01419 return(-1); 01420 } 01421 if (uri->fragment != NULL) { 01422 fragment = (xmlChar *) uri->fragment; 01423 uri->fragment = NULL; 01424 } 01425 if ((ctxt->incTab != NULL) && (ctxt->incTab[nr] != NULL) && 01426 (ctxt->incTab[nr]->fragment != NULL)) { 01427 if (fragment != NULL) xmlFree(fragment); 01428 fragment = xmlStrdup(ctxt->incTab[nr]->fragment); 01429 } 01430 URL = xmlSaveUri(uri); 01431 xmlFreeURI(uri); 01432 if (URL == NULL) { 01433 if (ctxt->incTab != NULL) 01434 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, 01435 XML_XINCLUDE_HREF_URI, 01436 "invalid value URI %s\n", url); 01437 else 01438 xmlXIncludeErr(ctxt, NULL, 01439 XML_XINCLUDE_HREF_URI, 01440 "invalid value URI %s\n", url); 01441 if (fragment != NULL) 01442 xmlFree(fragment); 01443 return(-1); 01444 } 01445 01446 /* 01447 * Handling of references to the local document are done 01448 * directly through ctxt->doc. 01449 */ 01450 if ((URL[0] == 0) || (URL[0] == '#') || 01451 ((ctxt->doc != NULL) && (xmlStrEqual(URL, ctxt->doc->URL)))) { 01452 doc = NULL; 01453 goto loaded; 01454 } 01455 01456 /* 01457 * Prevent reloading twice the document. 01458 */ 01459 for (i = 0; i < ctxt->incNr; i++) { 01460 if ((xmlStrEqual(URL, ctxt->incTab[i]->URI)) && 01461 (ctxt->incTab[i]->doc != NULL)) { 01462 doc = ctxt->incTab[i]->doc; 01463 #ifdef DEBUG_XINCLUDE 01464 printf("Already loaded %s\n", URL); 01465 #endif 01466 goto loaded; 01467 } 01468 } 01469 01470 /* 01471 * Load it. 01472 */ 01473 #ifdef DEBUG_XINCLUDE 01474 printf("loading %s\n", URL); 01475 #endif 01476 #ifdef LIBXML_XPTR_ENABLED 01477 /* 01478 * If this is an XPointer evaluation, we want to assure that 01479 * all entities have been resolved prior to processing the 01480 * referenced document 01481 */ 01482 saveFlags = ctxt->parseFlags; 01483 if (fragment != NULL) { /* if this is an XPointer eval */ 01484 ctxt->parseFlags |= XML_PARSE_NOENT; 01485 } 01486 #endif 01487 01488 doc = xmlXIncludeParseFile(ctxt, (const char *)URL); 01489 #ifdef LIBXML_XPTR_ENABLED 01490 ctxt->parseFlags = saveFlags; 01491 #endif 01492 if (doc == NULL) { 01493 xmlFree(URL); 01494 if (fragment != NULL) 01495 xmlFree(fragment); 01496 return(-1); 01497 } 01498 ctxt->incTab[nr]->doc = doc; 01499 /* 01500 * It's possible that the requested URL has been mapped to a 01501 * completely different location (e.g. through a catalog entry). 01502 * To check for this, we compare the URL with that of the doc 01503 * and change it if they disagree (bug 146988). 01504 */ 01505 if (!xmlStrEqual(URL, doc->URL)) { 01506 xmlFree(URL); 01507 URL = xmlStrdup(doc->URL); 01508 } 01509 for (i = nr + 1; i < ctxt->incNr; i++) { 01510 if (xmlStrEqual(URL, ctxt->incTab[i]->URI)) { 01511 ctxt->incTab[nr]->count++; 01512 #ifdef DEBUG_XINCLUDE 01513 printf("Increasing %s count since reused\n", URL); 01514 #endif 01515 break; 01516 } 01517 } 01518 01519 /* 01520 * Make sure we have all entities fixed up 01521 */ 01522 xmlXIncludeMergeEntities(ctxt, ctxt->doc, doc); 01523 01524 /* 01525 * We don't need the DTD anymore, free up space 01526 if (doc->intSubset != NULL) { 01527 xmlUnlinkNode((xmlNodePtr) doc->intSubset); 01528 xmlFreeNode((xmlNodePtr) doc->intSubset); 01529 doc->intSubset = NULL; 01530 } 01531 if (doc->extSubset != NULL) { 01532 xmlUnlinkNode((xmlNodePtr) doc->extSubset); 01533 xmlFreeNode((xmlNodePtr) doc->extSubset); 01534 doc->extSubset = NULL; 01535 } 01536 */ 01537 xmlXIncludeRecurseDoc(ctxt, doc, URL); 01538 01539 loaded: 01540 if (fragment == NULL) { 01541 /* 01542 * Add the top children list as the replacement copy. 01543 */ 01544 if (doc == NULL) 01545 { 01546 /* Hopefully a DTD declaration won't be copied from 01547 * the same document */ 01548 ctxt->incTab[nr]->inc = xmlCopyNodeList(ctxt->doc->children); 01549 } else { 01550 ctxt->incTab[nr]->inc = xmlXIncludeCopyNodeList(ctxt, ctxt->doc, 01551 doc, doc->children); 01552 } 01553 } 01554 #ifdef LIBXML_XPTR_ENABLED 01555 else { 01556 /* 01557 * Computes the XPointer expression and make a copy used 01558 * as the replacement copy. 01559 */ 01560 xmlXPathObjectPtr xptr; 01561 xmlXPathContextPtr xptrctxt; 01562 xmlNodeSetPtr set; 01563 01564 if (doc == NULL) { 01565 xptrctxt = xmlXPtrNewContext(ctxt->doc, ctxt->incTab[nr]->ref, 01566 NULL); 01567 } else { 01568 xptrctxt = xmlXPtrNewContext(doc, NULL, NULL); 01569 } 01570 if (xptrctxt == NULL) { 01571 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, 01572 XML_XINCLUDE_XPTR_FAILED, 01573 "could not create XPointer context\n", NULL); 01574 xmlFree(URL); 01575 xmlFree(fragment); 01576 return(-1); 01577 } 01578 xptr = xmlXPtrEval(fragment, xptrctxt); 01579 if (xptr == NULL) { 01580 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, 01581 XML_XINCLUDE_XPTR_FAILED, 01582 "XPointer evaluation failed: #%s\n", 01583 fragment); 01584 xmlXPathFreeContext(xptrctxt); 01585 xmlFree(URL); 01586 xmlFree(fragment); 01587 return(-1); 01588 } 01589 switch (xptr->type) { 01590 case XPATH_UNDEFINED: 01591 case XPATH_BOOLEAN: 01592 case XPATH_NUMBER: 01593 case XPATH_STRING: 01594 case XPATH_POINT: 01595 case XPATH_USERS: 01596 case XPATH_XSLT_TREE: 01597 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, 01598 XML_XINCLUDE_XPTR_RESULT, 01599 "XPointer is not a range: #%s\n", 01600 fragment); 01601 xmlXPathFreeContext(xptrctxt); 01602 xmlFree(URL); 01603 xmlFree(fragment); 01604 return(-1); 01605 case XPATH_NODESET: 01606 if ((xptr->nodesetval == NULL) || 01607 (xptr->nodesetval->nodeNr <= 0)) { 01608 xmlXPathFreeContext(xptrctxt); 01609 xmlFree(URL); 01610 xmlFree(fragment); 01611 return(-1); 01612 } 01613 01614 case XPATH_RANGE: 01615 case XPATH_LOCATIONSET: 01616 break; 01617 } 01618 set = xptr->nodesetval; 01619 if (set != NULL) { 01620 for (i = 0;i < set->nodeNr;i++) { 01621 if (set->nodeTab[i] == NULL) 01622 continue; 01623 switch (set->nodeTab[i]->type) { 01624 case XML_ELEMENT_NODE: 01625 case XML_TEXT_NODE: 01626 case XML_CDATA_SECTION_NODE: 01627 case XML_ENTITY_REF_NODE: 01628 case XML_ENTITY_NODE: 01629 case XML_PI_NODE: 01630 case XML_COMMENT_NODE: 01631 case XML_DOCUMENT_NODE: 01632 case XML_HTML_DOCUMENT_NODE: 01633 #ifdef LIBXML_DOCB_ENABLED 01634 case XML_DOCB_DOCUMENT_NODE: 01635 #endif 01636 continue; 01637 01638 case XML_ATTRIBUTE_NODE: 01639 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, 01640 XML_XINCLUDE_XPTR_RESULT, 01641 "XPointer selects an attribute: #%s\n", 01642 fragment); 01643 set->nodeTab[i] = NULL; 01644 continue; 01645 case XML_NAMESPACE_DECL: 01646 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, 01647 XML_XINCLUDE_XPTR_RESULT, 01648 "XPointer selects a namespace: #%s\n", 01649 fragment); 01650 set->nodeTab[i] = NULL; 01651 continue; 01652 case XML_DOCUMENT_TYPE_NODE: 01653 case XML_DOCUMENT_FRAG_NODE: 01654 case XML_NOTATION_NODE: 01655 case XML_DTD_NODE: 01656 case XML_ELEMENT_DECL: 01657 case XML_ATTRIBUTE_DECL: 01658 case XML_ENTITY_DECL: 01659 case XML_XINCLUDE_START: 01660 case XML_XINCLUDE_END: 01661 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, 01662 XML_XINCLUDE_XPTR_RESULT, 01663 "XPointer selects unexpected nodes: #%s\n", 01664 fragment); 01665 set->nodeTab[i] = NULL; 01666 set->nodeTab[i] = NULL; 01667 continue; /* for */ 01668 } 01669 } 01670 } 01671 if (doc == NULL) { 01672 ctxt->incTab[nr]->xptr = xptr; 01673 ctxt->incTab[nr]->inc = NULL; 01674 } else { 01675 ctxt->incTab[nr]->inc = 01676 xmlXIncludeCopyXPointer(ctxt, ctxt->doc, doc, xptr); 01677 xmlXPathFreeObject(xptr); 01678 } 01679 xmlXPathFreeContext(xptrctxt); 01680 xmlFree(fragment); 01681 } 01682 #endif 01683 01684 /* 01685 * Do the xml:base fixup if needed 01686 */ 01687 if ((doc != NULL) && (URL != NULL) && (xmlStrchr(URL, (xmlChar) '/')) && 01688 (!(ctxt->parseFlags & XML_PARSE_NOBASEFIX)) && 01689 (!(doc->parseFlags & XML_PARSE_NOBASEFIX))) { 01690 xmlNodePtr node; 01691 xmlChar *base; 01692 xmlChar *curBase; 01693 01694 /* 01695 * The base is only adjusted if "necessary", i.e. if the xinclude node 01696 * has a base specified, or the URL is relative 01697 */ 01698 base = xmlGetNsProp(ctxt->incTab[nr]->ref, BAD_CAST "base", 01699 XML_XML_NAMESPACE); 01700 if (base == NULL) { 01701 /* 01702 * No xml:base on the xinclude node, so we check whether the 01703 * URI base is different than (relative to) the context base 01704 */ 01705 curBase = xmlBuildRelativeURI(URL, ctxt->base); 01706 if (curBase == NULL) { /* Error return */ 01707 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, 01708 XML_XINCLUDE_HREF_URI, 01709 "trying to build relative URI from %s\n", URL); 01710 } else { 01711 /* If the URI doesn't contain a slash, it's not relative */ 01712 if (!xmlStrchr(curBase, (xmlChar) '/')) 01713 xmlFree(curBase); 01714 else 01715 base = curBase; 01716 } 01717 } 01718 if (base != NULL) { /* Adjustment may be needed */ 01719 node = ctxt->incTab[nr]->inc; 01720 while (node != NULL) { 01721 /* Only work on element nodes */ 01722 if (node->type == XML_ELEMENT_NODE) { 01723 curBase = xmlNodeGetBase(node->doc, node); 01724 /* If no current base, set it */ 01725 if (curBase == NULL) { 01726 xmlNodeSetBase(node, base); 01727 } else { 01728 /* 01729 * If the current base is the same as the 01730 * URL of the document, then reset it to be 01731 * the specified xml:base or the relative URI 01732 */ 01733 if (xmlStrEqual(curBase, node->doc->URL)) { 01734 xmlNodeSetBase(node, base); 01735 } else { 01736 /* 01737 * If the element already has an xml:base 01738 * set, then relativise it if necessary 01739 */ 01740 xmlChar *xmlBase; 01741 xmlBase = xmlGetNsProp(node, 01742 BAD_CAST "base", 01743 XML_XML_NAMESPACE); 01744 if (xmlBase != NULL) { 01745 xmlChar *relBase; 01746 relBase = xmlBuildURI(xmlBase, base); 01747 if (relBase == NULL) { /* error */ 01748 xmlXIncludeErr(ctxt, 01749 ctxt->incTab[nr]->ref, 01750 XML_XINCLUDE_HREF_URI, 01751 "trying to rebuild base from %s\n", 01752 xmlBase); 01753 } else { 01754 xmlNodeSetBase(node, relBase); 01755 xmlFree(relBase); 01756 } 01757 xmlFree(xmlBase); 01758 } 01759 } 01760 xmlFree(curBase); 01761 } 01762 } 01763 node = node->next; 01764 } 01765 xmlFree(base); 01766 } 01767 } 01768 if ((nr < ctxt->incNr) && (ctxt->incTab[nr]->doc != NULL) && 01769 (ctxt->incTab[nr]->count <= 1)) { 01770 #ifdef DEBUG_XINCLUDE 01771 printf("freeing %s\n", ctxt->incTab[nr]->doc->URL); 01772 #endif 01773 xmlFreeDoc(ctxt->incTab[nr]->doc); 01774 ctxt->incTab[nr]->doc = NULL; 01775 } 01776 xmlFree(URL); 01777 return(0); 01778 } 01779 01790 static int 01791 xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) { 01792 xmlParserInputBufferPtr buf; 01793 xmlNodePtr node; 01794 xmlURIPtr uri; 01795 xmlChar *URL; 01796 int i; 01797 xmlChar *encoding = NULL; 01798 xmlCharEncoding enc = (xmlCharEncoding) 0; 01799 01800 /* 01801 * Check the URL and remove any fragment identifier 01802 */ 01803 uri = xmlParseURI((const char *)url); 01804 if (uri == NULL) { 01805 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_HREF_URI, 01806 "invalid value URI %s\n", url); 01807 return(-1); 01808 } 01809 if (uri->fragment != NULL) { 01810 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_TEXT_FRAGMENT, 01811 "fragment identifier forbidden for text: %s\n", 01812 (const xmlChar *) uri->fragment); 01813 xmlFreeURI(uri); 01814 return(-1); 01815 } 01816 URL = xmlSaveUri(uri); 01817 xmlFreeURI(uri); 01818 if (URL == NULL) { 01819 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_HREF_URI, 01820 "invalid value URI %s\n", url); 01821 return(-1); 01822 } 01823 01824 /* 01825 * Handling of references to the local document are done 01826 * directly through ctxt->doc. 01827 */ 01828 if (URL[0] == 0) { 01829 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, 01830 XML_XINCLUDE_TEXT_DOCUMENT, 01831 "text serialization of document not available\n", NULL); 01832 xmlFree(URL); 01833 return(-1); 01834 } 01835 01836 /* 01837 * Prevent reloading twice the document. 01838 */ 01839 for (i = 0; i < ctxt->txtNr; i++) { 01840 if (xmlStrEqual(URL, ctxt->txturlTab[i])) { 01841 node = xmlCopyNode(ctxt->txtTab[i], 1); 01842 goto loaded; 01843 } 01844 } 01845 /* 01846 * Try to get the encoding if available 01847 */ 01848 if ((ctxt->incTab[nr] != NULL) && (ctxt->incTab[nr]->ref != NULL)) { 01849 encoding = xmlGetProp(ctxt->incTab[nr]->ref, XINCLUDE_PARSE_ENCODING); 01850 } 01851 if (encoding != NULL) { 01852 /* 01853 * TODO: we should not have to remap to the xmlCharEncoding 01854 * predefined set, a better interface than 01855 * xmlParserInputBufferCreateFilename should allow any 01856 * encoding supported by iconv 01857 */ 01858 enc = xmlParseCharEncoding((const char *) encoding); 01859 if (enc == XML_CHAR_ENCODING_ERROR) { 01860 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, 01861 XML_XINCLUDE_UNKNOWN_ENCODING, 01862 "encoding %s not supported\n", encoding); 01863 xmlFree(encoding); 01864 xmlFree(URL); 01865 return(-1); 01866 } 01867 xmlFree(encoding); 01868 } 01869 01870 /* 01871 * Load it. 01872 */ 01873 buf = xmlParserInputBufferCreateFilename((const char *)URL, enc); 01874 if (buf == NULL) { 01875 xmlFree(URL); 01876 return(-1); 01877 } 01878 node = xmlNewText(NULL); 01879 01880 /* 01881 * Scan all chars from the resource and add the to the node 01882 */ 01883 while (xmlParserInputBufferRead(buf, 128) > 0) { 01884 int len; 01885 const xmlChar *content; 01886 01887 content = xmlBufferContent(buf->buffer); 01888 len = xmlBufferLength(buf->buffer); 01889 for (i = 0;i < len;) { 01890 int cur; 01891 int l; 01892 01893 cur = xmlStringCurrentChar(NULL, &content[i], &l); 01894 if (!IS_CHAR(cur)) { 01895 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, 01896 XML_XINCLUDE_INVALID_CHAR, 01897 "%s contains invalid char\n", URL); 01898 xmlFreeParserInputBuffer(buf); 01899 xmlFree(URL); 01900 return(-1); 01901 } else { 01902 xmlNodeAddContentLen(node, &content[i], l); 01903 } 01904 i += l; 01905 } 01906 xmlBufferShrink(buf->buffer, len); 01907 } 01908 xmlFreeParserInputBuffer(buf); 01909 xmlXIncludeAddTxt(ctxt, node, URL); 01910 01911 loaded: 01912 /* 01913 * Add the element as the replacement copy. 01914 */ 01915 ctxt->incTab[nr]->inc = node; 01916 xmlFree(URL); 01917 return(0); 01918 } 01919 01931 static int 01932 xmlXIncludeLoadFallback(xmlXIncludeCtxtPtr ctxt, xmlNodePtr fallback, int nr) { 01933 xmlXIncludeCtxtPtr newctxt; 01934 int ret = 0; 01935 01936 if ((fallback == NULL) || (ctxt == NULL)) 01937 return(-1); 01938 if (fallback->children != NULL) { 01939 /* 01940 * It's possible that the fallback also has 'includes' 01941 * (Bug 129969), so we re-process the fallback just in case 01942 */ 01943 newctxt = xmlXIncludeNewContext(ctxt->doc); 01944 if (newctxt == NULL) 01945 return (-1); 01946 newctxt->_private = ctxt->_private; 01947 newctxt->base = xmlStrdup(ctxt->base); /* Inherit the base from the existing context */ 01948 xmlXIncludeSetFlags(newctxt, ctxt->parseFlags); 01949 ret = xmlXIncludeDoProcess(newctxt, ctxt->doc, fallback->children); 01950 if (ctxt->nbErrors > 0) 01951 ret = -1; 01952 else if (ret > 0) 01953 ret = 0; /* xmlXIncludeDoProcess can return +ve number */ 01954 xmlXIncludeFreeContext(newctxt); 01955 01956 ctxt->incTab[nr]->inc = xmlDocCopyNodeList(ctxt->doc, 01957 fallback->children); 01958 } else { 01959 ctxt->incTab[nr]->inc = NULL; 01960 ctxt->incTab[nr]->emptyFb = 1; /* flag empty callback */ 01961 } 01962 return(ret); 01963 } 01964 01965 /************************************************************************ 01966 * * 01967 * XInclude Processing * 01968 * * 01969 ************************************************************************/ 01970 01981 static xmlNodePtr 01982 xmlXIncludePreProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) { 01983 xmlXIncludeAddNode(ctxt, node); 01984 return(NULL); 01985 } 01986 01996 static int 01997 xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, int nr) { 01998 xmlNodePtr cur; 01999 xmlChar *href; 02000 xmlChar *parse; 02001 xmlChar *base; 02002 xmlChar *oldBase; 02003 xmlChar *URI; 02004 int xml = 1; /* default Issue 64 */ 02005 int ret; 02006 02007 if (ctxt == NULL) 02008 return(-1); 02009 if ((nr < 0) || (nr >= ctxt->incNr)) 02010 return(-1); 02011 cur = ctxt->incTab[nr]->ref; 02012 if (cur == NULL) 02013 return(-1); 02014 02015 /* 02016 * read the attributes 02017 */ 02018 href = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_HREF); 02019 if (href == NULL) { 02020 href = xmlStrdup(BAD_CAST ""); /* @@@@ href is now optional */ 02021 if (href == NULL) 02022 return(-1); 02023 } 02024 parse = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_PARSE); 02025 if (parse != NULL) { 02026 if (xmlStrEqual(parse, XINCLUDE_PARSE_XML)) 02027 xml = 1; 02028 else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT)) 02029 xml = 0; 02030 else { 02031 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, 02032 XML_XINCLUDE_PARSE_VALUE, 02033 "invalid value %s for 'parse'\n", parse); 02034 if (href != NULL) 02035 xmlFree(href); 02036 if (parse != NULL) 02037 xmlFree(parse); 02038 return(-1); 02039 } 02040 } 02041 02042 /* 02043 * compute the URI 02044 */ 02045 base = xmlNodeGetBase(ctxt->doc, cur); 02046 if (base == NULL) { 02047 URI = xmlBuildURI(href, ctxt->doc->URL); 02048 } else { 02049 URI = xmlBuildURI(href, base); 02050 } 02051 if (URI == NULL) { 02052 xmlChar *escbase; 02053 xmlChar *eschref; 02054 /* 02055 * Some escaping may be needed 02056 */ 02057 escbase = xmlURIEscape(base); 02058 eschref = xmlURIEscape(href); 02059 URI = xmlBuildURI(eschref, escbase); 02060 if (escbase != NULL) 02061 xmlFree(escbase); 02062 if (eschref != NULL) 02063 xmlFree(eschref); 02064 } 02065 if (URI == NULL) { 02066 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, 02067 XML_XINCLUDE_HREF_URI, "failed build URL\n", NULL); 02068 if (parse != NULL) 02069 xmlFree(parse); 02070 if (href != NULL) 02071 xmlFree(href); 02072 if (base != NULL) 02073 xmlFree(base); 02074 return(-1); 02075 } 02076 #ifdef DEBUG_XINCLUDE 02077 xmlGenericError(xmlGenericErrorContext, "parse: %s\n", 02078 xml ? "xml": "text"); 02079 xmlGenericError(xmlGenericErrorContext, "URI: %s\n", URI); 02080 #endif 02081 02082 /* 02083 * Save the base for this include (saving the current one) 02084 */ 02085 oldBase = ctxt->base; 02086 ctxt->base = base; 02087 02088 if (xml) { 02089 ret = xmlXIncludeLoadDoc(ctxt, URI, nr); 02090 /* xmlXIncludeGetFragment(ctxt, cur, URI); */ 02091 } else { 02092 ret = xmlXIncludeLoadTxt(ctxt, URI, nr); 02093 } 02094 02095 /* 02096 * Restore the original base before checking for fallback 02097 */ 02098 ctxt->base = oldBase; 02099 02100 if (ret < 0) { 02101 xmlNodePtr children; 02102 02103 /* 02104 * Time to try a fallback if availble 02105 */ 02106 #ifdef DEBUG_XINCLUDE 02107 xmlGenericError(xmlGenericErrorContext, "error looking for fallback\n"); 02108 #endif 02109 children = cur->children; 02110 while (children != NULL) { 02111 if ((children->type == XML_ELEMENT_NODE) && 02112 (children->ns != NULL) && 02113 (xmlStrEqual(children->name, XINCLUDE_FALLBACK)) && 02114 ((xmlStrEqual(children->ns->href, XINCLUDE_NS)) || 02115 (xmlStrEqual(children->ns->href, XINCLUDE_OLD_NS)))) { 02116 ret = xmlXIncludeLoadFallback(ctxt, children, nr); 02117 if (ret == 0) 02118 break; 02119 } 02120 children = children->next; 02121 } 02122 } 02123 if (ret < 0) { 02124 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, 02125 XML_XINCLUDE_NO_FALLBACK, 02126 "could not load %s, and no fallback was found\n", 02127 URI); 02128 } 02129 02130 /* 02131 * Cleanup 02132 */ 02133 if (URI != NULL) 02134 xmlFree(URI); 02135 if (parse != NULL) 02136 xmlFree(parse); 02137 if (href != NULL) 02138 xmlFree(href); 02139 if (base != NULL) 02140 xmlFree(base); 02141 return(0); 02142 } 02143 02153 static int 02154 xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) { 02155 xmlNodePtr cur, end, list, tmp; 02156 02157 if (ctxt == NULL) 02158 return(-1); 02159 if ((nr < 0) || (nr >= ctxt->incNr)) 02160 return(-1); 02161 cur = ctxt->incTab[nr]->ref; 02162 if (cur == NULL) 02163 return(-1); 02164 02165 /* 02166 * If we stored an XPointer a late computation may be needed 02167 */ 02168 if ((ctxt->incTab[nr]->inc == NULL) && 02169 (ctxt->incTab[nr]->xptr != NULL)) { 02170 ctxt->incTab[nr]->inc = 02171 xmlXIncludeCopyXPointer(ctxt, ctxt->doc, ctxt->doc, 02172 ctxt->incTab[nr]->xptr); 02173 xmlXPathFreeObject(ctxt->incTab[nr]->xptr); 02174 ctxt->incTab[nr]->xptr = NULL; 02175 } 02176 list = ctxt->incTab[nr]->inc; 02177 ctxt->incTab[nr]->inc = NULL; 02178 02179 /* 02180 * Check against the risk of generating a multi-rooted document 02181 */ 02182 if ((cur->parent != NULL) && 02183 (cur->parent->type != XML_ELEMENT_NODE)) { 02184 int nb_elem = 0; 02185 02186 tmp = list; 02187 while (tmp != NULL) { 02188 if (tmp->type == XML_ELEMENT_NODE) 02189 nb_elem++; 02190 tmp = tmp->next; 02191 } 02192 if (nb_elem > 1) { 02193 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, 02194 XML_XINCLUDE_MULTIPLE_ROOT, 02195 "XInclude error: would result in multiple root nodes\n", 02196 NULL); 02197 return(-1); 02198 } 02199 } 02200 02201 if (ctxt->parseFlags & XML_PARSE_NOXINCNODE) { 02202 /* 02203 * Add the list of nodes 02204 */ 02205 while (list != NULL) { 02206 end = list; 02207 list = list->next; 02208 02209 xmlAddPrevSibling(cur, end); 02210 } 02211 xmlUnlinkNode(cur); 02212 xmlFreeNode(cur); 02213 } else { 02214 /* 02215 * Change the current node as an XInclude start one, and add an 02216 * XInclude end one 02217 */ 02218 cur->type = XML_XINCLUDE_START; 02219 end = xmlNewDocNode(cur->doc, cur->ns, cur->name, NULL); 02220 if (end == NULL) { 02221 xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, 02222 XML_XINCLUDE_BUILD_FAILED, 02223 "failed to build node\n", NULL); 02224 return(-1); 02225 } 02226 end->type = XML_XINCLUDE_END; 02227 xmlAddNextSibling(cur, end); 02228 02229 /* 02230 * Add the list of nodes 02231 */ 02232 while (list != NULL) { 02233 cur = list; 02234 list = list->next; 02235 02236 xmlAddPrevSibling(end, cur); 02237 } 02238 } 02239 02240 02241 return(0); 02242 } 02243 02253 static int 02254 xmlXIncludeTestNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) { 02255 if (node == NULL) 02256 return(0); 02257 if (node->type != XML_ELEMENT_NODE) 02258 return(0); 02259 if (node->ns == NULL) 02260 return(0); 02261 if ((xmlStrEqual(node->ns->href, XINCLUDE_NS)) || 02262 (xmlStrEqual(node->ns->href, XINCLUDE_OLD_NS))) { 02263 if (xmlStrEqual(node->ns->href, XINCLUDE_OLD_NS)) { 02264 if (ctxt->legacy == 0) { 02265 #if 0 /* wait for the XML Core Working Group to get something stable ! */ 02266 xmlXIncludeWarn(ctxt, node, XML_XINCLUDE_DEPRECATED_NS, 02267 "Deprecated XInclude namespace found, use %s", 02268 XINCLUDE_NS); 02269 #endif 02270 ctxt->legacy = 1; 02271 } 02272 } 02273 if (xmlStrEqual(node->name, XINCLUDE_NODE)) { 02274 xmlNodePtr child = node->children; 02275 int nb_fallback = 0; 02276 02277 while (child != NULL) { 02278 if ((child->type == XML_ELEMENT_NODE) && 02279 (child->ns != NULL) && 02280 ((xmlStrEqual(child->ns->href, XINCLUDE_NS)) || 02281 (xmlStrEqual(child->ns->href, XINCLUDE_OLD_NS)))) { 02282 if (xmlStrEqual(child->name, XINCLUDE_NODE)) { 02283 xmlXIncludeErr(ctxt, node, 02284 XML_XINCLUDE_INCLUDE_IN_INCLUDE, 02285 "%s has an 'include' child\n", 02286 XINCLUDE_NODE); 02287 return(0); 02288 } 02289 if (xmlStrEqual(child->name, XINCLUDE_FALLBACK)) { 02290 nb_fallback++; 02291 } 02292 } 02293 child = child->next; 02294 } 02295 if (nb_fallback > 1) { 02296 xmlXIncludeErr(ctxt, node, XML_XINCLUDE_FALLBACKS_IN_INCLUDE, 02297 "%s has multiple fallback children\n", 02298 XINCLUDE_NODE); 02299 return(0); 02300 } 02301 return(1); 02302 } 02303 if (xmlStrEqual(node->name, XINCLUDE_FALLBACK)) { 02304 if ((node->parent == NULL) || 02305 (node->parent->type != XML_ELEMENT_NODE) || 02306 (node->parent->ns == NULL) || 02307 ((!xmlStrEqual(node->parent->ns->href, XINCLUDE_NS)) && 02308 (!xmlStrEqual(node->parent->ns->href, XINCLUDE_OLD_NS))) || 02309 (!xmlStrEqual(node->parent->name, XINCLUDE_NODE))) { 02310 xmlXIncludeErr(ctxt, node, 02311 XML_XINCLUDE_FALLBACK_NOT_IN_INCLUDE, 02312 "%s is not the child of an 'include'\n", 02313 XINCLUDE_FALLBACK); 02314 } 02315 } 02316 } 02317 return(0); 02318 } 02319 02331 static int 02332 xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr tree) { 02333 xmlNodePtr cur; 02334 int ret = 0; 02335 int i, start; 02336 02337 if ((doc == NULL) || (tree == NULL)) 02338 return(-1); 02339 if (ctxt == NULL) 02340 return(-1); 02341 02342 if (doc->URL != NULL) { 02343 ret = xmlXIncludeURLPush(ctxt, doc->URL); 02344 if (ret < 0) 02345 return(-1); 02346 } 02347 start = ctxt->incNr; 02348 02349 /* 02350 * First phase: lookup the elements in the document 02351 */ 02352 cur = tree; 02353 if (xmlXIncludeTestNode(ctxt, cur) == 1) 02354 xmlXIncludePreProcessNode(ctxt, cur); 02355 while ((cur != NULL) && (cur != tree->parent)) { 02356 /* TODO: need to work on entities -> stack */ 02357 if ((cur->children != NULL) && 02358 (cur->children->type != XML_ENTITY_DECL) && 02359 (cur->children->type != XML_XINCLUDE_START) && 02360 (cur->children->type != XML_XINCLUDE_END)) { 02361 cur = cur->children; 02362 if (xmlXIncludeTestNode(ctxt, cur)) 02363 xmlXIncludePreProcessNode(ctxt, cur); 02364 } else if (cur->next != NULL) { 02365 cur = cur->next; 02366 if (xmlXIncludeTestNode(ctxt, cur)) 02367 xmlXIncludePreProcessNode(ctxt, cur); 02368 } else { 02369 if (cur == tree) 02370 break; 02371 do { 02372 cur = cur->parent; 02373 if ((cur == NULL) || (cur == tree->parent)) 02374 break; /* do */ 02375 if (cur->next != NULL) { 02376 cur = cur->next; 02377 if (xmlXIncludeTestNode(ctxt, cur)) 02378 xmlXIncludePreProcessNode(ctxt, cur); 02379 break; /* do */ 02380 } 02381 } while (cur != NULL); 02382 } 02383 } 02384 02385 /* 02386 * Second Phase : collect the infosets fragments 02387 */ 02388 for (i = start;i < ctxt->incNr; i++) { 02389 xmlXIncludeLoadNode(ctxt, i); 02390 ret++; 02391 } 02392 02393 /* 02394 * Third phase: extend the original document infoset. 02395 * 02396 * Originally we bypassed the inclusion if there were any errors 02397 * encountered on any of the XIncludes. A bug was raised (bug 02398 * 132588) requesting that we output the XIncludes without error, 02399 * so the check for inc!=NULL || xptr!=NULL was put in. This may 02400 * give some other problems in the future, but for now it seems to 02401 * work ok. 02402 * 02403 */ 02404 for (i = ctxt->incBase;i < ctxt->incNr; i++) { 02405 if ((ctxt->incTab[i]->inc != NULL) || 02406 (ctxt->incTab[i]->xptr != NULL) || 02407 (ctxt->incTab[i]->emptyFb != 0)) /* (empty fallback) */ 02408 xmlXIncludeIncludeNode(ctxt, i); 02409 } 02410 02411 if (doc->URL != NULL) 02412 xmlXIncludeURLPop(ctxt); 02413 return(ret); 02414 } 02415 02425 int 02426 xmlXIncludeSetFlags(xmlXIncludeCtxtPtr ctxt, int flags) { 02427 if (ctxt == NULL) 02428 return(-1); 02429 ctxt->parseFlags = flags; 02430 return(0); 02431 } 02432 02446 int 02447 xmlXIncludeProcessTreeFlagsData(xmlNodePtr tree, int flags, void *data) { 02448 xmlXIncludeCtxtPtr ctxt; 02449 int ret = 0; 02450 02451 if ((tree == NULL) || (tree->doc == NULL)) 02452 return(-1); 02453 02454 ctxt = xmlXIncludeNewContext(tree->doc); 02455 if (ctxt == NULL) 02456 return(-1); 02457 ctxt->_private = data; 02458 ctxt->base = xmlStrdup((xmlChar *)tree->doc->URL); 02459 xmlXIncludeSetFlags(ctxt, flags); 02460 ret = xmlXIncludeDoProcess(ctxt, tree->doc, tree); 02461 if ((ret >= 0) && (ctxt->nbErrors > 0)) 02462 ret = -1; 02463 02464 xmlXIncludeFreeContext(ctxt); 02465 return(ret); 02466 } 02467 02480 int 02481 xmlXIncludeProcessFlagsData(xmlDocPtr doc, int flags, void *data) { 02482 xmlNodePtr tree; 02483 02484 if (doc == NULL) 02485 return(-1); 02486 tree = xmlDocGetRootElement(doc); 02487 if (tree == NULL) 02488 return(-1); 02489 return(xmlXIncludeProcessTreeFlagsData(tree, flags, data)); 02490 } 02491 02502 int 02503 xmlXIncludeProcessFlags(xmlDocPtr doc, int flags) { 02504 return xmlXIncludeProcessFlagsData(doc, flags, NULL); 02505 } 02506 02516 int 02517 xmlXIncludeProcess(xmlDocPtr doc) { 02518 return(xmlXIncludeProcessFlags(doc, 0)); 02519 } 02520 02531 int 02532 xmlXIncludeProcessTreeFlags(xmlNodePtr tree, int flags) { 02533 xmlXIncludeCtxtPtr ctxt; 02534 int ret = 0; 02535 02536 if ((tree == NULL) || (tree->doc == NULL)) 02537 return(-1); 02538 ctxt = xmlXIncludeNewContext(tree->doc); 02539 if (ctxt == NULL) 02540 return(-1); 02541 ctxt->base = xmlNodeGetBase(tree->doc, tree); 02542 xmlXIncludeSetFlags(ctxt, flags); 02543 ret = xmlXIncludeDoProcess(ctxt, tree->doc, tree); 02544 if ((ret >= 0) && (ctxt->nbErrors > 0)) 02545 ret = -1; 02546 02547 xmlXIncludeFreeContext(ctxt); 02548 return(ret); 02549 } 02550 02560 int 02561 xmlXIncludeProcessTree(xmlNodePtr tree) { 02562 return(xmlXIncludeProcessTreeFlags(tree, 0)); 02563 } 02564 02576 int 02577 xmlXIncludeProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) { 02578 int ret = 0; 02579 02580 if ((node == NULL) || (node->doc == NULL) || (ctxt == NULL)) 02581 return(-1); 02582 ret = xmlXIncludeDoProcess(ctxt, node->doc, node); 02583 if ((ret >= 0) && (ctxt->nbErrors > 0)) 02584 ret = -1; 02585 return(ret); 02586 } 02587 02588 #else /* !LIBXML_XINCLUDE_ENABLED */ 02589 #endif 02590 #define bottom_xinclude 02591 #include "elfgcchack.h" Generated on Sat May 26 2012 04:33:35 for ReactOS by
1.7.6.1
|