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