xml/libxml2libs/src/libxml2/libxml2_xinclude.c
changeset 0 e35f40988205
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xml/libxml2libs/src/libxml2/libxml2_xinclude.c	Thu Dec 17 09:29:21 2009 +0200
@@ -0,0 +1,2399 @@
+/*
+ * libxml2_xinclude.c : Code to implement XInclude processing
+ *
+ * World Wide Web Consortium W3C Last Call WorkingDraft 10 November 2003
+ * http://www.w3.org/TR/2003/WD-xinclude-20031110
+ *
+ * See Copyright for the status of this software.
+ *
+ * daniel@veillard.com
+ * Portion Copyright © 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. 
+ */
+
+#define IN_LIBXML
+#include "xmlenglibxml.h"
+
+#ifdef LIBXML_XINCLUDE_ENABLED
+
+#include <stdapis/libxml2/libxml2_globals.h>
+#include <stdapis/libxml2/libxml2_tree.h>
+#include <stdapis/libxml2/libxml2_parser.h>
+#include <stdapis/libxml2/libxml2_uri.h>
+#include <stdapis/libxml2/libxml2_xpointer.h>
+#include <stdapis/libxml2/libxml2_parserinternals.h>
+#include <stdapis/libxml2/libxml2_xmlerror.h>
+#include "libxml2_xmlerror2.h"
+#include <stdapis/libxml2/libxml2_encoding.h>
+#include "libxml2_xinclude.h"
+#include <string.h>
+
+#define XINCLUDE_MAX_DEPTH 40
+// #define DEBUG_XINCLUDE
+#ifdef DEBUG_XINCLUDE
+#  ifdef LIBXML_DEBUG_ENABLED
+#    include "Libxml2_debugXML.h"
+#  endif
+#endif
+
+/************************************************************************
+ *                                                                      *
+ *                      XInclude context handling                       *
+ *                                                                      *
+ ************************************************************************/
+
+/*
+ * An XInclude context
+ */
+typedef xmlChar *xmlURL;
+
+typedef struct _xmlXIncludeRef xmlXIncludeRef;
+typedef xmlXIncludeRef *xmlXIncludeRefPtr;
+struct _xmlXIncludeRef {
+    xmlChar              *URI; /* the fully resolved resource URL */
+    xmlChar         *fragment; /* the fragment in the URI */
+    xmlDocPtr             doc; /* the parsed document */
+    xmlNodePtr            ref; /* the node making the reference in the source */
+    xmlNodePtr            inc; /* the included copy */
+    int                   xml; /* xml or txt */
+    int                 count; /* how many refs use that specific doc */
+    xmlXPathObjectPtr    xptr; /* the xpointer if needed */
+    int               emptyFb; /* flag to show fallback empty */
+};
+
+struct _xmlXIncludeCtxt {
+    xmlDocPtr             doc; /* the source document */
+    int               incBase; /* the first include for this document */
+    int                 incNr; /* number of includes */
+    int                incMax; /* size of includes tab */
+    xmlXIncludeRefPtr *incTab; /* array of included references */
+
+    int                 txtNr; /* number of unparsed documents */
+    int                txtMax; /* size of unparsed documents tab */
+    xmlNodePtr        *txtTab; /* array of unparsed text nodes */
+    xmlURL         *txturlTab; /* array of unparsed text URLs */
+
+    xmlChar *             url; /* the current URL processed */
+    int                 urlNr; /* number of URLs stacked */
+    int                urlMax; /* size of URL stack */
+    xmlChar *         *urlTab; /* URL stack */
+
+    int              nbErrors; /* the number of errors detected */
+    int                legacy; /* using XINCLUDE_OLD_NS */
+    int            parseFlags; /* the flags used for parsing XML documents */
+};
+
+static int
+xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr tree);
+
+
+/************************************************************************
+ *                                                                      *
+ *                      XInclude error handler                          *
+ *                                                                      *
+ ************************************************************************/
+
+/**
+ * xmlXIncludeErrMemory:
+ * @param extra extra information
+ *
+ * Handle an out of memory condition
+ */
+static void
+xmlXIncludeErrMemory(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node,
+                     const char *extra)
+{
+    if (ctxt != NULL)
+        ctxt->nbErrors++;
+    __xmlRaiseError(NULL, NULL, NULL, ctxt, node, XML_FROM_XINCLUDE,
+                    XML_ERR_NO_MEMORY, XML_ERR_ERROR, NULL, 0,
+                    extra, NULL, NULL, 0, 0,
+                    "Memory allocation failed : %s\n", extra);
+}
+
+/**
+ * xmlXIncludeErr:
+ * @param ctxt the XInclude context
+ * @param node the context node
+ * @param msg the error message
+ * @param extra extra information
+ *
+ * Handle an XInclude error
+ */
+static void
+xmlXIncludeErr(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node, int error,
+               const char *msg, const xmlChar *extra)
+{
+    if (ctxt != NULL)
+        ctxt->nbErrors++;
+    __xmlRaiseError(NULL, NULL, NULL, ctxt, node, XML_FROM_XINCLUDE,
+                    error, XML_ERR_ERROR, NULL, 0,
+                    (const char *) extra, NULL, NULL, 0, 0,
+                    msg, (const char *) extra);
+}
+
+#if 0
+/**
+ * xmlXIncludeWarn:
+ * @param ctxt the XInclude context
+ * @param node the context node
+ * @param msg the error message
+ * @param extra extra information
+ *
+ * Emit an XInclude warning.
+ */
+static void
+xmlXIncludeWarn(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node, int error,
+               const char *msg, const xmlChar *extra)
+{
+    __xmlRaiseError(NULL, NULL, NULL, ctxt, node, XML_FROM_XINCLUDE,
+                    error, XML_ERR_WARNING, NULL, 0,
+                    (const char *) extra, NULL, NULL, 0, 0,
+                    msg, (const char *) extra);
+}
+#endif
+
+/**
+ * xmlXIncludeGetProp:
+ * @param ctxt the XInclude context
+ * @param cur the node
+ * @param name the attribute name
+ *
+ * Get an XInclude attribute
+ *
+ * Returns the value (to be freed) or NULL if not found
+ */
+static xmlChar *
+xmlXIncludeGetProp(xmlXIncludeCtxtPtr ctxt, xmlNodePtr cur,
+                   const xmlChar *name) {
+    xmlChar *ret;
+
+    ret = xmlGetNsProp(cur, XINCLUDE_NS, name);
+    if (ret != NULL)
+        return(ret);
+    if (ctxt->legacy != 0) {
+        ret = xmlGetNsProp(cur, XINCLUDE_OLD_NS, name);
+        if (ret != NULL)
+            return(ret);
+    }
+    ret = xmlGetProp(cur, name);
+    return(ret);
+}
+/**
+ * xmlXIncludeFreeRef:
+ * @param ref the XInclude reference
+ *
+ * Free an XInclude reference
+ */
+static void
+xmlXIncludeFreeRef(xmlXIncludeRefPtr ref) {
+    if (ref == NULL)
+        return;
+#ifdef DEBUG_XINCLUDE
+    xmlGenericError(xmlGenericErrorContext, "Freeing ref\n");
+#endif
+    if (ref->doc != NULL) {
+#ifdef DEBUG_XINCLUDE
+        xmlGenericError(xmlGenericErrorContext, "Freeing doc %s\n", ref->URI);
+#endif
+        xmlFreeDoc(ref->doc);
+    }
+    if (ref->URI != NULL)
+        xmlFree(ref->URI);
+    if (ref->fragment != NULL)
+        xmlFree(ref->fragment);
+    if (ref->xptr != NULL)
+        xmlXPathFreeObject(ref->xptr);
+    xmlFree(ref);
+}
+
+/**
+ * xmlXIncludeNewRef:
+ * @param ctxt the XInclude context
+ * @param URI the resource URI
+ *
+ * Creates a new reference within an XInclude context
+ *
+ * Returns the new set
+ */
+static xmlXIncludeRefPtr
+xmlXIncludeNewRef(xmlXIncludeCtxtPtr ctxt, const xmlChar* URI, xmlNodePtr ref)
+{
+    xmlXIncludeRefPtr ret;
+
+#ifdef DEBUG_XINCLUDE
+    xmlGenericError(xmlGenericErrorContext, "New ref %s\n", URI);
+#endif
+    ret = (xmlXIncludeRefPtr) xmlMalloc(sizeof(xmlXIncludeRef));
+    if (!ret)
+        goto OOM_exit;
+
+    memset(ret, 0, sizeof(xmlXIncludeRef));
+
+    ret->URI = URI ? xmlStrdup(URI) : (xmlChar*) /* NULL */ URI;
+    // DONE: remove unnecessary initialization to NULL
+    //ret->fragment = NULL;
+    ret->ref = ref;
+    //ret->doc = 0;
+    //ret->count = 0;
+    //ret->xml = 0;
+    //ret->inc = NULL;
+    if (ctxt->incMax == 0) {
+        xmlXIncludeRefPtr* tmp;
+        
+        tmp = (xmlXIncludeRefPtr*) xmlMalloc(4 * sizeof(ctxt->incTab[0]));
+        if (!tmp)
+            goto OOM;
+        ctxt->incTab = tmp;
+        ctxt->incMax = 4;
+    }
+    if (ctxt->incNr >= ctxt->incMax) {
+        xmlXIncludeRefPtr* tmp;
+        ctxt->incMax *= 2;
+        tmp = (xmlXIncludeRefPtr*) xmlRealloc(ctxt->incTab, // DONE: Fix xmlRealloc
+                        ctxt->incMax * sizeof(ctxt->incTab[0]));
+        if (!tmp) {
+            ctxt->incMax /= 2;
+OOM:
+            xmlXIncludeFreeRef(ret);
+OOM_exit:
+            xmlXIncludeErrMemory(ctxt, ref, "growing XInclude context");
+            return(NULL);
+        }
+        ctxt->incTab = tmp;
+    }
+    ctxt->incTab[ctxt->incNr++] = ret;
+    return(ret);
+}
+
+/**
+ * xmlXIncludeNewContext:
+ * @param doc an XML Document
+ *
+ * Creates a new XInclude context
+ *
+ * Returns the new set
+ */
+XMLPUBFUNEXPORT xmlXIncludeCtxtPtr
+xmlXIncludeNewContext(xmlDocPtr doc) {
+    xmlXIncludeCtxtPtr ret;
+
+#ifdef DEBUG_XINCLUDE
+    xmlGenericError(xmlGenericErrorContext, "New context\n");
+#endif
+    if (doc == NULL)
+        return(NULL);
+    ret = (xmlXIncludeCtxtPtr) xmlMalloc(sizeof(xmlXIncludeCtxt));
+    if (ret == NULL) {
+        xmlXIncludeErrMemory(NULL, (xmlNodePtr) doc,
+                             "creating XInclude context");
+        return(NULL);
+    }
+    memset(ret, 0, sizeof(xmlXIncludeCtxt));
+    ret->doc = doc;
+    ret->incNr = 0;
+    ret->incBase = 0;
+    ret->incMax = 0;
+    ret->incTab = NULL;
+    ret->nbErrors = 0;
+    return(ret);
+}
+
+/**
+ * xmlXIncludeURLPush:
+ * @param ctxt the parser context
+ * @param value the url
+ *
+ * Pushes a new url on top of the url stack
+ *
+ * Returns -1 in case of error, the index in the stack otherwise
+ */
+static int
+xmlXIncludeURLPush(xmlXIncludeCtxtPtr ctxt, const xmlChar* value)
+{
+    xmlChar* vcopy;
+    if (ctxt->urlNr > XINCLUDE_MAX_DEPTH) {
+        xmlXIncludeErr(ctxt, NULL, XML_XINCLUDE_RECURSION,
+                       "detected a recursion in %s\n", value);
+        return(-1);
+    }
+    if (ctxt->urlTab == NULL) {
+        ctxt->urlMax = 0;
+        ctxt->urlNr = 0;
+        
+        ctxt->urlTab = (xmlChar**) xmlMalloc(4 * sizeof(ctxt->urlTab[0]));
+        if (!ctxt->urlTab)
+            goto OOM_exit;
+        ctxt->urlMax = 4;
+    }
+    if (ctxt->urlNr >= ctxt->urlMax) {
+        xmlChar** tmp;
+        ctxt->urlMax *= 2;
+        tmp =  (xmlChar**) xmlRealloc(ctxt->urlTab, // DONE: Fix xmlRealloc
+                                      ctxt->urlMax *
+                                      sizeof(ctxt->urlTab[0]));
+        if (!tmp) {
+            ctxt->urlMax /= 2;
+OOM_exit:
+            xmlXIncludeErrMemory(ctxt, NULL, "adding URL");
+            return (-1);
+        }
+        ctxt->urlTab = tmp;
+    }
+    vcopy = value ? xmlStrdup(value) : (xmlChar*) value /* NULL */;
+    if(vcopy || !value)
+        {
+        ctxt->url = ctxt->urlTab[ctxt->urlNr] = vcopy;
+        return (ctxt->urlNr++);
+        }
+    else // OOM!
+        goto OOM_exit;
+}
+
+/**
+ * xmlXIncludeURLPop:
+ * @param ctxt the parser context
+ *
+ * Pops the top URL from the URL stack
+ */
+static void
+xmlXIncludeURLPop(xmlXIncludeCtxtPtr ctxt)
+{
+    xmlChar * ret;
+
+    if (ctxt->urlNr <= 0)
+        return;
+    ctxt->urlNr--;
+    if (ctxt->urlNr > 0)
+        ctxt->url = ctxt->urlTab[ctxt->urlNr - 1];
+    else
+        ctxt->url = NULL;
+    ret = ctxt->urlTab[ctxt->urlNr];
+    ctxt->urlTab[ctxt->urlNr] = 0;
+    if (ret != NULL)
+        xmlFree(ret);
+}
+
+/**
+ * xmlXIncludeFreeContext:
+ * @param ctxt the XInclude context
+ *
+ * Free an XInclude context
+ */
+XMLPUBFUNEXPORT void
+xmlXIncludeFreeContext(xmlXIncludeCtxtPtr ctxt) {
+    int i;
+
+#ifdef DEBUG_XINCLUDE
+    xmlGenericError(xmlGenericErrorContext, "Freeing context\n");
+#endif
+    if (ctxt == NULL)
+        return;
+    while (ctxt->urlNr > 0)
+        xmlXIncludeURLPop(ctxt);
+    if (ctxt->urlTab != NULL)
+        xmlFree(ctxt->urlTab);
+    for (i = 0;i < ctxt->incNr;i++) {
+        if (ctxt->incTab[i] != NULL)
+            xmlXIncludeFreeRef(ctxt->incTab[i]);
+    }
+    for (i = 0;i < ctxt->txtNr;i++) {
+        if (ctxt->txturlTab[i] != NULL)
+            xmlFree(ctxt->txturlTab[i]);
+    }
+    if (ctxt->incTab != NULL)
+        xmlFree(ctxt->incTab);
+    if (ctxt->txtTab != NULL)
+        xmlFree(ctxt->txtTab);
+    if (ctxt->txturlTab != NULL)
+        xmlFree(ctxt->txturlTab);
+    xmlFree(ctxt);
+}
+
+/**
+ * xmlXIncludeParseFile:
+ * @param ctxt the XInclude context
+ * @param URL the URL or file path
+ *
+ * parse a document for XInclude
+ */
+static xmlDocPtr
+xmlXIncludeParseFile(xmlXIncludeCtxtPtr ctxt, const char *URL) {
+    xmlDocPtr         ret;
+    xmlParserCtxtPtr  pctxt;
+    // 'directory' was removed during optimization
+    xmlParserInputPtr inputStream;
+
+    xmlInitParser();
+
+    pctxt = xmlNewParserCtxt();
+    if (!pctxt) {
+        xmlXIncludeErrMemory(ctxt, NULL, "cannot allocate parser context");
+        return(NULL);
+    }
+    /*
+     * try to ensure that new documents included are actually
+     * built with the same dictionary as the including document.
+     */
+    if (ctxt->doc       &&
+        ctxt->doc->dict &&
+        pctxt->dict)
+    {
+        xmlDictFree(pctxt->dict);
+        pctxt->dict = ctxt->doc->dict;
+        xmlDictReference(pctxt->dict);
+    }
+
+    xmlCtxtUseOptions(pctxt, ctxt->parseFlags | XML_PARSE_DTDLOAD);
+
+    inputStream = xmlLoadExternalEntity(URL, NULL, pctxt);
+    if (!inputStream) {
+        xmlFreeParserCtxt(pctxt);
+        return(NULL);
+    }
+
+    inputPush(pctxt, inputStream);
+
+    if (!pctxt->directory)
+        pctxt->directory = xmlParserGetDirectory(URL);
+
+    pctxt->loadsubset = XML_DETECT_IDS;
+
+    xmlParseDocument(pctxt);
+
+    if (pctxt->wellFormed) {
+        ret = pctxt->myDoc;
+    } else {
+        ret = NULL;
+        if (pctxt->myDoc){
+            xmlFreeDoc(pctxt->myDoc);
+            pctxt->myDoc = NULL;
+        }
+    }
+    xmlFreeParserCtxt(pctxt);
+
+    return(ret);
+}
+
+/**
+ * xmlXIncludeAddNode:
+ * @param ctxt the XInclude context
+ * @param cur the new node
+ *
+ * Add a new node to process to an XInclude context
+ */
+static int
+xmlXIncludeAddNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr cur) {
+    xmlXIncludeRefPtr ref;
+    xmlURIPtr uri;
+    xmlChar *URL;
+    xmlChar *fragment = NULL;
+    xmlChar *href;
+    xmlChar *parse;
+    xmlChar *base;
+    xmlChar *URI;
+    int xml = 1, i; /* default Issue 64 */
+    int local = 0;
+
+
+    if (ctxt == NULL)
+        return(-1);
+    if (cur == NULL)
+        return(-1);
+
+#ifdef DEBUG_XINCLUDE
+    xmlGenericError(xmlGenericErrorContext, "Add node\n");
+#endif
+    /*
+     * read the attributes
+     */
+    href = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_HREF);
+    if (href == NULL) {
+        href = xmlStrdup(BAD_CAST ""); /* @@@@ href is now optional */
+        if (href == NULL)
+            return(-1);
+        local = 1;
+    }
+    if (href[0] == '#')
+        local = 1;
+    parse = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_PARSE);
+    if (parse != NULL) {
+        if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
+            xml = 1;
+        else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
+            xml = 0;
+        else {
+            xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_PARSE_VALUE,
+                           "invalid value %s for 'parse'\n", parse);
+            if (href != NULL)
+                xmlFree(href);
+            if (parse != NULL)
+                xmlFree(parse);
+            return(-1);
+        }
+    }
+
+    /*
+     * compute the URI
+     */
+    base = xmlNodeGetBase(ctxt->doc, cur);
+    if (base == NULL) {
+        URI = xmlBuildURI(href, ctxt->doc->URL);
+    } else {
+        URI = xmlBuildURI(href, base);
+    }
+    if (URI == NULL) {
+        xmlChar *escbase;
+        xmlChar *eschref;
+        /*
+         * Some escaping may be needed
+         */
+        escbase = xmlURIEscape(base);
+        eschref = xmlURIEscape(href);
+        URI = xmlBuildURI(eschref, escbase);
+        if (escbase != NULL)
+            xmlFree(escbase);
+        if (eschref != NULL)
+            xmlFree(eschref);
+    }
+    if (parse != NULL)
+        xmlFree(parse);
+    if (href != NULL)
+        xmlFree(href);
+    if (base != NULL)
+        xmlFree(base);
+    if (URI == NULL) {
+        xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_HREF_URI,
+                       "failed build URL\n", NULL);
+        return(-1);
+    }
+    fragment = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_PARSE_XPOINTER);
+
+    /*
+     * Check the URL and remove any fragment identifier
+     */
+    uri = xmlParseURI((const char *)URI);
+    if (uri == NULL) {
+        xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_HREF_URI,
+                       "invalid value URI %s\n", URI);
+        if (fragment != NULL)
+            xmlFree(fragment);
+        xmlFree(URI);
+        return(-1);
+    }
+
+    if (uri->fragment != NULL) {
+        if (ctxt->legacy != 0) {
+            if (fragment == NULL) {
+                fragment = (xmlChar *) uri->fragment;
+            } else {
+                xmlFree(uri->fragment);
+            }
+        } else {
+            xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_FRAGMENT_ID,
+       "Invalid fragment identifier in URI %s use the xpointer attribute\n",
+                           URI);
+            if (fragment != NULL)
+                xmlFree(fragment);
+            xmlFreeURI(uri);
+            xmlFree(URI);
+            return(-1);
+        }
+        uri->fragment = NULL;
+    }
+    URL = xmlSaveUri(uri);
+    xmlFreeURI(uri);
+    xmlFree(URI);
+    if (URL == NULL) {
+        xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_HREF_URI,
+                       "invalid value URI %s\n", URI);
+        if (fragment != NULL)
+            xmlFree(fragment);
+        return(-1);
+    }
+
+    /*
+     * Check the URL against the stack for recursions
+     */
+    if (!local) {
+        for (i = 0;i < ctxt->urlNr;i++) {
+            if (xmlStrEqual(URL, ctxt->urlTab[i])) {
+                xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_RECURSION,
+                               "detected a recursion in %s\n", URL);
+                return(-1);
+            }
+        }
+    }
+
+    ref = xmlXIncludeNewRef(ctxt, URL, cur);
+    if (ref == NULL) {
+        return(-1);
+    }
+    ref->fragment = fragment;
+    ref->doc = NULL;
+    ref->xml = xml;
+    ref->count = 1;
+    xmlFree(URL);
+    return(0);
+}
+
+/**
+ * xmlXIncludeRecurseDoc:
+ * @param ctxt the XInclude context
+ * @param doc the new document
+ * @param url the associated URL
+ *
+ * The XInclude recursive nature is handled at this point.
+ */
+static void
+xmlXIncludeRecurseDoc(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc,
+                      const xmlURL url ATTRIBUTE_UNUSED) {
+    xmlXIncludeCtxtPtr newctxt;
+    int i;
+
+    /*
+     * Avoid recursion in already substitued resources
+    for (i = 0;i < ctxt->urlNr;i++) {
+        if (xmlStrEqual(doc->URL, ctxt->urlTab[i]))
+            return;
+    }
+     */
+
+#ifdef DEBUG_XINCLUDE
+    xmlGenericError(xmlGenericErrorContext, "Recursing in doc %s\n", doc->URL);
+#endif
+    /*
+     * Handle recursion here.
+     */
+
+    newctxt = xmlXIncludeNewContext(doc);
+    if (newctxt != NULL) {
+        /*
+         * Copy the existing document set
+         */
+        newctxt->incMax = ctxt->incMax;
+        newctxt->incNr = ctxt->incNr;
+        newctxt->incTab = (xmlXIncludeRefPtr *) xmlMalloc(newctxt->incMax *
+                                          sizeof(newctxt->incTab[0]));
+        if (newctxt->incTab == NULL) {
+            xmlXIncludeErrMemory(ctxt, (xmlNodePtr) doc, "processing doc");
+            xmlFree(newctxt);
+            return;
+        }
+        /*
+         * copy the urlTab
+         */
+        newctxt->urlMax = ctxt->urlMax;
+        newctxt->urlNr = ctxt->urlNr;
+        newctxt->urlTab = ctxt->urlTab;
+
+        /*
+         * Inherit the documents already in use by other includes
+         */
+        newctxt->incBase = ctxt->incNr;
+        for (i = 0;i < ctxt->incNr;i++) {
+            newctxt->incTab[i] = ctxt->incTab[i];
+            newctxt->incTab[i]->count++; /* prevent the recursion from
+                                            freeing it */
+        }
+        /*
+         * The new context should also inherit the Parse Flags
+         * 
+         */
+        newctxt->parseFlags = ctxt->parseFlags;
+        xmlXIncludeDoProcess(newctxt, doc, xmlDocGetRootElement(doc));
+        for (i = 0;i < ctxt->incNr;i++) {
+            newctxt->incTab[i]->count--;
+            newctxt->incTab[i] = NULL;
+        }
+
+        /* urlTab may have been reallocated */
+        ctxt->urlTab = newctxt->urlTab;
+        ctxt->urlMax = newctxt->urlMax;
+
+        newctxt->urlMax = 0;
+        newctxt->urlNr = 0;
+        newctxt->urlTab = NULL;
+
+        xmlXIncludeFreeContext(newctxt);
+    }
+#ifdef DEBUG_XINCLUDE
+    xmlGenericError(xmlGenericErrorContext, "Done recursing in doc %s\n", url);
+#endif
+}
+
+/**
+ * xmlXIncludeAddTxt:
+ * @param ctxt the XInclude context
+ * @param txt the new text node
+ * @param url the associated URL
+ *
+ * Add a new txtument to the list
+ */
+static void
+xmlXIncludeAddTxt(xmlXIncludeCtxtPtr ctxt, xmlNodePtr txt, const xmlURL url)
+{
+#ifdef DEBUG_XINCLUDE
+    xmlGenericError(xmlGenericErrorContext, "Adding text %s\n", url);
+#endif
+    if (ctxt->txtMax == 0) {
+        
+        ctxt->txtMax = 0;
+        ctxt->txtTab = (xmlNodePtr*) xmlMalloc(4 * sizeof(ctxt->txtTab[0]));
+        if (ctxt->txtTab)
+            goto OOM_exit;
+        ctxt->txturlTab = (xmlURL *) xmlMalloc(4 * sizeof(ctxt->txturlTab[0]));
+        if (!ctxt->txturlTab) {
+            if(ctxt->txtTab)
+                xmlFree(ctxt->txtTab);
+OOM_exit:
+            xmlXIncludeErrMemory(ctxt, NULL, "processing text");
+            return;
+        }
+        ctxt->txtMax = 4; // both arrays were allocated
+    }
+    if (ctxt->txtNr >= ctxt->txtMax) {
+        xmlNodePtr* tmpNodes;
+        xmlURL* tmpURL;
+        ctxt->txtMax *= 2; 
+        tmpNodes = (xmlNodePtr*) xmlRealloc(ctxt->txtTab, // DONE: Fix xmlRealloc
+                 ctxt->txtMax * sizeof(ctxt->txtTab[0]));
+        if (!tmpNodes)
+            goto OOM_exit;
+        ctxt->txtTab = tmpNodes;
+
+        tmpURL = (xmlURL*) xmlRealloc(ctxt->txturlTab, // DONE: Fix xmlRealloc
+                 ctxt->txtMax * sizeof(ctxt->txturlTab[0]));
+        if (!tmpURL)
+            goto OOM_exit;
+        ctxt->txturlTab = tmpURL;
+    }
+    ctxt->txtTab[ctxt->txtNr] = txt;
+    ctxt->txturlTab[ctxt->txtNr] = xmlStrdup(url);
+    ctxt->txtNr++;
+}
+
+/************************************************************************
+ *                                                                      *
+ *          Node copy with specific semantic                            *
+ *                                                                      *
+ ************************************************************************/
+
+/**
+ * xmlXIncludeCopyNode:
+ * @param ctxt the XInclude context
+ * @param target the document target
+ * @param source the document source
+ * @param elem the element
+ *
+ * Make a copy of the node while preserving the XInclude semantic
+ * of the Infoset copy
+ */
+static xmlNodePtr
+xmlXIncludeCopyNode(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
+                    xmlDocPtr source, xmlNodePtr elem) {
+    xmlNodePtr result = NULL;
+
+    if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
+        (elem == NULL))
+        return(NULL);
+    if (elem->type == XML_DTD_NODE)
+        return(NULL);
+    result = xmlDocCopyNode(elem, target, 1);
+    return(result);
+}
+
+/**
+ * xmlXIncludeCopyNodeList:
+ * @param ctxt the XInclude context
+ * @param target the document target
+ * @param source the document source
+ * @param elem the element list
+ *
+ * Make a copy of the node list while preserving the XInclude semantic
+ * of the Infoset copy
+ */
+static xmlNodePtr
+xmlXIncludeCopyNodeList(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
+                        xmlDocPtr source, xmlNodePtr elem) {
+    xmlNodePtr cur, res, result = NULL, last = NULL;
+
+    if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
+        (elem == NULL))
+        return(NULL);
+    cur = elem;
+    while (cur != NULL) {
+        res = xmlXIncludeCopyNode(ctxt, target, source, cur);
+        if (res != NULL) {
+            if (result == NULL) {
+                result = last = res;
+            } else {
+                last->next = res;
+                res->prev = last;
+                last = res;
+            }
+        }
+        cur = cur->next;
+    }
+    return(result);
+}
+
+/**
+ * xmlXIncludeGetNthChild:
+ * @param cur the node
+ * @param no the child number
+ *
+ * Returns the n'th element child of cur or NULL
+ */
+static xmlNodePtr
+xmlXIncludeGetNthChild(xmlNodePtr cur, int no) {
+    int i;
+    if (cur == NULL)
+        return(cur);
+    cur = cur->children;
+    for (i = 0;i <= no;cur = cur->next) {
+        if (cur == NULL)
+            return(cur);
+        if ((cur->type == XML_ELEMENT_NODE) ||
+            (cur->type == XML_DOCUMENT_NODE) ||
+            (cur->type == XML_HTML_DOCUMENT_NODE)) {
+            i++;
+            if (i == no)
+                break;
+        }
+    }
+    return(cur);
+}
+
+xmlNodePtr xmlXPtrAdvanceNode(xmlNodePtr cur, int *level); /* in xpointer.c */
+/**
+ * xmlXIncludeCopyRange:
+ * @param ctxt the XInclude context
+ * @param target the document target
+ * @param source the document source
+ * @param obj the XPointer result from the evaluation.
+ *
+ * Build a node list tree copy of the XPointer result.
+ *
+ * Returns an xmlNodePtr list or NULL.
+ *         The caller has to free the node tree.
+ */
+static xmlNodePtr
+xmlXIncludeCopyRange(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
+                    xmlDocPtr source, xmlXPathObjectPtr range) {
+    /* pointers to generated nodes */
+    xmlNodePtr list = NULL, last = NULL, listParent = NULL;
+    xmlNodePtr tmp, tmp2;
+    /* pointers to traversal nodes */
+    xmlNodePtr start, cur, end;
+    int index1, index2;
+    int level = 0, lastLevel = 0, endLevel = 0, endFlag = 0;
+
+    if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
+        (range == NULL))
+        return(NULL);
+    if (range->type != XPATH_RANGE)
+        return(NULL);
+    start = (xmlNodePtr) range->user;
+
+    if (start == NULL)
+        return(NULL);
+    end = range->user2;
+    if (end == NULL)
+        return(xmlDocCopyNode(start, target, 1));
+
+    cur = start;
+    index1 = range->index;
+    index2 = range->index2;
+    /*
+     * level is depth of the current node under consideration
+     * list is the pointer to the root of the output tree
+     * listParent is a pointer to the parent of output tree (within
+       the included file) in case we need to add another level
+     * last is a pointer to the last node added to the output tree
+     * lastLevel is the depth of last (relative to the root)
+     */
+    while (cur != NULL) {
+        /*
+         * Check if our output tree needs a parent
+         */
+        if (level < 0) {
+            while (level < 0) {
+                /* copy must include namespaces and properties */
+                tmp2 = xmlDocCopyNode(listParent, target, 2);
+                xmlAddChild(tmp2, list);
+                list = tmp2;
+                listParent = listParent->parent;
+                level++;
+            }
+            last = list;
+            lastLevel = 0;
+        }
+        /*
+         * Check whether we need to change our insertion point
+         */
+        while (level < lastLevel) {
+            last = last->parent;
+            lastLevel --;
+        }
+        if (cur == end) {       /* Are we at the end of the range? */
+            if (cur->type == XML_TEXT_NODE) {
+                const xmlChar *content = cur->content;
+                int len;
+
+                if (content == NULL) {
+                    tmp = xmlNewTextLen(NULL, 0);
+                } else {
+                    len = index2;
+                    if ((cur == start) && (index1 > 1)) {
+                        content += (index1 - 1);
+                        len -= (index1 - 1);
+                        index1 = 0;
+                    } else {
+                        len = index2;
+                    }
+                    tmp = xmlNewTextLen(content, len);
+                }
+                /* single sub text node selection */
+                if (list == NULL)
+                    return(tmp);
+                /* prune and return full set */
+                if (level == lastLevel)
+                    xmlAddNextSibling(last, tmp);
+                else
+                    xmlAddChild(last, tmp);
+                return(list);
+            } else {    /* ending node not a text node */
+                endLevel = level;       /* remember the level of the end node */
+                endFlag = 1;
+                /* last node - need to take care of properties + namespaces */
+                tmp = xmlDocCopyNode(cur, target, 2);
+                if (list == NULL) {
+                    list = tmp;
+                    listParent = cur->parent;
+                } else {
+                    if (level == lastLevel)
+                        xmlAddNextSibling(last, tmp);
+                    else {
+                        xmlAddChild(last, tmp);
+                        lastLevel = level;
+                    }
+                }
+                last = tmp;
+
+                if (index2 > 1) {
+                    end = xmlXIncludeGetNthChild(cur, index2 - 1);
+                    index2 = 0;
+                }
+                if ((cur == start) && (index1 > 1)) {
+                    cur = xmlXIncludeGetNthChild(cur, index1 - 1);
+                    index1 = 0;
+                }  else {
+                    cur = cur->children;
+                }
+                level++;        /* increment level to show change */
+                /*
+                 * Now gather the remaining nodes from cur to end
+                 */
+                continue;       /* while */
+            }
+        } else if (cur == start) {      /* Not at the end, are we at start? */
+            if ((cur->type == XML_TEXT_NODE) ||
+                (cur->type == XML_CDATA_SECTION_NODE)) {
+                const xmlChar *content = cur->content;
+
+                if (content == NULL) {
+                    tmp = xmlNewTextLen(NULL, 0);
+                } else {
+                    if (index1 > 1) {
+                        content += (index1 - 1);
+                        index1 = 0;
+                    }
+                    tmp = xmlNewText(content);
+                }
+                last = list = tmp;
+                listParent = cur->parent;
+            } else {            /* Not text node */
+                /*
+                 * start of the range - need to take care of
+                 * properties and namespaces
+                 */
+                tmp = xmlDocCopyNode(cur, target, 2);
+                list = last = tmp;
+                listParent = cur->parent;
+                if (index1 > 1) {       /* Do we need to position? */
+                    cur = xmlXIncludeGetNthChild(cur, index1 - 1);
+                    level = lastLevel = 1;
+                    index1 = 0;
+                    /*
+                     * Now gather the remaining nodes from cur to end
+                     */
+                    continue; /* while */
+                }
+            }
+        } else {
+            tmp = NULL;
+            switch (cur->type) {
+                case XML_DTD_NODE:
+                case XML_ELEMENT_DECL:
+                case XML_ATTRIBUTE_DECL:
+                case XML_ENTITY_NODE:
+                    /* Do not copy DTD informations */
+                    break;
+                case XML_ENTITY_DECL:
+                    /* handle crossing entities -> stack needed */
+                    break;
+                case XML_XINCLUDE_START:
+                case XML_XINCLUDE_END:
+                    /* don't consider it part of the tree content */
+                    break;
+                case XML_ATTRIBUTE_NODE:
+                    /* Humm, should not happen ! */
+                    break;
+                default:
+                    /*
+                     * Middle of the range - need to take care of
+                     * properties and namespaces
+                     */
+                    tmp = xmlDocCopyNode(cur, target, 2);
+                    break;
+            }
+            if (tmp != NULL) {
+                if (level == lastLevel)
+                    xmlAddNextSibling(last, tmp);
+                else {
+                    xmlAddChild(last, tmp);
+                    lastLevel = level;
+                }
+                last = tmp;
+            }
+        }
+        /*
+         * Skip to next node in document order
+         */
+        cur = xmlXPtrAdvanceNode(cur, &level);
+        if (endFlag && (level >= endLevel))
+            break;
+    }
+    return(list);
+}
+
+/**
+ * xmlXIncludeBuildNodeList:
+ * @param ctxt the XInclude context
+ * @param target the document target
+ * @param source the document source
+ * @param obj the XPointer result from the evaluation.
+ *
+ * Build a node list tree copy of the XPointer result.
+ * This will drop Attributes and Namespace declarations.
+ *
+ * Returns an xmlNodePtr list or NULL.
+ *         the caller has to free the node tree.
+ */
+static xmlNodePtr
+xmlXIncludeCopyXPointer(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
+                        xmlDocPtr source, xmlXPathObjectPtr obj) {
+    xmlNodePtr list = NULL, last = NULL;
+    int i;
+
+    if (source == NULL)
+        source = ctxt->doc;
+    if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
+        (obj == NULL))
+        return(NULL);
+    switch (obj->type) {
+        case XPATH_NODESET: {
+            xmlNodeSetPtr set = obj->nodesetval;
+            if (set == NULL)
+                return(NULL);
+            for (i = 0;i < set->nodeNr;i++) {
+                if (set->nodeTab[i] == NULL)
+                    continue;
+                switch (set->nodeTab[i]->type) {
+                    case XML_TEXT_NODE:
+                    case XML_CDATA_SECTION_NODE:
+                    case XML_ELEMENT_NODE:
+                    case XML_ENTITY_REF_NODE:
+                    case XML_ENTITY_NODE:
+                    case XML_PI_NODE:
+                    case XML_COMMENT_NODE:
+                    case XML_DOCUMENT_NODE:
+                    case XML_HTML_DOCUMENT_NODE:
+#ifdef LIBXML_DOCB_ENABLED
+                    case XML_DOCB_DOCUMENT_NODE:
+#endif
+                    case XML_XINCLUDE_END:
+                        break;
+                    case XML_XINCLUDE_START: {
+                        xmlNodePtr tmp, cur = set->nodeTab[i];
+
+                        cur = cur->next;
+                        while (cur != NULL) {
+                            switch(cur->type) {
+                                case XML_TEXT_NODE:
+                                case XML_CDATA_SECTION_NODE:
+                                case XML_ELEMENT_NODE:
+                                case XML_ENTITY_REF_NODE:
+                                case XML_ENTITY_NODE:
+                                case XML_PI_NODE:
+                                case XML_COMMENT_NODE:
+                                    tmp = xmlXIncludeCopyNode(ctxt, target,
+                                                              source, cur);
+                                    if (last == NULL) {
+                                        list = last = tmp;
+                                    } else {
+                                        xmlAddNextSibling(last, tmp);
+                                        last = tmp;
+                                    }
+                                    cur = cur->next;
+                                    continue;
+                                default:
+                                    break;
+                            }
+                            break;
+                        }
+                        continue;
+                    }
+                    case XML_ATTRIBUTE_NODE:
+                    case XML_NAMESPACE_DECL:
+                    case XML_DOCUMENT_TYPE_NODE:
+                    case XML_DOCUMENT_FRAG_NODE:
+                    case XML_NOTATION_NODE:
+                    case XML_DTD_NODE:
+                    case XML_ELEMENT_DECL:
+                    case XML_ATTRIBUTE_DECL:
+                    case XML_ENTITY_DECL:
+                        continue; /* for */
+                }
+                if (last == NULL)
+                    list = last = xmlXIncludeCopyNode(ctxt, target, source,
+                                                      set->nodeTab[i]);
+                else {
+                    xmlAddNextSibling(last,
+                            xmlXIncludeCopyNode(ctxt, target, source,
+                                                set->nodeTab[i]));
+                    if (last->next != NULL)
+                        last = last->next;
+                }
+            }
+            break;
+        }
+        case XPATH_LOCATIONSET: {
+            xmlLocationSetPtr set = (xmlLocationSetPtr) obj->user;
+            if (set == NULL)
+                return(NULL);
+            for (i = 0;i < set->locNr;i++) {
+                if (last == NULL)
+                    list = last = xmlXIncludeCopyXPointer(ctxt, target, source,
+                                                          set->locTab[i]);
+                else
+                    xmlAddNextSibling(last,
+                            xmlXIncludeCopyXPointer(ctxt, target, source,
+                                                    set->locTab[i]));
+                if (last != NULL) {
+                    while (last->next != NULL)
+                        last = last->next;
+                }
+            }
+            break;
+        }
+#ifdef LIBXML_XPTR_ENABLED
+        case XPATH_RANGE:
+            return(xmlXIncludeCopyRange(ctxt, target, source, obj));
+#endif
+        case XPATH_POINT:
+            /* points are ignored in XInclude */
+            break;
+        default:
+            break;
+    }
+    return(list);
+}
+/************************************************************************
+ *                                                                      *
+ *                      XInclude I/O handling                           *
+ *                                                                      *
+ ************************************************************************/
+
+typedef struct _xmlXIncludeMergeData xmlXIncludeMergeData;
+typedef xmlXIncludeMergeData *xmlXIncludeMergeDataPtr;
+struct _xmlXIncludeMergeData {
+    xmlDocPtr doc;
+    xmlXIncludeCtxtPtr ctxt;
+};
+
+/**
+ * xmlXIncludeMergeOneEntity:
+ * @param ent the entity
+ * @param doc the including doc
+ * @param nr the entity name
+ *
+ * Inplements the merge of one entity
+ */
+static void
+xmlXIncludeMergeEntity(xmlEntityPtr ent, xmlXIncludeMergeDataPtr data,
+                       xmlChar *name ATTRIBUTE_UNUSED) {
+    xmlEntityPtr ret, prev;
+    xmlDocPtr doc;
+    xmlXIncludeCtxtPtr ctxt;
+
+    if ((ent == NULL) || (data == NULL))
+        return;
+    ctxt = data->ctxt;
+    doc = data->doc;
+    if ((ctxt == NULL) || (doc == NULL))
+        return;
+    switch (ent->etype) {
+        case XML_INTERNAL_PARAMETER_ENTITY:
+        case XML_EXTERNAL_PARAMETER_ENTITY:
+        case XML_INTERNAL_PREDEFINED_ENTITY:
+            return;
+        case XML_INTERNAL_GENERAL_ENTITY:
+        case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
+        case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
+            break;
+    }
+    ret = xmlAddDocEntity(doc, ent->name, ent->etype, ent->ExternalID,
+                          ent->SystemID, ent->content);
+    if (ret != NULL) {
+        if (ent->URI != NULL)
+            ret->URI = xmlStrdup(ent->URI);
+    } else {
+        prev = xmlGetDocEntity(doc, ent->name);
+        if (prev != NULL) {
+            if (ent->etype != prev->etype)
+                goto error;
+
+            if ((ent->SystemID != NULL) && (prev->SystemID != NULL)) {
+                if (!xmlStrEqual(ent->SystemID, prev->SystemID))
+                    goto error;
+            } else if ((ent->ExternalID != NULL) &&
+                       (prev->ExternalID != NULL)) {
+                if (!xmlStrEqual(ent->ExternalID, prev->ExternalID))
+                    goto error;
+            } else if ((ent->content != NULL) && (prev->content != NULL)) {
+                if (!xmlStrEqual(ent->content, prev->content))
+                    goto error;
+            } else {
+                goto error;
+            }
+
+        }
+    }
+    return;
+error:
+    switch (ent->etype) {
+        case XML_INTERNAL_PARAMETER_ENTITY:
+        case XML_EXTERNAL_PARAMETER_ENTITY:
+        case XML_INTERNAL_PREDEFINED_ENTITY:
+        case XML_INTERNAL_GENERAL_ENTITY:
+        case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
+            return;
+        case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
+            break;
+    }
+    xmlXIncludeErr(ctxt, (xmlNodePtr) ent, XML_XINCLUDE_ENTITY_DEF_MISMATCH,
+                   "mismatch in redefinition of entity %s\n",
+                   ent->name);
+}
+
+/**
+ * xmlXIncludeMergeEntities:
+ * @param ctxt an XInclude context
+ * @param doc the including doc
+ * @param from the included doc
+ *
+ * Inplements the entity merge
+ *
+ * Returns 0 if merge succeeded, -1 if some processing failed
+ */
+static int
+xmlXIncludeMergeEntities(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc,
+                         xmlDocPtr from) {
+    xmlNodePtr cur;
+    xmlDtdPtr target, source;
+
+    if (ctxt == NULL)
+        return(-1);
+
+    if ((from == NULL) || (from->intSubset == NULL))
+        return(0);
+
+    target = doc->intSubset;
+    if (target == NULL) {
+        cur = xmlDocGetRootElement(doc);
+        if (cur == NULL)
+            return(-1);
+        target = xmlCreateIntSubset(doc, cur->name, NULL, NULL);
+        if (target == NULL)
+            return(-1);
+    }
+
+    source = from->intSubset;
+    if ((source != NULL) && (source->entities != NULL)) {
+        xmlXIncludeMergeData data;
+
+        data.ctxt = ctxt;
+        data.doc = doc;
+
+        xmlHashScan((xmlHashTablePtr) source->entities,
+                    (xmlHashScanner) xmlXIncludeMergeEntity, &data);
+    }
+    source = from->extSubset;
+    if ((source != NULL) && (source->entities != NULL)) {
+        xmlXIncludeMergeData data;
+
+        data.ctxt = ctxt;
+        data.doc = doc;
+
+        /*
+         * don't duplicate existing stuff when external subsets are the same
+         */
+        if ((!xmlStrEqual(target->ExternalID, source->ExternalID)) &&
+            (!xmlStrEqual(target->SystemID, source->SystemID))) {
+            xmlHashScan((xmlHashTablePtr) source->entities,
+                        (xmlHashScanner) xmlXIncludeMergeEntity, &data);
+        }
+    }
+    return(0);
+}
+
+/**
+ * xmlXIncludeLoadDoc:
+ * @param ctxt the XInclude context
+ * @param url the associated URL
+ * @param nr the xinclude node number
+ *
+ * Load the document, and store the result in the XInclude context
+ *
+ * Returns 0 in case of success, -1 in case of failure
+ */
+static int
+xmlXIncludeLoadDoc(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
+    xmlDocPtr doc;
+    xmlURIPtr uri;
+    xmlChar *URL;
+    xmlChar *fragment = NULL;
+    int i = 0;
+#ifdef LIBXML_XPTR_ENABLED
+    int saveFlags;
+#endif
+
+#ifdef DEBUG_XINCLUDE
+    xmlGenericError(xmlGenericErrorContext, "Loading doc %s:%d\n", url, nr);
+#endif
+    /*
+     * Check the URL and remove any fragment identifier
+     */
+    uri = xmlParseURI((const char *)url);
+    if (uri == NULL) {
+        xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
+                       XML_XINCLUDE_HREF_URI,
+                       "invalid value URI %s\n", url);
+        return(-1);
+    }
+    if (uri->fragment != NULL) {
+        fragment = (xmlChar *) uri->fragment;
+        uri->fragment = NULL;
+    }
+    if ((ctxt->incTab != NULL) && (ctxt->incTab[nr] != NULL) &&
+        (ctxt->incTab[nr]->fragment != NULL)) {
+        if (fragment != NULL) xmlFree(fragment);
+        fragment = xmlStrdup(ctxt->incTab[nr]->fragment);
+    }
+    URL = xmlSaveUri(uri);
+    xmlFreeURI(uri);
+    if (URL == NULL) {
+        xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
+                       XML_XINCLUDE_HREF_URI,
+                       "invalid value URI %s\n", url);
+        if (fragment != NULL)
+            xmlFree(fragment);
+        return(-1);
+    }
+
+    /*
+     * Handling of references to the local document are done
+     * directly through ctxt->doc.
+     */
+    if ((URL[0] == 0) || (URL[0] == '#') ||
+        ((ctxt->doc != NULL) && (xmlStrEqual(URL, ctxt->doc->URL)))) {
+        doc = NULL;
+        goto loaded;
+    }
+
+    /*
+     * Prevent reloading twice the document.
+     */
+    for (i = 0; i < ctxt->incNr; i++) {
+        if ((xmlStrEqual(URL, ctxt->incTab[i]->URI)) &&
+            (ctxt->incTab[i]->doc != NULL)) {
+            doc = ctxt->incTab[i]->doc;
+#ifdef DEBUG_XINCLUDE
+            printf("Already loaded %s\n", URL);
+#endif
+            goto loaded;
+        }
+    }
+
+    /*
+     * Load it.
+     */
+#ifdef DEBUG_XINCLUDE
+    printf("loading %s\n", URL);
+#endif
+#ifdef LIBXML_XPTR_ENABLED
+    /*
+     * If this is an XPointer evaluation, we want to assure that
+     * all entities have been resolved prior to processing the
+     * referenced document
+     */
+    saveFlags = ctxt->parseFlags;
+    if (fragment != NULL) {     /* if this is an XPointer eval */
+        ctxt->parseFlags |= XML_PARSE_NOENT;
+    }
+#endif
+
+    doc = xmlXIncludeParseFile(ctxt, (const char *)URL);
+#ifdef LIBXML_XPTR_ENABLED
+    ctxt->parseFlags = saveFlags;
+#endif
+    if (doc == NULL) {
+        xmlFree(URL);
+        if (fragment != NULL)
+            xmlFree(fragment);
+        return(-1);
+    }
+    ctxt->incTab[nr]->doc = doc;
+    for (i = nr + 1; i < ctxt->incNr; i++) {
+        if (xmlStrEqual(URL, ctxt->incTab[i]->URI)) {
+            ctxt->incTab[nr]->count++;
+#ifdef DEBUG_XINCLUDE
+            printf("Increasing %s count since reused\n", URL);
+#endif
+            break;
+        }
+    }
+
+    /*
+     * Make sure we have all entities fixed up
+     */
+    xmlXIncludeMergeEntities(ctxt, ctxt->doc, doc);
+
+    /*
+     * We don't need the DTD anymore, free up space
+    if (doc->intSubset != NULL) {
+        xmlUnlinkNode((xmlNodePtr) doc->intSubset);
+        xmlFreeNode((xmlNodePtr) doc->intSubset);
+        doc->intSubset = NULL;
+    }
+    if (doc->extSubset != NULL) {
+        xmlUnlinkNode((xmlNodePtr) doc->extSubset);
+        xmlFreeNode((xmlNodePtr) doc->extSubset);
+        doc->extSubset = NULL;
+    }
+     */
+    xmlXIncludeRecurseDoc(ctxt, doc, URL);
+
+loaded:
+    if (fragment == NULL) {
+        /*
+         * Add the top children list as the replacement copy.
+         */
+        if (doc == NULL)
+        {
+            /* Hopefully a DTD declaration won't be copied from
+             * the same document */
+            ctxt->incTab[nr]->inc = xmlCopyNodeList(ctxt->doc->children);
+        } else {
+            ctxt->incTab[nr]->inc = xmlXIncludeCopyNodeList(ctxt, ctxt->doc,
+                                                       doc, doc->children);
+        }
+    }
+#ifdef LIBXML_XPTR_ENABLED
+    else {
+        /*
+         * Computes the XPointer expression and make a copy used
+         * as the replacement copy.
+         */
+        xmlXPathObjectPtr xptr;
+        xmlXPathContextPtr xptrctxt;
+        xmlNodeSetPtr set;
+
+        if (doc == NULL) {
+            xptrctxt = xmlXPtrNewContext(ctxt->doc, ctxt->incTab[nr]->ref,
+                                         NULL);
+        } else {
+            xptrctxt = xmlXPtrNewContext(doc, NULL, NULL);
+        }
+        if (xptrctxt == NULL) {
+            xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
+                           XML_XINCLUDE_XPTR_FAILED,
+                           "could not create XPointer context\n", NULL);
+            xmlFree(URL);
+            xmlFree(fragment);
+            return(-1);
+        }
+        xptr = xmlXPtrEval(fragment, xptrctxt);
+        if (xptr == NULL) {
+            xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
+                           XML_XINCLUDE_XPTR_FAILED,
+                           "XPointer evaluation failed: #%s\n",
+                           fragment);
+            xmlXPathFreeContext(xptrctxt);
+            xmlFree(URL);
+            xmlFree(fragment);
+            return(-1);
+        }
+        switch (xptr->type) {
+            case XPATH_UNDEFINED:
+            case XPATH_BOOLEAN:
+            case XPATH_NUMBER:
+            case XPATH_STRING:
+            case XPATH_POINT:
+            case XPATH_USERS:
+            case XPATH_XSLT_TREE:
+                xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
+                               XML_XINCLUDE_XPTR_RESULT,
+                               "XPointer is not a range: #%s\n",
+                               fragment);
+                xmlXPathFreeContext(xptrctxt);
+                xmlFree(URL);
+                xmlFree(fragment);
+                return(-1);
+            case XPATH_NODESET:
+                if ((xptr->nodesetval == NULL) ||
+                    (xptr->nodesetval->nodeNr <= 0)) {
+                    xmlXPathFreeContext(xptrctxt);
+                    xmlFree(URL);
+                    xmlFree(fragment);
+                    return(-1);
+                }
+            case XPATH_RANGE:
+            case XPATH_LOCATIONSET:
+                break;
+        }
+        set = xptr->nodesetval;
+        if (set != NULL) {
+            for (i = 0;i < set->nodeNr;i++) {
+                if (set->nodeTab[i] == NULL)
+                    continue;
+                switch (set->nodeTab[i]->type) {
+                    case XML_TEXT_NODE:
+                    case XML_CDATA_SECTION_NODE:
+                    case XML_ELEMENT_NODE:
+                    case XML_ENTITY_REF_NODE:
+                    case XML_ENTITY_NODE:
+                    case XML_PI_NODE:
+                    case XML_COMMENT_NODE:
+                    case XML_DOCUMENT_NODE:
+                    case XML_HTML_DOCUMENT_NODE:
+#ifdef LIBXML_DOCB_ENABLED
+                    case XML_DOCB_DOCUMENT_NODE:
+#endif
+                        continue;
+                    case XML_ATTRIBUTE_NODE:
+                        xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
+                                       XML_XINCLUDE_XPTR_RESULT,
+                                       "XPointer selects an attribute: #%s\n",
+                                       fragment);
+                        set->nodeTab[i] = NULL;
+                        continue;
+                    case XML_NAMESPACE_DECL:
+                        xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
+                                       XML_XINCLUDE_XPTR_RESULT,
+                                       "XPointer selects a namespace: #%s\n",
+                                       fragment);
+                        set->nodeTab[i] = NULL;
+                        continue;
+                    case XML_DOCUMENT_TYPE_NODE:
+                    case XML_DOCUMENT_FRAG_NODE:
+                    case XML_NOTATION_NODE:
+                    case XML_DTD_NODE:
+                    case XML_ELEMENT_DECL:
+                    case XML_ATTRIBUTE_DECL:
+                    case XML_ENTITY_DECL:
+                    case XML_XINCLUDE_START:
+                    case XML_XINCLUDE_END:
+                        xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
+                                       XML_XINCLUDE_XPTR_RESULT,
+                                   "XPointer selects unexpected nodes: #%s\n",
+                                       fragment);
+                        set->nodeTab[i] = NULL;
+                        set->nodeTab[i] = NULL;
+                        continue; /* for */
+                }
+            }
+        }
+        if (doc == NULL) {
+            ctxt->incTab[nr]->xptr = xptr;
+            ctxt->incTab[nr]->inc = NULL;
+        } else {
+            ctxt->incTab[nr]->inc =
+                xmlXIncludeCopyXPointer(ctxt, ctxt->doc, doc, xptr);
+            xmlXPathFreeObject(xptr);
+        }
+        xmlXPathFreeContext(xptrctxt);
+        xmlFree(fragment);
+    }
+#endif
+
+    /*
+     * Do the xml:base fixup if needed
+     */
+    if ((doc != NULL) && (URL != NULL) && (xmlStrchr(URL, (xmlChar) '/'))) {
+        xmlNodePtr node;
+
+        node = ctxt->incTab[nr]->inc;
+        while (node != NULL) {
+            if (node->type == XML_ELEMENT_NODE)
+                xmlNodeSetBase(node, URL);
+            node = node->next;
+        }
+    }
+    if ((nr < ctxt->incNr) && (ctxt->incTab[nr]->doc != NULL) &&
+        (ctxt->incTab[nr]->count <= 1)) {
+#ifdef DEBUG_XINCLUDE
+        printf("freeing %s\n", ctxt->incTab[nr]->doc->URL);
+#endif
+        xmlFreeDoc(ctxt->incTab[nr]->doc);
+        ctxt->incTab[nr]->doc = NULL;
+    }
+    xmlFree(URL);
+    return(0);
+}
+
+/**
+ * xmlXIncludeLoadTxt:
+ * @param ctxt the XInclude context
+ * @param url the associated URL
+ * @param nr the xinclude node number
+ *
+ * Load the content, and store the result in the XInclude context
+ *
+ * Returns 0 in case of success, -1 in case of failure
+ */
+static int
+xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
+    xmlParserInputBufferPtr buf;
+    xmlNodePtr node;
+    xmlURIPtr uri;
+    xmlChar *URL;
+    int i;
+    xmlChar *encoding = NULL;
+    xmlCharEncoding enc = (xmlCharEncoding) 0;
+
+    /*
+     * Check the URL and remove any fragment identifier
+     */
+    uri = xmlParseURI((const char *)url);
+    if (uri == NULL) {
+        xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_HREF_URI,
+                       "invalid value URI %s\n", url);
+        return(-1);
+    }
+    if (uri->fragment != NULL) {
+        xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_TEXT_FRAGMENT,
+                       "fragment identifier forbidden for text: %s\n",
+                       (const xmlChar *) uri->fragment);
+        xmlFreeURI(uri);
+        return(-1);
+    }
+    URL = xmlSaveUri(uri);
+    xmlFreeURI(uri);
+    if (URL == NULL) {
+        xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_HREF_URI,
+                       "invalid value URI %s\n", url);
+        return(-1);
+    }
+
+    /*
+     * Handling of references to the local document are done
+     * directly through ctxt->doc.
+     */
+    if (URL[0] == 0) {
+        xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
+                       XML_XINCLUDE_TEXT_DOCUMENT,
+                       "text serialization of document not available\n", NULL);
+        xmlFree(URL);
+        return(-1);
+    }
+
+    /*
+     * Prevent reloading twice the document.
+     */
+    for (i = 0; i < ctxt->txtNr; i++) {
+        if (xmlStrEqual(URL, ctxt->txturlTab[i])) {
+            node = xmlCopyNode(ctxt->txtTab[i], 1);
+            goto loaded;
+        }
+    }
+    /*
+     * Try to get the encoding if available
+     */
+    if ((ctxt->incTab[nr] != NULL) && (ctxt->incTab[nr]->ref != NULL)) {
+        encoding = xmlGetProp(ctxt->incTab[nr]->ref, XINCLUDE_PARSE_ENCODING);
+    }
+    if (encoding != NULL) {
+        /*
+         *  we should not have to remap to the xmlCharEncoding
+         *       predefined set, a better interface than
+         *       xmlParserInputBufferCreateFilename should allow any
+         *       encoding supported by iconv
+         */
+        enc = xmlParseCharEncoding((const char *) encoding);
+        if (enc == XML_CHAR_ENCODING_ERROR) {
+            xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
+                           XML_XINCLUDE_UNKNOWN_ENCODING,
+                           "encoding %s not supported\n", encoding);
+            xmlFree(encoding);
+            xmlFree(URL);
+            return(-1);
+        }
+        xmlFree(encoding);
+    }
+
+    /*
+     * Load it.
+     */
+    buf = xmlParserInputBufferCreateFilename((const char *)URL, enc);
+    if (buf == NULL) {
+        xmlFree(URL);
+        return(-1);
+    }
+    node = xmlNewText(NULL);
+
+    /*
+     * Scan all chars from the resource and add the to the node
+     */
+    while (xmlParserInputBufferRead(buf, 128) > 0) {
+    int len;
+    const xmlChar *content;
+
+    content = xmlBufferContent(buf->buffer);
+    len = xmlBufferLength(buf->buffer);
+    for (i = 0;i < len;) {
+        int cur;
+        int k; // DONE: Rename  'l' --> 'k'
+
+        cur = xmlStringCurrentChar(NULL, &content[i], &k);
+        if (!IS_CHAR(cur)) {
+        xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
+                       XML_XINCLUDE_INVALID_CHAR,
+                   "%s contains invalid char\n", URL);
+        } else {
+        xmlNodeAddContentLen(node, &content[i], k); // may set OOM flag
+        }
+        i += k;
+    }
+    xmlBufferShrink(buf->buffer, len);
+    }
+    xmlFreeParserInputBuffer(buf);
+    xmlXIncludeAddTxt(ctxt, node, URL);
+
+loaded:
+    /*
+     * Add the element as the replacement copy.
+     */
+    ctxt->incTab[nr]->inc = node;
+    xmlFree(URL);
+    return(0);
+}
+
+/**
+ * xmlXIncludeLoadFallback:
+ * @param ctxt the XInclude context
+ * @param fallback the fallback node
+ * @param nr the xinclude node number
+ *
+ * Load the content of the fallback node, and store the result
+ * in the XInclude context
+ *
+ * Returns 0 in case of success, -1 in case of failure
+ */
+static int
+xmlXIncludeLoadFallback(xmlXIncludeCtxtPtr ctxt, xmlNodePtr fallback, int nr) {
+    xmlXIncludeCtxtPtr newctxt;
+    int ret = 0;
+
+    if ((fallback == NULL) || (ctxt == NULL))
+        return(-1);
+    if (fallback->children != NULL) {
+        /*
+         * It's possible that the fallback also has 'includes'
+         * , so we re-process the fallback just in case
+         */
+        newctxt = xmlXIncludeNewContext(ctxt->doc);
+        if (newctxt == NULL)
+            return (-1);
+        xmlXIncludeSetFlags(newctxt, ctxt->parseFlags);
+        ret = xmlXIncludeDoProcess(newctxt, ctxt->doc, fallback->children);
+        if (ctxt->nbErrors > 0)
+            ret = -1;
+        else if (ret > 0)
+            ret = 0;    /* xmlXIncludeDoProcess can return +ve number */
+        xmlXIncludeFreeContext(newctxt);
+
+        ctxt->incTab[nr]->inc = xmlCopyNodeList(fallback->children);
+    } else {
+        ctxt->incTab[nr]->inc = NULL;
+        ctxt->incTab[nr]->emptyFb = 1;  /* flag empty callback */
+    }
+    return(ret);
+}
+
+/************************************************************************
+ *                                                                      *
+ *                      XInclude Processing                             *
+ *                                                                      *
+ ************************************************************************/
+
+/**
+ * xmlXIncludePreProcessNode:
+ * @param ctxt an XInclude context
+ * @param node an XInclude node
+ *
+ * Implement the XInclude preprocessing, currently just adding the element
+ * for further processing.
+ *
+ * Returns the result list or NULL in case of error
+ */
+static xmlNodePtr
+xmlXIncludePreProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
+    xmlXIncludeAddNode(ctxt, node);
+    return(0);
+}
+
+/**
+ * xmlXIncludeLoadNode:
+ * @param ctxt an XInclude context
+ * @param nr the node number
+ *
+ * Find and load the infoset replacement for the given node.
+ *
+ * Returns 0 if substitution succeeded, -1 if some processing failed
+ */
+static int
+xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, int nr) {
+    xmlNodePtr cur;
+    xmlChar *href;
+    xmlChar *parse;
+    xmlChar *base;
+    xmlChar *URI;
+    int xml = 1; /* default Issue 64 */
+    int ret;
+
+    if (ctxt == NULL)
+        return(-1);
+    if ((nr < 0) || (nr >= ctxt->incNr))
+        return(-1);
+    cur = ctxt->incTab[nr]->ref;
+    if (cur == NULL)
+        return(-1);
+
+    /*
+     * read the attributes
+     */
+    href = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_HREF);
+    if (href == NULL) {
+        href = xmlStrdup(BAD_CAST ""); /* @@@@ href is now optional */
+        if (href == NULL)
+            return(-1);
+    }
+    parse = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_PARSE);
+    if (parse != NULL) {
+        if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
+            xml = 1;
+        else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
+            xml = 0;
+        else {
+            xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
+                           XML_XINCLUDE_PARSE_VALUE,
+                           "invalid value %s for 'parse'\n", parse);
+            if (href != NULL)
+                xmlFree(href);
+            if (parse != NULL)
+                xmlFree(parse);
+            return(-1);
+        }
+    }
+
+    /*
+     * compute the URI
+     */
+    base = xmlNodeGetBase(ctxt->doc, cur);
+    if (base == NULL) {
+        URI = xmlBuildURI(href, ctxt->doc->URL);
+    } else {
+        URI = xmlBuildURI(href, base);
+    }
+    if (URI == NULL) {
+        xmlChar *escbase;
+        xmlChar *eschref;
+        /*
+         * Some escaping may be needed
+         */
+        escbase = xmlURIEscape(base);
+        eschref = xmlURIEscape(href);
+        URI = xmlBuildURI(eschref, escbase);
+        if (escbase != NULL)
+            xmlFree(escbase);
+        if (eschref != NULL)
+            xmlFree(eschref);
+    }
+    if (URI == NULL) {
+        xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
+                       XML_XINCLUDE_HREF_URI, "failed build URL\n", NULL);
+        if (parse != NULL)
+            xmlFree(parse);
+        if (href != NULL)
+            xmlFree(href);
+        if (base != NULL)
+            xmlFree(base);
+        return(-1);
+    }
+#ifdef DEBUG_XINCLUDE
+    xmlGenericError(xmlGenericErrorContext, "parse: %s\n",
+            xml ? "xml": "text");
+    xmlGenericError(xmlGenericErrorContext, "URI: %s\n", URI);
+#endif
+
+    /*
+     * Cleanup
+     */
+    if (xml) {
+        ret = xmlXIncludeLoadDoc(ctxt, URI, nr);
+        /* xmlXIncludeGetFragment(ctxt, cur, URI); */
+    } else {
+        ret = xmlXIncludeLoadTxt(ctxt, URI, nr);
+    }
+    if (ret < 0) {
+        xmlNodePtr children;
+
+        /*
+         * Time to try a fallback if availble
+         */
+#ifdef DEBUG_XINCLUDE
+        xmlGenericError(xmlGenericErrorContext, "error looking for fallback\n");
+#endif
+        children = cur->children;
+        while (children != NULL) {
+            if ((children->type == XML_ELEMENT_NODE) &&
+                (children->ns != NULL) &&
+                (xmlStrEqual(children->name, XINCLUDE_FALLBACK)) &&
+                ((xmlStrEqual(children->ns->href, XINCLUDE_NS)) ||
+                 (xmlStrEqual(children->ns->href, XINCLUDE_OLD_NS)))) {
+                ret = xmlXIncludeLoadFallback(ctxt, children, nr);
+                if (ret == 0)
+                    break;
+            }
+            children = children->next;
+        }
+    }
+    if (ret < 0) {
+        xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
+                       XML_XINCLUDE_NO_FALLBACK,
+                       "could not load %s, and no fallback was found\n",
+                       URI);
+    }
+
+    /*
+     * Cleanup
+     */
+    if (URI != NULL)
+        xmlFree(URI);
+    if (parse != NULL)
+        xmlFree(parse);
+    if (href != NULL)
+        xmlFree(href);
+    if (base != NULL)
+        xmlFree(base);
+    return(0);
+}
+
+/**
+ * xmlXIncludeIncludeNode:
+ * @param ctxt an XInclude context
+ * @param nr the node number
+ *
+ * Inplement the infoset replacement for the given node
+ *
+ * Returns 0 if substitution succeeded, -1 if some processing failed
+ */
+static int
+xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) {
+    xmlNodePtr cur, end, list, tmp;
+
+    if (ctxt == NULL)
+        return(-1);
+    if ((nr < 0) || (nr >= ctxt->incNr))
+        return(-1);
+    cur = ctxt->incTab[nr]->ref;
+    if (cur == NULL)
+        return(-1);
+
+    /*
+     * If we stored an XPointer a late computation may be needed
+     */
+    if ((ctxt->incTab[nr]->inc == NULL) &&
+        (ctxt->incTab[nr]->xptr != NULL)) {
+        ctxt->incTab[nr]->inc =
+            xmlXIncludeCopyXPointer(ctxt, ctxt->doc, ctxt->doc,
+                                    ctxt->incTab[nr]->xptr);
+        xmlXPathFreeObject(ctxt->incTab[nr]->xptr);
+        ctxt->incTab[nr]->xptr = NULL;
+    }
+    list = ctxt->incTab[nr]->inc;
+    ctxt->incTab[nr]->inc = NULL;
+
+    /*
+     * Check against the risk of generating a multi-rooted document
+     */
+    if ((cur->parent != NULL) &&
+        (cur->parent->type != XML_ELEMENT_NODE)) {
+        int nb_elem = 0;
+
+        tmp = list;
+        while (tmp != NULL) {
+            if (tmp->type == XML_ELEMENT_NODE)
+                nb_elem++;
+            tmp = tmp->next;
+        }
+        if (nb_elem > 1) {
+            xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
+                           XML_XINCLUDE_MULTIPLE_ROOT,
+                       "XInclude error: would result in multiple root nodes\n",
+                           NULL);
+            return(-1);
+        }
+    }
+
+    /*
+     * Change the current node as an XInclude start one, and add an
+     * entity end one
+     */
+    cur->type = XML_XINCLUDE_START;
+    end = xmlNewNode(cur->ns, cur->name);
+    if (end == NULL) {
+        xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_BUILD_FAILED,
+                       "failed to build node\n", NULL);
+        return(-1);
+    }
+    end->type = XML_XINCLUDE_END;
+    xmlAddNextSibling(cur, end);
+
+    /*
+     * Add the list of nodes
+     */
+    while (list != NULL) {
+        cur = list;
+        list = list->next;
+
+        xmlAddPrevSibling(end, cur);
+    }
+
+
+    return(0);
+}
+
+/**
+ * xmlXIncludeTestNode:
+ * @param ctxt the XInclude processing context
+ * @param node an XInclude node
+ *
+ * test if the node is an XInclude node
+ *
+ * Returns 1 true, 0 otherwise
+ */
+static int
+xmlXIncludeTestNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
+    if (node == NULL)
+        return(0);
+    if (node->type != XML_ELEMENT_NODE)
+        return(0);
+    if (node->ns == NULL)
+        return(0);
+    if ((xmlStrEqual(node->ns->href, XINCLUDE_NS)) ||
+        (xmlStrEqual(node->ns->href, XINCLUDE_OLD_NS))) {
+        if (xmlStrEqual(node->ns->href, XINCLUDE_OLD_NS)) {
+            if (ctxt->legacy == 0) {
+#if 0 /* wait for the XML Core Working Group to get something stable ! */
+                xmlXIncludeWarn(ctxt, node, XML_XINCLUDE_DEPRECATED_NS,
+                       "Deprecated XInclude namespace found, use %s",
+                                XINCLUDE_NS);
+#endif
+                ctxt->legacy = 1;
+            }
+        }
+        if (xmlStrEqual(node->name, XINCLUDE_NODE)) {
+            xmlNodePtr child = node->children;
+            int nb_fallback = 0;
+
+            while (child != NULL) {
+                if ((child->type == XML_ELEMENT_NODE) &&
+                    (child->ns != NULL) &&
+                    ((xmlStrEqual(child->ns->href, XINCLUDE_NS)) ||
+                     (xmlStrEqual(child->ns->href, XINCLUDE_OLD_NS)))) {
+                    if (xmlStrEqual(child->name, XINCLUDE_NODE)) {
+                        xmlXIncludeErr(ctxt, node,
+                                       XML_XINCLUDE_INCLUDE_IN_INCLUDE,
+                                       "%s has an 'include' child\n",
+                                       XINCLUDE_NODE);
+                        return(0);
+                    }
+                    if (xmlStrEqual(child->name, XINCLUDE_FALLBACK)) {
+                        nb_fallback++;
+                    }
+                }
+                child = child->next;
+            }
+            if (nb_fallback > 1) {
+                xmlXIncludeErr(ctxt, node, XML_XINCLUDE_FALLBACKS_IN_INCLUDE,
+                               "%s has multiple fallback children\n",
+                               XINCLUDE_NODE);
+                return(0);
+            }
+            return(1);
+        }
+        if (xmlStrEqual(node->name, XINCLUDE_FALLBACK)) {
+            if ((node->parent == NULL) ||
+                (node->parent->type != XML_ELEMENT_NODE) ||
+                (node->parent->ns == NULL) ||
+                ((!xmlStrEqual(node->parent->ns->href, XINCLUDE_NS)) &&
+                 (!xmlStrEqual(node->parent->ns->href, XINCLUDE_OLD_NS))) ||
+                (!xmlStrEqual(node->parent->name, XINCLUDE_NODE))) {
+                xmlXIncludeErr(ctxt, node,
+                               XML_XINCLUDE_FALLBACK_NOT_IN_INCLUDE,
+                               "%s is not the child of an 'include'\n",
+                               XINCLUDE_FALLBACK);
+            }
+        }
+    }
+    return(0);
+}
+
+/**
+ * xmlXIncludeDoProcess:
+ * @param ctxt the XInclude processing context
+ * @param doc an XML document
+ * @param tree the top of the tree to process
+ *
+ * Implement the XInclude substitution on the XML document doc
+ *
+ * Returns 0 if no substitution were done, -1 if some processing failed
+ *    or the number of substitutions done.
+ */
+static int
+xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr tree) {
+    xmlNodePtr cur;
+    int ret = 0;
+    int i;
+
+    if ((doc == NULL) || (tree == NULL))
+        return(-1);
+    if (ctxt == NULL)
+        return(-1);
+
+    if (doc->URL != NULL) {
+        ret = xmlXIncludeURLPush(ctxt, doc->URL);
+        if (ret < 0)
+            return(-1);
+    }
+
+    /*
+     * First phase: lookup the elements in the document
+     */
+    cur = tree;
+    if (xmlXIncludeTestNode(ctxt, cur) == 1)
+        xmlXIncludePreProcessNode(ctxt, cur);
+    while ((cur != NULL) && (cur != tree->parent)) {
+        
+        if ((cur->children != NULL) &&
+            (cur->children->type != XML_ENTITY_DECL) &&
+            (cur->children->type != XML_XINCLUDE_START) &&
+            (cur->children->type != XML_XINCLUDE_END)) {
+            cur = cur->children;
+            if (xmlXIncludeTestNode(ctxt, cur))
+                xmlXIncludePreProcessNode(ctxt, cur);
+        } else if (cur->next != NULL) {
+            cur = cur->next;
+            if (xmlXIncludeTestNode(ctxt, cur))
+                xmlXIncludePreProcessNode(ctxt, cur);
+        } else {
+            if (cur == tree)
+                break;
+            do {
+                cur = cur->parent;
+                if ((cur == NULL) || (cur == tree->parent))
+                    break; /* do */
+                if (cur->next != NULL) {
+                    cur = cur->next;
+                    if (xmlXIncludeTestNode(ctxt, cur))
+                        xmlXIncludePreProcessNode(ctxt, cur);
+                    break; /* do */
+                }
+            } while (cur != NULL);
+        }
+    }
+
+    /*
+     * Second Phase : collect the infosets fragments
+     */
+    for (i = ctxt->incBase;i < ctxt->incNr; i++) {
+        xmlXIncludeLoadNode(ctxt, i);
+        ret++;
+    }
+
+    /*
+     * Third phase: extend the original document infoset.
+     *
+     * Originally we bypassed the inclusion if there were any errors
+     * encountered on any of the XIncludes.  A bug132588 was raised requesting that we output the XIncludes without error,
+     * so the check for inc!=NULL || xptr!=NULL was put in.  This may
+     * give some other problems in the future, but for now it seems to
+     * work ok.
+     *
+     */
+    for (i = ctxt->incBase;i < ctxt->incNr; i++) {
+        if ((ctxt->incTab[i]->inc != NULL) ||
+                (ctxt->incTab[i]->xptr != NULL) ||
+                (ctxt->incTab[i]->emptyFb != 0))        /* (empty fallback) */
+            xmlXIncludeIncludeNode(ctxt, i);
+    }
+
+    if (doc->URL != NULL)
+        xmlXIncludeURLPop(ctxt);
+    return(ret);
+}
+
+/**
+ * xmlXIncludeSetFlags:
+ * @param ctxt an XInclude processing context
+ * @param flags a set of xmlParserOption used for parsing XML includes
+ *
+ * Set the flags used for further processing of XML resources.
+ *
+ * Returns 0 in case of success and -1 in case of error.
+ */
+XMLPUBFUNEXPORT int
+xmlXIncludeSetFlags(xmlXIncludeCtxtPtr ctxt, int flags) {
+    if (ctxt == NULL)
+        return(-1);
+    ctxt->parseFlags = flags;
+    return(0);
+}
+
+/**
+ * xmlXIncludeProcessFlags:
+ * @param doc an XML document
+ * @param flags a set of xmlParserOption used for parsing XML includes
+ *
+ * Implement the XInclude substitution on the XML document doc
+ *
+ * Returns 0 if no substitution were done, -1 if some processing failed
+ *    or the number of substitutions done.
+ */
+XMLPUBFUNEXPORT int
+xmlXIncludeProcessFlags(xmlDocPtr doc, int flags) {
+    xmlXIncludeCtxtPtr ctxt;
+    xmlNodePtr tree;
+    int ret = 0;
+
+    if (doc == NULL)
+        return(-1);
+    tree = xmlDocGetRootElement(doc);
+    if (tree == NULL)
+        return(-1);
+    ctxt = xmlXIncludeNewContext(doc);
+    if (ctxt == NULL)
+        return(-1);
+    xmlXIncludeSetFlags(ctxt, flags);
+    ret = xmlXIncludeDoProcess(ctxt, doc, tree);
+    if ((ret >= 0) && (ctxt->nbErrors > 0))
+        ret = -1;
+
+    xmlXIncludeFreeContext(ctxt);
+    return(ret);
+}
+
+/**
+ * xmlXIncludeProcess:
+ * @param doc an XML document
+ *
+ * Implement the XInclude substitution on the XML document doc
+ *
+ * Returns 0 if no substitution were done, -1 if some processing failed
+ *    or the number of substitutions done.
+ */
+XMLPUBFUNEXPORT int
+xmlXIncludeProcess(xmlDocPtr doc) {
+    return(xmlXIncludeProcessFlags(doc, 0));
+}
+
+/**
+ * xmlXIncludeProcessTreeFlags:
+ * @param tree a node in an XML document
+ * @param flags a set of xmlParserOption used for parsing XML includes
+ *
+ * Implement the XInclude substitution for the given subtree
+ *
+ * Returns 0 if no substitution were done, -1 if some processing failed
+ *    or the number of substitutions done.
+ */
+XMLPUBFUNEXPORT int
+xmlXIncludeProcessTreeFlags(xmlNodePtr tree, int flags) {
+    xmlXIncludeCtxtPtr ctxt;
+    int ret = 0;
+
+    if ((tree == NULL) || (tree->doc == NULL))
+        return(-1);
+    ctxt = xmlXIncludeNewContext(tree->doc);
+    if (ctxt == NULL)
+        return(-1);
+    xmlXIncludeSetFlags(ctxt, flags);
+    ret = xmlXIncludeDoProcess(ctxt, tree->doc, tree);
+    if ((ret >= 0) && (ctxt->nbErrors > 0))
+        ret = -1;
+
+    xmlXIncludeFreeContext(ctxt);
+    return(ret);
+}
+
+/**
+ * xmlXIncludeProcessTree:
+ * @param tree a node in an XML document
+ *
+ * Implement the XInclude substitution for the given subtree
+ *
+ * Returns 0 if no substitution were done, -1 if some processing failed
+ *    or the number of substitutions done.
+ */
+XMLPUBFUNEXPORT int
+xmlXIncludeProcessTree(xmlNodePtr tree) {
+    return(xmlXIncludeProcessTreeFlags(tree, 0));
+}
+
+/**
+ * xmlXIncludeProcessNode:
+ * @param ctxt an existing XInclude context
+ * @param node a node in an XML document
+ *
+ * Implement the XInclude substitution for the given subtree reusing
+ * the informations and data coming from the given context.
+ *
+ * Returns 0 if no substitution were done, -1 if some processing failed
+ *    or the number of substitutions done.
+ */
+XMLPUBFUNEXPORT int
+xmlXIncludeProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
+    int ret = 0;
+
+    if ((node == NULL) || (node->doc == NULL) || (ctxt == NULL))
+        return(-1);
+    ret = xmlXIncludeDoProcess(ctxt, node->doc, node);
+    if ((ret >= 0) && (ctxt->nbErrors > 0))
+        ret = -1;
+    return(ret);
+}
+
+#endif   /* LIBXML_XINCLUDE_ENABLED */