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