Home | History | Annotate | Download | only in libxml2
      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 (at) 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(xmlEntityPtr ent, xmlXIncludeMergeDataPtr data,
   1265 	               xmlChar *name ATTRIBUTE_UNUSED) {
   1266     xmlEntityPtr ret, prev;
   1267     xmlDocPtr doc;
   1268     xmlXIncludeCtxtPtr ctxt;
   1269 
   1270     if ((ent == NULL) || (data == NULL))
   1271 	return;
   1272     ctxt = data->ctxt;
   1273     doc = data->doc;
   1274     if ((ctxt == NULL) || (doc == NULL))
   1275 	return;
   1276     switch (ent->etype) {
   1277         case XML_INTERNAL_PARAMETER_ENTITY:
   1278         case XML_EXTERNAL_PARAMETER_ENTITY:
   1279         case XML_INTERNAL_PREDEFINED_ENTITY:
   1280 	    return;
   1281         case XML_INTERNAL_GENERAL_ENTITY:
   1282         case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
   1283         case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
   1284 	    break;
   1285     }
   1286     ret = xmlAddDocEntity(doc, ent->name, ent->etype, ent->ExternalID,
   1287 			  ent->SystemID, ent->content);
   1288     if (ret != NULL) {
   1289 	if (ent->URI != NULL)
   1290 	    ret->URI = xmlStrdup(ent->URI);
   1291     } else {
   1292 	prev = xmlGetDocEntity(doc, ent->name);
   1293 	if (prev != NULL) {
   1294 	    if (ent->etype != prev->etype)
   1295 		goto error;
   1296 
   1297 	    if ((ent->SystemID != NULL) && (prev->SystemID != NULL)) {
   1298 		if (!xmlStrEqual(ent->SystemID, prev->SystemID))
   1299 		    goto error;
   1300 	    } else if ((ent->ExternalID != NULL) &&
   1301 		       (prev->ExternalID != NULL)) {
   1302 		if (!xmlStrEqual(ent->ExternalID, prev->ExternalID))
   1303 		    goto error;
   1304 	    } else if ((ent->content != NULL) && (prev->content != NULL)) {
   1305 		if (!xmlStrEqual(ent->content, prev->content))
   1306 		    goto error;
   1307 	    } else {
   1308 		goto error;
   1309 	    }
   1310 
   1311 	}
   1312     }
   1313     return;
   1314 error:
   1315     switch (ent->etype) {
   1316         case XML_INTERNAL_PARAMETER_ENTITY:
   1317         case XML_EXTERNAL_PARAMETER_ENTITY:
   1318         case XML_INTERNAL_PREDEFINED_ENTITY:
   1319         case XML_INTERNAL_GENERAL_ENTITY:
   1320         case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
   1321 	    return;
   1322         case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
   1323 	    break;
   1324     }
   1325     xmlXIncludeErr(ctxt, (xmlNodePtr) ent, XML_XINCLUDE_ENTITY_DEF_MISMATCH,
   1326                    "mismatch in redefinition of entity %s\n",
   1327 		   ent->name);
   1328 }
   1329 
   1330 /**
   1331  * xmlXIncludeMergeEntities:
   1332  * @ctxt: an XInclude context
   1333  * @doc:  the including doc
   1334  * @from:  the included doc
   1335  *
   1336  * Inplements the entity merge
   1337  *
   1338  * Returns 0 if merge succeeded, -1 if some processing failed
   1339  */
   1340 static int
   1341 xmlXIncludeMergeEntities(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc,
   1342 	                 xmlDocPtr from) {
   1343     xmlNodePtr cur;
   1344     xmlDtdPtr target, source;
   1345 
   1346     if (ctxt == NULL)
   1347 	return(-1);
   1348 
   1349     if ((from == NULL) || (from->intSubset == NULL))
   1350 	return(0);
   1351 
   1352     target = doc->intSubset;
   1353     if (target == NULL) {
   1354 	cur = xmlDocGetRootElement(doc);
   1355 	if (cur == NULL)
   1356 	    return(-1);
   1357         target = xmlCreateIntSubset(doc, cur->name, NULL, NULL);
   1358 	if (target == NULL)
   1359 	    return(-1);
   1360     }
   1361 
   1362     source = from->intSubset;
   1363     if ((source != NULL) && (source->entities != NULL)) {
   1364 	xmlXIncludeMergeData data;
   1365 
   1366 	data.ctxt = ctxt;
   1367 	data.doc = doc;
   1368 
   1369 	xmlHashScan((xmlHashTablePtr) source->entities,
   1370 		    (xmlHashScanner) xmlXIncludeMergeEntity, &data);
   1371     }
   1372     source = from->extSubset;
   1373     if ((source != NULL) && (source->entities != NULL)) {
   1374 	xmlXIncludeMergeData data;
   1375 
   1376 	data.ctxt = ctxt;
   1377 	data.doc = doc;
   1378 
   1379 	/*
   1380 	 * don't duplicate existing stuff when external subsets are the same
   1381 	 */
   1382 	if ((!xmlStrEqual(target->ExternalID, source->ExternalID)) &&
   1383 	    (!xmlStrEqual(target->SystemID, source->SystemID))) {
   1384 	    xmlHashScan((xmlHashTablePtr) source->entities,
   1385 			(xmlHashScanner) xmlXIncludeMergeEntity, &data);
   1386 	}
   1387     }
   1388     return(0);
   1389 }
   1390 
   1391 /**
   1392  * xmlXIncludeLoadDoc:
   1393  * @ctxt:  the XInclude context
   1394  * @url:  the associated URL
   1395  * @nr:  the xinclude node number
   1396  *
   1397  * Load the document, and store the result in the XInclude context
   1398  *
   1399  * Returns 0 in case of success, -1 in case of failure
   1400  */
   1401 static int
   1402 xmlXIncludeLoadDoc(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
   1403     xmlDocPtr doc;
   1404     xmlURIPtr uri;
   1405     xmlChar *URL;
   1406     xmlChar *fragment = NULL;
   1407     int i = 0;
   1408 #ifdef LIBXML_XPTR_ENABLED
   1409     int saveFlags;
   1410 #endif
   1411 
   1412 #ifdef DEBUG_XINCLUDE
   1413     xmlGenericError(xmlGenericErrorContext, "Loading doc %s:%d\n", url, nr);
   1414 #endif
   1415     /*
   1416      * Check the URL and remove any fragment identifier
   1417      */
   1418     uri = xmlParseURI((const char *)url);
   1419     if (uri == NULL) {
   1420 	xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
   1421 	               XML_XINCLUDE_HREF_URI,
   1422 		       "invalid value URI %s\n", url);
   1423 	return(-1);
   1424     }
   1425     if (uri->fragment != NULL) {
   1426 	fragment = (xmlChar *) uri->fragment;
   1427 	uri->fragment = NULL;
   1428     }
   1429     if ((ctxt->incTab != NULL) && (ctxt->incTab[nr] != NULL) &&
   1430         (ctxt->incTab[nr]->fragment != NULL)) {
   1431 	if (fragment != NULL) xmlFree(fragment);
   1432 	fragment = xmlStrdup(ctxt->incTab[nr]->fragment);
   1433     }
   1434     URL = xmlSaveUri(uri);
   1435     xmlFreeURI(uri);
   1436     if (URL == NULL) {
   1437         if (ctxt->incTab != NULL)
   1438 	    xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
   1439 			   XML_XINCLUDE_HREF_URI,
   1440 			   "invalid value URI %s\n", url);
   1441 	else
   1442 	    xmlXIncludeErr(ctxt, NULL,
   1443 			   XML_XINCLUDE_HREF_URI,
   1444 			   "invalid value URI %s\n", url);
   1445 	if (fragment != NULL)
   1446 	    xmlFree(fragment);
   1447 	return(-1);
   1448     }
   1449 
   1450     /*
   1451      * Handling of references to the local document are done
   1452      * directly through ctxt->doc.
   1453      */
   1454     if ((URL[0] == 0) || (URL[0] == '#') ||
   1455 	((ctxt->doc != NULL) && (xmlStrEqual(URL, ctxt->doc->URL)))) {
   1456 	doc = NULL;
   1457         goto loaded;
   1458     }
   1459 
   1460     /*
   1461      * Prevent reloading twice the document.
   1462      */
   1463     for (i = 0; i < ctxt->incNr; i++) {
   1464 	if ((xmlStrEqual(URL, ctxt->incTab[i]->URI)) &&
   1465 	    (ctxt->incTab[i]->doc != NULL)) {
   1466 	    doc = ctxt->incTab[i]->doc;
   1467 #ifdef DEBUG_XINCLUDE
   1468 	    printf("Already loaded %s\n", URL);
   1469 #endif
   1470 	    goto loaded;
   1471 	}
   1472     }
   1473 
   1474     /*
   1475      * Load it.
   1476      */
   1477 #ifdef DEBUG_XINCLUDE
   1478     printf("loading %s\n", URL);
   1479 #endif
   1480 #ifdef LIBXML_XPTR_ENABLED
   1481     /*
   1482      * If this is an XPointer evaluation, we want to assure that
   1483      * all entities have been resolved prior to processing the
   1484      * referenced document
   1485      */
   1486     saveFlags = ctxt->parseFlags;
   1487     if (fragment != NULL) {	/* if this is an XPointer eval */
   1488 	ctxt->parseFlags |= XML_PARSE_NOENT;
   1489     }
   1490 #endif
   1491 
   1492     doc = xmlXIncludeParseFile(ctxt, (const char *)URL);
   1493 #ifdef LIBXML_XPTR_ENABLED
   1494     ctxt->parseFlags = saveFlags;
   1495 #endif
   1496     if (doc == NULL) {
   1497 	xmlFree(URL);
   1498 	if (fragment != NULL)
   1499 	    xmlFree(fragment);
   1500 	return(-1);
   1501     }
   1502     ctxt->incTab[nr]->doc = doc;
   1503     /*
   1504      * It's possible that the requested URL has been mapped to a
   1505      * completely different location (e.g. through a catalog entry).
   1506      * To check for this, we compare the URL with that of the doc
   1507      * and change it if they disagree (bug 146988).
   1508      */
   1509    if (!xmlStrEqual(URL, doc->URL)) {
   1510        xmlFree(URL);
   1511        URL = xmlStrdup(doc->URL);
   1512    }
   1513     for (i = nr + 1; i < ctxt->incNr; i++) {
   1514 	if (xmlStrEqual(URL, ctxt->incTab[i]->URI)) {
   1515 	    ctxt->incTab[nr]->count++;
   1516 #ifdef DEBUG_XINCLUDE
   1517 	    printf("Increasing %s count since reused\n", URL);
   1518 #endif
   1519             break;
   1520 	}
   1521     }
   1522 
   1523     /*
   1524      * Make sure we have all entities fixed up
   1525      */
   1526     xmlXIncludeMergeEntities(ctxt, ctxt->doc, doc);
   1527 
   1528     /*
   1529      * We don't need the DTD anymore, free up space
   1530     if (doc->intSubset != NULL) {
   1531 	xmlUnlinkNode((xmlNodePtr) doc->intSubset);
   1532 	xmlFreeNode((xmlNodePtr) doc->intSubset);
   1533 	doc->intSubset = NULL;
   1534     }
   1535     if (doc->extSubset != NULL) {
   1536 	xmlUnlinkNode((xmlNodePtr) doc->extSubset);
   1537 	xmlFreeNode((xmlNodePtr) doc->extSubset);
   1538 	doc->extSubset = NULL;
   1539     }
   1540      */
   1541     xmlXIncludeRecurseDoc(ctxt, doc, URL);
   1542 
   1543 loaded:
   1544     if (fragment == NULL) {
   1545 	/*
   1546 	 * Add the top children list as the replacement copy.
   1547 	 */
   1548 	if (doc == NULL)
   1549 	{
   1550 	    /* Hopefully a DTD declaration won't be copied from
   1551 	     * the same document */
   1552 	    ctxt->incTab[nr]->inc = xmlCopyNodeList(ctxt->doc->children);
   1553 	} else {
   1554 	    ctxt->incTab[nr]->inc = xmlXIncludeCopyNodeList(ctxt, ctxt->doc,
   1555 		                                       doc, doc->children);
   1556 	}
   1557     }
   1558 #ifdef LIBXML_XPTR_ENABLED
   1559     else {
   1560 	/*
   1561 	 * Computes the XPointer expression and make a copy used
   1562 	 * as the replacement copy.
   1563 	 */
   1564 	xmlXPathObjectPtr xptr;
   1565 	xmlXPathContextPtr xptrctxt;
   1566 	xmlNodeSetPtr set;
   1567 
   1568 	if (doc == NULL) {
   1569 	    xptrctxt = xmlXPtrNewContext(ctxt->doc, ctxt->incTab[nr]->ref,
   1570 		                         NULL);
   1571 	} else {
   1572 	    xptrctxt = xmlXPtrNewContext(doc, NULL, NULL);
   1573 	}
   1574 	if (xptrctxt == NULL) {
   1575 	    xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
   1576 	                   XML_XINCLUDE_XPTR_FAILED,
   1577 			   "could not create XPointer context\n", NULL);
   1578 	    xmlFree(URL);
   1579 	    xmlFree(fragment);
   1580 	    return(-1);
   1581 	}
   1582 	xptr = xmlXPtrEval(fragment, xptrctxt);
   1583 	if (xptr == NULL) {
   1584 	    xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
   1585 	                   XML_XINCLUDE_XPTR_FAILED,
   1586 			   "XPointer evaluation failed: #%s\n",
   1587 			   fragment);
   1588 	    xmlXPathFreeContext(xptrctxt);
   1589 	    xmlFree(URL);
   1590 	    xmlFree(fragment);
   1591 	    return(-1);
   1592 	}
   1593 	switch (xptr->type) {
   1594 	    case XPATH_UNDEFINED:
   1595 	    case XPATH_BOOLEAN:
   1596 	    case XPATH_NUMBER:
   1597 	    case XPATH_STRING:
   1598 	    case XPATH_POINT:
   1599 	    case XPATH_USERS:
   1600 	    case XPATH_XSLT_TREE:
   1601 		xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
   1602 		               XML_XINCLUDE_XPTR_RESULT,
   1603 			       "XPointer is not a range: #%s\n",
   1604 			       fragment);
   1605 		xmlXPathFreeContext(xptrctxt);
   1606 		xmlFree(URL);
   1607 		xmlFree(fragment);
   1608 		return(-1);
   1609 	    case XPATH_NODESET:
   1610 	        if ((xptr->nodesetval == NULL) ||
   1611 		    (xptr->nodesetval->nodeNr <= 0)) {
   1612 		    xmlXPathFreeContext(xptrctxt);
   1613 		    xmlFree(URL);
   1614 		    xmlFree(fragment);
   1615 		    return(-1);
   1616 		}
   1617 
   1618 	    case XPATH_RANGE:
   1619 	    case XPATH_LOCATIONSET:
   1620 		break;
   1621 	}
   1622 	set = xptr->nodesetval;
   1623 	if (set != NULL) {
   1624 	    for (i = 0;i < set->nodeNr;i++) {
   1625 		if (set->nodeTab[i] == NULL)
   1626 		    continue;
   1627 		switch (set->nodeTab[i]->type) {
   1628 		    case XML_ELEMENT_NODE:
   1629 		    case XML_TEXT_NODE:
   1630 		    case XML_CDATA_SECTION_NODE:
   1631 		    case XML_ENTITY_REF_NODE:
   1632 		    case XML_ENTITY_NODE:
   1633 		    case XML_PI_NODE:
   1634 		    case XML_COMMENT_NODE:
   1635 		    case XML_DOCUMENT_NODE:
   1636 		    case XML_HTML_DOCUMENT_NODE:
   1637 #ifdef LIBXML_DOCB_ENABLED
   1638 		    case XML_DOCB_DOCUMENT_NODE:
   1639 #endif
   1640 			continue;
   1641 
   1642 		    case XML_ATTRIBUTE_NODE:
   1643 			xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
   1644 			               XML_XINCLUDE_XPTR_RESULT,
   1645 				       "XPointer selects an attribute: #%s\n",
   1646 				       fragment);
   1647 			set->nodeTab[i] = NULL;
   1648 			continue;
   1649 		    case XML_NAMESPACE_DECL:
   1650 			xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
   1651 			               XML_XINCLUDE_XPTR_RESULT,
   1652 				       "XPointer selects a namespace: #%s\n",
   1653 				       fragment);
   1654 			set->nodeTab[i] = NULL;
   1655 			continue;
   1656 		    case XML_DOCUMENT_TYPE_NODE:
   1657 		    case XML_DOCUMENT_FRAG_NODE:
   1658 		    case XML_NOTATION_NODE:
   1659 		    case XML_DTD_NODE:
   1660 		    case XML_ELEMENT_DECL:
   1661 		    case XML_ATTRIBUTE_DECL:
   1662 		    case XML_ENTITY_DECL:
   1663 		    case XML_XINCLUDE_START:
   1664 		    case XML_XINCLUDE_END:
   1665 			xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
   1666 			               XML_XINCLUDE_XPTR_RESULT,
   1667 				   "XPointer selects unexpected nodes: #%s\n",
   1668 				       fragment);
   1669 			set->nodeTab[i] = NULL;
   1670 			set->nodeTab[i] = NULL;
   1671 			continue; /* for */
   1672 		}
   1673 	    }
   1674 	}
   1675 	if (doc == NULL) {
   1676 	    ctxt->incTab[nr]->xptr = xptr;
   1677 	    ctxt->incTab[nr]->inc = NULL;
   1678 	} else {
   1679 	    ctxt->incTab[nr]->inc =
   1680 		xmlXIncludeCopyXPointer(ctxt, ctxt->doc, doc, xptr);
   1681 	    xmlXPathFreeObject(xptr);
   1682 	}
   1683 	xmlXPathFreeContext(xptrctxt);
   1684 	xmlFree(fragment);
   1685     }
   1686 #endif
   1687 
   1688     /*
   1689      * Do the xml:base fixup if needed
   1690      */
   1691     if ((doc != NULL) && (URL != NULL) &&
   1692         (!(ctxt->parseFlags & XML_PARSE_NOBASEFIX)) &&
   1693 	(!(doc->parseFlags & XML_PARSE_NOBASEFIX))) {
   1694 	xmlNodePtr node;
   1695 	xmlChar *base;
   1696 	xmlChar *curBase;
   1697 
   1698 	/*
   1699 	 * The base is only adjusted if "necessary", i.e. if the xinclude node
   1700 	 * has a base specified, or the URL is relative
   1701 	 */
   1702 	base = xmlGetNsProp(ctxt->incTab[nr]->ref, BAD_CAST "base",
   1703 			XML_XML_NAMESPACE);
   1704 	if (base == NULL) {
   1705 	    /*
   1706 	     * No xml:base on the xinclude node, so we check whether the
   1707 	     * URI base is different than (relative to) the context base
   1708 	     */
   1709 	    curBase = xmlBuildRelativeURI(URL, ctxt->base);
   1710 	    if (curBase == NULL) {	/* Error return */
   1711 	        xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
   1712 	               XML_XINCLUDE_HREF_URI,
   1713 		       "trying to build relative URI from %s\n", URL);
   1714 	    } else {
   1715 		/* If the URI doesn't contain a slash, it's not relative */
   1716 	        if (!xmlStrchr(curBase, (xmlChar) '/'))
   1717 		    xmlFree(curBase);
   1718 		else
   1719 		    base = curBase;
   1720 	    }
   1721 	}
   1722 	if (base != NULL) {	/* Adjustment may be needed */
   1723 	    node = ctxt->incTab[nr]->inc;
   1724 	    while (node != NULL) {
   1725 		/* Only work on element nodes */
   1726 		if (node->type == XML_ELEMENT_NODE) {
   1727 		    curBase = xmlNodeGetBase(node->doc, node);
   1728 		    /* If no current base, set it */
   1729 		    if (curBase == NULL) {
   1730 			xmlNodeSetBase(node, base);
   1731 		    } else {
   1732 			/*
   1733 			 * If the current base is the same as the
   1734 			 * URL of the document, then reset it to be
   1735 			 * the specified xml:base or the relative URI
   1736 			 */
   1737 			if (xmlStrEqual(curBase, node->doc->URL)) {
   1738 			    xmlNodeSetBase(node, base);
   1739 			} else {
   1740 			    /*
   1741 			     * If the element already has an xml:base
   1742 			     * set, then relativise it if necessary
   1743 			     */
   1744 			    xmlChar *xmlBase;
   1745 			    xmlBase = xmlGetNsProp(node,
   1746 					    BAD_CAST "base",
   1747 					    XML_XML_NAMESPACE);
   1748 			    if (xmlBase != NULL) {
   1749 				xmlChar *relBase;
   1750 				relBase = xmlBuildURI(xmlBase, base);
   1751 				if (relBase == NULL) { /* error */
   1752 				    xmlXIncludeErr(ctxt,
   1753 						ctxt->incTab[nr]->ref,
   1754 						XML_XINCLUDE_HREF_URI,
   1755 					"trying to rebuild base from %s\n",
   1756 						xmlBase);
   1757 				} else {
   1758 				    xmlNodeSetBase(node, relBase);
   1759 				    xmlFree(relBase);
   1760 				}
   1761 				xmlFree(xmlBase);
   1762 			    }
   1763 			}
   1764 			xmlFree(curBase);
   1765 		    }
   1766 		}
   1767 	        node = node->next;
   1768 	    }
   1769 	    xmlFree(base);
   1770 	}
   1771     }
   1772     if ((nr < ctxt->incNr) && (ctxt->incTab[nr]->doc != NULL) &&
   1773 	(ctxt->incTab[nr]->count <= 1)) {
   1774 #ifdef DEBUG_XINCLUDE
   1775         printf("freeing %s\n", ctxt->incTab[nr]->doc->URL);
   1776 #endif
   1777 	xmlFreeDoc(ctxt->incTab[nr]->doc);
   1778 	ctxt->incTab[nr]->doc = NULL;
   1779     }
   1780     xmlFree(URL);
   1781     return(0);
   1782 }
   1783 
   1784 /**
   1785  * xmlXIncludeLoadTxt:
   1786  * @ctxt:  the XInclude context
   1787  * @url:  the associated URL
   1788  * @nr:  the xinclude node number
   1789  *
   1790  * Load the content, and store the result in the XInclude context
   1791  *
   1792  * Returns 0 in case of success, -1 in case of failure
   1793  */
   1794 static int
   1795 xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
   1796     xmlParserInputBufferPtr buf;
   1797     xmlNodePtr node;
   1798     xmlURIPtr uri;
   1799     xmlChar *URL;
   1800     int i;
   1801     xmlChar *encoding = NULL;
   1802     xmlCharEncoding enc = (xmlCharEncoding) 0;
   1803     xmlParserCtxtPtr pctxt;
   1804     xmlParserInputPtr inputStream;
   1805     int xinclude_multibyte_fallback_used = 0;
   1806 
   1807     /*
   1808      * Check the URL and remove any fragment identifier
   1809      */
   1810     uri = xmlParseURI((const char *)url);
   1811     if (uri == NULL) {
   1812 	xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_HREF_URI,
   1813 	               "invalid value URI %s\n", url);
   1814 	return(-1);
   1815     }
   1816     if (uri->fragment != NULL) {
   1817 	xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_TEXT_FRAGMENT,
   1818 	               "fragment identifier forbidden for text: %s\n",
   1819 		       (const xmlChar *) uri->fragment);
   1820 	xmlFreeURI(uri);
   1821 	return(-1);
   1822     }
   1823     URL = xmlSaveUri(uri);
   1824     xmlFreeURI(uri);
   1825     if (URL == NULL) {
   1826 	xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_HREF_URI,
   1827 	               "invalid value URI %s\n", url);
   1828 	return(-1);
   1829     }
   1830 
   1831     /*
   1832      * Handling of references to the local document are done
   1833      * directly through ctxt->doc.
   1834      */
   1835     if (URL[0] == 0) {
   1836 	xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
   1837 	               XML_XINCLUDE_TEXT_DOCUMENT,
   1838 		       "text serialization of document not available\n", NULL);
   1839 	xmlFree(URL);
   1840 	return(-1);
   1841     }
   1842 
   1843     /*
   1844      * Prevent reloading twice the document.
   1845      */
   1846     for (i = 0; i < ctxt->txtNr; i++) {
   1847 	if (xmlStrEqual(URL, ctxt->txturlTab[i])) {
   1848 	    node = xmlCopyNode(ctxt->txtTab[i], 1);
   1849 	    goto loaded;
   1850 	}
   1851     }
   1852     /*
   1853      * Try to get the encoding if available
   1854      */
   1855     if ((ctxt->incTab[nr] != NULL) && (ctxt->incTab[nr]->ref != NULL)) {
   1856 	encoding = xmlGetProp(ctxt->incTab[nr]->ref, XINCLUDE_PARSE_ENCODING);
   1857     }
   1858     if (encoding != NULL) {
   1859 	/*
   1860 	 * TODO: we should not have to remap to the xmlCharEncoding
   1861 	 *       predefined set, a better interface than
   1862 	 *       xmlParserInputBufferCreateFilename should allow any
   1863 	 *       encoding supported by iconv
   1864 	 */
   1865         enc = xmlParseCharEncoding((const char *) encoding);
   1866 	if (enc == XML_CHAR_ENCODING_ERROR) {
   1867 	    xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
   1868 	                   XML_XINCLUDE_UNKNOWN_ENCODING,
   1869 			   "encoding %s not supported\n", encoding);
   1870 	    xmlFree(encoding);
   1871 	    xmlFree(URL);
   1872 	    return(-1);
   1873 	}
   1874 	xmlFree(encoding);
   1875     }
   1876 
   1877     /*
   1878      * Load it.
   1879      */
   1880     pctxt = xmlNewParserCtxt();
   1881     inputStream = xmlLoadExternalEntity((const char*)URL, NULL, pctxt);
   1882     if(inputStream == NULL) {
   1883 	xmlFreeParserCtxt(pctxt);
   1884 	xmlFree(URL);
   1885 	return(-1);
   1886     }
   1887     buf = inputStream->buf;
   1888     if (buf == NULL) {
   1889 	xmlFreeInputStream (inputStream);
   1890 	xmlFreeParserCtxt(pctxt);
   1891 	xmlFree(URL);
   1892 	return(-1);
   1893     }
   1894     if (buf->encoder)
   1895 	xmlCharEncCloseFunc(buf->encoder);
   1896     buf->encoder = xmlGetCharEncodingHandler(enc);
   1897     node = xmlNewText(NULL);
   1898 
   1899     /*
   1900      * Scan all chars from the resource and add the to the node
   1901      */
   1902 xinclude_multibyte_fallback:
   1903     while (xmlParserInputBufferRead(buf, 128) > 0) {
   1904 	int len;
   1905 	const xmlChar *content;
   1906 
   1907 	content = xmlBufContent(buf->buffer);
   1908 	len = xmlBufLength(buf->buffer);
   1909 	for (i = 0;i < len;) {
   1910 	    int cur;
   1911 	    int l;
   1912 
   1913 	    cur = xmlStringCurrentChar(NULL, &content[i], &l);
   1914 	    if (!IS_CHAR(cur)) {
   1915 		/* Handle splitted multibyte char at buffer boundary */
   1916 		if (((len - i) < 4) && (!xinclude_multibyte_fallback_used)) {
   1917 		    xinclude_multibyte_fallback_used = 1;
   1918 		    xmlBufShrink(buf->buffer, i);
   1919 		    goto xinclude_multibyte_fallback;
   1920 		} else {
   1921 		    xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
   1922 				   XML_XINCLUDE_INVALID_CHAR,
   1923 				   "%s contains invalid char\n", URL);
   1924 		    xmlFreeParserInputBuffer(buf);
   1925 		    xmlFree(URL);
   1926 		    return(-1);
   1927 		}
   1928 	    } else {
   1929 		xinclude_multibyte_fallback_used = 0;
   1930 		xmlNodeAddContentLen(node, &content[i], l);
   1931 	    }
   1932 	    i += l;
   1933 	}
   1934 	xmlBufShrink(buf->buffer, len);
   1935     }
   1936     xmlFreeParserCtxt(pctxt);
   1937     xmlXIncludeAddTxt(ctxt, node, URL);
   1938     xmlFreeInputStream(inputStream);
   1939 
   1940 loaded:
   1941     /*
   1942      * Add the element as the replacement copy.
   1943      */
   1944     ctxt->incTab[nr]->inc = node;
   1945     xmlFree(URL);
   1946     return(0);
   1947 }
   1948 
   1949 /**
   1950  * xmlXIncludeLoadFallback:
   1951  * @ctxt:  the XInclude context
   1952  * @fallback:  the fallback node
   1953  * @nr:  the xinclude node number
   1954  *
   1955  * Load the content of the fallback node, and store the result
   1956  * in the XInclude context
   1957  *
   1958  * Returns 0 in case of success, -1 in case of failure
   1959  */
   1960 static int
   1961 xmlXIncludeLoadFallback(xmlXIncludeCtxtPtr ctxt, xmlNodePtr fallback, int nr) {
   1962     xmlXIncludeCtxtPtr newctxt;
   1963     int ret = 0;
   1964 
   1965     if ((fallback == NULL) || (fallback->type == XML_NAMESPACE_DECL) ||
   1966         (ctxt == NULL))
   1967 	return(-1);
   1968     if (fallback->children != NULL) {
   1969 	/*
   1970 	 * It's possible that the fallback also has 'includes'
   1971 	 * (Bug 129969), so we re-process the fallback just in case
   1972 	 */
   1973 	newctxt = xmlXIncludeNewContext(ctxt->doc);
   1974 	if (newctxt == NULL)
   1975 	    return (-1);
   1976 	newctxt->_private = ctxt->_private;
   1977 	newctxt->base = xmlStrdup(ctxt->base);	/* Inherit the base from the existing context */
   1978 	xmlXIncludeSetFlags(newctxt, ctxt->parseFlags);
   1979 	ret = xmlXIncludeDoProcess(newctxt, ctxt->doc, fallback->children);
   1980 	if (ctxt->nbErrors > 0)
   1981 	    ret = -1;
   1982 	else if (ret > 0)
   1983 	    ret = 0;	/* xmlXIncludeDoProcess can return +ve number */
   1984 	xmlXIncludeFreeContext(newctxt);
   1985 
   1986 	ctxt->incTab[nr]->inc = xmlDocCopyNodeList(ctxt->doc,
   1987 	                                           fallback->children);
   1988     } else {
   1989         ctxt->incTab[nr]->inc = NULL;
   1990 	ctxt->incTab[nr]->emptyFb = 1;	/* flag empty callback */
   1991     }
   1992     return(ret);
   1993 }
   1994 
   1995 /************************************************************************
   1996  *									*
   1997  *			XInclude Processing				*
   1998  *									*
   1999  ************************************************************************/
   2000 
   2001 /**
   2002  * xmlXIncludePreProcessNode:
   2003  * @ctxt: an XInclude context
   2004  * @node: an XInclude node
   2005  *
   2006  * Implement the XInclude preprocessing, currently just adding the element
   2007  * for further processing.
   2008  *
   2009  * Returns the result list or NULL in case of error
   2010  */
   2011 static xmlNodePtr
   2012 xmlXIncludePreProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
   2013     xmlXIncludeAddNode(ctxt, node);
   2014     return(NULL);
   2015 }
   2016 
   2017 /**
   2018  * xmlXIncludeLoadNode:
   2019  * @ctxt: an XInclude context
   2020  * @nr: the node number
   2021  *
   2022  * Find and load the infoset replacement for the given node.
   2023  *
   2024  * Returns 0 if substitution succeeded, -1 if some processing failed
   2025  */
   2026 static int
   2027 xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, int nr) {
   2028     xmlNodePtr cur;
   2029     xmlChar *href;
   2030     xmlChar *parse;
   2031     xmlChar *base;
   2032     xmlChar *oldBase;
   2033     xmlChar *URI;
   2034     int xml = 1; /* default Issue 64 */
   2035     int ret;
   2036 
   2037     if (ctxt == NULL)
   2038 	return(-1);
   2039     if ((nr < 0) || (nr >= ctxt->incNr))
   2040 	return(-1);
   2041     cur = ctxt->incTab[nr]->ref;
   2042     if (cur == NULL)
   2043 	return(-1);
   2044 
   2045     /*
   2046      * read the attributes
   2047      */
   2048     href = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_HREF);
   2049     if (href == NULL) {
   2050 	href = xmlStrdup(BAD_CAST ""); /* @@@@ href is now optional */
   2051 	if (href == NULL)
   2052 	    return(-1);
   2053     }
   2054     parse = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_PARSE);
   2055     if (parse != NULL) {
   2056 	if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
   2057 	    xml = 1;
   2058 	else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
   2059 	    xml = 0;
   2060 	else {
   2061 	    xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
   2062 	                   XML_XINCLUDE_PARSE_VALUE,
   2063 			   "invalid value %s for 'parse'\n", parse);
   2064 	    if (href != NULL)
   2065 		xmlFree(href);
   2066 	    if (parse != NULL)
   2067 		xmlFree(parse);
   2068 	    return(-1);
   2069 	}
   2070     }
   2071 
   2072     /*
   2073      * compute the URI
   2074      */
   2075     base = xmlNodeGetBase(ctxt->doc, cur);
   2076     if (base == NULL) {
   2077 	URI = xmlBuildURI(href, ctxt->doc->URL);
   2078     } else {
   2079 	URI = xmlBuildURI(href, base);
   2080     }
   2081     if (URI == NULL) {
   2082 	xmlChar *escbase;
   2083 	xmlChar *eschref;
   2084 	/*
   2085 	 * Some escaping may be needed
   2086 	 */
   2087 	escbase = xmlURIEscape(base);
   2088 	eschref = xmlURIEscape(href);
   2089 	URI = xmlBuildURI(eschref, escbase);
   2090 	if (escbase != NULL)
   2091 	    xmlFree(escbase);
   2092 	if (eschref != NULL)
   2093 	    xmlFree(eschref);
   2094     }
   2095     if (URI == NULL) {
   2096 	xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
   2097 	               XML_XINCLUDE_HREF_URI, "failed build URL\n", NULL);
   2098 	if (parse != NULL)
   2099 	    xmlFree(parse);
   2100 	if (href != NULL)
   2101 	    xmlFree(href);
   2102 	if (base != NULL)
   2103 	    xmlFree(base);
   2104 	return(-1);
   2105     }
   2106 #ifdef DEBUG_XINCLUDE
   2107     xmlGenericError(xmlGenericErrorContext, "parse: %s\n",
   2108 	    xml ? "xml": "text");
   2109     xmlGenericError(xmlGenericErrorContext, "URI: %s\n", URI);
   2110 #endif
   2111 
   2112     /*
   2113      * Save the base for this include (saving the current one)
   2114      */
   2115     oldBase = ctxt->base;
   2116     ctxt->base = base;
   2117 
   2118     if (xml) {
   2119 	ret = xmlXIncludeLoadDoc(ctxt, URI, nr);
   2120 	/* xmlXIncludeGetFragment(ctxt, cur, URI); */
   2121     } else {
   2122 	ret = xmlXIncludeLoadTxt(ctxt, URI, nr);
   2123     }
   2124 
   2125     /*
   2126      * Restore the original base before checking for fallback
   2127      */
   2128     ctxt->base = oldBase;
   2129 
   2130     if (ret < 0) {
   2131 	xmlNodePtr children;
   2132 
   2133 	/*
   2134 	 * Time to try a fallback if availble
   2135 	 */
   2136 #ifdef DEBUG_XINCLUDE
   2137 	xmlGenericError(xmlGenericErrorContext, "error looking for fallback\n");
   2138 #endif
   2139 	children = cur->children;
   2140 	while (children != NULL) {
   2141 	    if ((children->type == XML_ELEMENT_NODE) &&
   2142 		(children->ns != NULL) &&
   2143 		(xmlStrEqual(children->name, XINCLUDE_FALLBACK)) &&
   2144 		((xmlStrEqual(children->ns->href, XINCLUDE_NS)) ||
   2145 		 (xmlStrEqual(children->ns->href, XINCLUDE_OLD_NS)))) {
   2146 		ret = xmlXIncludeLoadFallback(ctxt, children, nr);
   2147 		if (ret == 0)
   2148 		    break;
   2149 	    }
   2150 	    children = children->next;
   2151 	}
   2152     }
   2153     if (ret < 0) {
   2154 	xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
   2155 	               XML_XINCLUDE_NO_FALLBACK,
   2156 		       "could not load %s, and no fallback was found\n",
   2157 		       URI);
   2158     }
   2159 
   2160     /*
   2161      * Cleanup
   2162      */
   2163     if (URI != NULL)
   2164 	xmlFree(URI);
   2165     if (parse != NULL)
   2166 	xmlFree(parse);
   2167     if (href != NULL)
   2168 	xmlFree(href);
   2169     if (base != NULL)
   2170 	xmlFree(base);
   2171     return(0);
   2172 }
   2173 
   2174 /**
   2175  * xmlXIncludeIncludeNode:
   2176  * @ctxt: an XInclude context
   2177  * @nr: the node number
   2178  *
   2179  * Inplement the infoset replacement for the given node
   2180  *
   2181  * Returns 0 if substitution succeeded, -1 if some processing failed
   2182  */
   2183 static int
   2184 xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) {
   2185     xmlNodePtr cur, end, list, tmp;
   2186 
   2187     if (ctxt == NULL)
   2188 	return(-1);
   2189     if ((nr < 0) || (nr >= ctxt->incNr))
   2190 	return(-1);
   2191     cur = ctxt->incTab[nr]->ref;
   2192     if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
   2193 	return(-1);
   2194 
   2195     /*
   2196      * If we stored an XPointer a late computation may be needed
   2197      */
   2198     if ((ctxt->incTab[nr]->inc == NULL) &&
   2199 	(ctxt->incTab[nr]->xptr != NULL)) {
   2200 	ctxt->incTab[nr]->inc =
   2201 	    xmlXIncludeCopyXPointer(ctxt, ctxt->doc, ctxt->doc,
   2202 		                    ctxt->incTab[nr]->xptr);
   2203 	xmlXPathFreeObject(ctxt->incTab[nr]->xptr);
   2204 	ctxt->incTab[nr]->xptr = NULL;
   2205     }
   2206     list = ctxt->incTab[nr]->inc;
   2207     ctxt->incTab[nr]->inc = NULL;
   2208 
   2209     /*
   2210      * Check against the risk of generating a multi-rooted document
   2211      */
   2212     if ((cur->parent != NULL) &&
   2213 	(cur->parent->type != XML_ELEMENT_NODE)) {
   2214 	int nb_elem = 0;
   2215 
   2216 	tmp = list;
   2217 	while (tmp != NULL) {
   2218 	    if (tmp->type == XML_ELEMENT_NODE)
   2219 		nb_elem++;
   2220 	    tmp = tmp->next;
   2221 	}
   2222 	if (nb_elem > 1) {
   2223 	    xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
   2224 	                   XML_XINCLUDE_MULTIPLE_ROOT,
   2225 		       "XInclude error: would result in multiple root nodes\n",
   2226 			   NULL);
   2227 	    return(-1);
   2228 	}
   2229     }
   2230 
   2231     if (ctxt->parseFlags & XML_PARSE_NOXINCNODE) {
   2232 	/*
   2233 	 * Add the list of nodes
   2234 	 */
   2235 	while (list != NULL) {
   2236 	    end = list;
   2237 	    list = list->next;
   2238 
   2239 	    xmlAddPrevSibling(cur, end);
   2240 	}
   2241 	xmlUnlinkNode(cur);
   2242 	xmlFreeNode(cur);
   2243     } else {
   2244 	/*
   2245 	 * Change the current node as an XInclude start one, and add an
   2246 	 * XInclude end one
   2247 	 */
   2248 	cur->type = XML_XINCLUDE_START;
   2249 	end = xmlNewDocNode(cur->doc, cur->ns, cur->name, NULL);
   2250 	if (end == NULL) {
   2251 	    xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
   2252 	                   XML_XINCLUDE_BUILD_FAILED,
   2253 			   "failed to build node\n", NULL);
   2254 	    return(-1);
   2255 	}
   2256 	end->type = XML_XINCLUDE_END;
   2257 	xmlAddNextSibling(cur, end);
   2258 
   2259 	/*
   2260 	 * Add the list of nodes
   2261 	 */
   2262 	while (list != NULL) {
   2263 	    cur = list;
   2264 	    list = list->next;
   2265 
   2266 	    xmlAddPrevSibling(end, cur);
   2267 	}
   2268     }
   2269 
   2270 
   2271     return(0);
   2272 }
   2273 
   2274 /**
   2275  * xmlXIncludeTestNode:
   2276  * @ctxt: the XInclude processing context
   2277  * @node: an XInclude node
   2278  *
   2279  * test if the node is an XInclude node
   2280  *
   2281  * Returns 1 true, 0 otherwise
   2282  */
   2283 static int
   2284 xmlXIncludeTestNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
   2285     if (node == NULL)
   2286 	return(0);
   2287     if (node->type != XML_ELEMENT_NODE)
   2288 	return(0);
   2289     if (node->ns == NULL)
   2290 	return(0);
   2291     if ((xmlStrEqual(node->ns->href, XINCLUDE_NS)) ||
   2292         (xmlStrEqual(node->ns->href, XINCLUDE_OLD_NS))) {
   2293 	if (xmlStrEqual(node->ns->href, XINCLUDE_OLD_NS)) {
   2294 	    if (ctxt->legacy == 0) {
   2295 #if 0 /* wait for the XML Core Working Group to get something stable ! */
   2296 		xmlXIncludeWarn(ctxt, node, XML_XINCLUDE_DEPRECATED_NS,
   2297 	               "Deprecated XInclude namespace found, use %s",
   2298 		                XINCLUDE_NS);
   2299 #endif
   2300 	        ctxt->legacy = 1;
   2301 	    }
   2302 	}
   2303 	if (xmlStrEqual(node->name, XINCLUDE_NODE)) {
   2304 	    xmlNodePtr child = node->children;
   2305 	    int nb_fallback = 0;
   2306 
   2307 	    while (child != NULL) {
   2308 		if ((child->type == XML_ELEMENT_NODE) &&
   2309 		    (child->ns != NULL) &&
   2310 		    ((xmlStrEqual(child->ns->href, XINCLUDE_NS)) ||
   2311 		     (xmlStrEqual(child->ns->href, XINCLUDE_OLD_NS)))) {
   2312 		    if (xmlStrEqual(child->name, XINCLUDE_NODE)) {
   2313 			xmlXIncludeErr(ctxt, node,
   2314 			               XML_XINCLUDE_INCLUDE_IN_INCLUDE,
   2315 				       "%s has an 'include' child\n",
   2316 				       XINCLUDE_NODE);
   2317 			return(0);
   2318 		    }
   2319 		    if (xmlStrEqual(child->name, XINCLUDE_FALLBACK)) {
   2320 			nb_fallback++;
   2321 		    }
   2322 		}
   2323 		child = child->next;
   2324 	    }
   2325 	    if (nb_fallback > 1) {
   2326 		xmlXIncludeErr(ctxt, node, XML_XINCLUDE_FALLBACKS_IN_INCLUDE,
   2327 			       "%s has multiple fallback children\n",
   2328 		               XINCLUDE_NODE);
   2329 		return(0);
   2330 	    }
   2331 	    return(1);
   2332 	}
   2333 	if (xmlStrEqual(node->name, XINCLUDE_FALLBACK)) {
   2334 	    if ((node->parent == NULL) ||
   2335 		(node->parent->type != XML_ELEMENT_NODE) ||
   2336 		(node->parent->ns == NULL) ||
   2337 		((!xmlStrEqual(node->parent->ns->href, XINCLUDE_NS)) &&
   2338 		 (!xmlStrEqual(node->parent->ns->href, XINCLUDE_OLD_NS))) ||
   2339 		(!xmlStrEqual(node->parent->name, XINCLUDE_NODE))) {
   2340 		xmlXIncludeErr(ctxt, node,
   2341 		               XML_XINCLUDE_FALLBACK_NOT_IN_INCLUDE,
   2342 			       "%s is not the child of an 'include'\n",
   2343 			       XINCLUDE_FALLBACK);
   2344 	    }
   2345 	}
   2346     }
   2347     return(0);
   2348 }
   2349 
   2350 /**
   2351  * xmlXIncludeDoProcess:
   2352  * @ctxt: the XInclude processing context
   2353  * @doc: an XML document
   2354  * @tree: the top of the tree to process
   2355  *
   2356  * Implement the XInclude substitution on the XML document @doc
   2357  *
   2358  * Returns 0 if no substitution were done, -1 if some processing failed
   2359  *    or the number of substitutions done.
   2360  */
   2361 static int
   2362 xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr tree) {
   2363     xmlNodePtr cur;
   2364     int ret = 0;
   2365     int i, start;
   2366 
   2367     if ((doc == NULL) || (tree == NULL) || (tree->type == XML_NAMESPACE_DECL))
   2368 	return(-1);
   2369     if (ctxt == NULL)
   2370 	return(-1);
   2371 
   2372     if (doc->URL != NULL) {
   2373 	ret = xmlXIncludeURLPush(ctxt, doc->URL);
   2374 	if (ret < 0)
   2375 	    return(-1);
   2376     }
   2377     start = ctxt->incNr;
   2378 
   2379     /*
   2380      * First phase: lookup the elements in the document
   2381      */
   2382     cur = tree;
   2383     if (xmlXIncludeTestNode(ctxt, cur) == 1)
   2384 	xmlXIncludePreProcessNode(ctxt, cur);
   2385     while ((cur != NULL) && (cur != tree->parent)) {
   2386 	/* TODO: need to work on entities -> stack */
   2387 	if ((cur->children != NULL) &&
   2388 	    (cur->children->type != XML_ENTITY_DECL) &&
   2389 	    (cur->children->type != XML_XINCLUDE_START) &&
   2390 	    (cur->children->type != XML_XINCLUDE_END)) {
   2391 	    cur = cur->children;
   2392 	    if (xmlXIncludeTestNode(ctxt, cur))
   2393 		xmlXIncludePreProcessNode(ctxt, cur);
   2394 	} else if (cur->next != NULL) {
   2395 	    cur = cur->next;
   2396 	    if (xmlXIncludeTestNode(ctxt, cur))
   2397 		xmlXIncludePreProcessNode(ctxt, cur);
   2398 	} else {
   2399 	    if (cur == tree)
   2400 	        break;
   2401 	    do {
   2402 		cur = cur->parent;
   2403 		if ((cur == NULL) || (cur == tree->parent))
   2404 		    break; /* do */
   2405 		if (cur->next != NULL) {
   2406 		    cur = cur->next;
   2407 		    if (xmlXIncludeTestNode(ctxt, cur))
   2408 			xmlXIncludePreProcessNode(ctxt, cur);
   2409 		    break; /* do */
   2410 		}
   2411 	    } while (cur != NULL);
   2412 	}
   2413     }
   2414 
   2415     /*
   2416      * Second Phase : collect the infosets fragments
   2417      */
   2418     for (i = start;i < ctxt->incNr; i++) {
   2419         xmlXIncludeLoadNode(ctxt, i);
   2420 	ret++;
   2421     }
   2422 
   2423     /*
   2424      * Third phase: extend the original document infoset.
   2425      *
   2426      * Originally we bypassed the inclusion if there were any errors
   2427      * encountered on any of the XIncludes.  A bug was raised (bug
   2428      * 132588) requesting that we output the XIncludes without error,
   2429      * so the check for inc!=NULL || xptr!=NULL was put in.  This may
   2430      * give some other problems in the future, but for now it seems to
   2431      * work ok.
   2432      *
   2433      */
   2434     for (i = ctxt->incBase;i < ctxt->incNr; i++) {
   2435 	if ((ctxt->incTab[i]->inc != NULL) ||
   2436 		(ctxt->incTab[i]->xptr != NULL) ||
   2437 		(ctxt->incTab[i]->emptyFb != 0))	/* (empty fallback) */
   2438 	    xmlXIncludeIncludeNode(ctxt, i);
   2439     }
   2440 
   2441     if (doc->URL != NULL)
   2442 	xmlXIncludeURLPop(ctxt);
   2443     return(ret);
   2444 }
   2445 
   2446 /**
   2447  * xmlXIncludeSetFlags:
   2448  * @ctxt:  an XInclude processing context
   2449  * @flags: a set of xmlParserOption used for parsing XML includes
   2450  *
   2451  * Set the flags used for further processing of XML resources.
   2452  *
   2453  * Returns 0 in case of success and -1 in case of error.
   2454  */
   2455 int
   2456 xmlXIncludeSetFlags(xmlXIncludeCtxtPtr ctxt, int flags) {
   2457     if (ctxt == NULL)
   2458         return(-1);
   2459     ctxt->parseFlags = flags;
   2460     return(0);
   2461 }
   2462 
   2463 /**
   2464  * xmlXIncludeProcessTreeFlagsData:
   2465  * @tree: an XML node
   2466  * @flags: a set of xmlParserOption used for parsing XML includes
   2467  * @data: application data that will be passed to the parser context
   2468  *        in the _private field of the parser context(s)
   2469  *
   2470  * Implement the XInclude substitution on the XML node @tree
   2471  *
   2472  * Returns 0 if no substitution were done, -1 if some processing failed
   2473  *    or the number of substitutions done.
   2474  */
   2475 
   2476 int
   2477 xmlXIncludeProcessTreeFlagsData(xmlNodePtr tree, int flags, void *data) {
   2478     xmlXIncludeCtxtPtr ctxt;
   2479     int ret = 0;
   2480 
   2481     if ((tree == NULL) || (tree->type == XML_NAMESPACE_DECL) ||
   2482         (tree->doc == NULL))
   2483         return(-1);
   2484 
   2485     ctxt = xmlXIncludeNewContext(tree->doc);
   2486     if (ctxt == NULL)
   2487         return(-1);
   2488     ctxt->_private = data;
   2489     ctxt->base = xmlStrdup((xmlChar *)tree->doc->URL);
   2490     xmlXIncludeSetFlags(ctxt, flags);
   2491     ret = xmlXIncludeDoProcess(ctxt, tree->doc, tree);
   2492     if ((ret >= 0) && (ctxt->nbErrors > 0))
   2493         ret = -1;
   2494 
   2495     xmlXIncludeFreeContext(ctxt);
   2496     return(ret);
   2497 }
   2498 
   2499 /**
   2500  * xmlXIncludeProcessFlagsData:
   2501  * @doc: an XML document
   2502  * @flags: a set of xmlParserOption used for parsing XML includes
   2503  * @data: application data that will be passed to the parser context
   2504  *        in the _private field of the parser context(s)
   2505  *
   2506  * Implement the XInclude substitution on the XML document @doc
   2507  *
   2508  * Returns 0 if no substitution were done, -1 if some processing failed
   2509  *    or the number of substitutions done.
   2510  */
   2511 int
   2512 xmlXIncludeProcessFlagsData(xmlDocPtr doc, int flags, void *data) {
   2513     xmlNodePtr tree;
   2514 
   2515     if (doc == NULL)
   2516 	return(-1);
   2517     tree = xmlDocGetRootElement(doc);
   2518     if (tree == NULL)
   2519 	return(-1);
   2520     return(xmlXIncludeProcessTreeFlagsData(tree, flags, data));
   2521 }
   2522 
   2523 /**
   2524  * xmlXIncludeProcessFlags:
   2525  * @doc: an XML document
   2526  * @flags: a set of xmlParserOption used for parsing XML includes
   2527  *
   2528  * Implement the XInclude substitution on the XML document @doc
   2529  *
   2530  * Returns 0 if no substitution were done, -1 if some processing failed
   2531  *    or the number of substitutions done.
   2532  */
   2533 int
   2534 xmlXIncludeProcessFlags(xmlDocPtr doc, int flags) {
   2535     return xmlXIncludeProcessFlagsData(doc, flags, NULL);
   2536 }
   2537 
   2538 /**
   2539  * xmlXIncludeProcess:
   2540  * @doc: an XML document
   2541  *
   2542  * Implement the XInclude substitution on the XML document @doc
   2543  *
   2544  * Returns 0 if no substitution were done, -1 if some processing failed
   2545  *    or the number of substitutions done.
   2546  */
   2547 int
   2548 xmlXIncludeProcess(xmlDocPtr doc) {
   2549     return(xmlXIncludeProcessFlags(doc, 0));
   2550 }
   2551 
   2552 /**
   2553  * xmlXIncludeProcessTreeFlags:
   2554  * @tree: a node in an XML document
   2555  * @flags: a set of xmlParserOption used for parsing XML includes
   2556  *
   2557  * Implement the XInclude substitution for the given subtree
   2558  *
   2559  * Returns 0 if no substitution were done, -1 if some processing failed
   2560  *    or the number of substitutions done.
   2561  */
   2562 int
   2563 xmlXIncludeProcessTreeFlags(xmlNodePtr tree, int flags) {
   2564     xmlXIncludeCtxtPtr ctxt;
   2565     int ret = 0;
   2566 
   2567     if ((tree == NULL) || (tree->type == XML_NAMESPACE_DECL) ||
   2568         (tree->doc == NULL))
   2569 	return(-1);
   2570     ctxt = xmlXIncludeNewContext(tree->doc);
   2571     if (ctxt == NULL)
   2572 	return(-1);
   2573     ctxt->base = xmlNodeGetBase(tree->doc, tree);
   2574     xmlXIncludeSetFlags(ctxt, flags);
   2575     ret = xmlXIncludeDoProcess(ctxt, tree->doc, tree);
   2576     if ((ret >= 0) && (ctxt->nbErrors > 0))
   2577 	ret = -1;
   2578 
   2579     xmlXIncludeFreeContext(ctxt);
   2580     return(ret);
   2581 }
   2582 
   2583 /**
   2584  * xmlXIncludeProcessTree:
   2585  * @tree: a node in an XML document
   2586  *
   2587  * Implement the XInclude substitution for the given subtree
   2588  *
   2589  * Returns 0 if no substitution were done, -1 if some processing failed
   2590  *    or the number of substitutions done.
   2591  */
   2592 int
   2593 xmlXIncludeProcessTree(xmlNodePtr tree) {
   2594     return(xmlXIncludeProcessTreeFlags(tree, 0));
   2595 }
   2596 
   2597 /**
   2598  * xmlXIncludeProcessNode:
   2599  * @ctxt: an existing XInclude context
   2600  * @node: a node in an XML document
   2601  *
   2602  * Implement the XInclude substitution for the given subtree reusing
   2603  * the informations and data coming from the given context.
   2604  *
   2605  * Returns 0 if no substitution were done, -1 if some processing failed
   2606  *    or the number of substitutions done.
   2607  */
   2608 int
   2609 xmlXIncludeProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
   2610     int ret = 0;
   2611 
   2612     if ((node == NULL) || (node->type == XML_NAMESPACE_DECL) ||
   2613         (node->doc == NULL) || (ctxt == NULL))
   2614 	return(-1);
   2615     ret = xmlXIncludeDoProcess(ctxt, node->doc, node);
   2616     if ((ret >= 0) && (ctxt->nbErrors > 0))
   2617 	ret = -1;
   2618     return(ret);
   2619 }
   2620 
   2621 #else /* !LIBXML_XINCLUDE_ENABLED */
   2622 #endif
   2623 #define bottom_xinclude
   2624 #include "elfgcchack.h"
   2625