File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libxml2 / xinclude.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jun 15 19:53:31 2014 UTC (9 years, 11 months ago) by misho
Branches: libxml2, MAIN
CVS tags: v2_9_1p0, v2_9_1, HEAD
libxml2 2.9.1

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

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