Home | History | Annotate | Download | only in src
      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        if (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 static xmlNodePtr
    802 xmlXIncludeCopyNodeList(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
    803 	                xmlDocPtr source, xmlNodePtr elem);
    804 
    805 /**
    806  * xmlXIncludeCopyNode:
    807  * @ctxt:  the XInclude context
    808  * @target:  the document target
    809  * @source:  the document source
    810  * @elem:  the element
    811  *
    812  * Make a copy of the node while preserving the XInclude semantic
    813  * of the Infoset copy
    814  */
    815 static xmlNodePtr
    816 xmlXIncludeCopyNode(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
    817 	            xmlDocPtr source, xmlNodePtr elem) {
    818     xmlNodePtr result = NULL;
    819 
    820     if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
    821 	(elem == NULL))
    822 	return(NULL);
    823     if (elem->type == XML_DTD_NODE)
    824 	return(NULL);
    825     if (elem->type == XML_DOCUMENT_NODE)
    826 	result = xmlXIncludeCopyNodeList(ctxt, target, source, elem->children);
    827     else
    828         result = xmlDocCopyNode(elem, target, 1);
    829     return(result);
    830 }
    831 
    832 /**
    833  * xmlXIncludeCopyNodeList:
    834  * @ctxt:  the XInclude context
    835  * @target:  the document target
    836  * @source:  the document source
    837  * @elem:  the element list
    838  *
    839  * Make a copy of the node list while preserving the XInclude semantic
    840  * of the Infoset copy
    841  */
    842 static xmlNodePtr
    843 xmlXIncludeCopyNodeList(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
    844 	                xmlDocPtr source, xmlNodePtr elem) {
    845     xmlNodePtr cur, res, result = NULL, last = NULL;
    846 
    847     if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
    848 	(elem == NULL))
    849 	return(NULL);
    850     cur = elem;
    851     while (cur != NULL) {
    852 	res = xmlXIncludeCopyNode(ctxt, target, source, cur);
    853 	if (res != NULL) {
    854 	    if (result == NULL) {
    855 		result = last = res;
    856 	    } else {
    857 		last->next = res;
    858 		res->prev = last;
    859 		last = res;
    860 	    }
    861 	}
    862 	cur = cur->next;
    863     }
    864     return(result);
    865 }
    866 
    867 /**
    868  * xmlXIncludeGetNthChild:
    869  * @cur:  the node
    870  * @no:  the child number
    871  *
    872  * Returns the @n'th element child of @cur or NULL
    873  */
    874 static xmlNodePtr
    875 xmlXIncludeGetNthChild(xmlNodePtr cur, int no) {
    876     int i;
    877     if (cur == NULL)
    878 	return(cur);
    879     cur = cur->children;
    880     for (i = 0;i <= no;cur = cur->next) {
    881 	if (cur == NULL)
    882 	    return(cur);
    883 	if ((cur->type == XML_ELEMENT_NODE) ||
    884 	    (cur->type == XML_DOCUMENT_NODE) ||
    885 	    (cur->type == XML_HTML_DOCUMENT_NODE)) {
    886 	    i++;
    887 	    if (i == no)
    888 		break;
    889 	}
    890     }
    891     return(cur);
    892 }
    893 
    894 xmlNodePtr xmlXPtrAdvanceNode(xmlNodePtr cur, int *level); /* in xpointer.c */
    895 /**
    896  * xmlXIncludeCopyRange:
    897  * @ctxt:  the XInclude context
    898  * @target:  the document target
    899  * @source:  the document source
    900  * @obj:  the XPointer result from the evaluation.
    901  *
    902  * Build a node list tree copy of the XPointer result.
    903  *
    904  * Returns an xmlNodePtr list or NULL.
    905  *         The caller has to free the node tree.
    906  */
    907 static xmlNodePtr
    908 xmlXIncludeCopyRange(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
    909 	                xmlDocPtr source, xmlXPathObjectPtr range) {
    910     /* pointers to generated nodes */
    911     xmlNodePtr list = NULL, last = NULL, listParent = NULL;
    912     xmlNodePtr tmp, tmp2;
    913     /* pointers to traversal nodes */
    914     xmlNodePtr start, cur, end;
    915     int index1, index2;
    916     int level = 0, lastLevel = 0, endLevel = 0, endFlag = 0;
    917 
    918     if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
    919 	(range == NULL))
    920 	return(NULL);
    921     if (range->type != XPATH_RANGE)
    922 	return(NULL);
    923     start = (xmlNodePtr) range->user;
    924 
    925     if (start == NULL)
    926 	return(NULL);
    927     end = range->user2;
    928     if (end == NULL)
    929 	return(xmlDocCopyNode(start, target, 1));
    930 
    931     cur = start;
    932     index1 = range->index;
    933     index2 = range->index2;
    934     /*
    935      * level is depth of the current node under consideration
    936      * list is the pointer to the root of the output tree
    937      * listParent is a pointer to the parent of output tree (within
    938        the included file) in case we need to add another level
    939      * last is a pointer to the last node added to the output tree
    940      * lastLevel is the depth of last (relative to the root)
    941      */
    942     while (cur != NULL) {
    943 	/*
    944 	 * Check if our output tree needs a parent
    945 	 */
    946 	if (level < 0) {
    947 	    while (level < 0) {
    948 	        /* copy must include namespaces and properties */
    949 	        tmp2 = xmlDocCopyNode(listParent, target, 2);
    950 	        xmlAddChild(tmp2, list);
    951 	        list = tmp2;
    952 	        listParent = listParent->parent;
    953 	        level++;
    954 	    }
    955 	    last = list;
    956 	    lastLevel = 0;
    957 	}
    958 	/*
    959 	 * Check whether we need to change our insertion point
    960 	 */
    961 	while (level < lastLevel) {
    962 	    last = last->parent;
    963 	    lastLevel --;
    964 	}
    965 	if (cur == end) {	/* Are we at the end of the range? */
    966 	    if (cur->type == XML_TEXT_NODE) {
    967 		const xmlChar *content = cur->content;
    968 		int len;
    969 
    970 		if (content == NULL) {
    971 		    tmp = xmlNewTextLen(NULL, 0);
    972 		} else {
    973 		    len = index2;
    974 		    if ((cur == start) && (index1 > 1)) {
    975 			content += (index1 - 1);
    976 			len -= (index1 - 1);
    977 		    } else {
    978 			len = index2;
    979 		    }
    980 		    tmp = xmlNewTextLen(content, len);
    981 		}
    982 		/* single sub text node selection */
    983 		if (list == NULL)
    984 		    return(tmp);
    985 		/* prune and return full set */
    986 		if (level == lastLevel)
    987 		    xmlAddNextSibling(last, tmp);
    988 		else
    989 		    xmlAddChild(last, tmp);
    990 		return(list);
    991 	    } else {	/* ending node not a text node */
    992 	        endLevel = level;	/* remember the level of the end node */
    993 		endFlag = 1;
    994 		/* last node - need to take care of properties + namespaces */
    995 		tmp = xmlDocCopyNode(cur, target, 2);
    996 		if (list == NULL) {
    997 		    list = tmp;
    998 		    listParent = cur->parent;
    999 		} else {
   1000 		    if (level == lastLevel)
   1001 			xmlAddNextSibling(last, tmp);
   1002 		    else {
   1003 			xmlAddChild(last, tmp);
   1004 			lastLevel = level;
   1005 		    }
   1006 		}
   1007 		last = tmp;
   1008 
   1009 		if (index2 > 1) {
   1010 		    end = xmlXIncludeGetNthChild(cur, index2 - 1);
   1011 		    index2 = 0;
   1012 		}
   1013 		if ((cur == start) && (index1 > 1)) {
   1014 		    cur = xmlXIncludeGetNthChild(cur, index1 - 1);
   1015 		    index1 = 0;
   1016 		}  else {
   1017 		    cur = cur->children;
   1018 		}
   1019 		level++;	/* increment level to show change */
   1020 		/*
   1021 		 * Now gather the remaining nodes from cur to end
   1022 		 */
   1023 		continue;	/* while */
   1024 	    }
   1025 	} else if (cur == start) {	/* Not at the end, are we at start? */
   1026 	    if ((cur->type == XML_TEXT_NODE) ||
   1027 		(cur->type == XML_CDATA_SECTION_NODE)) {
   1028 		const xmlChar *content = cur->content;
   1029 
   1030 		if (content == NULL) {
   1031 		    tmp = xmlNewTextLen(NULL, 0);
   1032 		} else {
   1033 		    if (index1 > 1) {
   1034 			content += (index1 - 1);
   1035 			index1 = 0;
   1036 		    }
   1037 		    tmp = xmlNewText(content);
   1038 		}
   1039 		last = list = tmp;
   1040 		listParent = cur->parent;
   1041 	    } else {		/* Not text node */
   1042 	        /*
   1043 		 * start of the range - need to take care of
   1044 		 * properties and namespaces
   1045 		 */
   1046 		tmp = xmlDocCopyNode(cur, target, 2);
   1047 		list = last = tmp;
   1048 		listParent = cur->parent;
   1049 		if (index1 > 1) {	/* Do we need to position? */
   1050 		    cur = xmlXIncludeGetNthChild(cur, index1 - 1);
   1051 		    level = lastLevel = 1;
   1052 		    index1 = 0;
   1053 		    /*
   1054 		     * Now gather the remaining nodes from cur to end
   1055 		     */
   1056 		    continue; /* while */
   1057 		}
   1058 	    }
   1059 	} else {
   1060 	    tmp = NULL;
   1061 	    switch (cur->type) {
   1062 		case XML_DTD_NODE:
   1063 		case XML_ELEMENT_DECL:
   1064 		case XML_ATTRIBUTE_DECL:
   1065 		case XML_ENTITY_NODE:
   1066 		    /* Do not copy DTD informations */
   1067 		    break;
   1068 		case XML_ENTITY_DECL:
   1069 		    /* handle crossing entities -> stack needed */
   1070 		    break;
   1071 		case XML_XINCLUDE_START:
   1072 		case XML_XINCLUDE_END:
   1073 		    /* don't consider it part of the tree content */
   1074 		    break;
   1075 		case XML_ATTRIBUTE_NODE:
   1076 		    /* Humm, should not happen ! */
   1077 		    break;
   1078 		default:
   1079 		    /*
   1080 		     * Middle of the range - need to take care of
   1081 		     * properties and namespaces
   1082 		     */
   1083 		    tmp = xmlDocCopyNode(cur, target, 2);
   1084 		    break;
   1085 	    }
   1086 	    if (tmp != NULL) {
   1087 		if (level == lastLevel)
   1088 		    xmlAddNextSibling(last, tmp);
   1089 		else {
   1090 		    xmlAddChild(last, tmp);
   1091 		    lastLevel = level;
   1092 		}
   1093 		last = tmp;
   1094 	    }
   1095 	}
   1096 	/*
   1097 	 * Skip to next node in document order
   1098 	 */
   1099 	cur = xmlXPtrAdvanceNode(cur, &level);
   1100 	if (endFlag && (level >= endLevel))
   1101 	    break;
   1102     }
   1103     return(list);
   1104 }
   1105 
   1106 /**
   1107  * xmlXIncludeBuildNodeList:
   1108  * @ctxt:  the XInclude context
   1109  * @target:  the document target
   1110  * @source:  the document source
   1111  * @obj:  the XPointer result from the evaluation.
   1112  *
   1113  * Build a node list tree copy of the XPointer result.
   1114  * This will drop Attributes and Namespace declarations.
   1115  *
   1116  * Returns an xmlNodePtr list or NULL.
   1117  *         the caller has to free the node tree.
   1118  */
   1119 static xmlNodePtr
   1120 xmlXIncludeCopyXPointer(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
   1121 	                xmlDocPtr source, xmlXPathObjectPtr obj) {
   1122     xmlNodePtr list = NULL, last = NULL;
   1123     int i;
   1124 
   1125     if (source == NULL)
   1126 	source = ctxt->doc;
   1127     if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
   1128 	(obj == NULL))
   1129 	return(NULL);
   1130     switch (obj->type) {
   1131         case XPATH_NODESET: {
   1132 	    xmlNodeSetPtr set = obj->nodesetval;
   1133 	    if (set == NULL)
   1134 		return(NULL);
   1135 	    for (i = 0;i < set->nodeNr;i++) {
   1136 		if (set->nodeTab[i] == NULL)
   1137 		    continue;
   1138 		switch (set->nodeTab[i]->type) {
   1139 		    case XML_TEXT_NODE:
   1140 		    case XML_CDATA_SECTION_NODE:
   1141 		    case XML_ELEMENT_NODE:
   1142 		    case XML_ENTITY_REF_NODE:
   1143 		    case XML_ENTITY_NODE:
   1144 		    case XML_PI_NODE:
   1145 		    case XML_COMMENT_NODE:
   1146 		    case XML_DOCUMENT_NODE:
   1147 		    case XML_HTML_DOCUMENT_NODE:
   1148 #ifdef LIBXML_DOCB_ENABLED
   1149 		    case XML_DOCB_DOCUMENT_NODE:
   1150 #endif
   1151 		    case XML_XINCLUDE_END:
   1152 			break;
   1153 		    case XML_XINCLUDE_START: {
   1154 	                xmlNodePtr tmp, cur = set->nodeTab[i];
   1155 
   1156 			cur = cur->next;
   1157 			while (cur != NULL) {
   1158 			    switch(cur->type) {
   1159 				case XML_TEXT_NODE:
   1160 				case XML_CDATA_SECTION_NODE:
   1161 				case XML_ELEMENT_NODE:
   1162 				case XML_ENTITY_REF_NODE:
   1163 				case XML_ENTITY_NODE:
   1164 				case XML_PI_NODE:
   1165 				case XML_COMMENT_NODE:
   1166 				    tmp = xmlXIncludeCopyNode(ctxt, target,
   1167 							      source, cur);
   1168 				    if (last == NULL) {
   1169 					list = last = tmp;
   1170 				    } else {
   1171 					xmlAddNextSibling(last, tmp);
   1172 					last = tmp;
   1173 				    }
   1174 				    cur = cur->next;
   1175 				    continue;
   1176 				default:
   1177 				    break;
   1178 			    }
   1179 			    break;
   1180 			}
   1181 			continue;
   1182 		    }
   1183 		    case XML_ATTRIBUTE_NODE:
   1184 		    case XML_NAMESPACE_DECL:
   1185 		    case XML_DOCUMENT_TYPE_NODE:
   1186 		    case XML_DOCUMENT_FRAG_NODE:
   1187 		    case XML_NOTATION_NODE:
   1188 		    case XML_DTD_NODE:
   1189 		    case XML_ELEMENT_DECL:
   1190 		    case XML_ATTRIBUTE_DECL:
   1191 		    case XML_ENTITY_DECL:
   1192 			continue; /* for */
   1193 		}
   1194 		if (last == NULL)
   1195 		    list = last = xmlXIncludeCopyNode(ctxt, target, source,
   1196 			                              set->nodeTab[i]);
   1197 		else {
   1198 		    xmlAddNextSibling(last,
   1199 			    xmlXIncludeCopyNode(ctxt, target, source,
   1200 				                set->nodeTab[i]));
   1201 		    if (last->next != NULL)
   1202 			last = last->next;
   1203 		}
   1204 	    }
   1205 	    break;
   1206 	}
   1207 	case XPATH_LOCATIONSET: {
   1208 	    xmlLocationSetPtr set = (xmlLocationSetPtr) obj->user;
   1209 	    if (set == NULL)
   1210 		return(NULL);
   1211 	    for (i = 0;i < set->locNr;i++) {
   1212 		if (last == NULL)
   1213 		    list = last = xmlXIncludeCopyXPointer(ctxt, target, source,
   1214 			                                  set->locTab[i]);
   1215 		else
   1216 		    xmlAddNextSibling(last,
   1217 			    xmlXIncludeCopyXPointer(ctxt, target, source,
   1218 				                    set->locTab[i]));
   1219 		if (last != NULL) {
   1220 		    while (last->next != NULL)
   1221 			last = last->next;
   1222 		}
   1223 	    }
   1224 	    break;
   1225 	}
   1226 #ifdef LIBXML_XPTR_ENABLED
   1227 	case XPATH_RANGE:
   1228 	    return(xmlXIncludeCopyRange(ctxt, target, source, obj));
   1229 #endif
   1230 	case XPATH_POINT:
   1231 	    /* points are ignored in XInclude */
   1232 	    break;
   1233 	default:
   1234 	    break;
   1235     }
   1236     return(list);
   1237 }
   1238 /************************************************************************
   1239  *									*
   1240  *			XInclude I/O handling				*
   1241  *									*
   1242  ************************************************************************/
   1243 
   1244 typedef struct _xmlXIncludeMergeData xmlXIncludeMergeData;
   1245 typedef xmlXIncludeMergeData *xmlXIncludeMergeDataPtr;
   1246 struct _xmlXIncludeMergeData {
   1247     xmlDocPtr doc;
   1248     xmlXIncludeCtxtPtr ctxt;
   1249 };
   1250 
   1251 /**
   1252  * xmlXIncludeMergeOneEntity:
   1253  * @ent: the entity
   1254  * @doc:  the including doc
   1255  * @nr: the entity name
   1256  *
   1257  * Inplements the merge of one entity
   1258  */
   1259 static void
   1260 xmlXIncludeMergeEntity(xmlEntityPtr ent, xmlXIncludeMergeDataPtr data,
   1261 	               xmlChar *name ATTRIBUTE_UNUSED) {
   1262     xmlEntityPtr ret, prev;
   1263     xmlDocPtr doc;
   1264     xmlXIncludeCtxtPtr ctxt;
   1265 
   1266     if ((ent == NULL) || (data == NULL))
   1267 	return;
   1268     ctxt = data->ctxt;
   1269     doc = data->doc;
   1270     if ((ctxt == NULL) || (doc == NULL))
   1271 	return;
   1272     switch (ent->etype) {
   1273         case XML_INTERNAL_PARAMETER_ENTITY:
   1274         case XML_EXTERNAL_PARAMETER_ENTITY:
   1275         case XML_INTERNAL_PREDEFINED_ENTITY:
   1276 	    return;
   1277         case XML_INTERNAL_GENERAL_ENTITY:
   1278         case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
   1279         case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
   1280 	    break;
   1281     }
   1282     ret = xmlAddDocEntity(doc, ent->name, ent->etype, ent->ExternalID,
   1283 			  ent->SystemID, ent->content);
   1284     if (ret != NULL) {
   1285 	if (ent->URI != NULL)
   1286 	    ret->URI = xmlStrdup(ent->URI);
   1287     } else {
   1288 	prev = xmlGetDocEntity(doc, ent->name);
   1289 	if (prev != NULL) {
   1290 	    if (ent->etype != prev->etype)
   1291 		goto error;
   1292 
   1293 	    if ((ent->SystemID != NULL) && (prev->SystemID != NULL)) {
   1294 		if (!xmlStrEqual(ent->SystemID, prev->SystemID))
   1295 		    goto error;
   1296 	    } else if ((ent->ExternalID != NULL) &&
   1297 		       (prev->ExternalID != NULL)) {
   1298 		if (!xmlStrEqual(ent->ExternalID, prev->ExternalID))
   1299 		    goto error;
   1300 	    } else if ((ent->content != NULL) && (prev->content != NULL)) {
   1301 		if (!xmlStrEqual(ent->content, prev->content))
   1302 		    goto error;
   1303 	    } else {
   1304 		goto error;
   1305 	    }
   1306 
   1307 	}
   1308     }
   1309     return;
   1310 error:
   1311     switch (ent->etype) {
   1312         case XML_INTERNAL_PARAMETER_ENTITY:
   1313         case XML_EXTERNAL_PARAMETER_ENTITY:
   1314         case XML_INTERNAL_PREDEFINED_ENTITY:
   1315         case XML_INTERNAL_GENERAL_ENTITY:
   1316         case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
   1317 	    return;
   1318         case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
   1319 	    break;
   1320     }
   1321     xmlXIncludeErr(ctxt, (xmlNodePtr) ent, XML_XINCLUDE_ENTITY_DEF_MISMATCH,
   1322                    "mismatch in redefinition of entity %s\n",
   1323 		   ent->name);
   1324 }
   1325 
   1326 /**
   1327  * xmlXIncludeMergeEntities:
   1328  * @ctxt: an XInclude context
   1329  * @doc:  the including doc
   1330  * @from:  the included doc
   1331  *
   1332  * Inplements the entity merge
   1333  *
   1334  * Returns 0 if merge succeeded, -1 if some processing failed
   1335  */
   1336 static int
   1337 xmlXIncludeMergeEntities(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc,
   1338 	                 xmlDocPtr from) {
   1339     xmlNodePtr cur;
   1340     xmlDtdPtr target, source;
   1341 
   1342     if (ctxt == NULL)
   1343 	return(-1);
   1344 
   1345     if ((from == NULL) || (from->intSubset == NULL))
   1346 	return(0);
   1347 
   1348     target = doc->intSubset;
   1349     if (target == NULL) {
   1350 	cur = xmlDocGetRootElement(doc);
   1351 	if (cur == NULL)
   1352 	    return(-1);
   1353         target = xmlCreateIntSubset(doc, cur->name, NULL, NULL);
   1354 	if (target == NULL)
   1355 	    return(-1);
   1356     }
   1357 
   1358     source = from->intSubset;
   1359     if ((source != NULL) && (source->entities != NULL)) {
   1360 	xmlXIncludeMergeData data;
   1361 
   1362 	data.ctxt = ctxt;
   1363 	data.doc = doc;
   1364 
   1365 	xmlHashScan((xmlHashTablePtr) source->entities,
   1366 		    (xmlHashScanner) xmlXIncludeMergeEntity, &data);
   1367     }
   1368     source = from->extSubset;
   1369     if ((source != NULL) && (source->entities != NULL)) {
   1370 	xmlXIncludeMergeData data;
   1371 
   1372 	data.ctxt = ctxt;
   1373 	data.doc = doc;
   1374 
   1375 	/*
   1376 	 * don't duplicate existing stuff when external subsets are the same
   1377 	 */
   1378 	if ((!xmlStrEqual(target->ExternalID, source->ExternalID)) &&
   1379 	    (!xmlStrEqual(target->SystemID, source->SystemID))) {
   1380 	    xmlHashScan((xmlHashTablePtr) source->entities,
   1381 			(xmlHashScanner) xmlXIncludeMergeEntity, &data);
   1382 	}
   1383     }
   1384     return(0);
   1385 }
   1386 
   1387 /**
   1388  * xmlXIncludeLoadDoc:
   1389  * @ctxt:  the XInclude context
   1390  * @url:  the associated URL
   1391  * @nr:  the xinclude node number
   1392  *
   1393  * Load the document, and store the result in the XInclude context
   1394  *
   1395  * Returns 0 in case of success, -1 in case of failure
   1396  */
   1397 static int
   1398 xmlXIncludeLoadDoc(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
   1399     xmlDocPtr doc;
   1400     xmlURIPtr uri;
   1401     xmlChar *URL;
   1402     xmlChar *fragment = NULL;
   1403     int i = 0;
   1404 #ifdef LIBXML_XPTR_ENABLED
   1405     int saveFlags;
   1406 #endif
   1407 
   1408 #ifdef DEBUG_XINCLUDE
   1409     xmlGenericError(xmlGenericErrorContext, "Loading doc %s:%d\n", url, nr);
   1410 #endif
   1411     /*
   1412      * Check the URL and remove any fragment identifier
   1413      */
   1414     uri = xmlParseURI((const char *)url);
   1415     if (uri == NULL) {
   1416 	xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
   1417 	               XML_XINCLUDE_HREF_URI,
   1418 		       "invalid value URI %s\n", url);
   1419 	return(-1);
   1420     }
   1421     if (uri->fragment != NULL) {
   1422 	fragment = (xmlChar *) uri->fragment;
   1423 	uri->fragment = NULL;
   1424     }
   1425     if ((ctxt->incTab != NULL) && (ctxt->incTab[nr] != NULL) &&
   1426         (ctxt->incTab[nr]->fragment != NULL)) {
   1427 	if (fragment != NULL) xmlFree(fragment);
   1428 	fragment = xmlStrdup(ctxt->incTab[nr]->fragment);
   1429     }
   1430     URL = xmlSaveUri(uri);
   1431     xmlFreeURI(uri);
   1432     if (URL == NULL) {
   1433         if (ctxt->incTab != NULL)
   1434 	    xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
   1435 			   XML_XINCLUDE_HREF_URI,
   1436 			   "invalid value URI %s\n", url);
   1437 	else
   1438 	    xmlXIncludeErr(ctxt, NULL,
   1439 			   XML_XINCLUDE_HREF_URI,
   1440 			   "invalid value URI %s\n", url);
   1441 	if (fragment != NULL)
   1442 	    xmlFree(fragment);
   1443 	return(-1);
   1444     }
   1445 
   1446     /*
   1447      * Handling of references to the local document are done
   1448      * directly through ctxt->doc.
   1449      */
   1450     if ((URL[0] == 0) || (URL[0] == '#') ||
   1451 	((ctxt->doc != NULL) && (xmlStrEqual(URL, ctxt->doc->URL)))) {
   1452 	doc = NULL;
   1453         goto loaded;
   1454     }
   1455 
   1456     /*
   1457      * Prevent reloading twice the document.
   1458      */
   1459     for (i = 0; i < ctxt->incNr; i++) {
   1460 	if ((xmlStrEqual(URL, ctxt->incTab[i]->URI)) &&
   1461 	    (ctxt->incTab[i]->doc != NULL)) {
   1462 	    doc = ctxt->incTab[i]->doc;
   1463 #ifdef DEBUG_XINCLUDE
   1464 	    printf("Already loaded %s\n", URL);
   1465 #endif
   1466 	    goto loaded;
   1467 	}
   1468     }
   1469 
   1470     /*
   1471      * Load it.
   1472      */
   1473 #ifdef DEBUG_XINCLUDE
   1474     printf("loading %s\n", URL);
   1475 #endif
   1476 #ifdef LIBXML_XPTR_ENABLED
   1477     /*
   1478      * If this is an XPointer evaluation, we want to assure that
   1479      * all entities have been resolved prior to processing the
   1480      * referenced document
   1481      */
   1482     saveFlags = ctxt->parseFlags;
   1483     if (fragment != NULL) {	/* if this is an XPointer eval */
   1484 	ctxt->parseFlags |= XML_PARSE_NOENT;
   1485     }
   1486 #endif
   1487 
   1488     doc = xmlXIncludeParseFile(ctxt, (const char *)URL);
   1489 #ifdef LIBXML_XPTR_ENABLED
   1490     ctxt->parseFlags = saveFlags;
   1491 #endif
   1492     if (doc == NULL) {
   1493 	xmlFree(URL);
   1494 	if (fragment != NULL)
   1495 	    xmlFree(fragment);
   1496 	return(-1);
   1497     }
   1498     ctxt->incTab[nr]->doc = doc;
   1499     /*
   1500      * It's possible that the requested URL has been mapped to a
   1501      * completely different location (e.g. through a catalog entry).
   1502      * To check for this, we compare the URL with that of the doc
   1503      * and change it if they disagree (bug 146988).
   1504      */
   1505    if (!xmlStrEqual(URL, doc->URL)) {
   1506        xmlFree(URL);
   1507        URL = xmlStrdup(doc->URL);
   1508    }
   1509     for (i = nr + 1; i < ctxt->incNr; i++) {
   1510 	if (xmlStrEqual(URL, ctxt->incTab[i]->URI)) {
   1511 	    ctxt->incTab[nr]->count++;
   1512 #ifdef DEBUG_XINCLUDE
   1513 	    printf("Increasing %s count since reused\n", URL);
   1514 #endif
   1515             break;
   1516 	}
   1517     }
   1518 
   1519     /*
   1520      * Make sure we have all entities fixed up
   1521      */
   1522     xmlXIncludeMergeEntities(ctxt, ctxt->doc, doc);
   1523 
   1524     /*
   1525      * We don't need the DTD anymore, free up space
   1526     if (doc->intSubset != NULL) {
   1527 	xmlUnlinkNode((xmlNodePtr) doc->intSubset);
   1528 	xmlFreeNode((xmlNodePtr) doc->intSubset);
   1529 	doc->intSubset = NULL;
   1530     }
   1531     if (doc->extSubset != NULL) {
   1532 	xmlUnlinkNode((xmlNodePtr) doc->extSubset);
   1533 	xmlFreeNode((xmlNodePtr) doc->extSubset);
   1534 	doc->extSubset = NULL;
   1535     }
   1536      */
   1537     xmlXIncludeRecurseDoc(ctxt, doc, URL);
   1538 
   1539 loaded:
   1540     if (fragment == NULL) {
   1541 	/*
   1542 	 * Add the top children list as the replacement copy.
   1543 	 */
   1544 	if (doc == NULL)
   1545 	{
   1546 	    /* Hopefully a DTD declaration won't be copied from
   1547 	     * the same document */
   1548 	    ctxt->incTab[nr]->inc = xmlCopyNodeList(ctxt->doc->children);
   1549 	} else {
   1550 	    ctxt->incTab[nr]->inc = xmlXIncludeCopyNodeList(ctxt, ctxt->doc,
   1551 		                                       doc, doc->children);
   1552 	}
   1553     }
   1554 #ifdef LIBXML_XPTR_ENABLED
   1555     else {
   1556 	/*
   1557 	 * Computes the XPointer expression and make a copy used
   1558 	 * as the replacement copy.
   1559 	 */
   1560 	xmlXPathObjectPtr xptr;
   1561 	xmlXPathContextPtr xptrctxt;
   1562 	xmlNodeSetPtr set;
   1563 
   1564 	if (doc == NULL) {
   1565 	    xptrctxt = xmlXPtrNewContext(ctxt->doc, ctxt->incTab[nr]->ref,
   1566 		                         NULL);
   1567 	} else {
   1568 	    xptrctxt = xmlXPtrNewContext(doc, NULL, NULL);
   1569 	}
   1570 	if (xptrctxt == NULL) {
   1571 	    xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
   1572 	                   XML_XINCLUDE_XPTR_FAILED,
   1573 			   "could not create XPointer context\n", NULL);
   1574 	    xmlFree(URL);
   1575 	    xmlFree(fragment);
   1576 	    return(-1);
   1577 	}
   1578 	xptr = xmlXPtrEval(fragment, xptrctxt);
   1579 	if (xptr == NULL) {
   1580 	    xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
   1581 	                   XML_XINCLUDE_XPTR_FAILED,
   1582 			   "XPointer evaluation failed: #%s\n",
   1583 			   fragment);
   1584 	    xmlXPathFreeContext(xptrctxt);
   1585 	    xmlFree(URL);
   1586 	    xmlFree(fragment);
   1587 	    return(-1);
   1588 	}
   1589 	switch (xptr->type) {
   1590 	    case XPATH_UNDEFINED:
   1591 	    case XPATH_BOOLEAN:
   1592 	    case XPATH_NUMBER:
   1593 	    case XPATH_STRING:
   1594 	    case XPATH_POINT:
   1595 	    case XPATH_USERS:
   1596 	    case XPATH_XSLT_TREE:
   1597 		xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
   1598 		               XML_XINCLUDE_XPTR_RESULT,
   1599 			       "XPointer is not a range: #%s\n",
   1600 			       fragment);
   1601 		xmlXPathFreeContext(xptrctxt);
   1602 		xmlFree(URL);
   1603 		xmlFree(fragment);
   1604 		return(-1);
   1605 	    case XPATH_NODESET:
   1606 	        if ((xptr->nodesetval == NULL) ||
   1607 		    (xptr->nodesetval->nodeNr <= 0)) {
   1608 		    xmlXPathFreeContext(xptrctxt);
   1609 		    xmlFree(URL);
   1610 		    xmlFree(fragment);
   1611 		    return(-1);
   1612 		}
   1613 
   1614 	    case XPATH_RANGE:
   1615 	    case XPATH_LOCATIONSET:
   1616 		break;
   1617 	}
   1618 	set = xptr->nodesetval;
   1619 	if (set != NULL) {
   1620 	    for (i = 0;i < set->nodeNr;i++) {
   1621 		if (set->nodeTab[i] == NULL)
   1622 		    continue;
   1623 		switch (set->nodeTab[i]->type) {
   1624 		    case XML_ELEMENT_NODE:
   1625 		    case XML_TEXT_NODE:
   1626 		    case XML_CDATA_SECTION_NODE:
   1627 		    case XML_ENTITY_REF_NODE:
   1628 		    case XML_ENTITY_NODE:
   1629 		    case XML_PI_NODE:
   1630 		    case XML_COMMENT_NODE:
   1631 		    case XML_DOCUMENT_NODE:
   1632 		    case XML_HTML_DOCUMENT_NODE:
   1633 #ifdef LIBXML_DOCB_ENABLED
   1634 		    case XML_DOCB_DOCUMENT_NODE:
   1635 #endif
   1636 			continue;
   1637 
   1638 		    case XML_ATTRIBUTE_NODE:
   1639 			xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
   1640 			               XML_XINCLUDE_XPTR_RESULT,
   1641 				       "XPointer selects an attribute: #%s\n",
   1642 				       fragment);
   1643 			set->nodeTab[i] = NULL;
   1644 			continue;
   1645 		    case XML_NAMESPACE_DECL:
   1646 			xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
   1647 			               XML_XINCLUDE_XPTR_RESULT,
   1648 				       "XPointer selects a namespace: #%s\n",
   1649 				       fragment);
   1650 			set->nodeTab[i] = NULL;
   1651 			continue;
   1652 		    case XML_DOCUMENT_TYPE_NODE:
   1653 		    case XML_DOCUMENT_FRAG_NODE:
   1654 		    case XML_NOTATION_NODE:
   1655 		    case XML_DTD_NODE:
   1656 		    case XML_ELEMENT_DECL:
   1657 		    case XML_ATTRIBUTE_DECL:
   1658 		    case XML_ENTITY_DECL:
   1659 		    case XML_XINCLUDE_START:
   1660 		    case XML_XINCLUDE_END:
   1661 			xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
   1662 			               XML_XINCLUDE_XPTR_RESULT,
   1663 				   "XPointer selects unexpected nodes: #%s\n",
   1664 				       fragment);
   1665 			set->nodeTab[i] = NULL;
   1666 			set->nodeTab[i] = NULL;
   1667 			continue; /* for */
   1668 		}
   1669 	    }
   1670 	}
   1671 	if (doc == NULL) {
   1672 	    ctxt->incTab[nr]->xptr = xptr;
   1673 	    ctxt->incTab[nr]->inc = NULL;
   1674 	} else {
   1675 	    ctxt->incTab[nr]->inc =
   1676 		xmlXIncludeCopyXPointer(ctxt, ctxt->doc, doc, xptr);
   1677 	    xmlXPathFreeObject(xptr);
   1678 	}
   1679 	xmlXPathFreeContext(xptrctxt);
   1680 	xmlFree(fragment);
   1681     }
   1682 #endif
   1683 
   1684     /*
   1685      * Do the xml:base fixup if needed
   1686      */
   1687     if ((doc != NULL) && (URL != NULL) && (xmlStrchr(URL, (xmlChar) '/')) &&
   1688         (!(ctxt->parseFlags & XML_PARSE_NOBASEFIX)) &&
   1689 	(!(doc->parseFlags & XML_PARSE_NOBASEFIX))) {
   1690 	xmlNodePtr node;
   1691 	xmlChar *base;
   1692 	xmlChar *curBase;
   1693 
   1694 	/*
   1695 	 * The base is only adjusted if "necessary", i.e. if the xinclude node
   1696 	 * has a base specified, or the URL is relative
   1697 	 */
   1698 	base = xmlGetNsProp(ctxt->incTab[nr]->ref, BAD_CAST "base",
   1699 			XML_XML_NAMESPACE);
   1700 	if (base == NULL) {
   1701 	    /*
   1702 	     * No xml:base on the xinclude node, so we check whether the
   1703 	     * URI base is different than (relative to) the context base
   1704 	     */
   1705 	    curBase = xmlBuildRelativeURI(URL, ctxt->base);
   1706 	    if (curBase == NULL) {	/* Error return */
   1707 	        xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
   1708 	               XML_XINCLUDE_HREF_URI,
   1709 		       "trying to build relative URI from %s\n", URL);
   1710 	    } else {
   1711 		/* If the URI doesn't contain a slash, it's not relative */
   1712 	        if (!xmlStrchr(curBase, (xmlChar) '/'))
   1713 		    xmlFree(curBase);
   1714 		else
   1715 		    base = curBase;
   1716 	    }
   1717 	}
   1718 	if (base != NULL) {	/* Adjustment may be needed */
   1719 	    node = ctxt->incTab[nr]->inc;
   1720 	    while (node != NULL) {
   1721 		/* Only work on element nodes */
   1722 		if (node->type == XML_ELEMENT_NODE) {
   1723 		    curBase = xmlNodeGetBase(node->doc, node);
   1724 		    /* If no current base, set it */
   1725 		    if (curBase == NULL) {
   1726 			xmlNodeSetBase(node, base);
   1727 		    } else {
   1728 			/*
   1729 			 * If the current base is the same as the
   1730 			 * URL of the document, then reset it to be
   1731 			 * the specified xml:base or the relative URI
   1732 			 */
   1733 			if (xmlStrEqual(curBase, node->doc->URL)) {
   1734 			    xmlNodeSetBase(node, base);
   1735 			} else {
   1736 			    /*
   1737 			     * If the element already has an xml:base
   1738 			     * set, then relativise it if necessary
   1739 			     */
   1740 			    xmlChar *xmlBase;
   1741 			    xmlBase = xmlGetNsProp(node,
   1742 					    BAD_CAST "base",
   1743 					    XML_XML_NAMESPACE);
   1744 			    if (xmlBase != NULL) {
   1745 				xmlChar *relBase;
   1746 				relBase = xmlBuildURI(xmlBase, base);
   1747 				if (relBase == NULL) { /* error */
   1748 				    xmlXIncludeErr(ctxt,
   1749 						ctxt->incTab[nr]->ref,
   1750 						XML_XINCLUDE_HREF_URI,
   1751 					"trying to rebuild base from %s\n",
   1752 						xmlBase);
   1753 				} else {
   1754 				    xmlNodeSetBase(node, relBase);
   1755 				    xmlFree(relBase);
   1756 				}
   1757 				xmlFree(xmlBase);
   1758 			    }
   1759 			}
   1760 			xmlFree(curBase);
   1761 		    }
   1762 		}
   1763 	        node = node->next;
   1764 	    }
   1765 	    xmlFree(base);
   1766 	}
   1767     }
   1768     if ((nr < ctxt->incNr) && (ctxt->incTab[nr]->doc != NULL) &&
   1769 	(ctxt->incTab[nr]->count <= 1)) {
   1770 #ifdef DEBUG_XINCLUDE
   1771         printf("freeing %s\n", ctxt->incTab[nr]->doc->URL);
   1772 #endif
   1773 	xmlFreeDoc(ctxt->incTab[nr]->doc);
   1774 	ctxt->incTab[nr]->doc = NULL;
   1775     }
   1776     xmlFree(URL);
   1777     return(0);
   1778 }
   1779 
   1780 /**
   1781  * xmlXIncludeLoadTxt:
   1782  * @ctxt:  the XInclude context
   1783  * @url:  the associated URL
   1784  * @nr:  the xinclude node number
   1785  *
   1786  * Load the content, and store the result in the XInclude context
   1787  *
   1788  * Returns 0 in case of success, -1 in case of failure
   1789  */
   1790 static int
   1791 xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
   1792     xmlParserInputBufferPtr buf;
   1793     xmlNodePtr node;
   1794     xmlURIPtr uri;
   1795     xmlChar *URL;
   1796     int i;
   1797     xmlChar *encoding = NULL;
   1798     xmlCharEncoding enc = (xmlCharEncoding) 0;
   1799 
   1800     /*
   1801      * Check the URL and remove any fragment identifier
   1802      */
   1803     uri = xmlParseURI((const char *)url);
   1804     if (uri == NULL) {
   1805 	xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_HREF_URI,
   1806 	               "invalid value URI %s\n", url);
   1807 	return(-1);
   1808     }
   1809     if (uri->fragment != NULL) {
   1810 	xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_TEXT_FRAGMENT,
   1811 	               "fragment identifier forbidden for text: %s\n",
   1812 		       (const xmlChar *) uri->fragment);
   1813 	xmlFreeURI(uri);
   1814 	return(-1);
   1815     }
   1816     URL = xmlSaveUri(uri);
   1817     xmlFreeURI(uri);
   1818     if (URL == NULL) {
   1819 	xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_HREF_URI,
   1820 	               "invalid value URI %s\n", url);
   1821 	return(-1);
   1822     }
   1823 
   1824     /*
   1825      * Handling of references to the local document are done
   1826      * directly through ctxt->doc.
   1827      */
   1828     if (URL[0] == 0) {
   1829 	xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
   1830 	               XML_XINCLUDE_TEXT_DOCUMENT,
   1831 		       "text serialization of document not available\n", NULL);
   1832 	xmlFree(URL);
   1833 	return(-1);
   1834     }
   1835 
   1836     /*
   1837      * Prevent reloading twice the document.
   1838      */
   1839     for (i = 0; i < ctxt->txtNr; i++) {
   1840 	if (xmlStrEqual(URL, ctxt->txturlTab[i])) {
   1841 	    node = xmlCopyNode(ctxt->txtTab[i], 1);
   1842 	    goto loaded;
   1843 	}
   1844     }
   1845     /*
   1846      * Try to get the encoding if available
   1847      */
   1848     if ((ctxt->incTab[nr] != NULL) && (ctxt->incTab[nr]->ref != NULL)) {
   1849 	encoding = xmlGetProp(ctxt->incTab[nr]->ref, XINCLUDE_PARSE_ENCODING);
   1850     }
   1851     if (encoding != NULL) {
   1852 	/*
   1853 	 * TODO: we should not have to remap to the xmlCharEncoding
   1854 	 *       predefined set, a better interface than
   1855 	 *       xmlParserInputBufferCreateFilename should allow any
   1856 	 *       encoding supported by iconv
   1857 	 */
   1858         enc = xmlParseCharEncoding((const char *) encoding);
   1859 	if (enc == XML_CHAR_ENCODING_ERROR) {
   1860 	    xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
   1861 	                   XML_XINCLUDE_UNKNOWN_ENCODING,
   1862 			   "encoding %s not supported\n", encoding);
   1863 	    xmlFree(encoding);
   1864 	    xmlFree(URL);
   1865 	    return(-1);
   1866 	}
   1867 	xmlFree(encoding);
   1868     }
   1869 
   1870     /*
   1871      * Load it.
   1872      */
   1873     buf = xmlParserInputBufferCreateFilename((const char *)URL, enc);
   1874     if (buf == NULL) {
   1875 	xmlFree(URL);
   1876 	return(-1);
   1877     }
   1878     node = xmlNewText(NULL);
   1879 
   1880     /*
   1881      * Scan all chars from the resource and add the to the node
   1882      */
   1883     while (xmlParserInputBufferRead(buf, 128) > 0) {
   1884 	int len;
   1885 	const xmlChar *content;
   1886 
   1887 	content = xmlBufferContent(buf->buffer);
   1888 	len = xmlBufferLength(buf->buffer);
   1889 	for (i = 0;i < len;) {
   1890 	    int cur;
   1891 	    int l;
   1892 
   1893 	    cur = xmlStringCurrentChar(NULL, &content[i], &l);
   1894 	    if (!IS_CHAR(cur)) {
   1895 		xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
   1896 		               XML_XINCLUDE_INVALID_CHAR,
   1897 			       "%s contains invalid char\n", URL);
   1898 		xmlFreeParserInputBuffer(buf);
   1899 		xmlFree(URL);
   1900 		return(-1);
   1901 	    } else {
   1902 		xmlNodeAddContentLen(node, &content[i], l);
   1903 	    }
   1904 	    i += l;
   1905 	}
   1906 	xmlBufferShrink(buf->buffer, len);
   1907     }
   1908     xmlFreeParserInputBuffer(buf);
   1909     xmlXIncludeAddTxt(ctxt, node, URL);
   1910 
   1911 loaded:
   1912     /*
   1913      * Add the element as the replacement copy.
   1914      */
   1915     ctxt->incTab[nr]->inc = node;
   1916     xmlFree(URL);
   1917     return(0);
   1918 }
   1919 
   1920 /**
   1921  * xmlXIncludeLoadFallback:
   1922  * @ctxt:  the XInclude context
   1923  * @fallback:  the fallback node
   1924  * @nr:  the xinclude node number
   1925  *
   1926  * Load the content of the fallback node, and store the result
   1927  * in the XInclude context
   1928  *
   1929  * Returns 0 in case of success, -1 in case of failure
   1930  */
   1931 static int
   1932 xmlXIncludeLoadFallback(xmlXIncludeCtxtPtr ctxt, xmlNodePtr fallback, int nr) {
   1933     xmlXIncludeCtxtPtr newctxt;
   1934     int ret = 0;
   1935 
   1936     if ((fallback == NULL) || (ctxt == NULL))
   1937 	return(-1);
   1938     if (fallback->children != NULL) {
   1939 	/*
   1940 	 * It's possible that the fallback also has 'includes'
   1941 	 * (Bug 129969), so we re-process the fallback just in case
   1942 	 */
   1943 	newctxt = xmlXIncludeNewContext(ctxt->doc);
   1944 	if (newctxt == NULL)
   1945 	    return (-1);
   1946 	newctxt->_private = ctxt->_private;
   1947 	newctxt->base = xmlStrdup(ctxt->base);	/* Inherit the base from the existing context */
   1948 	xmlXIncludeSetFlags(newctxt, ctxt->parseFlags);
   1949 	ret = xmlXIncludeDoProcess(newctxt, ctxt->doc, fallback->children);
   1950 	if (ctxt->nbErrors > 0)
   1951 	    ret = -1;
   1952 	else if (ret > 0)
   1953 	    ret = 0;	/* xmlXIncludeDoProcess can return +ve number */
   1954 	xmlXIncludeFreeContext(newctxt);
   1955 
   1956 	ctxt->incTab[nr]->inc = xmlDocCopyNodeList(ctxt->doc,
   1957 	                                           fallback->children);
   1958     } else {
   1959         ctxt->incTab[nr]->inc = NULL;
   1960 	ctxt->incTab[nr]->emptyFb = 1;	/* flag empty callback */
   1961     }
   1962     return(ret);
   1963 }
   1964 
   1965 /************************************************************************
   1966  *									*
   1967  *			XInclude Processing				*
   1968  *									*
   1969  ************************************************************************/
   1970 
   1971 /**
   1972  * xmlXIncludePreProcessNode:
   1973  * @ctxt: an XInclude context
   1974  * @node: an XInclude node
   1975  *
   1976  * Implement the XInclude preprocessing, currently just adding the element
   1977  * for further processing.
   1978  *
   1979  * Returns the result list or NULL in case of error
   1980  */
   1981 static xmlNodePtr
   1982 xmlXIncludePreProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
   1983     xmlXIncludeAddNode(ctxt, node);
   1984     return(NULL);
   1985 }
   1986 
   1987 /**
   1988  * xmlXIncludeLoadNode:
   1989  * @ctxt: an XInclude context
   1990  * @nr: the node number
   1991  *
   1992  * Find and load the infoset replacement for the given node.
   1993  *
   1994  * Returns 0 if substitution succeeded, -1 if some processing failed
   1995  */
   1996 static int
   1997 xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, int nr) {
   1998     xmlNodePtr cur;
   1999     xmlChar *href;
   2000     xmlChar *parse;
   2001     xmlChar *base;
   2002     xmlChar *oldBase;
   2003     xmlChar *URI;
   2004     int xml = 1; /* default Issue 64 */
   2005     int ret;
   2006 
   2007     if (ctxt == NULL)
   2008 	return(-1);
   2009     if ((nr < 0) || (nr >= ctxt->incNr))
   2010 	return(-1);
   2011     cur = ctxt->incTab[nr]->ref;
   2012     if (cur == NULL)
   2013 	return(-1);
   2014 
   2015     /*
   2016      * read the attributes
   2017      */
   2018     href = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_HREF);
   2019     if (href == NULL) {
   2020 	href = xmlStrdup(BAD_CAST ""); /* @@@@ href is now optional */
   2021 	if (href == NULL)
   2022 	    return(-1);
   2023     }
   2024     parse = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_PARSE);
   2025     if (parse != NULL) {
   2026 	if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
   2027 	    xml = 1;
   2028 	else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
   2029 	    xml = 0;
   2030 	else {
   2031 	    xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
   2032 	                   XML_XINCLUDE_PARSE_VALUE,
   2033 			   "invalid value %s for 'parse'\n", parse);
   2034 	    if (href != NULL)
   2035 		xmlFree(href);
   2036 	    if (parse != NULL)
   2037 		xmlFree(parse);
   2038 	    return(-1);
   2039 	}
   2040     }
   2041 
   2042     /*
   2043      * compute the URI
   2044      */
   2045     base = xmlNodeGetBase(ctxt->doc, cur);
   2046     if (base == NULL) {
   2047 	URI = xmlBuildURI(href, ctxt->doc->URL);
   2048     } else {
   2049 	URI = xmlBuildURI(href, base);
   2050     }
   2051     if (URI == NULL) {
   2052 	xmlChar *escbase;
   2053 	xmlChar *eschref;
   2054 	/*
   2055 	 * Some escaping may be needed
   2056 	 */
   2057 	escbase = xmlURIEscape(base);
   2058 	eschref = xmlURIEscape(href);
   2059 	URI = xmlBuildURI(eschref, escbase);
   2060 	if (escbase != NULL)
   2061 	    xmlFree(escbase);
   2062 	if (eschref != NULL)
   2063 	    xmlFree(eschref);
   2064     }
   2065     if (URI == NULL) {
   2066 	xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
   2067 	               XML_XINCLUDE_HREF_URI, "failed build URL\n", NULL);
   2068 	if (parse != NULL)
   2069 	    xmlFree(parse);
   2070 	if (href != NULL)
   2071 	    xmlFree(href);
   2072 	if (base != NULL)
   2073 	    xmlFree(base);
   2074 	return(-1);
   2075     }
   2076 #ifdef DEBUG_XINCLUDE
   2077     xmlGenericError(xmlGenericErrorContext, "parse: %s\n",
   2078 	    xml ? "xml": "text");
   2079     xmlGenericError(xmlGenericErrorContext, "URI: %s\n", URI);
   2080 #endif
   2081 
   2082     /*
   2083      * Save the base for this include (saving the current one)
   2084      */
   2085     oldBase = ctxt->base;
   2086     ctxt->base = base;
   2087 
   2088     if (xml) {
   2089 	ret = xmlXIncludeLoadDoc(ctxt, URI, nr);
   2090 	/* xmlXIncludeGetFragment(ctxt, cur, URI); */
   2091     } else {
   2092 	ret = xmlXIncludeLoadTxt(ctxt, URI, nr);
   2093     }
   2094 
   2095     /*
   2096      * Restore the original base before checking for fallback
   2097      */
   2098     ctxt->base = oldBase;
   2099 
   2100     if (ret < 0) {
   2101 	xmlNodePtr children;
   2102 
   2103 	/*
   2104 	 * Time to try a fallback if availble
   2105 	 */
   2106 #ifdef DEBUG_XINCLUDE
   2107 	xmlGenericError(xmlGenericErrorContext, "error looking for fallback\n");
   2108 #endif
   2109 	children = cur->children;
   2110 	while (children != NULL) {
   2111 	    if ((children->type == XML_ELEMENT_NODE) &&
   2112 		(children->ns != NULL) &&
   2113 		(xmlStrEqual(children->name, XINCLUDE_FALLBACK)) &&
   2114 		((xmlStrEqual(children->ns->href, XINCLUDE_NS)) ||
   2115 		 (xmlStrEqual(children->ns->href, XINCLUDE_OLD_NS)))) {
   2116 		ret = xmlXIncludeLoadFallback(ctxt, children, nr);
   2117 		if (ret == 0)
   2118 		    break;
   2119 	    }
   2120 	    children = children->next;
   2121 	}
   2122     }
   2123     if (ret < 0) {
   2124 	xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
   2125 	               XML_XINCLUDE_NO_FALLBACK,
   2126 		       "could not load %s, and no fallback was found\n",
   2127 		       URI);
   2128     }
   2129 
   2130     /*
   2131      * Cleanup
   2132      */
   2133     if (URI != NULL)
   2134 	xmlFree(URI);
   2135     if (parse != NULL)
   2136 	xmlFree(parse);
   2137     if (href != NULL)
   2138 	xmlFree(href);
   2139     if (base != NULL)
   2140 	xmlFree(base);
   2141     return(0);
   2142 }
   2143 
   2144 /**
   2145  * xmlXIncludeIncludeNode:
   2146  * @ctxt: an XInclude context
   2147  * @nr: the node number
   2148  *
   2149  * Inplement the infoset replacement for the given node
   2150  *
   2151  * Returns 0 if substitution succeeded, -1 if some processing failed
   2152  */
   2153 static int
   2154 xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) {
   2155     xmlNodePtr cur, end, list, tmp;
   2156 
   2157     if (ctxt == NULL)
   2158 	return(-1);
   2159     if ((nr < 0) || (nr >= ctxt->incNr))
   2160 	return(-1);
   2161     cur = ctxt->incTab[nr]->ref;
   2162     if (cur == NULL)
   2163 	return(-1);
   2164 
   2165     /*
   2166      * If we stored an XPointer a late computation may be needed
   2167      */
   2168     if ((ctxt->incTab[nr]->inc == NULL) &&
   2169 	(ctxt->incTab[nr]->xptr != NULL)) {
   2170 	ctxt->incTab[nr]->inc =
   2171 	    xmlXIncludeCopyXPointer(ctxt, ctxt->doc, ctxt->doc,
   2172 		                    ctxt->incTab[nr]->xptr);
   2173 	xmlXPathFreeObject(ctxt->incTab[nr]->xptr);
   2174 	ctxt->incTab[nr]->xptr = NULL;
   2175     }
   2176     list = ctxt->incTab[nr]->inc;
   2177     ctxt->incTab[nr]->inc = NULL;
   2178 
   2179     /*
   2180      * Check against the risk of generating a multi-rooted document
   2181      */
   2182     if ((cur->parent != NULL) &&
   2183 	(cur->parent->type != XML_ELEMENT_NODE)) {
   2184 	int nb_elem = 0;
   2185 
   2186 	tmp = list;
   2187 	while (tmp != NULL) {
   2188 	    if (tmp->type == XML_ELEMENT_NODE)
   2189 		nb_elem++;
   2190 	    tmp = tmp->next;
   2191 	}
   2192 	if (nb_elem > 1) {
   2193 	    xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
   2194 	                   XML_XINCLUDE_MULTIPLE_ROOT,
   2195 		       "XInclude error: would result in multiple root nodes\n",
   2196 			   NULL);
   2197 	    return(-1);
   2198 	}
   2199     }
   2200 
   2201     if (ctxt->parseFlags & XML_PARSE_NOXINCNODE) {
   2202 	/*
   2203 	 * Add the list of nodes
   2204 	 */
   2205 	while (list != NULL) {
   2206 	    end = list;
   2207 	    list = list->next;
   2208 
   2209 	    xmlAddPrevSibling(cur, end);
   2210 	}
   2211 	xmlUnlinkNode(cur);
   2212 	xmlFreeNode(cur);
   2213     } else {
   2214 	/*
   2215 	 * Change the current node as an XInclude start one, and add an
   2216 	 * XInclude end one
   2217 	 */
   2218 	cur->type = XML_XINCLUDE_START;
   2219 	end = xmlNewDocNode(cur->doc, cur->ns, cur->name, NULL);
   2220 	if (end == NULL) {
   2221 	    xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
   2222 	                   XML_XINCLUDE_BUILD_FAILED,
   2223 			   "failed to build node\n", NULL);
   2224 	    return(-1);
   2225 	}
   2226 	end->type = XML_XINCLUDE_END;
   2227 	xmlAddNextSibling(cur, end);
   2228 
   2229 	/*
   2230 	 * Add the list of nodes
   2231 	 */
   2232 	while (list != NULL) {
   2233 	    cur = list;
   2234 	    list = list->next;
   2235 
   2236 	    xmlAddPrevSibling(end, cur);
   2237 	}
   2238     }
   2239 
   2240 
   2241     return(0);
   2242 }
   2243 
   2244 /**
   2245  * xmlXIncludeTestNode:
   2246  * @ctxt: the XInclude processing context
   2247  * @node: an XInclude node
   2248  *
   2249  * test if the node is an XInclude node
   2250  *
   2251  * Returns 1 true, 0 otherwise
   2252  */
   2253 static int
   2254 xmlXIncludeTestNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
   2255     if (node == NULL)
   2256 	return(0);
   2257     if (node->type != XML_ELEMENT_NODE)
   2258 	return(0);
   2259     if (node->ns == NULL)
   2260 	return(0);
   2261     if ((xmlStrEqual(node->ns->href, XINCLUDE_NS)) ||
   2262         (xmlStrEqual(node->ns->href, XINCLUDE_OLD_NS))) {
   2263 	if (xmlStrEqual(node->ns->href, XINCLUDE_OLD_NS)) {
   2264 	    if (ctxt->legacy == 0) {
   2265 #if 0 /* wait for the XML Core Working Group to get something stable ! */
   2266 		xmlXIncludeWarn(ctxt, node, XML_XINCLUDE_DEPRECATED_NS,
   2267 	               "Deprecated XInclude namespace found, use %s",
   2268 		                XINCLUDE_NS);
   2269 #endif
   2270 	        ctxt->legacy = 1;
   2271 	    }
   2272 	}
   2273 	if (xmlStrEqual(node->name, XINCLUDE_NODE)) {
   2274 	    xmlNodePtr child = node->children;
   2275 	    int nb_fallback = 0;
   2276 
   2277 	    while (child != NULL) {
   2278 		if ((child->type == XML_ELEMENT_NODE) &&
   2279 		    (child->ns != NULL) &&
   2280 		    ((xmlStrEqual(child->ns->href, XINCLUDE_NS)) ||
   2281 		     (xmlStrEqual(child->ns->href, XINCLUDE_OLD_NS)))) {
   2282 		    if (xmlStrEqual(child->name, XINCLUDE_NODE)) {
   2283 			xmlXIncludeErr(ctxt, node,
   2284 			               XML_XINCLUDE_INCLUDE_IN_INCLUDE,
   2285 				       "%s has an 'include' child\n",
   2286 				       XINCLUDE_NODE);
   2287 			return(0);
   2288 		    }
   2289 		    if (xmlStrEqual(child->name, XINCLUDE_FALLBACK)) {
   2290 			nb_fallback++;
   2291 		    }
   2292 		}
   2293 		child = child->next;
   2294 	    }
   2295 	    if (nb_fallback > 1) {
   2296 		xmlXIncludeErr(ctxt, node, XML_XINCLUDE_FALLBACKS_IN_INCLUDE,
   2297 			       "%s has multiple fallback children\n",
   2298 		               XINCLUDE_NODE);
   2299 		return(0);
   2300 	    }
   2301 	    return(1);
   2302 	}
   2303 	if (xmlStrEqual(node->name, XINCLUDE_FALLBACK)) {
   2304 	    if ((node->parent == NULL) ||
   2305 		(node->parent->type != XML_ELEMENT_NODE) ||
   2306 		(node->parent->ns == NULL) ||
   2307 		((!xmlStrEqual(node->parent->ns->href, XINCLUDE_NS)) &&
   2308 		 (!xmlStrEqual(node->parent->ns->href, XINCLUDE_OLD_NS))) ||
   2309 		(!xmlStrEqual(node->parent->name, XINCLUDE_NODE))) {
   2310 		xmlXIncludeErr(ctxt, node,
   2311 		               XML_XINCLUDE_FALLBACK_NOT_IN_INCLUDE,
   2312 			       "%s is not the child of an 'include'\n",
   2313 			       XINCLUDE_FALLBACK);
   2314 	    }
   2315 	}
   2316     }
   2317     return(0);
   2318 }
   2319 
   2320 /**
   2321  * xmlXIncludeDoProcess:
   2322  * @ctxt: the XInclude processing context
   2323  * @doc: an XML document
   2324  * @tree: the top of the tree to process
   2325  *
   2326  * Implement the XInclude substitution on the XML document @doc
   2327  *
   2328  * Returns 0 if no substitution were done, -1 if some processing failed
   2329  *    or the number of substitutions done.
   2330  */
   2331 static int
   2332 xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr tree) {
   2333     xmlNodePtr cur;
   2334     int ret = 0;
   2335     int i, start;
   2336 
   2337     if ((doc == NULL) || (tree == NULL))
   2338 	return(-1);
   2339     if (ctxt == NULL)
   2340 	return(-1);
   2341 
   2342     if (doc->URL != NULL) {
   2343 	ret = xmlXIncludeURLPush(ctxt, doc->URL);
   2344 	if (ret < 0)
   2345 	    return(-1);
   2346     }
   2347     start = ctxt->incNr;
   2348 
   2349     /*
   2350      * First phase: lookup the elements in the document
   2351      */
   2352     cur = tree;
   2353     if (xmlXIncludeTestNode(ctxt, cur) == 1)
   2354 	xmlXIncludePreProcessNode(ctxt, cur);
   2355     while ((cur != NULL) && (cur != tree->parent)) {
   2356 	/* TODO: need to work on entities -> stack */
   2357 	if ((cur->children != NULL) &&
   2358 	    (cur->children->type != XML_ENTITY_DECL) &&
   2359 	    (cur->children->type != XML_XINCLUDE_START) &&
   2360 	    (cur->children->type != XML_XINCLUDE_END)) {
   2361 	    cur = cur->children;
   2362 	    if (xmlXIncludeTestNode(ctxt, cur))
   2363 		xmlXIncludePreProcessNode(ctxt, cur);
   2364 	} else if (cur->next != NULL) {
   2365 	    cur = cur->next;
   2366 	    if (xmlXIncludeTestNode(ctxt, cur))
   2367 		xmlXIncludePreProcessNode(ctxt, cur);
   2368 	} else {
   2369 	    if (cur == tree)
   2370 	        break;
   2371 	    do {
   2372 		cur = cur->parent;
   2373 		if ((cur == NULL) || (cur == tree->parent))
   2374 		    break; /* do */
   2375 		if (cur->next != NULL) {
   2376 		    cur = cur->next;
   2377 		    if (xmlXIncludeTestNode(ctxt, cur))
   2378 			xmlXIncludePreProcessNode(ctxt, cur);
   2379 		    break; /* do */
   2380 		}
   2381 	    } while (cur != NULL);
   2382 	}
   2383     }
   2384 
   2385     /*
   2386      * Second Phase : collect the infosets fragments
   2387      */
   2388     for (i = start;i < ctxt->incNr; i++) {
   2389         xmlXIncludeLoadNode(ctxt, i);
   2390 	ret++;
   2391     }
   2392 
   2393     /*
   2394      * Third phase: extend the original document infoset.
   2395      *
   2396      * Originally we bypassed the inclusion if there were any errors
   2397      * encountered on any of the XIncludes.  A bug was raised (bug
   2398      * 132588) requesting that we output the XIncludes without error,
   2399      * so the check for inc!=NULL || xptr!=NULL was put in.  This may
   2400      * give some other problems in the future, but for now it seems to
   2401      * work ok.
   2402      *
   2403      */
   2404     for (i = ctxt->incBase;i < ctxt->incNr; i++) {
   2405 	if ((ctxt->incTab[i]->inc != NULL) ||
   2406 		(ctxt->incTab[i]->xptr != NULL) ||
   2407 		(ctxt->incTab[i]->emptyFb != 0))	/* (empty fallback) */
   2408 	    xmlXIncludeIncludeNode(ctxt, i);
   2409     }
   2410 
   2411     if (doc->URL != NULL)
   2412 	xmlXIncludeURLPop(ctxt);
   2413     return(ret);
   2414 }
   2415 
   2416 /**
   2417  * xmlXIncludeSetFlags:
   2418  * @ctxt:  an XInclude processing context
   2419  * @flags: a set of xmlParserOption used for parsing XML includes
   2420  *
   2421  * Set the flags used for further processing of XML resources.
   2422  *
   2423  * Returns 0 in case of success and -1 in case of error.
   2424  */
   2425 int
   2426 xmlXIncludeSetFlags(xmlXIncludeCtxtPtr ctxt, int flags) {
   2427     if (ctxt == NULL)
   2428         return(-1);
   2429     ctxt->parseFlags = flags;
   2430     return(0);
   2431 }
   2432 
   2433 /**
   2434  * xmlXIncludeProcessTreeFlagsData:
   2435  * @tree: an XML node
   2436  * @flags: a set of xmlParserOption used for parsing XML includes
   2437  * @data: application data that will be passed to the parser context
   2438  *        in the _private field of the parser context(s)
   2439  *
   2440  * Implement the XInclude substitution on the XML node @tree
   2441  *
   2442  * Returns 0 if no substitution were done, -1 if some processing failed
   2443  *    or the number of substitutions done.
   2444  */
   2445 
   2446 int
   2447 xmlXIncludeProcessTreeFlagsData(xmlNodePtr tree, int flags, void *data) {
   2448     xmlXIncludeCtxtPtr ctxt;
   2449     int ret = 0;
   2450 
   2451     if ((tree == NULL) || (tree->doc == NULL))
   2452         return(-1);
   2453 
   2454     ctxt = xmlXIncludeNewContext(tree->doc);
   2455     if (ctxt == NULL)
   2456         return(-1);
   2457     ctxt->_private = data;
   2458     ctxt->base = xmlStrdup((xmlChar *)tree->doc->URL);
   2459     xmlXIncludeSetFlags(ctxt, flags);
   2460     ret = xmlXIncludeDoProcess(ctxt, tree->doc, tree);
   2461     if ((ret >= 0) && (ctxt->nbErrors > 0))
   2462         ret = -1;
   2463 
   2464     xmlXIncludeFreeContext(ctxt);
   2465     return(ret);
   2466 }
   2467 
   2468 /**
   2469  * xmlXIncludeProcessFlagsData:
   2470  * @doc: an XML document
   2471  * @flags: a set of xmlParserOption used for parsing XML includes
   2472  * @data: application data that will be passed to the parser context
   2473  *        in the _private field of the parser context(s)
   2474  *
   2475  * Implement the XInclude substitution on the XML document @doc
   2476  *
   2477  * Returns 0 if no substitution were done, -1 if some processing failed
   2478  *    or the number of substitutions done.
   2479  */
   2480 int
   2481 xmlXIncludeProcessFlagsData(xmlDocPtr doc, int flags, void *data) {
   2482     xmlNodePtr tree;
   2483 
   2484     if (doc == NULL)
   2485 	return(-1);
   2486     tree = xmlDocGetRootElement(doc);
   2487     if (tree == NULL)
   2488 	return(-1);
   2489     return(xmlXIncludeProcessTreeFlagsData(tree, flags, data));
   2490 }
   2491 
   2492 /**
   2493  * xmlXIncludeProcessFlags:
   2494  * @doc: an XML document
   2495  * @flags: a set of xmlParserOption used for parsing XML includes
   2496  *
   2497  * Implement the XInclude substitution on the XML document @doc
   2498  *
   2499  * Returns 0 if no substitution were done, -1 if some processing failed
   2500  *    or the number of substitutions done.
   2501  */
   2502 int
   2503 xmlXIncludeProcessFlags(xmlDocPtr doc, int flags) {
   2504     return xmlXIncludeProcessFlagsData(doc, flags, NULL);
   2505 }
   2506 
   2507 /**
   2508  * xmlXIncludeProcess:
   2509  * @doc: an XML document
   2510  *
   2511  * Implement the XInclude substitution on the XML document @doc
   2512  *
   2513  * Returns 0 if no substitution were done, -1 if some processing failed
   2514  *    or the number of substitutions done.
   2515  */
   2516 int
   2517 xmlXIncludeProcess(xmlDocPtr doc) {
   2518     return(xmlXIncludeProcessFlags(doc, 0));
   2519 }
   2520 
   2521 /**
   2522  * xmlXIncludeProcessTreeFlags:
   2523  * @tree: a node in an XML document
   2524  * @flags: a set of xmlParserOption used for parsing XML includes
   2525  *
   2526  * Implement the XInclude substitution for the given subtree
   2527  *
   2528  * Returns 0 if no substitution were done, -1 if some processing failed
   2529  *    or the number of substitutions done.
   2530  */
   2531 int
   2532 xmlXIncludeProcessTreeFlags(xmlNodePtr tree, int flags) {
   2533     xmlXIncludeCtxtPtr ctxt;
   2534     int ret = 0;
   2535 
   2536     if ((tree == NULL) || (tree->doc == NULL))
   2537 	return(-1);
   2538     ctxt = xmlXIncludeNewContext(tree->doc);
   2539     if (ctxt == NULL)
   2540 	return(-1);
   2541     ctxt->base = xmlNodeGetBase(tree->doc, tree);
   2542     xmlXIncludeSetFlags(ctxt, flags);
   2543     ret = xmlXIncludeDoProcess(ctxt, tree->doc, tree);
   2544     if ((ret >= 0) && (ctxt->nbErrors > 0))
   2545 	ret = -1;
   2546 
   2547     xmlXIncludeFreeContext(ctxt);
   2548     return(ret);
   2549 }
   2550 
   2551 /**
   2552  * xmlXIncludeProcessTree:
   2553  * @tree: a node in an XML document
   2554  *
   2555  * Implement the XInclude substitution for the given subtree
   2556  *
   2557  * Returns 0 if no substitution were done, -1 if some processing failed
   2558  *    or the number of substitutions done.
   2559  */
   2560 int
   2561 xmlXIncludeProcessTree(xmlNodePtr tree) {
   2562     return(xmlXIncludeProcessTreeFlags(tree, 0));
   2563 }
   2564 
   2565 /**
   2566  * xmlXIncludeProcessNode:
   2567  * @ctxt: an existing XInclude context
   2568  * @node: a node in an XML document
   2569  *
   2570  * Implement the XInclude substitution for the given subtree reusing
   2571  * the informations and data coming from the given context.
   2572  *
   2573  * Returns 0 if no substitution were done, -1 if some processing failed
   2574  *    or the number of substitutions done.
   2575  */
   2576 int
   2577 xmlXIncludeProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
   2578     int ret = 0;
   2579 
   2580     if ((node == NULL) || (node->doc == NULL) || (ctxt == NULL))
   2581 	return(-1);
   2582     ret = xmlXIncludeDoProcess(ctxt, node->doc, node);
   2583     if ((ret >= 0) && (ctxt->nbErrors > 0))
   2584 	ret = -1;
   2585     return(ret);
   2586 }
   2587 
   2588 #else /* !LIBXML_XINCLUDE_ENABLED */
   2589 #endif
   2590 #define bottom_xinclude
   2591 #include "elfgcchack.h"
   2592