File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libxml2 / xinclude.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Jul 22 01:22:18 2013 UTC (10 years, 11 months ago) by misho
Branches: libxml2, MAIN
CVS tags: v2_8_0p0, v2_8_0, HEAD
2.8.0

    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@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:     xmlParserCtxtPtr pctxt;
 1800:     xmlParserInputPtr inputStream;
 1801: 
 1802:     /*
 1803:      * Check the URL and remove any fragment identifier
 1804:      */
 1805:     uri = xmlParseURI((const char *)url);
 1806:     if (uri == NULL) {
 1807: 	xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_HREF_URI,
 1808: 	               "invalid value URI %s\n", url);
 1809: 	return(-1);
 1810:     }
 1811:     if (uri->fragment != NULL) {
 1812: 	xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_TEXT_FRAGMENT,
 1813: 	               "fragment identifier forbidden for text: %s\n",
 1814: 		       (const xmlChar *) uri->fragment);
 1815: 	xmlFreeURI(uri);
 1816: 	return(-1);
 1817:     }
 1818:     URL = xmlSaveUri(uri);
 1819:     xmlFreeURI(uri);
 1820:     if (URL == NULL) {
 1821: 	xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_HREF_URI,
 1822: 	               "invalid value URI %s\n", url);
 1823: 	return(-1);
 1824:     }
 1825: 
 1826:     /*
 1827:      * Handling of references to the local document are done
 1828:      * directly through ctxt->doc.
 1829:      */
 1830:     if (URL[0] == 0) {
 1831: 	xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, 
 1832: 	               XML_XINCLUDE_TEXT_DOCUMENT,
 1833: 		       "text serialization of document not available\n", NULL);
 1834: 	xmlFree(URL);
 1835: 	return(-1);
 1836:     }
 1837: 
 1838:     /*
 1839:      * Prevent reloading twice the document.
 1840:      */
 1841:     for (i = 0; i < ctxt->txtNr; i++) {
 1842: 	if (xmlStrEqual(URL, ctxt->txturlTab[i])) {
 1843: 	    node = xmlCopyNode(ctxt->txtTab[i], 1);
 1844: 	    goto loaded;
 1845: 	}
 1846:     }
 1847:     /*
 1848:      * Try to get the encoding if available
 1849:      */
 1850:     if ((ctxt->incTab[nr] != NULL) && (ctxt->incTab[nr]->ref != NULL)) {
 1851: 	encoding = xmlGetProp(ctxt->incTab[nr]->ref, XINCLUDE_PARSE_ENCODING);
 1852:     }
 1853:     if (encoding != NULL) {
 1854: 	/*
 1855: 	 * TODO: we should not have to remap to the xmlCharEncoding
 1856: 	 *       predefined set, a better interface than
 1857: 	 *       xmlParserInputBufferCreateFilename should allow any
 1858: 	 *       encoding supported by iconv
 1859: 	 */
 1860:         enc = xmlParseCharEncoding((const char *) encoding);
 1861: 	if (enc == XML_CHAR_ENCODING_ERROR) {
 1862: 	    xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
 1863: 	                   XML_XINCLUDE_UNKNOWN_ENCODING,
 1864: 			   "encoding %s not supported\n", encoding);
 1865: 	    xmlFree(encoding);
 1866: 	    xmlFree(URL);
 1867: 	    return(-1);
 1868: 	}
 1869: 	xmlFree(encoding);
 1870:     }
 1871: 
 1872:     /*
 1873:      * Load it.
 1874:      */
 1875:     pctxt = xmlNewParserCtxt();
 1876:     inputStream = xmlLoadExternalEntity((const char*)URL, NULL, pctxt);
 1877:     if(inputStream == NULL) {
 1878: 	xmlFreeParserCtxt(pctxt);
 1879: 	xmlFree(URL);
 1880: 	return(-1);
 1881:     }
 1882:     buf = inputStream->buf;
 1883:     if (buf == NULL) {
 1884: 	xmlFreeInputStream (inputStream);
 1885: 	xmlFreeParserCtxt(pctxt);
 1886: 	xmlFree(URL);
 1887: 	return(-1);
 1888:     }
 1889:     if (buf->encoder)
 1890: 	xmlCharEncCloseFunc(buf->encoder);
 1891:     buf->encoder = xmlGetCharEncodingHandler(enc);
 1892:     node = xmlNewText(NULL);
 1893: 
 1894:     /*
 1895:      * Scan all chars from the resource and add the to the node
 1896:      */
 1897:     while (xmlParserInputBufferRead(buf, 128) > 0) {
 1898: 	int len;
 1899: 	const xmlChar *content;
 1900: 
 1901: 	content = xmlBufferContent(buf->buffer);
 1902: 	len = xmlBufferLength(buf->buffer);
 1903: 	for (i = 0;i < len;) {
 1904: 	    int cur;
 1905: 	    int l;
 1906: 
 1907: 	    cur = xmlStringCurrentChar(NULL, &content[i], &l);
 1908: 	    if (!IS_CHAR(cur)) {
 1909: 		xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
 1910: 		               XML_XINCLUDE_INVALID_CHAR,
 1911: 			       "%s contains invalid char\n", URL);
 1912: 		xmlFreeParserInputBuffer(buf);
 1913: 		xmlFree(URL);
 1914: 		return(-1);
 1915: 	    } else {
 1916: 		xmlNodeAddContentLen(node, &content[i], l);
 1917: 	    }
 1918: 	    i += l;
 1919: 	}
 1920: 	xmlBufferShrink(buf->buffer, len);
 1921:     }
 1922:     xmlFreeParserCtxt(pctxt);
 1923:     xmlXIncludeAddTxt(ctxt, node, URL);
 1924:     xmlFreeInputStream(inputStream);
 1925: 
 1926: loaded:
 1927:     /*
 1928:      * Add the element as the replacement copy.
 1929:      */
 1930:     ctxt->incTab[nr]->inc = node;
 1931:     xmlFree(URL);
 1932:     return(0);
 1933: }
 1934: 
 1935: /**
 1936:  * xmlXIncludeLoadFallback:
 1937:  * @ctxt:  the XInclude context
 1938:  * @fallback:  the fallback node
 1939:  * @nr:  the xinclude node number
 1940:  * 
 1941:  * Load the content of the fallback node, and store the result
 1942:  * in the XInclude context
 1943:  *
 1944:  * Returns 0 in case of success, -1 in case of failure
 1945:  */
 1946: static int
 1947: xmlXIncludeLoadFallback(xmlXIncludeCtxtPtr ctxt, xmlNodePtr fallback, int nr) {
 1948:     xmlXIncludeCtxtPtr newctxt;
 1949:     int ret = 0;
 1950:     
 1951:     if ((fallback == NULL) || (ctxt == NULL))
 1952: 	return(-1);
 1953:     if (fallback->children != NULL) {
 1954: 	/*
 1955: 	 * It's possible that the fallback also has 'includes'
 1956: 	 * (Bug 129969), so we re-process the fallback just in case
 1957: 	 */
 1958: 	newctxt = xmlXIncludeNewContext(ctxt->doc);
 1959: 	if (newctxt == NULL)
 1960: 	    return (-1);
 1961: 	newctxt->_private = ctxt->_private;
 1962: 	newctxt->base = xmlStrdup(ctxt->base);	/* Inherit the base from the existing context */
 1963: 	xmlXIncludeSetFlags(newctxt, ctxt->parseFlags);
 1964: 	ret = xmlXIncludeDoProcess(newctxt, ctxt->doc, fallback->children);
 1965: 	if (ctxt->nbErrors > 0)
 1966: 	    ret = -1;
 1967: 	else if (ret > 0)
 1968: 	    ret = 0;	/* xmlXIncludeDoProcess can return +ve number */
 1969: 	xmlXIncludeFreeContext(newctxt);
 1970: 
 1971: 	ctxt->incTab[nr]->inc = xmlDocCopyNodeList(ctxt->doc,
 1972: 	                                           fallback->children);
 1973:     } else {
 1974:         ctxt->incTab[nr]->inc = NULL;
 1975: 	ctxt->incTab[nr]->emptyFb = 1;	/* flag empty callback */
 1976:     }
 1977:     return(ret);
 1978: }
 1979: 
 1980: /************************************************************************
 1981:  *									*
 1982:  *			XInclude Processing				*
 1983:  *									*
 1984:  ************************************************************************/
 1985: 
 1986: /**
 1987:  * xmlXIncludePreProcessNode:
 1988:  * @ctxt: an XInclude context
 1989:  * @node: an XInclude node
 1990:  *
 1991:  * Implement the XInclude preprocessing, currently just adding the element
 1992:  * for further processing.
 1993:  *
 1994:  * Returns the result list or NULL in case of error
 1995:  */
 1996: static xmlNodePtr
 1997: xmlXIncludePreProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
 1998:     xmlXIncludeAddNode(ctxt, node);
 1999:     return(NULL);
 2000: }
 2001: 
 2002: /**
 2003:  * xmlXIncludeLoadNode:
 2004:  * @ctxt: an XInclude context
 2005:  * @nr: the node number
 2006:  *
 2007:  * Find and load the infoset replacement for the given node.
 2008:  *
 2009:  * Returns 0 if substitution succeeded, -1 if some processing failed
 2010:  */
 2011: static int
 2012: xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, int nr) {
 2013:     xmlNodePtr cur;
 2014:     xmlChar *href;
 2015:     xmlChar *parse;
 2016:     xmlChar *base;
 2017:     xmlChar *oldBase;
 2018:     xmlChar *URI;
 2019:     int xml = 1; /* default Issue 64 */
 2020:     int ret;
 2021: 
 2022:     if (ctxt == NULL)
 2023: 	return(-1);
 2024:     if ((nr < 0) || (nr >= ctxt->incNr))
 2025: 	return(-1);
 2026:     cur = ctxt->incTab[nr]->ref;
 2027:     if (cur == NULL)
 2028: 	return(-1);
 2029: 
 2030:     /*
 2031:      * read the attributes
 2032:      */
 2033:     href = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_HREF);
 2034:     if (href == NULL) {
 2035: 	href = xmlStrdup(BAD_CAST ""); /* @@@@ href is now optional */
 2036: 	if (href == NULL) 
 2037: 	    return(-1);
 2038:     }
 2039:     parse = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_PARSE);
 2040:     if (parse != NULL) {
 2041: 	if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
 2042: 	    xml = 1;
 2043: 	else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
 2044: 	    xml = 0;
 2045: 	else {
 2046: 	    xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
 2047: 	                   XML_XINCLUDE_PARSE_VALUE,
 2048: 			   "invalid value %s for 'parse'\n", parse);
 2049: 	    if (href != NULL)
 2050: 		xmlFree(href);
 2051: 	    if (parse != NULL)
 2052: 		xmlFree(parse);
 2053: 	    return(-1);
 2054: 	}
 2055:     }
 2056: 
 2057:     /*
 2058:      * compute the URI
 2059:      */
 2060:     base = xmlNodeGetBase(ctxt->doc, cur);
 2061:     if (base == NULL) {
 2062: 	URI = xmlBuildURI(href, ctxt->doc->URL);
 2063:     } else {
 2064: 	URI = xmlBuildURI(href, base);
 2065:     }
 2066:     if (URI == NULL) {
 2067: 	xmlChar *escbase;
 2068: 	xmlChar *eschref;
 2069: 	/*
 2070: 	 * Some escaping may be needed
 2071: 	 */
 2072: 	escbase = xmlURIEscape(base);
 2073: 	eschref = xmlURIEscape(href);
 2074: 	URI = xmlBuildURI(eschref, escbase);
 2075: 	if (escbase != NULL)
 2076: 	    xmlFree(escbase);
 2077: 	if (eschref != NULL)
 2078: 	    xmlFree(eschref);
 2079:     }
 2080:     if (URI == NULL) {
 2081: 	xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, 
 2082: 	               XML_XINCLUDE_HREF_URI, "failed build URL\n", NULL);
 2083: 	if (parse != NULL)
 2084: 	    xmlFree(parse);
 2085: 	if (href != NULL)
 2086: 	    xmlFree(href);
 2087: 	if (base != NULL)
 2088: 	    xmlFree(base);
 2089: 	return(-1);
 2090:     }
 2091: #ifdef DEBUG_XINCLUDE
 2092:     xmlGenericError(xmlGenericErrorContext, "parse: %s\n",
 2093: 	    xml ? "xml": "text");
 2094:     xmlGenericError(xmlGenericErrorContext, "URI: %s\n", URI);
 2095: #endif
 2096: 
 2097:     /*
 2098:      * Save the base for this include (saving the current one)
 2099:      */
 2100:     oldBase = ctxt->base;
 2101:     ctxt->base = base;
 2102: 
 2103:     if (xml) {
 2104: 	ret = xmlXIncludeLoadDoc(ctxt, URI, nr);
 2105: 	/* xmlXIncludeGetFragment(ctxt, cur, URI); */
 2106:     } else {
 2107: 	ret = xmlXIncludeLoadTxt(ctxt, URI, nr);
 2108:     }
 2109: 
 2110:     /*
 2111:      * Restore the original base before checking for fallback
 2112:      */
 2113:     ctxt->base = oldBase;
 2114:     
 2115:     if (ret < 0) {
 2116: 	xmlNodePtr children;
 2117: 
 2118: 	/*
 2119: 	 * Time to try a fallback if availble
 2120: 	 */
 2121: #ifdef DEBUG_XINCLUDE
 2122: 	xmlGenericError(xmlGenericErrorContext, "error looking for fallback\n");
 2123: #endif
 2124: 	children = cur->children;
 2125: 	while (children != NULL) {
 2126: 	    if ((children->type == XML_ELEMENT_NODE) &&
 2127: 		(children->ns != NULL) &&
 2128: 		(xmlStrEqual(children->name, XINCLUDE_FALLBACK)) &&
 2129: 		((xmlStrEqual(children->ns->href, XINCLUDE_NS)) ||
 2130: 		 (xmlStrEqual(children->ns->href, XINCLUDE_OLD_NS)))) {
 2131: 		ret = xmlXIncludeLoadFallback(ctxt, children, nr);
 2132: 		if (ret == 0) 
 2133: 		    break;
 2134: 	    }
 2135: 	    children = children->next;
 2136: 	}
 2137:     }
 2138:     if (ret < 0) {
 2139: 	xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, 
 2140: 	               XML_XINCLUDE_NO_FALLBACK,
 2141: 		       "could not load %s, and no fallback was found\n",
 2142: 		       URI);
 2143:     }
 2144: 
 2145:     /*
 2146:      * Cleanup
 2147:      */
 2148:     if (URI != NULL)
 2149: 	xmlFree(URI);
 2150:     if (parse != NULL)
 2151: 	xmlFree(parse);
 2152:     if (href != NULL)
 2153: 	xmlFree(href);
 2154:     if (base != NULL)
 2155: 	xmlFree(base);
 2156:     return(0);
 2157: }
 2158: 
 2159: /**
 2160:  * xmlXIncludeIncludeNode:
 2161:  * @ctxt: an XInclude context
 2162:  * @nr: the node number
 2163:  *
 2164:  * Inplement the infoset replacement for the given node
 2165:  *
 2166:  * Returns 0 if substitution succeeded, -1 if some processing failed
 2167:  */
 2168: static int
 2169: xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) {
 2170:     xmlNodePtr cur, end, list, tmp;
 2171: 
 2172:     if (ctxt == NULL)
 2173: 	return(-1);
 2174:     if ((nr < 0) || (nr >= ctxt->incNr))
 2175: 	return(-1);
 2176:     cur = ctxt->incTab[nr]->ref;
 2177:     if (cur == NULL)
 2178: 	return(-1);
 2179: 
 2180:     /*
 2181:      * If we stored an XPointer a late computation may be needed
 2182:      */
 2183:     if ((ctxt->incTab[nr]->inc == NULL) &&
 2184: 	(ctxt->incTab[nr]->xptr != NULL)) {
 2185: 	ctxt->incTab[nr]->inc =
 2186: 	    xmlXIncludeCopyXPointer(ctxt, ctxt->doc, ctxt->doc,
 2187: 		                    ctxt->incTab[nr]->xptr);
 2188: 	xmlXPathFreeObject(ctxt->incTab[nr]->xptr);
 2189: 	ctxt->incTab[nr]->xptr = NULL;
 2190:     }
 2191:     list = ctxt->incTab[nr]->inc;
 2192:     ctxt->incTab[nr]->inc = NULL;
 2193: 
 2194:     /*
 2195:      * Check against the risk of generating a multi-rooted document
 2196:      */
 2197:     if ((cur->parent != NULL) &&
 2198: 	(cur->parent->type != XML_ELEMENT_NODE)) {
 2199: 	int nb_elem = 0;
 2200: 
 2201: 	tmp = list;
 2202: 	while (tmp != NULL) {
 2203: 	    if (tmp->type == XML_ELEMENT_NODE)
 2204: 		nb_elem++;
 2205: 	    tmp = tmp->next;
 2206: 	}
 2207: 	if (nb_elem > 1) {
 2208: 	    xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, 
 2209: 	                   XML_XINCLUDE_MULTIPLE_ROOT,
 2210: 		       "XInclude error: would result in multiple root nodes\n",
 2211: 			   NULL);
 2212: 	    return(-1);
 2213: 	}
 2214:     }
 2215: 
 2216:     if (ctxt->parseFlags & XML_PARSE_NOXINCNODE) {
 2217: 	/*
 2218: 	 * Add the list of nodes
 2219: 	 */
 2220: 	while (list != NULL) {
 2221: 	    end = list;
 2222: 	    list = list->next;
 2223: 
 2224: 	    xmlAddPrevSibling(cur, end);
 2225: 	}
 2226: 	xmlUnlinkNode(cur);
 2227: 	xmlFreeNode(cur);
 2228:     } else {
 2229: 	/*
 2230: 	 * Change the current node as an XInclude start one, and add an
 2231: 	 * XInclude end one
 2232: 	 */
 2233: 	cur->type = XML_XINCLUDE_START;
 2234: 	end = xmlNewDocNode(cur->doc, cur->ns, cur->name, NULL);
 2235: 	if (end == NULL) {
 2236: 	    xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
 2237: 	                   XML_XINCLUDE_BUILD_FAILED,
 2238: 			   "failed to build node\n", NULL);
 2239: 	    return(-1);
 2240: 	}
 2241: 	end->type = XML_XINCLUDE_END;
 2242: 	xmlAddNextSibling(cur, end);
 2243: 
 2244: 	/*
 2245: 	 * Add the list of nodes
 2246: 	 */
 2247: 	while (list != NULL) {
 2248: 	    cur = list;
 2249: 	    list = list->next;
 2250: 
 2251: 	    xmlAddPrevSibling(end, cur);
 2252: 	}
 2253:     }
 2254: 
 2255:     
 2256:     return(0);
 2257: }
 2258: 
 2259: /**
 2260:  * xmlXIncludeTestNode:
 2261:  * @ctxt: the XInclude processing context
 2262:  * @node: an XInclude node
 2263:  *
 2264:  * test if the node is an XInclude node
 2265:  *
 2266:  * Returns 1 true, 0 otherwise
 2267:  */
 2268: static int
 2269: xmlXIncludeTestNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
 2270:     if (node == NULL)
 2271: 	return(0);
 2272:     if (node->type != XML_ELEMENT_NODE)
 2273: 	return(0);
 2274:     if (node->ns == NULL)
 2275: 	return(0);
 2276:     if ((xmlStrEqual(node->ns->href, XINCLUDE_NS)) ||
 2277:         (xmlStrEqual(node->ns->href, XINCLUDE_OLD_NS))) {
 2278: 	if (xmlStrEqual(node->ns->href, XINCLUDE_OLD_NS)) {
 2279: 	    if (ctxt->legacy == 0) {
 2280: #if 0 /* wait for the XML Core Working Group to get something stable ! */
 2281: 		xmlXIncludeWarn(ctxt, node, XML_XINCLUDE_DEPRECATED_NS,
 2282: 	               "Deprecated XInclude namespace found, use %s",
 2283: 		                XINCLUDE_NS);
 2284: #endif
 2285: 	        ctxt->legacy = 1;
 2286: 	    }
 2287: 	}
 2288: 	if (xmlStrEqual(node->name, XINCLUDE_NODE)) {
 2289: 	    xmlNodePtr child = node->children;
 2290: 	    int nb_fallback = 0;
 2291: 
 2292: 	    while (child != NULL) {
 2293: 		if ((child->type == XML_ELEMENT_NODE) &&
 2294: 		    (child->ns != NULL) &&
 2295: 		    ((xmlStrEqual(child->ns->href, XINCLUDE_NS)) ||
 2296: 		     (xmlStrEqual(child->ns->href, XINCLUDE_OLD_NS)))) {
 2297: 		    if (xmlStrEqual(child->name, XINCLUDE_NODE)) {
 2298: 			xmlXIncludeErr(ctxt, node,
 2299: 			               XML_XINCLUDE_INCLUDE_IN_INCLUDE,
 2300: 				       "%s has an 'include' child\n",
 2301: 				       XINCLUDE_NODE);
 2302: 			return(0);
 2303: 		    }
 2304: 		    if (xmlStrEqual(child->name, XINCLUDE_FALLBACK)) {
 2305: 			nb_fallback++;
 2306: 		    }
 2307: 		}
 2308: 		child = child->next;
 2309: 	    }
 2310: 	    if (nb_fallback > 1) {
 2311: 		xmlXIncludeErr(ctxt, node, XML_XINCLUDE_FALLBACKS_IN_INCLUDE,
 2312: 			       "%s has multiple fallback children\n",
 2313: 		               XINCLUDE_NODE);
 2314: 		return(0);
 2315: 	    }
 2316: 	    return(1);
 2317: 	}
 2318: 	if (xmlStrEqual(node->name, XINCLUDE_FALLBACK)) {
 2319: 	    if ((node->parent == NULL) ||
 2320: 		(node->parent->type != XML_ELEMENT_NODE) ||
 2321: 		(node->parent->ns == NULL) ||
 2322: 		((!xmlStrEqual(node->parent->ns->href, XINCLUDE_NS)) &&
 2323: 		 (!xmlStrEqual(node->parent->ns->href, XINCLUDE_OLD_NS))) ||
 2324: 		(!xmlStrEqual(node->parent->name, XINCLUDE_NODE))) {
 2325: 		xmlXIncludeErr(ctxt, node,
 2326: 		               XML_XINCLUDE_FALLBACK_NOT_IN_INCLUDE,
 2327: 			       "%s is not the child of an 'include'\n",
 2328: 			       XINCLUDE_FALLBACK);
 2329: 	    }
 2330: 	}
 2331:     }
 2332:     return(0);
 2333: }
 2334: 
 2335: /**
 2336:  * xmlXIncludeDoProcess:
 2337:  * @ctxt: the XInclude processing context
 2338:  * @doc: an XML document
 2339:  * @tree: the top of the tree to process
 2340:  *
 2341:  * Implement the XInclude substitution on the XML document @doc
 2342:  *
 2343:  * Returns 0 if no substitution were done, -1 if some processing failed
 2344:  *    or the number of substitutions done.
 2345:  */
 2346: static int
 2347: xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr tree) {
 2348:     xmlNodePtr cur;
 2349:     int ret = 0;
 2350:     int i, start;
 2351: 
 2352:     if ((doc == NULL) || (tree == NULL))
 2353: 	return(-1);
 2354:     if (ctxt == NULL)
 2355: 	return(-1);
 2356: 
 2357:     if (doc->URL != NULL) {
 2358: 	ret = xmlXIncludeURLPush(ctxt, doc->URL);
 2359: 	if (ret < 0)
 2360: 	    return(-1);
 2361:     }
 2362:     start = ctxt->incNr;
 2363: 
 2364:     /*
 2365:      * First phase: lookup the elements in the document
 2366:      */
 2367:     cur = tree;
 2368:     if (xmlXIncludeTestNode(ctxt, cur) == 1)
 2369: 	xmlXIncludePreProcessNode(ctxt, cur);
 2370:     while ((cur != NULL) && (cur != tree->parent)) {
 2371: 	/* TODO: need to work on entities -> stack */
 2372: 	if ((cur->children != NULL) &&
 2373: 	    (cur->children->type != XML_ENTITY_DECL) &&
 2374: 	    (cur->children->type != XML_XINCLUDE_START) &&
 2375: 	    (cur->children->type != XML_XINCLUDE_END)) {
 2376: 	    cur = cur->children;
 2377: 	    if (xmlXIncludeTestNode(ctxt, cur))
 2378: 		xmlXIncludePreProcessNode(ctxt, cur);
 2379: 	} else if (cur->next != NULL) {
 2380: 	    cur = cur->next;
 2381: 	    if (xmlXIncludeTestNode(ctxt, cur))
 2382: 		xmlXIncludePreProcessNode(ctxt, cur);
 2383: 	} else {
 2384: 	    if (cur == tree)
 2385: 	        break;
 2386: 	    do {
 2387: 		cur = cur->parent;
 2388: 		if ((cur == NULL) || (cur == tree->parent))
 2389: 		    break; /* do */
 2390: 		if (cur->next != NULL) {
 2391: 		    cur = cur->next;
 2392: 		    if (xmlXIncludeTestNode(ctxt, cur))
 2393: 			xmlXIncludePreProcessNode(ctxt, cur);
 2394: 		    break; /* do */
 2395: 		}
 2396: 	    } while (cur != NULL);
 2397: 	}
 2398:     }
 2399: 
 2400:     /*
 2401:      * Second Phase : collect the infosets fragments
 2402:      */
 2403:     for (i = start;i < ctxt->incNr; i++) {
 2404:         xmlXIncludeLoadNode(ctxt, i);
 2405: 	ret++;
 2406:     }
 2407: 
 2408:     /*
 2409:      * Third phase: extend the original document infoset.
 2410:      *
 2411:      * Originally we bypassed the inclusion if there were any errors
 2412:      * encountered on any of the XIncludes.  A bug was raised (bug
 2413:      * 132588) requesting that we output the XIncludes without error,
 2414:      * so the check for inc!=NULL || xptr!=NULL was put in.  This may
 2415:      * give some other problems in the future, but for now it seems to
 2416:      * work ok.
 2417:      *
 2418:      */
 2419:     for (i = ctxt->incBase;i < ctxt->incNr; i++) {
 2420: 	if ((ctxt->incTab[i]->inc != NULL) ||
 2421: 		(ctxt->incTab[i]->xptr != NULL) ||
 2422: 		(ctxt->incTab[i]->emptyFb != 0))	/* (empty fallback) */
 2423: 	    xmlXIncludeIncludeNode(ctxt, i);
 2424:     }
 2425: 
 2426:     if (doc->URL != NULL)
 2427: 	xmlXIncludeURLPop(ctxt);
 2428:     return(ret);
 2429: }
 2430: 
 2431: /**
 2432:  * xmlXIncludeSetFlags:
 2433:  * @ctxt:  an XInclude processing context
 2434:  * @flags: a set of xmlParserOption used for parsing XML includes
 2435:  *
 2436:  * Set the flags used for further processing of XML resources.
 2437:  *
 2438:  * Returns 0 in case of success and -1 in case of error.
 2439:  */
 2440: int
 2441: xmlXIncludeSetFlags(xmlXIncludeCtxtPtr ctxt, int flags) {
 2442:     if (ctxt == NULL)
 2443:         return(-1);
 2444:     ctxt->parseFlags = flags;
 2445:     return(0);
 2446: }
 2447: 
 2448: /**
 2449:  * xmlXIncludeProcessTreeFlagsData:
 2450:  * @tree: an XML node
 2451:  * @flags: a set of xmlParserOption used for parsing XML includes
 2452:  * @data: application data that will be passed to the parser context
 2453:  *        in the _private field of the parser context(s)
 2454:  *
 2455:  * Implement the XInclude substitution on the XML node @tree
 2456:  *
 2457:  * Returns 0 if no substitution were done, -1 if some processing failed
 2458:  *    or the number of substitutions done.
 2459:  */
 2460: 
 2461: int
 2462: xmlXIncludeProcessTreeFlagsData(xmlNodePtr tree, int flags, void *data) {
 2463:     xmlXIncludeCtxtPtr ctxt;
 2464:     int ret = 0;
 2465: 
 2466:     if ((tree == NULL) || (tree->doc == NULL))
 2467:         return(-1);
 2468: 
 2469:     ctxt = xmlXIncludeNewContext(tree->doc);
 2470:     if (ctxt == NULL)
 2471:         return(-1);
 2472:     ctxt->_private = data;
 2473:     ctxt->base = xmlStrdup((xmlChar *)tree->doc->URL);
 2474:     xmlXIncludeSetFlags(ctxt, flags);
 2475:     ret = xmlXIncludeDoProcess(ctxt, tree->doc, tree);
 2476:     if ((ret >= 0) && (ctxt->nbErrors > 0))
 2477:         ret = -1;
 2478: 
 2479:     xmlXIncludeFreeContext(ctxt);
 2480:     return(ret);
 2481: }
 2482: 
 2483: /**
 2484:  * xmlXIncludeProcessFlagsData:
 2485:  * @doc: an XML document
 2486:  * @flags: a set of xmlParserOption used for parsing XML includes
 2487:  * @data: application data that will be passed to the parser context
 2488:  *        in the _private field of the parser context(s)
 2489:  *
 2490:  * Implement the XInclude substitution on the XML document @doc
 2491:  *
 2492:  * Returns 0 if no substitution were done, -1 if some processing failed
 2493:  *    or the number of substitutions done.
 2494:  */
 2495: int
 2496: xmlXIncludeProcessFlagsData(xmlDocPtr doc, int flags, void *data) {
 2497:     xmlNodePtr tree;
 2498: 
 2499:     if (doc == NULL)
 2500: 	return(-1);
 2501:     tree = xmlDocGetRootElement(doc);
 2502:     if (tree == NULL)
 2503: 	return(-1);
 2504:     return(xmlXIncludeProcessTreeFlagsData(tree, flags, data));
 2505: }
 2506: 
 2507: /**
 2508:  * xmlXIncludeProcessFlags:
 2509:  * @doc: an XML document
 2510:  * @flags: a set of xmlParserOption used for parsing XML includes
 2511:  *
 2512:  * Implement the XInclude substitution on the XML document @doc
 2513:  *
 2514:  * Returns 0 if no substitution were done, -1 if some processing failed
 2515:  *    or the number of substitutions done.
 2516:  */
 2517: int
 2518: xmlXIncludeProcessFlags(xmlDocPtr doc, int flags) {
 2519:     return xmlXIncludeProcessFlagsData(doc, flags, NULL);
 2520: }
 2521: 
 2522: /**
 2523:  * xmlXIncludeProcess:
 2524:  * @doc: an XML document
 2525:  *
 2526:  * Implement the XInclude substitution on the XML document @doc
 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: xmlXIncludeProcess(xmlDocPtr doc) {
 2533:     return(xmlXIncludeProcessFlags(doc, 0));
 2534: }
 2535: 
 2536: /**
 2537:  * xmlXIncludeProcessTreeFlags:
 2538:  * @tree: a node in an XML document
 2539:  * @flags: a set of xmlParserOption used for parsing XML includes
 2540:  *
 2541:  * Implement the XInclude substitution for the given subtree
 2542:  *
 2543:  * Returns 0 if no substitution were done, -1 if some processing failed
 2544:  *    or the number of substitutions done.
 2545:  */
 2546: int
 2547: xmlXIncludeProcessTreeFlags(xmlNodePtr tree, int flags) {
 2548:     xmlXIncludeCtxtPtr ctxt;
 2549:     int ret = 0;
 2550: 
 2551:     if ((tree == NULL) || (tree->doc == NULL))
 2552: 	return(-1);
 2553:     ctxt = xmlXIncludeNewContext(tree->doc);
 2554:     if (ctxt == NULL)
 2555: 	return(-1);
 2556:     ctxt->base = xmlNodeGetBase(tree->doc, tree);
 2557:     xmlXIncludeSetFlags(ctxt, flags);
 2558:     ret = xmlXIncludeDoProcess(ctxt, tree->doc, tree);
 2559:     if ((ret >= 0) && (ctxt->nbErrors > 0))
 2560: 	ret = -1;
 2561: 
 2562:     xmlXIncludeFreeContext(ctxt);
 2563:     return(ret);
 2564: }
 2565: 
 2566: /**
 2567:  * xmlXIncludeProcessTree:
 2568:  * @tree: a node in an XML document
 2569:  *
 2570:  * Implement the XInclude substitution for the given subtree
 2571:  *
 2572:  * Returns 0 if no substitution were done, -1 if some processing failed
 2573:  *    or the number of substitutions done.
 2574:  */
 2575: int
 2576: xmlXIncludeProcessTree(xmlNodePtr tree) {
 2577:     return(xmlXIncludeProcessTreeFlags(tree, 0));
 2578: }
 2579: 
 2580: /**
 2581:  * xmlXIncludeProcessNode:
 2582:  * @ctxt: an existing XInclude context
 2583:  * @node: a node in an XML document
 2584:  *
 2585:  * Implement the XInclude substitution for the given subtree reusing
 2586:  * the informations and data coming from the given context.
 2587:  *
 2588:  * Returns 0 if no substitution were done, -1 if some processing failed
 2589:  *    or the number of substitutions done.
 2590:  */
 2591: int
 2592: xmlXIncludeProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
 2593:     int ret = 0;
 2594: 
 2595:     if ((node == NULL) || (node->doc == NULL) || (ctxt == NULL))
 2596: 	return(-1);
 2597:     ret = xmlXIncludeDoProcess(ctxt, node->doc, node);
 2598:     if ((ret >= 0) && (ctxt->nbErrors > 0))
 2599: 	ret = -1;
 2600:     return(ret);
 2601: }
 2602: 
 2603: #else /* !LIBXML_XINCLUDE_ENABLED */
 2604: #endif
 2605: #define bottom_xinclude
 2606: #include "elfgcchack.h"

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>