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