webengine/osswebengine/WebCore/platform/symbian/Libxml2/Libxml2_xmlIO.c
changeset 0 dd21522fd290
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/webengine/osswebengine/WebCore/platform/symbian/Libxml2/Libxml2_xmlIO.c	Mon Mar 30 12:54:55 2009 +0300
@@ -0,0 +1,3649 @@
+/*
+ * xmlIO.c : implementation of the I/O interfaces used by the parser
+ *
+ * See Copyright for the status of this software.
+ *
+ * daniel@veillard.com
+ *
+ * 14 Nov 2000 ht - for VMS, truncated name of long functions to under 32 char
+ */
+
+#define IN_LIBXML
+#include "XmlEnglibxml.h"
+
+#include <string.h>
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
+#include <stdio.h>
+// TODO: XE Cleanup
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_ZLIB_H
+#include <zlib.h>
+#endif
+
+/* Figure a portable way to know if a file is a directory. */
+#ifndef HAVE_STAT
+#  ifdef HAVE__STAT
+     /* MS C library seems to define stat and _stat. The definition
+        is identical. Still, mapping them to each other causes a warning. */
+#    ifndef _MSC_VER
+#      define stat(x,y) _stat(x,y)
+#    endif
+#    define HAVE_STAT
+#  endif
+#endif
+#ifdef HAVE_STAT
+#  ifndef S_ISDIR
+#    ifdef _S_ISDIR
+#      define S_ISDIR(x) _S_ISDIR(x)
+#    else
+#      ifdef S_IFDIR
+#        ifndef S_IFMT
+#          ifdef _S_IFMT
+#            define S_IFMT _S_IFMT
+#          endif
+#        endif
+#        ifdef S_IFMT
+#          define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#        endif
+#      endif
+#    endif
+#  endif
+#endif
+
+#include "Libxml2_parserInternals.h"
+//#include "Libxml2_xmlIO.h"
+#include "Libxml2_uri.h"
+
+#ifdef LIBXML_CATALOG_ENABLED
+#include <catalog.h>
+#endif
+
+#include "Libxml2_globals.h"
+#include <errno.h>
+
+/* #define VERBOSE_FAILURE */
+/* #define DEBUG_EXTERNAL_ENTITIES */
+/* #define DEBUG_INPUT */
+
+#ifdef DEBUG_INPUT
+#define MINLEN 40
+#else
+#define MINLEN 4000
+#endif
+
+/************************************************************************
+ *                                                                      *
+ *      Tree memory error handler                                       *
+ *                                                                      *
+ ************************************************************************/
+
+const char * const  IOerr[] = {
+    EMBED_ERRTXT("Unknown IO error"),                   /* UNKNOWN */
+    EMBED_ERRTXT("Permission denied"),                  /* EACCES */
+    EMBED_ERRTXT("Resource temporarily unavailable"),   /* EAGAIN */
+    EMBED_ERRTXT("Bad file descriptor"),                /* EBADF */
+    EMBED_ERRTXT("Bad message"),                        /* EBADMSG */
+    EMBED_ERRTXT("Resource busy"),                      /* EBUSY */
+    EMBED_ERRTXT("Operation canceled"),                 /* ECANCELED */
+    EMBED_ERRTXT("No child processes"),                 /* ECHILD */
+    EMBED_ERRTXT("Resource deadlock avoided"),          /* EDEADLK */
+    EMBED_ERRTXT("Domain error"),                       /* EDOM */
+    EMBED_ERRTXT("File exists"),                        /* EEXIST */
+    EMBED_ERRTXT("Bad address"),                        /* EFAULT */
+    EMBED_ERRTXT("File too large"),                     /* EFBIG */
+    EMBED_ERRTXT("Operation in progress"),              /* EINPROGRESS */
+    EMBED_ERRTXT("Interrupted function call"),          /* EINTR */
+    EMBED_ERRTXT("Invalid argument"),                   /* EINVAL */
+    EMBED_ERRTXT("Input/output error"),                 /* EIO */
+    EMBED_ERRTXT("Is a directory"),                     /* EISDIR */
+    EMBED_ERRTXT("Too many open files"),                /* EMFILE */
+    EMBED_ERRTXT("Too many links"),                     /* EMLINK */
+    EMBED_ERRTXT("Inappropriate message buffer length"),/* EMSGSIZE */
+    EMBED_ERRTXT("Filename too long"),                  /* ENAMETOOLONG */
+    EMBED_ERRTXT("Too many open files in system"),      /* ENFILE */
+    EMBED_ERRTXT("No such device"),                     /* ENODEV */
+    EMBED_ERRTXT("No such file or directory"),          /* ENOENT */
+    EMBED_ERRTXT("Exec format error"),                  /* ENOEXEC */
+    EMBED_ERRTXT("No locks available"),                 /* ENOLCK */
+    EMBED_ERRTXT("Not enough space"),                   /* ENOMEM */
+    EMBED_ERRTXT("No space left on device"),            /* ENOSPC */
+    EMBED_ERRTXT("Function not implemented"),           /* ENOSYS */
+    EMBED_ERRTXT("Not a directory"),                    /* ENOTDIR */
+    EMBED_ERRTXT("Directory not empty"),                /* ENOTEMPTY */
+    EMBED_ERRTXT("Not supported"),                      /* ENOTSUP */
+    EMBED_ERRTXT("Inappropriate I/O control operation"),/* ENOTTY */
+    EMBED_ERRTXT("No such device or address"),          /* ENXIO */
+    EMBED_ERRTXT("Operation not permitted"),            /* EPERM */
+    EMBED_ERRTXT("Broken pipe"),                        /* EPIPE */
+    EMBED_ERRTXT("Result too large"),                   /* ERANGE */
+    EMBED_ERRTXT("Read-only file system"),              /* EROFS */
+    EMBED_ERRTXT("Invalid seek"),                       /* ESPIPE */
+    EMBED_ERRTXT("No such process"),                    /* ESRCH */
+    EMBED_ERRTXT("Operation timed out"),                /* ETIMEDOUT */
+    EMBED_ERRTXT("Improper link"),                      /* EXDEV */
+    EMBED_ERRTXT("Attempt to load network entity %s"),  /* XML_IO_NETWORK_ATTEMPT */
+    EMBED_ERRTXT("encoder error"),                      /* XML_IO_ENCODER */
+    EMBED_ERRTXT("flush error"),
+    EMBED_ERRTXT("write error"),
+    EMBED_ERRTXT("no input"),
+    EMBED_ERRTXT("buffer full"),
+    EMBED_ERRTXT("loading error"),
+    EMBED_ERRTXT("not a socket"),                       /* ENOTSOCK */
+    EMBED_ERRTXT("already connected"),                  /* EISCONN */
+    EMBED_ERRTXT("connection refuxed"),                 /* ECONNREFUSED */
+    EMBED_ERRTXT("unreachable network"),                /* ENETUNREACH */
+    EMBED_ERRTXT("adddress in use"),                    /* EADDRINUSE */
+    EMBED_ERRTXT("already in use"),                     /* EALREADY */
+    EMBED_ERRTXT("unknown address familly")             /* EAFNOSUPPORT */
+};
+
+// TODO: make xmlIOErrMemory() compiled in allways (needed for logging)
+#ifdef XMLENGINE_EXCLUDE_IOERRMEMORY
+#  define xmlIOErrMemory(arg) SET_OOM_FLAG
+#  define xmlIOErr(arg1,arg2)
+#else
+/**
+ * xmlIOErrMemory:
+ * @extra:  extra informations
+ *
+ * Handle an out of memory condition
+ */
+static void
+xmlIOErrMemory(const char *extra)
+{
+    SET_OOM_FLAG;
+    __xmlSimpleError(XML_FROM_IO, XML_ERR_NO_MEMORY, NULL, NULL, extra);
+}
+
+/**
+ * __xmlIOErr:
+ * @code:  the error number
+ * @
+ * @extra:  extra informations
+ *
+ * Handle an I/O error
+ */
+void
+__xmlIOErr(int domain, int code, const char *extra)
+{
+    unsigned int idx;
+
+    if (code == 0) {
+#ifdef HAVE_ERRNO_H
+    if (errno == 0) code = 0;
+#ifdef EACCES
+        else if (errno == EACCES) code = XML_IO_EACCES;
+#endif
+#ifdef EAGAIN
+        else if (errno == EAGAIN) code = XML_IO_EAGAIN;
+#endif
+#ifdef EBADF
+        else if (errno == EBADF) code = XML_IO_EBADF;
+#endif
+#ifdef EBADMSG
+        else if (errno == EBADMSG) code = XML_IO_EBADMSG;
+#endif
+#ifdef EBUSY
+        else if (errno == EBUSY) code = XML_IO_EBUSY;
+#endif
+#ifdef ECANCELED
+        else if (errno == ECANCELED) code = XML_IO_ECANCELED;
+#endif
+#ifdef ECHILD
+        else if (errno == ECHILD) code = XML_IO_ECHILD;
+#endif
+#ifdef EDEADLK
+        else if (errno == EDEADLK) code = XML_IO_EDEADLK;
+#endif
+#ifdef EDOM
+        else if (errno == EDOM) code = XML_IO_EDOM;
+#endif
+#ifdef EEXIST
+        else if (errno == EEXIST) code = XML_IO_EEXIST;
+#endif
+#ifdef EFAULT
+        else if (errno == EFAULT) code = XML_IO_EFAULT;
+#endif
+#ifdef EFBIG
+        else if (errno == EFBIG) code = XML_IO_EFBIG;
+#endif
+#ifdef EINPROGRESS
+        else if (errno == EINPROGRESS) code = XML_IO_EINPROGRESS;
+#endif
+#ifdef EINTR
+        else if (errno == EINTR) code = XML_IO_EINTR;
+#endif
+#ifdef EINVAL
+        else if (errno == EINVAL) code = XML_IO_EINVAL;
+#endif
+#ifdef EIO
+        else if (errno == EIO) code = XML_IO_EIO;
+#endif
+#ifdef EISDIR
+        else if (errno == EISDIR) code = XML_IO_EISDIR;
+#endif
+#ifdef EMFILE
+        else if (errno == EMFILE) code = XML_IO_EMFILE;
+#endif
+#ifdef EMLINK
+        else if (errno == EMLINK) code = XML_IO_EMLINK;
+#endif
+#ifdef EMSGSIZE
+        else if (errno == EMSGSIZE) code = XML_IO_EMSGSIZE;
+#endif
+#ifdef ENAMETOOLONG
+        else if (errno == ENAMETOOLONG) code = XML_IO_ENAMETOOLONG;
+#endif
+#ifdef ENFILE
+        else if (errno == ENFILE) code = XML_IO_ENFILE;
+#endif
+#ifdef ENODEV
+        else if (errno == ENODEV) code = XML_IO_ENODEV;
+#endif
+#ifdef ENOENT
+        else if (errno == ENOENT) code = XML_IO_ENOENT;
+#endif
+#ifdef ENOEXEC
+        else if (errno == ENOEXEC) code = XML_IO_ENOEXEC;
+#endif
+#ifdef ENOLCK
+        else if (errno == ENOLCK) code = XML_IO_ENOLCK;
+#endif
+#ifdef ENOMEM
+        else if (errno == ENOMEM) code = XML_IO_ENOMEM;
+#endif
+#ifdef ENOSPC
+        else if (errno == ENOSPC) code = XML_IO_ENOSPC;
+#endif
+#ifdef ENOSYS
+        else if (errno == ENOSYS) code = XML_IO_ENOSYS;
+#endif
+#ifdef ENOTDIR
+        else if (errno == ENOTDIR) code = XML_IO_ENOTDIR;
+#endif
+#ifdef ENOTEMPTY
+        else if (errno == ENOTEMPTY) code = XML_IO_ENOTEMPTY;
+#endif
+#ifdef ENOTSUP
+        else if (errno == ENOTSUP) code = XML_IO_ENOTSUP;
+#endif
+#ifdef ENOTTY
+        else if (errno == ENOTTY) code = XML_IO_ENOTTY;
+#endif
+#ifdef ENXIO
+        else if (errno == ENXIO) code = XML_IO_ENXIO;
+#endif
+#ifdef EPERM
+        else if (errno == EPERM) code = XML_IO_EPERM;
+#endif
+#ifdef EPIPE
+        else if (errno == EPIPE) code = XML_IO_EPIPE;
+#endif
+#ifdef ERANGE
+        else if (errno == ERANGE) code = XML_IO_ERANGE;
+#endif
+#ifdef EROFS
+        else if (errno == EROFS) code = XML_IO_EROFS;
+#endif
+#ifdef ESPIPE
+        else if (errno == ESPIPE) code = XML_IO_ESPIPE;
+#endif
+#ifdef ESRCH
+        else if (errno == ESRCH) code = XML_IO_ESRCH;
+#endif
+#ifdef ETIMEDOUT
+        else if (errno == ETIMEDOUT) code = XML_IO_ETIMEDOUT;
+#endif
+#ifdef EXDEV
+        else if (errno == EXDEV) code = XML_IO_EXDEV;
+#endif
+#ifdef ENOTSOCK
+        else if (errno == ENOTSOCK) code = XML_IO_ENOTSOCK;
+#endif
+#ifdef EISCONN
+        else if (errno == EISCONN) code = XML_IO_EISCONN;
+#endif
+#ifdef ECONNREFUSED
+        else if (errno == ECONNREFUSED) code = XML_IO_ECONNREFUSED;
+#endif
+#ifdef ETIMEDOUT
+        else if (errno == ETIMEDOUT) code = XML_IO_ETIMEDOUT;
+#endif
+#ifdef ENETUNREACH
+        else if (errno == ENETUNREACH) code = XML_IO_ENETUNREACH;
+#endif
+#ifdef EADDRINUSE
+        else if (errno == EADDRINUSE) code = XML_IO_EADDRINUSE;
+#endif
+#ifdef EINPROGRESS
+        else if (errno == EINPROGRESS) code = XML_IO_EINPROGRESS;
+#endif
+#ifdef EALREADY
+        else if (errno == EALREADY) code = XML_IO_EALREADY;
+#endif
+#ifdef EAFNOSUPPORT
+        else if (errno == EAFNOSUPPORT) code = XML_IO_EAFNOSUPPORT;
+#endif
+        else code = XML_IO_UNKNOWN;
+#endif /* HAVE_ERRNO_H */
+    }
+    idx = 0;
+    if (code >= XML_IO_UNKNOWN) idx = code - XML_IO_UNKNOWN;
+
+#ifdef LIBXML_OUTPUT_ENABLED
+    if (idx >= (sizeof(IOerr) / sizeof(IOerr[0]))) idx = 0;
+    __xmlSimpleError(domain, code, NULL, IOerr[idx], extra);
+#else
+    __xmlSimpleError(domain, code, NULL, EMBED_ERRTXT("IOError"), extra);
+#endif /* LIBXML_OUTPUT_ENABLED */
+
+}
+
+/**
+ * xmlIOErr:
+ * @code:  the error number
+ * @extra:  extra informations
+ *
+ * Handle an I/O error
+ */
+static void
+xmlIOErr(int code, const char *extra)
+{
+    __xmlIOErr(XML_FROM_IO, code, extra);
+}
+
+/**
+ * __xmlLoaderErr:
+ * @ctx: the parser context
+ * @extra:  extra informations
+ *
+ * Handle a resource access error
+ */
+void
+__xmlLoaderErr(void *ctx, const char *msg, const char *filename)
+{
+    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
+    xmlStructuredErrorFunc schannel = NULL;
+    xmlGenericErrorFunc channel = NULL;
+    void *data = NULL;
+    xmlErrorLevel level = XML_ERR_ERROR;
+
+    if ((ctxt != NULL) && (ctxt->disableSAX != 0) &&
+        (ctxt->instate == XML_PARSER_EOF))
+    return;
+    if ((ctxt != NULL) && (ctxt->sax != NULL)) {
+        if (ctxt->validate) {
+        channel = ctxt->sax->error;
+        level = XML_ERR_ERROR;
+    } else {
+        channel = ctxt->sax->warning;
+        level = XML_ERR_WARNING;
+    }
+    schannel = ctxt->sax->serror;
+    data = ctxt->userData;
+    }
+    __xmlRaiseError(schannel, channel, data, ctxt, NULL, XML_FROM_IO,
+                    XML_IO_LOAD_ERROR, level, NULL, 0,
+            filename, NULL, NULL, 0, 0,
+            msg, filename);
+
+}
+#endif /* ifndef XMLENGINE_EXCLUDE_IOERRMEMORY */
+
+#ifndef XMLENGINE_EXCLUDE_OBSOLETE_CODE
+/************************************************************************
+ *                                                                      *
+ *      Tree memory error handler                                       *
+ *                                                                      *
+ ************************************************************************/
+/**
+ * xmlNormalizeWindowsPath:
+ * @path: the input file path
+ *
+ * This function is obsolete. Please see xmlURIFromPath in uri.c for
+ * a better solution.
+ *
+ * Returns a canonicalized version of the path
+ */
+ // TODO: XE Cleanup
+xmlChar *
+xmlNormalizeWindowsPath(const xmlChar *path)
+{
+    return xmlCanonicPath(path);
+}
+#endif
+
+/**
+ * xmlCleanupInputCallbacks:
+ *
+ * clears the entire input callback table. this includes the
+ * compiled-in I/O.
+ *
+ * OOM: never
+ */
+void
+xmlCleanupInputCallbacks(void)
+{
+    int i;
+
+    if (!xmlInputCallbackInitialized)
+        return;
+    // TODO: OPTIMIZE: prefetch pointer to calback table from _globalState
+    for (i = xmlInputCallbackNr - 1; i >= 0; i--) {
+        xmlInputCallbackTable[i].matchcallback = NULL;
+        xmlInputCallbackTable[i].opencallback = NULL;
+        xmlInputCallbackTable[i].readcallback = NULL;
+        xmlInputCallbackTable[i].closecallback = NULL;
+    }
+
+    xmlInputCallbackNr = 0;
+    xmlInputCallbackInitialized = 0;
+}
+
+/**
+ * xmlPopInputCallback:
+ *
+ * Clear the top input callback from the input stack. this includes the
+ * compiled-in I/O.
+ *
+ * Returns the number of input callback registered or -1 in case of error.
+ */
+int
+xmlPopInputCallbacks(void)
+{
+    if (!xmlInputCallbackInitialized)
+        return(-1);
+
+    if (xmlInputCallbackNr <= 0)
+        return(-1);
+
+    xmlInputCallbackNr--;
+    xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = NULL;
+    xmlInputCallbackTable[xmlInputCallbackNr].opencallback = NULL;
+    xmlInputCallbackTable[xmlInputCallbackNr].readcallback = NULL;
+    xmlInputCallbackTable[xmlInputCallbackNr].closecallback = NULL;
+
+    return(xmlInputCallbackNr);
+}
+
+#ifdef LIBXML_OUTPUT_ENABLED
+/**
+ * xmlCleanupOutputCallbacks:
+ *
+ * clears the entire output callback table. this includes the
+ * compiled-in I/O callbacks.
+ */
+void
+xmlCleanupOutputCallbacks(void)
+{
+    int i;
+
+    if (!xmlOutputCallbackInitialized)
+        return;
+
+    for (i = xmlOutputCallbackNr - 1; i >= 0; i--) {
+        xmlOutputCallbackTable[i].matchcallback = NULL;
+        xmlOutputCallbackTable[i].opencallback = NULL;
+        xmlOutputCallbackTable[i].writecallback = NULL;
+        xmlOutputCallbackTable[i].closecallback = NULL;
+    }
+
+    xmlOutputCallbackNr = 0;
+    xmlOutputCallbackInitialized = 0;
+}
+#endif /* LIBXML_OUTPUT_ENABLED */
+
+/************************************************************************
+ *                                                                      *
+ *      Standard I/O for file accesses                                  *
+ *                                                                      *
+ ************************************************************************/
+
+/**
+ * xmlCheckFilename:
+ * @path:  the path to check
+ *
+ * function checks to see if @path is a valid source
+ * (file, socket...) for XML.
+ *
+ * if stat is not available on the target machine,
+ * returns 1.  if stat fails, returns 0 (if calling
+ * stat on the filename fails, it can't be right).
+ * if stat succeeds and the file is a directory,
+ * returns 2.  otherwise returns 1.
+ */
+// TODO: XE Cleanup
+#include <sys/stat.h>
+int
+xmlCheckFilename (const char* path)
+{
+#ifdef HAVE_STAT
+    struct stat stat_buffer;
+
+    if (stat(path, &stat_buffer) == -1)
+        return 0;
+
+#ifdef S_ISDIR
+    if (S_ISDIR(stat_buffer.st_mode)) {
+        return 2;
+    }
+#endif
+#endif
+    return 1;
+}
+
+static int
+xmlNop(void) {
+    return(0);
+}
+
+/**
+ * xmlFdRead:
+ * @context:  the I/O context
+ * @buffer:  where to drop data
+ * @len:  number of bytes to read
+ *
+ * Read @len bytes to @buffer from the I/O channel.
+ *
+ * Returns the number of bytes written
+ */
+static int
+xmlFdRead (void * context, char * buffer, int len) {
+    int ret;
+
+    ret = read((int) (long) context, &buffer[0], len);
+    if (ret < 0) xmlIOErr(0, EMBED_ERRTXT("read()"));
+    return(ret);
+}
+
+#ifdef LIBXML_OUTPUT_ENABLED
+/**
+ * xmlFdWrite:
+ * @context:  the I/O context
+ * @buffer:  where to get data
+ * @len:  number of bytes to write
+ *
+ * Write @len bytes from @buffer to the I/O channel.
+ *
+ * Returns the number of bytes written
+ */
+static int
+xmlFdWrite (void * context, const char * buffer, int len) {
+    int ret;
+
+    ret = write((int) (long) context, &buffer[0], len);
+    if (ret < 0) xmlIOErr(0, "write()");
+    return(ret);
+}
+#endif /* LIBXML_OUTPUT_ENABLED */
+
+/**
+ * xmlFdClose:
+ * @context:  the I/O context
+ *
+ * Close an I/O channel
+ *
+ * Returns 0 in case of success and error code otherwise
+ */
+static int
+xmlFdClose (void * context) {
+    int ret;
+    ret = close((int) (long) context);
+    if (ret < 0) xmlIOErr(0, EMBED_ERRTXT("close()"));
+    return(ret);
+}
+
+/**
+ * xmlFileMatch:
+ * @filename:  the URI for matching
+ *
+ * input from FILE *
+ *
+ * Returns 1 if matches, 0 otherwise
+ */
+int
+xmlFileMatch (const char* filename ATTRIBUTE_UNUSED) {
+    return(1);
+}
+
+
+/**
+ * xmlFileOpen_real:
+ * @filename:  the URI for matching
+ *
+ * input from FILE *, supports compressed input
+ * if @filename is " " then the standard input is used
+ *
+ * Returns an I/O context or NULL in case of error
+ */
+//static
+void *
+xmlFileOpen_real (const char *filename) {
+    const char *path;
+    FILE *fd;
+    int err;
+
+    if (!strcmp(filename, "-")) {
+        fd = stdin;
+        return((void *) fd);
+    }
+
+    if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
+#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
+    path = &filename[17];
+#else
+    path = &filename[16];
+#endif
+    else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
+#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
+    path = &filename[8];
+#else
+    path = &filename[7];
+#endif
+    } else
+    path = filename;
+
+//  TODO: Make a note in documentation that backslashes should be used only!
+
+    if (path == NULL)
+        return(NULL);
+
+    if (!xmlCheckFilename(path))
+        {
+
+        return(NULL);
+        }
+
+
+#if defined(WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
+    fd = fopen(path, "rb");
+#else
+    fd = fopen(path, "r");
+#endif /* WIN32 */
+    err = errno;
+    if (err == ENOMEM)
+        {
+        SET_OOM_FLAG;
+        }
+    if (fd == NULL)
+        {
+        xmlIOErr(0, path);
+        }
+    return((void *) fd);
+}
+
+
+/**
+ * xmlFileOpen:
+ * @filename:  the URI for matching
+ *
+ * Wrapper around xmlFileOpen_real that try it with an unescaped
+ * version of @filename, if this fails fallback to @filename
+ *
+ * Returns a handler or NULL in case or failure
+ */
+void *
+xmlFileOpen (const char *filename) {
+    char *unescaped;
+    void *retval;
+    unescaped = xmlURIUnescapeString(filename, 0, NULL);
+    if (unescaped != NULL) {
+    retval = xmlFileOpen_real(unescaped);
+    } else {
+    if ( OOM_FLAG )
+        return 0;
+    retval = xmlFileOpen_real(filename);
+    }
+    xmlFree(unescaped);
+    return retval;
+}
+
+#ifdef LIBXML_OUTPUT_ENABLED
+/**
+ * xmlFileOpenW:
+ * @filename:  the URI for matching
+ *
+ * output to from FILE *,
+ * if @filename is "-" then the standard output is used
+ *
+ * Returns an I/O context or NULL in case of error
+ */
+static void *
+xmlFileOpenW (const char *filename) {
+    const char *path = NULL;
+    FILE *fd;
+
+    if (!strcmp(filename, "-")) {
+    fd = stdout;
+    return((void *) fd);
+    }
+
+    if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
+#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
+    path = &filename[17];
+#else
+    path = &filename[16];
+#endif
+    else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
+#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
+    path = &filename[8];
+#else
+    path = &filename[7];
+#endif
+    } else
+    path = filename;
+
+    if (path == NULL)
+    return(NULL);
+
+    fd = fopen(path, "wb");
+    if (fd == NULL) xmlIOErr(0, path);
+    return((void *) fd);
+}
+#endif /* LIBXML_OUTPUT_ENABLED */
+
+
+
+/**
+ * xmlFileRead:
+ * @context:  the I/O context
+ * @buffer:  where to drop data
+ * @len:  number of bytes to write
+ *
+ * Read @len bytes to @buffer from the I/O channel.
+ *
+ * Returns the number of bytes written
+ */
+int
+xmlFileRead (void * context, char * buffer, int len) {
+    int ret;
+    ret = fread(&buffer[0], 1,  len, (FILE *) context);
+    if (ret < 0) xmlIOErr(0, EMBED_ERRTXT("fread()"));
+    return(ret);
+}
+
+
+#ifdef LIBXML_OUTPUT_ENABLED
+/**
+ * xmlFileWrite:
+ * @context:  the I/O context
+ * @buffer:  where to drop data
+ * @len:  number of bytes to write
+ *
+ * Write @len bytes from @buffer to the I/O channel.
+ *
+ * Returns the number of bytes written
+ */
+//static
+int
+xmlFileWrite (void * context, const char * buffer, int len) {
+    int items;
+
+    items = fwrite(&buffer[0], len, 1, (FILE *) context);
+    if ((items == 0) && (ferror((FILE *) context))) {
+        xmlIOErr(0, EMBED_ERRTXT("fwrite()"));
+    return(-1);
+    }
+    return(items * len);
+}
+#endif /* LIBXML_OUTPUT_ENABLED */
+
+
+
+/**
+ * xmlFileClose:
+ * @context:  the I/O context
+ *
+ * Close an I/O channel
+ *
+ * Returns 0 or -1 in case of error
+ */
+int
+xmlFileClose (void * context) {
+    FILE *fil;
+    int ret;
+
+    fil = (FILE *) context;
+    if ((fil == stdout) || (fil == stderr)) {
+        ret = fflush(fil);
+    if (ret < 0)
+        xmlIOErr(0, EMBED_ERRTXT("fflush()"));
+    return(0);
+    }
+    if (fil == stdin)
+    return(0);
+    ret = ( fclose((FILE *) context) == EOF ) ? -1 : 0;
+    if (ret < 0)
+        xmlIOErr(0, EMBED_ERRTXT("fclose()"));
+    return(ret);
+}
+
+
+//#ifndef XMLENGINE_EXCLUDE_FILE_FUNC
+/**
+ * xmlFileFlush:
+ * @context:  the I/O context
+ *
+ * Flush an I/O channel
+ */
+static int
+xmlFileFlush (void * context) {
+    int ret;
+    ret = ( fflush((FILE *) context) == EOF ) ? -1 : 0;
+    if (ret < 0)
+        xmlIOErr(0, EMBED_ERRTXT("fflush()"));
+    return(ret);
+}
+//#endif
+
+#ifdef HAVE_ZLIB_H
+/************************************************************************
+ *                                  *
+ *      I/O for compressed file accesses            *
+ *                                  *
+ ************************************************************************/
+/**
+ * xmlGzfileMatch:
+ * @filename:  the URI for matching
+ *
+ * input from compressed file test
+ *
+ * Returns 1 if matches, 0 otherwise
+ */
+static int
+xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
+    return(1);
+}
+
+/**
+ * xmlGzfileOpen_real:
+ * @filename:  the URI for matching
+ *
+ * input from compressed file open
+ * if @filename is " " then the standard input is used
+ *
+ * Returns an I/O context or NULL in case of error
+ */
+static void *
+xmlGzfileOpen_real (const char *filename) {
+    const char *path = NULL;
+    gzFile fd;
+
+    if (!strcmp(filename, "-")) {
+        fd = gzdopen(dup(0), "rb");
+    return((void *) fd);
+    }
+
+    if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
+#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
+    path = &filename[17];
+#else
+    path = &filename[16];
+#endif
+    else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
+#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
+    path = &filename[8];
+#else
+    path = &filename[7];
+#endif
+    } else
+    path = filename;
+
+    if (path == NULL)
+    return(NULL);
+    if (!xmlCheckFilename(path))
+        return(NULL);
+
+    fd = gzopen(path, "rb");
+    return((void *) fd);
+}
+
+/**
+ * xmlGzfileOpen:
+ * @filename:  the URI for matching
+ *
+ * Wrapper around xmlGzfileOpen if the open fais, it will
+ * try to unescape @filename
+ */
+static void *
+xmlGzfileOpen (const char *filename) {
+    char *unescaped;
+    void *retval;
+
+    retval = xmlGzfileOpen_real(filename);
+    if (retval == NULL) {
+    unescaped = xmlURIUnescapeString(filename, 0, NULL);
+    if (unescaped != NULL) {
+        retval = xmlGzfileOpen_real(unescaped);
+    }
+    xmlFree(unescaped);
+    }
+    return retval;
+}
+
+#ifdef LIBXML_OUTPUT_ENABLED
+/**
+ * xmlGzfileOpenW:
+ * @filename:  the URI for matching
+ * @compression:  the compression factor (0 - 9 included)
+ *
+ * input from compressed file open
+ * if @filename is " " then the standard input is used
+ *
+ * Returns an I/O context or NULL in case of error
+ */
+static void *
+xmlGzfileOpenW (const char *filename, int compression) {
+    const char *path = NULL;
+    char mode[15];
+    gzFile fd;
+
+    snprintf(mode, sizeof(mode), "wb%d", compression);
+    if (!strcmp(filename, "-")) {
+        fd = gzdopen(dup(1), mode);
+    return((void *) fd);
+    }
+
+    if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
+#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
+    path = &filename[17];
+#else
+    path = &filename[16];
+#endif
+    else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
+#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
+    path = &filename[8];
+#else
+    path = &filename[7];
+#endif
+    } else
+    path = filename;
+
+    if (path == NULL)
+    return(NULL);
+
+    fd = gzopen(path, mode);
+    return((void *) fd);
+}
+#endif /* LIBXML_OUTPUT_ENABLED */
+
+/**
+ * xmlGzfileRead:
+ * @context:  the I/O context
+ * @buffer:  where to drop data
+ * @len:  number of bytes to write
+ *
+ * Read @len bytes to @buffer from the compressed I/O channel.
+ *
+ * Returns the number of bytes written
+ */
+static int
+xmlGzfileRead (void * context, char * buffer, int len) {
+    int ret;
+
+    ret = gzread((gzFile) context, &buffer[0], len);
+    if (ret < 0) xmlIOErr(0, EMBED_ERRTXT("gzread()"));
+    return(ret);
+}
+
+#ifdef LIBXML_OUTPUT_ENABLED
+/**
+ * xmlGzfileWrite:
+ * @context:  the I/O context
+ * @buffer:  where to drop data
+ * @len:  number of bytes to write
+ *
+ * Write @len bytes from @buffer to the compressed I/O channel.
+ *
+ * Returns the number of bytes written
+ */
+static int
+xmlGzfileWrite (void * context, const char * buffer, int len) {
+    int ret;
+
+    ret = gzwrite((gzFile) context, (char *) &buffer[0], len);
+    if (ret < 0) xmlIOErr(0, EMBED_ERRTXT("gzwrite()"));
+    return(ret);
+}
+#endif /* LIBXML_OUTPUT_ENABLED */
+
+/**
+ * xmlGzfileClose:
+ * @context:  the I/O context
+ *
+ * Close a compressed I/O channel
+ */
+static int
+xmlGzfileClose (void * context) {
+    int ret;
+
+    ret =  (gzclose((gzFile) context) == Z_OK ) ? 0 : -1;
+    if (ret < 0) xmlIOErr(0, EMBED_ERRTXT("gzclose()"));
+    return(ret);
+}
+#endif /* HAVE_ZLIB_H */
+
+#ifdef LIBXML_HTTP_ENABLED
+/************************************************************************
+ *                                  *
+ *          I/O for HTTP file accesses          *
+ *                                  *
+ ************************************************************************/
+
+#ifdef LIBXML_OUTPUT_ENABLED
+typedef struct xmlIOHTTPWriteCtxt_
+{
+    int         compression;
+
+    char *      uri;
+
+    void *      doc_buff;
+
+} xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr;
+
+#ifdef HAVE_ZLIB_H
+
+#define DFLT_WBITS      ( -15 )
+#define DFLT_MEM_LVL        ( 8 )
+#define GZ_MAGIC1       ( 0x1f )
+#define GZ_MAGIC2       ( 0x8b )
+#define LXML_ZLIB_OS_CODE   ( 0x03 )
+#define INIT_HTTP_BUFF_SIZE ( 32768 )
+#define DFLT_ZLIB_RATIO     ( 5 )
+
+/*
+**  Data structure and functions to work with sending compressed data
+**  via HTTP.
+*/
+
+typedef struct xmlZMemBuff_
+{
+   unsigned long    size;
+   unsigned long    crc;
+
+   unsigned char *  zbuff;
+   z_stream     zctrl;
+
+} xmlZMemBuff, *xmlZMemBuffPtr;
+
+/**
+ * append_reverse_ulong
+ * @buff:  Compressed memory buffer
+ * @data:  Unsigned long to append
+ *
+ * Append a unsigned long in reverse byte order to the end of the
+ * memory buffer.
+ */
+static void
+append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) {
+
+    int     idx;
+
+    if ( buff == NULL )
+    return;
+
+    /*
+    **  This is plagiarized from putLong in gzio.c (zlib source) where
+    **  the number "4" is hardcoded.  If zlib is ever patched to
+    **  support 64 bit file sizes, this code would need to be patched
+    **  as well.
+    */
+
+    for ( idx = 0; idx < 4; idx++ ) {
+    *buff->zctrl.next_out = ( data & 0xff );
+    data >>= 8;
+    buff->zctrl.next_out++;
+    }
+
+    return;
+}
+
+/**
+ *
+ * xmlFreeZMemBuff
+ * @buff:  The memory buffer context to clear
+ *
+ * Release all the resources associated with the compressed memory buffer.
+ */
+static void
+xmlFreeZMemBuff( xmlZMemBuffPtr buff ) {
+
+#ifdef DEBUG_HTTP
+    int z_err;
+#endif
+
+    if ( buff == NULL )
+    return;
+
+    xmlFree( buff->zbuff );
+#ifdef DEBUG_HTTP
+    z_err = deflateEnd( &buff->zctrl );
+    if ( z_err != Z_OK )
+    xmlGenericError( xmlGenericErrorContext,
+            EMBED_ERRTXT("xmlFreeZMemBuff:  Error releasing zlib context:  %d\n"),
+            z_err );
+#else
+    deflateEnd( &buff->zctrl );
+#endif
+
+    xmlFree( buff );
+    return;
+}
+
+/**
+ * xmlCreateZMemBuff
+ *@compression: Compression value to use
+ *
+ * Create a memory buffer to hold the compressed XML document.  The
+ * compressed document in memory will end up being identical to what
+ * would be created if gzopen/gzwrite/gzclose were being used to
+ * write the document to disk.  The code for the header/trailer data to
+ * the compression is plagiarized from the zlib source files.
+ */
+static void *
+xmlCreateZMemBuff( int compression ) {
+
+    int         z_err;
+    int         hdr_lgth;
+    xmlZMemBuffPtr  buff = NULL;
+
+    if ( ( compression < 1 ) || ( compression > 9 ) )
+    return ( NULL );
+
+    /*  Create the control and data areas  */
+
+    buff = xmlMalloc( sizeof( xmlZMemBuff ) );
+    if ( buff == NULL ) {
+    xmlIOErrMemory(EMBED_ERRTXT("creating buffer context"));
+    return ( NULL );
+    }
+
+    (void)memset( buff, 0, sizeof( xmlZMemBuff ) );
+    buff->size = INIT_HTTP_BUFF_SIZE;
+    buff->zbuff = xmlMalloc( buff->size );
+    if ( buff->zbuff == NULL ) {
+    xmlFreeZMemBuff( buff );
+    xmlIOErrMemory(EMBED_ERRTXT("creating buffer"));
+    return ( NULL );
+    }
+
+    z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
+                DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
+    if ( z_err != Z_OK ) {
+    xmlChar msg[500];
+    xmlFreeZMemBuff( buff );
+    buff = NULL;
+    xmlStrPrintf(msg, 500,
+            (const xmlChar *) EMBED_ERRTXT("xmlCreateZMemBuff:  %s %d\n"),
+            EMBED_ERRTXT("Error initializing compression context.  ZLIB error:"),
+            z_err );
+    xmlIOErr(XML_IO_WRITE, (const char *) msg);
+    return ( NULL );
+    }
+
+    /*  Set the header data.  The CRC will be needed for the trailer  */
+    buff->crc = crc32( 0L, Z_NULL, 0 );
+    hdr_lgth = snprintf( (char *)buff->zbuff, buff->size,
+            "%c%c%c%c%c%c%c%c%c%c",
+            GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED,
+            0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE );
+    buff->zctrl.next_out  = buff->zbuff + hdr_lgth;
+    buff->zctrl.avail_out = buff->size - hdr_lgth;
+
+    return ( buff );
+}
+
+/**
+ * xmlZMemBuffExtend
+ * @buff:  Buffer used to compress and consolidate data.
+ * @ext_amt:   Number of bytes to extend the buffer.
+ *
+ * Extend the internal buffer used to store the compressed data by the
+ * specified amount.
+ *
+ * Returns 0 on success or -1 on failure to extend the buffer.  On failure
+ * the original buffer still exists at the original size.
+ */
+static int
+xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) {
+
+    int         rc = -1;
+    size_t      new_size;
+    size_t      cur_used;
+
+    unsigned char * tmp_ptr = NULL;
+
+    if ( buff == NULL )
+    return ( -1 );
+
+    else if ( ext_amt == 0 )
+    return ( 0 );
+
+    cur_used = buff->zctrl.next_out - buff->zbuff;
+    new_size = buff->size + ext_amt;
+
+#ifdef DEBUG_HTTP
+    if ( cur_used > new_size )
+    xmlGenericError( xmlGenericErrorContext,
+            "xmlZMemBuffExtend:  %s\n%s %d bytes.\n",
+            "Buffer overwrite detected during compressed memory",
+            "buffer extension.  Overflowed by",
+            (cur_used - new_size ) );
+#endif
+
+    tmp_ptr = xmlRealloc( buff->zbuff, new_size );
+    if ( tmp_ptr != NULL ) {
+    rc = 0;
+    buff->size  = new_size;
+    buff->zbuff = tmp_ptr;
+    buff->zctrl.next_out  = tmp_ptr + cur_used;
+    buff->zctrl.avail_out = new_size - cur_used;
+    }
+    else {
+    xmlChar msg[500];
+    xmlStrPrintf(msg, 500,
+            (const xmlChar *) EMBED_ERRTXT("xmlZMemBuffExtend:  %s %lu bytes.\n"),
+            EMBED_ERRTXT("Allocation failure extending output buffer to"),
+            new_size );
+    xmlIOErr(XML_IO_WRITE, (const char *) msg);
+    }
+
+    return ( rc );
+}
+
+/**
+ * xmlZMemBuffAppend
+ * @buff:  Buffer used to compress and consolidate data
+ * @src:   Uncompressed source content to append to buffer
+ * @len:   Length of source data to append to buffer
+ *
+ * Compress and append data to the internal buffer.  The data buffer
+ * will be expanded if needed to store the additional data.
+ *
+ * Returns the number of bytes appended to the buffer or -1 on error.
+ */
+static int
+xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) {
+
+    int     z_err;
+    size_t  min_accept;
+
+    if ( ( buff == NULL ) || ( src == NULL ) )
+    return ( -1 );
+
+    buff->zctrl.avail_in = len;
+    buff->zctrl.next_in  = (unsigned char *)src;
+    while ( buff->zctrl.avail_in > 0 ) {
+    /*
+    **  Extend the buffer prior to deflate call if a reasonable amount
+    **  of output buffer space is not available.
+    */
+    min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO;
+    if ( buff->zctrl.avail_out <= min_accept ) {
+        if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
+        return ( -1 );
+    }
+
+    z_err = deflate( &buff->zctrl, Z_NO_FLUSH );
+    if ( z_err != Z_OK ) {
+        xmlChar msg[500];
+        xmlStrPrintf(msg, 500,
+            (const xmlChar *) EMBED_ERRTXT("xmlZMemBuffAppend:  %s %d %s - %d"),
+            EMBED_ERRTXT("Compression error while appending"),
+            len, EMBED_ERRTXT("bytes to buffer.  ZLIB error"), z_err );
+        xmlIOErr(XML_IO_WRITE, (const char *) msg);
+        return ( -1 );
+    }
+    }
+
+    buff->crc = crc32( buff->crc, (unsigned char *)src, len );
+
+    return ( len );
+}
+
+/**
+ * xmlZMemBuffGetContent
+ * @buff:  Compressed memory content buffer
+ * @data_ref:  Pointer reference to point to compressed content
+ *
+ * Flushes the compression buffers, appends gzip file trailers and
+ * returns the compressed content and length of the compressed data.
+ * NOTE:  The gzip trailer code here is plagiarized from zlib source.
+ *
+ * Returns the length of the compressed data or -1 on error.
+ */
+static int
+xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) {
+
+    int     zlgth = -1;
+    int     z_err;
+
+    if ( ( buff == NULL ) || ( data_ref == NULL ) )
+    return ( -1 );
+
+    /*  Need to loop until compression output buffers are flushed  */
+
+    do
+    {
+    z_err = deflate( &buff->zctrl, Z_FINISH );
+    if ( z_err == Z_OK ) {
+        /*  In this case Z_OK means more buffer space needed  */
+
+        if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
+        return ( -1 );
+    }
+    }
+    while ( z_err == Z_OK );
+
+    /*  If the compression state is not Z_STREAM_END, some error occurred  */
+
+    if ( z_err == Z_STREAM_END ) {
+
+    /*  Need to append the gzip data trailer  */
+
+    if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) {
+        if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 )
+        return ( -1 );
+    }
+
+    /*
+    **  For whatever reason, the CRC and length data are pushed out
+    **  in reverse byte order.  So a memcpy can't be used here.
+    */
+
+    append_reverse_ulong( buff, buff->crc );
+    append_reverse_ulong( buff, buff->zctrl.total_in );
+
+    zlgth = buff->zctrl.next_out - buff->zbuff;
+    *data_ref = (char *)buff->zbuff;
+    }
+
+    else {
+    xmlChar msg[500];
+    xmlStrPrintf(msg, 500,
+            (const xmlChar *) EMBED_ERRTXT("xmlZMemBuffGetContent:  %s - %d\n"),
+            EMBED_ERRTXT("Error flushing zlib buffers.  Error code"), z_err );
+    xmlIOErr(XML_IO_WRITE, (const char *) msg);
+    }
+
+    return ( zlgth );
+}
+#endif /* LIBXML_OUTPUT_ENABLED */
+#endif  /*  HAVE_ZLIB_H  */
+
+#ifdef LIBXML_OUTPUT_ENABLED
+/**
+ * xmlFreeHTTPWriteCtxt
+ * @ctxt:  Context to cleanup
+ *
+ * Free allocated memory and reclaim system resources.
+ *
+ * No return value.
+ */
+static void
+xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt )
+{
+    if ( ctxt->uri != NULL )
+    xmlFree( ctxt->uri );
+
+    if ( ctxt->doc_buff != NULL ) {
+
+#ifdef HAVE_ZLIB_H
+    if ( ctxt->compression > 0 ) {
+        xmlFreeZMemBuff( ctxt->doc_buff );
+    }
+    else
+#endif
+    {
+        xmlOutputBufferClose( ctxt->doc_buff );
+    }
+    }
+
+    xmlFree( ctxt );
+    return;
+}
+#endif /* LIBXML_OUTPUT_ENABLED */
+
+
+/**
+ * xmlIOHTTPMatch:
+ * @filename:  the URI for matching
+ *
+ * check if the URI matches an HTTP one
+ *
+ * Returns 1 if matches, 0 otherwise
+ */
+int
+xmlIOHTTPMatch (const char *filename) {
+    if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "http://", 7))
+    return(1);
+    return(0);
+}
+
+/**
+ * xmlIOHTTPOpen:
+ * @filename:  the URI for matching
+ *
+ * open an HTTP I/O channel
+ *
+ * Returns an I/O context or NULL in case of error
+ */
+void *
+xmlIOHTTPOpen (const char *filename) {
+    return(xmlNanoHTTPOpen(filename, NULL));
+}
+
+#ifdef LIBXML_OUTPUT_ENABLED
+/**
+ * xmlIOHTTPOpenW:
+ * @post_uri:  The destination URI for the document
+ * @compression:  The compression desired for the document.
+ *
+ * Open a temporary buffer to collect the document for a subsequent HTTP POST
+ * request.  Non-static as is called from the output buffer creation routine.
+ *
+ * Returns an I/O context or NULL in case of error.
+ */
+
+void *
+xmlIOHTTPOpenW(const char *post_uri, int compression)
+{
+
+    xmlIOHTTPWriteCtxtPtr ctxt = NULL;
+
+    if (post_uri == NULL)
+        return (NULL);
+
+    ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt));
+    if (ctxt == NULL) {
+    xmlIOErrMemory(EMBED_ERRTXT("creating HTTP output context"));
+        return (NULL);
+    }
+
+    (void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt));
+
+    ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri);
+    if (ctxt->uri == NULL) {
+    xmlIOErrMemory(EMBED_ERRTXT("copying URI"));
+        xmlFreeHTTPWriteCtxt(ctxt);
+        return (NULL);
+    }
+
+    /*
+     * **  Since the document length is required for an HTTP post,
+     * **  need to put the document into a buffer.  A memory buffer
+     * **  is being used to avoid pushing the data to disk and back.
+     */
+
+#ifdef HAVE_ZLIB_H
+    if ((compression > 0) && (compression <= 9)) {
+
+        ctxt->compression = compression;
+        ctxt->doc_buff = xmlCreateZMemBuff(compression);
+    } else
+#endif
+    {
+        /*  Any character conversions should have been done before this  */
+
+        ctxt->doc_buff = xmlAllocOutputBuffer(NULL);
+    }
+
+    if (ctxt->doc_buff == NULL) {
+        xmlFreeHTTPWriteCtxt(ctxt);
+        ctxt = NULL;
+    }
+
+    return (ctxt);
+}
+#endif /* LIBXML_OUTPUT_ENABLED */
+
+#ifdef LIBXML_OUTPUT_ENABLED
+/**
+ * xmlIOHTTPDfltOpenW
+ * @post_uri:  The destination URI for this document.
+ *
+ * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
+ * HTTP post command.  This function should generally not be used as
+ * the open callback is short circuited in xmlOutputBufferCreateFile.
+ *
+ * Returns a pointer to the new IO context.
+ */
+static void *
+xmlIOHTTPDfltOpenW( const char * post_uri ) {
+    return ( xmlIOHTTPOpenW( post_uri, 0 ) );
+}
+#endif /* LIBXML_OUTPUT_ENABLED */
+
+/**
+ * xmlIOHTTPRead:
+ * @context:  the I/O context
+ * @buffer:  where to drop data
+ * @len:  number of bytes to write
+ *
+ * Read @len bytes to @buffer from the I/O channel.
+ *
+ * Returns the number of bytes written
+ */
+int
+xmlIOHTTPRead(void * context, char * buffer, int len) {
+    return(xmlNanoHTTPRead(context, &buffer[0], len));
+}
+
+#ifdef LIBXML_OUTPUT_ENABLED
+/**
+ * xmlIOHTTPWrite
+ * @context:  previously opened writing context
+ * @buffer:   data to output to temporary buffer
+ * @len:      bytes to output
+ *
+ * Collect data from memory buffer into a temporary file for later
+ * processing.
+ *
+ * Returns number of bytes written.
+ */
+
+static int
+xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
+
+    xmlIOHTTPWriteCtxtPtr   ctxt = context;
+
+    if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
+    return ( -1 );
+
+    if ( len > 0 ) {
+
+    /*  Use gzwrite or fwrite as previously setup in the open call  */
+
+#ifdef HAVE_ZLIB_H
+    if ( ctxt->compression > 0 )
+        len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len );
+
+    else
+#endif
+        len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
+
+    if ( len < 0 ) {
+        xmlChar msg[500];
+        xmlStrPrintf(msg, 500,
+            (const xmlChar *) EMBED_ERRTXT("xmlIOHTTPWrite:  %s\n%s '%s'.\n"),
+            EMBED_ERRTXT("Error appending to internal buffer."),
+            EMBED_ERRTXT("Error sending document to URI"),
+            ctxt->uri );
+        xmlIOErr(XML_IO_WRITE, (const char *) msg);
+    }
+    }
+
+    return ( len );
+}
+#endif /* LIBXML_OUTPUT_ENABLED */
+
+
+/**
+ * xmlIOHTTPClose:
+ * @context:  the I/O context
+ *
+ * Close an HTTP I/O channel
+ *
+ * Returns 0
+ */
+int
+xmlIOHTTPClose (void * context) {
+    xmlNanoHTTPClose(context);
+    return 0;
+}
+
+#ifdef LIBXML_OUTPUT_ENABLED
+/**
+ * xmlIOHTTCloseWrite
+ * @context:  The I/O context
+ * @http_mthd: The HTTP method to be used when sending the data
+ *
+ * Close the transmit HTTP I/O channel and actually send the data.
+ */
+static int
+xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
+
+    int             close_rc = -1;
+    int             http_rtn = 0;
+    int             content_lgth = 0;
+    xmlIOHTTPWriteCtxtPtr   ctxt = context;
+
+    char *          http_content = NULL;
+    char *          content_encoding = NULL;
+    char *          content_type = (char *) "text/xml";
+    void *          http_ctxt = NULL;
+
+    if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
+    return ( -1 );
+
+    /*  Retrieve the content from the appropriate buffer  */
+
+#ifdef HAVE_ZLIB_H
+
+    if ( ctxt->compression > 0 ) {
+    content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
+    content_encoding = (char *) "Content-Encoding: gzip";
+    }
+    else
+#endif
+    {
+    /*  Pull the data out of the memory output buffer  */
+
+    xmlOutputBufferPtr  dctxt = ctxt->doc_buff;
+    http_content = (char *)dctxt->buffer->content;
+    content_lgth = dctxt->buffer->use;
+    }
+
+    if ( http_content == NULL ) {
+    xmlChar msg[500];
+    xmlStrPrintf(msg, 500,
+             (const xmlChar *) EMBED_ERRTXT("xmlIOHTTPCloseWrite:  %s '%s' %s '%s'.\n"),
+             EMBED_ERRTXT("Error retrieving content.\nUnable to"),
+             http_mthd, EMBED_ERRTXT("data to URI"), ctxt->uri );
+    xmlIOErr(XML_IO_WRITE, (const char *) msg);
+    }
+
+    else {
+
+    http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
+                    &content_type, content_encoding,
+                    content_lgth );
+
+    if ( http_ctxt != NULL ) {
+#ifdef DEBUG_HTTP
+        /*  If testing/debugging - dump reply with request content  */
+
+        FILE *  tst_file = NULL;
+        char    buffer[ 4096 ];
+        char *  dump_name = NULL;
+        int     avail;
+
+        xmlGenericError( xmlGenericErrorContext,
+            "xmlNanoHTTPCloseWrite:  HTTP %s to\n%s returned %d.\n",
+            http_mthd, ctxt->uri,
+            xmlNanoHTTPReturnCode( http_ctxt ) );
+
+        /*
+        **  Since either content or reply may be gzipped,
+        **  dump them to separate files instead of the
+        **  standard error context.
+        */
+
+        dump_name = tempnam( NULL, "lxml" );
+        if ( dump_name != NULL ) {
+        (void)snprintf( buffer, sizeof(buffer), "%s.content", dump_name );
+
+        tst_file = fopen( buffer, "wb" );
+        if ( tst_file != NULL ) {
+            xmlGenericError( xmlGenericErrorContext,
+            "Transmitted content saved in file:  %s\n", buffer );
+
+            fwrite( http_content, sizeof( char ),
+                    content_lgth, tst_file );
+            fclose( tst_file );
+        }
+
+        (void)snprintf( buffer, sizeof(buffer), "%s.reply", dump_name );
+        tst_file = fopen( buffer, "wb" );
+        if ( tst_file != NULL ) {
+            xmlGenericError( xmlGenericErrorContext,
+            "Reply content saved in file:  %s\n", buffer );
+
+
+            while ( (avail = xmlNanoHTTPRead( http_ctxt,
+                    buffer, sizeof( buffer ) )) > 0 ) {
+
+            fwrite( buffer, sizeof( char ), avail, tst_file );
+            }
+
+            fclose( tst_file );
+        }
+
+        free( dump_name );
+        }
+#endif  /*  DEBUG_HTTP  */
+
+        http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
+        if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
+        close_rc = 0;
+        else {
+                xmlChar msg[500];
+                xmlStrPrintf(msg, 500,
+    (const xmlChar *) EMBED_ERRTXT("xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n"),
+                http_mthd, content_lgth,
+                EMBED_ERRTXT("bytes to URI"), ctxt->uri,
+                EMBED_ERRTXT("failed.  HTTP return code:"), http_rtn );
+        xmlIOErr(XML_IO_WRITE, (const char *) msg);
+            }
+
+        xmlNanoHTTPClose( http_ctxt );
+        xmlFree( content_type );
+    }
+    }
+
+    /*  Final cleanups  */
+
+    xmlFreeHTTPWriteCtxt( ctxt );
+
+    return ( close_rc );
+}
+
+/**
+ * xmlIOHTTPClosePut
+ *
+ * @context:  The I/O context
+ *
+ * Close the transmit HTTP I/O channel and actually send data using a PUT
+ * HTTP method.
+ */
+static int
+xmlIOHTTPClosePut( void * ctxt ) {
+    return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
+}
+
+
+/**
+ * xmlIOHTTPClosePost
+ *
+ * @context:  The I/O context
+ *
+ * Close the transmit HTTP I/O channel and actually send data using a POST
+ * HTTP method.
+ */
+static int
+xmlIOHTTPClosePost( void * ctxt ) {
+    return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
+}
+#endif /* LIBXML_OUTPUT_ENABLED */
+
+#endif /* LIBXML_HTTP_ENABLED */
+
+#ifdef LIBXML_FTP_ENABLED
+/************************************************************************
+ *                                  *
+ *          I/O for FTP file accesses           *
+ *                                  *
+ ************************************************************************/
+/**
+ * xmlIOFTPMatch:
+ * @filename:  the URI for matching
+ *
+ * check if the URI matches an FTP one
+ *
+ * Returns 1 if matches, 0 otherwise
+ */
+int
+xmlIOFTPMatch (const char *filename) {
+    if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "ftp://", 6))
+    return(1);
+    return(0);
+}
+
+/**
+ * xmlIOFTPOpen:
+ * @filename:  the URI for matching
+ *
+ * open an FTP I/O channel
+ *
+ * Returns an I/O context or NULL in case of error
+ */
+void *
+xmlIOFTPOpen (const char *filename) {
+    return(xmlNanoFTPOpen(filename));
+}
+
+/**
+ * xmlIOFTPRead:
+ * @context:  the I/O context
+ * @buffer:  where to drop data
+ * @len:  number of bytes to write
+ *
+ * Read @len bytes to @buffer from the I/O channel.
+ *
+ * Returns the number of bytes written
+ */
+int
+xmlIOFTPRead(void * context, char * buffer, int len) {
+    return(xmlNanoFTPRead(context, &buffer[0], len));
+}
+
+/**
+ * xmlIOFTPClose:
+ * @context:  the I/O context
+ *
+ * Close an FTP I/O channel
+ *
+ * Returns 0
+ */
+int
+xmlIOFTPClose (void * context) {
+    return ( xmlNanoFTPClose(context) );
+}
+#endif /* LIBXML_FTP_ENABLED */
+
+
+/**
+ * xmlRegisterInputCallbacks:
+ * @matchFunc:  the xmlInputMatchCallback
+ * @openFunc:  the xmlInputOpenCallback
+ * @readFunc:  the xmlInputReadCallback
+ * @closeFunc:  the xmlInputCloseCallback
+ *
+ * Register a new set of I/O callback for handling parser input.
+ *
+ * Returns the registered handler number or -1 in case of error
+ *
+ * OOM: never
+ */
+int
+xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
+    xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
+    xmlInputCloseCallback closeFunc) {
+    if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
+        return(-1);
+    }
+    xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
+    xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
+    xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
+    xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
+    xmlInputCallbackInitialized = 1;
+    return(xmlInputCallbackNr++);
+}
+
+#ifdef LIBXML_OUTPUT_ENABLED
+/**
+ * xmlRegisterOutputCallbacks:
+ * @matchFunc:  the xmlOutputMatchCallback
+ * @openFunc:   the xmlOutputOpenCallback
+ * @writeFunc:  the xmlOutputWriteCallback
+ * @closeFunc:  the xmlOutputCloseCallback
+ *
+ * Register a new set of I/O callback for handling output.
+ *
+ * Returns the registered handler number or -1 in case of error
+ *
+ * OOM: never
+ */
+int
+xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
+    xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
+    xmlOutputCloseCallback closeFunc) {
+    if (xmlOutputCallbackNr >= MAX_INPUT_CALLBACK) {
+        return(-1);
+    }
+    // TODO: Optimize: reuse xmlOutputCallbackTable[xmlOutputCallbackNr]
+    xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
+    xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
+    xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
+    xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
+    xmlOutputCallbackInitialized = 1;
+    return(xmlOutputCallbackNr++);
+}
+#endif /* LIBXML_OUTPUT_ENABLED */
+
+/**
+ * xmlRegisterDefaultInputCallbacks:
+ *
+ * Registers the default compiled-in I/O handlers.
+ *
+ * OOM: never
+ */
+void
+xmlRegisterDefaultInputCallbacks
+(void) {
+    if (xmlInputCallbackInitialized){
+        // TODO: compilation error
+        return;
+        }
+
+    xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
+                          xmlFileRead, xmlFileClose);
+#ifdef HAVE_ZLIB_H
+    xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
+                          xmlGzfileRead, xmlGzfileClose);
+#endif /* HAVE_ZLIB_H */
+
+//#ifdef LIBXML_HTTP_ENABLED
+//    xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
+//                        xmlIOHTTPRead, xmlIOHTTPClose);
+//#endif /* LIBXML_HTTP_ENABLED */
+//
+//#ifdef LIBXML_FTP_ENABLED
+//    xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
+//                        xmlIOFTPRead, xmlIOFTPClose);
+//#endif /* LIBXML_FTP_ENABLED */
+    xmlInputCallbackInitialized = 1;
+}
+
+#ifdef LIBXML_OUTPUT_ENABLED
+/**
+ * xmlRegisterDefaultOutputCallbacks:
+ *
+ * Registers the default compiled-in I/O handlers.
+ *
+ * OOM: never (at least as far as initial size of table is enough)
+ */
+void
+xmlRegisterDefaultOutputCallbacks(void) {
+    if (xmlOutputCallbackInitialized)
+        return;
+    xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
+                               xmlFileWrite, xmlFileClose);
+#ifdef LIBXML_HTTP_ENABLED
+    xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
+                         xmlIOHTTPWrite, xmlIOHTTPClosePut);
+#endif
+
+/*********************************
+ No way a-priori to distinguish between gzipped files from
+ uncompressed ones except opening if existing then closing
+ and saving with same compression ratio ... a pain.
+
+#ifdef HAVE_ZLIB_H
+    xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
+                           xmlGzfileWrite, xmlGzfileClose);
+#endif
+
+ Nor FTP PUT ....
+#ifdef LIBXML_FTP_ENABLED
+    xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
+                           xmlIOFTPWrite, xmlIOFTPClose);
+#endif
+ **********************************/
+    xmlOutputCallbackInitialized = 1;
+}
+
+#ifdef LIBXML_HTTP_ENABLED
+/**
+ * xmlRegisterHTTPPostCallbacks:
+ *
+ * By default, libxml submits HTTP output requests using the "PUT" method.
+ * Calling this method changes the HTTP output method to use the "POST"
+ * method instead.
+ *
+ */
+void
+xmlRegisterHTTPPostCallbacks( void ) {
+
+    /*  Register defaults if not done previously  */
+
+    if ( xmlOutputCallbackInitialized == 0 )
+    xmlRegisterDefaultOutputCallbacks( );
+
+    xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
+                           xmlIOHTTPWrite, xmlIOHTTPClosePost);
+    return;
+}
+#endif
+#endif /* LIBXML_OUTPUT_ENABLED */
+
+/**
+ * xmlAllocParserInputBuffer:
+ * @enc:  the charset encoding if known
+ *
+ * Create a buffered parser input for progressive parsing
+ *
+ * Returns the new parser input or NULL
+ *
+ * OOM: possible --> NULL returned and OOM flag is set
+ */
+xmlParserInputBufferPtr
+xmlAllocParserInputBuffer(xmlCharEncoding enc) {
+    xmlParserInputBufferPtr ret;
+
+    ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
+    if (ret == NULL) {
+        xmlIOErrMemory(EMBED_ERRTXT("creating input buffer"));
+        return(NULL);
+    }
+    memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
+    ret->buffer = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
+    if (! ret->buffer) 
+        goto OOM;
+    // TODO: OPTIMIZE: Use more intelligent reallocation scheme
+    ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
+    ret->encoder = xmlGetCharEncodingHandler(enc);
+
+   if(OOM_FLAG)
+        goto OOM;
+
+    if (ret->encoder != NULL){
+        ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize); // sets OOM flag
+        if(! ret->raw)
+            goto OOM;
+    }else{
+        ret->raw = NULL;
+    }
+    ret->readcallback = NULL;
+    ret->closecallback = NULL;
+    ret->context = NULL;
+    ret->compressed = -1;
+    ret->rawconsumed = 0;
+
+    return(ret);
+//-------------------
+OOM:
+    xmlFreeParserInputBuffer(ret);
+    return NULL;
+}
+
+#ifdef LIBXML_OUTPUT_ENABLED
+/**
+ * xmlAllocOutputBuffer:
+ * @encoder:  the encoding converter or NULL
+ *
+ * Create a buffered parser output
+ *
+ * Returns the new parser output or NULL
+ *
+ * OOM: possible --> NULL is returned && OOM flag is set
+ * TODO: xmlCharEncOutFunc has unknown OOM status when encoder!=NULL
+ */
+xmlOutputBufferPtr
+xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
+    xmlOutputBufferPtr ret;
+
+    ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
+    if (ret == NULL) {
+        xmlIOErrMemory(EMBED_ERRTXT("creating output buffer"));
+        return(NULL);
+    }
+    memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
+    ret->buffer = xmlBufferCreate();
+    if (ret->buffer == NULL) {
+        xmlFree(ret);
+        return(NULL);
+    }
+    ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
+    ret->encoder = encoder;
+    if (encoder != NULL) {
+        // TODO: OPTIMIZE: "magic number" - make a controllable parameter
+        ret->conv = xmlBufferCreateSize(4000);
+        /*
+        * This call is designed to initiate the encoder state
+        */
+        xmlCharEncOutFunc(encoder, ret->conv, NULL); // may set OOM flag
+    } else
+        ret->conv = NULL;
+    ret->writecallback = NULL;
+    ret->closecallback = NULL;
+    ret->context = NULL;
+    ret->written = 0;
+
+    return(ret);
+}
+#endif /* LIBXML_OUTPUT_ENABLED */
+
+/**
+ * xmlFreeParserInputBuffer:
+ * @in:  a buffered parser input
+ *
+ * Free up the memory used by a buffered parser input
+ *
+ * OOM: never // TODO: check status returned by callbacks
+ */
+void
+xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
+    if (in == NULL) return;
+
+    if (in->raw) {
+        xmlBufferFree(in->raw);
+        in->raw = NULL;
+    }
+    if (in->encoder != NULL) {
+        xmlCharEncCloseFunc(in->encoder);
+    }
+    if (in->closecallback != NULL) {
+        in->closecallback(in->context);
+    }
+    if (in->buffer != NULL) {
+        xmlBufferFree(in->buffer);
+        in->buffer = NULL;
+    }
+
+    xmlFree(in);
+}
+
+#ifdef LIBXML_OUTPUT_ENABLED
+/**
+ * xmlOutputBufferClose:
+ * @out:  a buffered output
+ *
+ * flushes and close the output I/O channel
+ * and free up all the associated resources
+ *
+ * Returns the number of byte written or -1 in case of error.
+ */
+int
+xmlOutputBufferClose(xmlOutputBufferPtr out)
+{
+    int written;
+    int err_rc = 0; // TODO: put
+
+    if (!out)
+        return (-1);
+    if (out->writecallback != NULL)
+        xmlOutputBufferFlush(out);
+    if (out->closecallback != NULL) {
+        err_rc = out->closecallback(out->context);
+    }
+    written = out->written;
+    if (out->conv) {
+        xmlBufferFree(out->conv);
+        out->conv = NULL;
+    }
+    if (out->encoder != NULL) {
+        xmlCharEncCloseFunc(out->encoder);
+    }
+    if (out->buffer != NULL) {
+        xmlBufferFree(out->buffer);
+        out->buffer = NULL;
+    }
+
+    if (out->error)
+        err_rc = -1;
+    xmlFree(out);
+    return ((err_rc == 0) ? written : err_rc);
+}
+#endif /* LIBXML_OUTPUT_ENABLED */
+
+/**
+ * xmlParserInputBufferCreateFilename:
+ * @URI:  a C string containing the URI or filename
+ * @enc:  the charset encoding if known
+ *
+ * Create a buffered parser input for the progressive parsing of a file
+ * If filename is "-' then we use stdin as the input.
+ * Automatic support for ZLIB/Compress compressed document is provided
+ * by default if found at compile-time.
+ * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
+ *
+ * Returns the new parser input or NULL
+ */
+xmlParserInputBufferPtr
+xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
+    xmlParserInputBufferPtr ret;
+    int i = 0;
+    void *context = NULL;
+
+    if (xmlInputCallbackInitialized == 0)
+    xmlRegisterDefaultInputCallbacks();
+
+    if (URI == NULL) return(NULL);
+
+    /*
+     * Try to find one of the input accept method accepting that scheme
+     * Go in reverse to give precedence to user defined handlers.
+     */
+    if (context == NULL) {
+    for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
+        if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
+        (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
+        context = xmlInputCallbackTable[i].opencallback(URI);
+        if (context != NULL) {
+            break;
+        }
+        }
+    }
+    }
+    if (context == NULL) {
+    return(NULL);
+    }
+
+    /*
+     * Allocate the Input buffer front-end.
+     */
+    ret = xmlAllocParserInputBuffer(enc);
+    if (ret != NULL) {
+    ret->context = context;
+    ret->readcallback = xmlInputCallbackTable[i].readcallback;
+    ret->closecallback = xmlInputCallbackTable[i].closecallback;
+#ifdef HAVE_ZLIB_H
+    if ((xmlInputCallbackTable[i].opencallback == xmlGzfileOpen) &&
+        (strcmp(URI, "-") != 0)) {
+        if (((z_stream *)context)->avail_in > 4) {
+            char *cptr, buff4[4];
+        cptr = (char *) ((z_stream *)context)->next_in;
+        if (gzread(context, buff4, 4) == 4) {
+            if (strncmp(buff4, cptr, 4) == 0)
+                ret->compressed = 0;
+            else
+                ret->compressed = 1;
+            gzrewind(context);
+        }
+        }
+    }
+#endif
+    }
+    return(ret);
+}
+
+#ifdef LIBXML_OUTPUT_ENABLED
+/**
+ * xmlOutputBufferCreateFilename:
+ * @URI:  a C string containing the URI or filename
+ * @encoder:  the encoding converter or NULL
+ * @compression:  the compression ration (0 none, 9 max).
+ *
+ * Create a buffered  output for the progressive saving of a file
+ * If filename is "-' then we use stdout as the output.
+ * Automatic support for ZLIB/Compress compressed document is provided
+ * by default if found at compile-time.
+ * TODO: currently if compression is set, the library only support
+ *       writing to a local file.
+ *
+ * Returns the new output or NULL
+ */
+xmlOutputBufferPtr
+xmlOutputBufferCreateFilename(const char *URI,
+								xmlCharEncodingHandlerPtr encoder,
+								int compression ATTRIBUTE_UNUSED) {
+    xmlOutputBufferPtr ret;
+    xmlURIPtr puri;
+    int i = 0;
+    void *context = NULL;
+    char *unescaped = NULL;
+    int is_file_uri = 1;
+
+    if (xmlOutputCallbackInitialized == 0)
+        xmlRegisterDefaultOutputCallbacks();
+
+    if (URI == NULL) return(NULL);
+
+    puri = xmlParseURI(URI);
+    if (!puri)
+        return NULL;
+        if ((puri->scheme != NULL) &&
+            (!xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
+            is_file_uri = 0;
+    /*
+     * try to limit the damages of the URI unescaping code.
+     */
+    if (puri->scheme != NULL)
+        {
+        unescaped = xmlURIUnescapeString(URI, 0, NULL);
+        // TODO: Check OOM, free resources, quit early
+        }
+    xmlFreeURI(puri);
+
+
+    /*
+     * Try to find one of the output accept method accepting that scheme
+     * Go in reverse to give precedence to user defined handlers.
+     * try with an unescaped version of the URI
+     */
+    if (unescaped != NULL) {
+#ifdef HAVE_ZLIB_H
+    if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
+        context = xmlGzfileOpenW(unescaped, compression);
+        if (context != NULL) {
+        ret = xmlAllocOutputBuffer(encoder);
+        if (ret != NULL) {
+            ret->context = context;
+            ret->writecallback = xmlGzfileWrite;
+            ret->closecallback = xmlGzfileClose;
+        }
+        xmlFree(unescaped);
+        return(ret);
+        }
+    }
+#endif
+    for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
+        if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
+        (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
+#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
+        /*  Need to pass compression parameter into HTTP open calls  */
+        if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
+            context = xmlIOHTTPOpenW(unescaped, compression);
+        else
+#endif
+            context = xmlOutputCallbackTable[i].opencallback(unescaped);
+        if (context != NULL)
+            break;
+        }
+    }
+    xmlFree(unescaped);
+    }
+
+    /*
+     * If this failed try with a non-escaped URI this may be a strange
+     * filename
+     */
+    if (context == NULL) {
+#ifdef HAVE_ZLIB_H
+    if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
+        context = xmlGzfileOpenW(URI, compression);
+        if (context != NULL) {
+        ret = xmlAllocOutputBuffer(encoder);
+        if (ret != NULL) {
+            ret->context = context;
+            ret->writecallback = xmlGzfileWrite;
+            ret->closecallback = xmlGzfileClose;
+        }
+        return(ret);
+        }
+    }
+#endif
+    for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
+        if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
+        (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
+#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
+        /*  Need to pass compression parameter into HTTP open calls  */
+        if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
+            context = xmlIOHTTPOpenW(URI, compression);
+        else
+#endif
+            context = xmlOutputCallbackTable[i].opencallback(URI);
+        if (context != NULL)
+            break;
+        }
+    }
+    }
+
+    if (context == NULL) {
+        return(NULL);
+    }
+
+    /*
+     * Allocate the Output buffer front-end.
+     */
+    ret = xmlAllocOutputBuffer(encoder);
+    if (ret != NULL) {
+        ret->context = context;
+        ret->writecallback = xmlOutputCallbackTable[i].writecallback;
+        ret->closecallback = xmlOutputCallbackTable[i].closecallback;
+    }
+    return(ret);
+}
+#endif /* LIBXML_OUTPUT_ENABLED */
+
+#ifndef XMLENGINE_EXCLUDE_FILE_FUNC
+/**
+ * xmlParserInputBufferCreateFile:
+ * @file:  a FILE*
+ * @enc:  the charset encoding if known
+ *
+ * Create a buffered parser input for the progressive parsing of a FILE *
+ * buffered C I/O
+ *
+ * Returns the new parser input or NULL
+ */
+xmlParserInputBufferPtr
+xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
+    xmlParserInputBufferPtr ret;
+
+    if (xmlInputCallbackInitialized == 0)
+    xmlRegisterDefaultInputCallbacks();
+
+    if (file == NULL) return(NULL);
+
+    ret = xmlAllocParserInputBuffer(enc);
+    if (ret != NULL) {
+        ret->context = file;
+    ret->readcallback = xmlFileRead;
+    ret->closecallback = xmlFileFlush;
+    }
+
+    return(ret);
+}
+#endif
+
+#ifdef LIBXML_OUTPUT_ENABLED
+/**
+ * xmlOutputBufferCreateFile:
+ * @file:  a FILE*
+ * @encoder:  the encoding converter or NULL
+ *
+ * Create a buffered output for the progressive saving to a FILE *
+ * buffered C I/O
+ *
+ * Returns the new parser output or NULL
+ */
+xmlOutputBufferPtr
+xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
+    xmlOutputBufferPtr ret;
+
+    if (xmlOutputCallbackInitialized == 0)
+    xmlRegisterDefaultOutputCallbacks();
+
+    if (file == NULL) return(NULL);
+
+    ret = xmlAllocOutputBuffer(encoder);
+
+    CHECK_OOM(ret); // return NULL if OOM
+
+    ret->context = file;
+    ret->writecallback = xmlFileWrite;
+    ret->closecallback = xmlFileFlush;
+
+    return(ret);
+}
+#endif /* LIBXML_OUTPUT_ENABLED */
+
+
+/**
+ * xmlParserInputBufferCreateFd:
+ * @fd:  a file descriptor number
+ * @enc:  the charset encoding if known
+ *
+ * Create a buffered parser input for the progressive parsing for the input
+ * from a file descriptor
+ *
+ * Returns the new parser input or NULL
+ */
+xmlParserInputBufferPtr
+xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
+    xmlParserInputBufferPtr ret;
+
+    if (fd < 0) return(NULL);
+
+    ret = xmlAllocParserInputBuffer(enc);
+    if (ret != NULL) {
+        ret->context = (void *) (long) fd;
+    ret->readcallback = xmlFdRead;
+    ret->closecallback = xmlFdClose;
+    }
+
+    return(ret);
+}
+
+/**
+ * xmlParserInputBufferCreateMem:
+ * @mem:  the memory input
+ * @size:  the length of the memory block
+ * @enc:  the charset encoding if known
+ *
+ * Create a buffered parser input for the progressive parsing for the input
+ * from a memory area.
+ *
+ * Returns the new parser input or NULL
+ *
+ * OOM: possible --> sets OOM flag, returns NULL for mem!=NULL && size>0
+ */ 
+xmlParserInputBufferPtr
+xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
+    xmlParserInputBufferPtr ret;
+
+    if (size <= 0) return(NULL);
+    if (mem == NULL) return(NULL);
+
+    ret = xmlAllocParserInputBuffer(enc);
+    if (ret != NULL) {
+        ret->context = (void*) mem;
+        ret->readcallback = (xmlInputReadCallback) xmlNop;
+        ret->closecallback = NULL;
+        xmlBufferAdd(ret->buffer, (const xmlChar*) mem, size);
+        if(OOM_FLAG){
+            xmlFreeParserInputBuffer(ret);
+            return NULL;
+        }
+    }
+
+    return(ret);
+}
+
+/**
+ * xmlParserInputBufferCreateStatic:
+ * @mem:  the memory input
+ * @size:  the length of the memory block
+ * @enc:  the charset encoding if known
+ *
+ * Create a buffered parser input for the progressive parsing for the input
+ * from an immutable memory area. This will not copy the memory area to
+ * the buffer, but the memory is expected to be available until the end of
+ * the parsing, this is useful for example when using mmap'ed file.
+ *
+ * Returns the new parser input or NULL
+ */
+xmlParserInputBufferPtr
+xmlParserInputBufferCreateStatic(const char *mem, int size,
+                                 xmlCharEncoding enc) {
+    xmlParserInputBufferPtr ret;
+
+    if (size <= 0) return(NULL);
+    if (mem == NULL) return(NULL);
+
+    ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
+    if (ret == NULL) {
+    xmlIOErrMemory(EMBED_ERRTXT("creating input buffer"));
+    return(NULL);
+    }
+    memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
+    ret->buffer = xmlBufferCreateStatic((void *)mem, (size_t) size);
+    if (ret->buffer == NULL) {
+        xmlFree(ret);
+    return(NULL);
+    }
+    ret->encoder = xmlGetCharEncodingHandler(enc);
+    if (ret->encoder != NULL)
+        ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
+    else
+        ret->raw = NULL;
+    ret->compressed = -1;
+    ret->context = (void *) mem;
+    ret->readcallback = NULL;
+    ret->closecallback = NULL;
+
+    return(ret);
+}
+
+#ifdef LIBXML_OUTPUT_ENABLED
+/**
+ * xmlOutputBufferCreateFd:
+ * @fd:  a file descriptor number
+ * @encoder:  the encoding converter or NULL
+ *
+ * Create a buffered output for the progressive saving
+ * to a file descriptor
+ *
+ * Returns the new parser output or NULL
+ */
+xmlOutputBufferPtr
+xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
+    xmlOutputBufferPtr ret;
+
+    if (fd < 0) return(NULL);
+
+    ret = xmlAllocOutputBuffer(encoder);
+    if (ret != NULL) {
+        ret->context = (void *) (long) fd;
+    ret->writecallback = xmlFdWrite;
+    ret->closecallback = NULL;
+    }
+
+    return(ret);
+}
+#endif /* LIBXML_OUTPUT_ENABLED */
+
+/**
+ * xmlParserInputBufferCreateIO:
+ * @ioread:  an I/O read function
+ * @ioclose:  an I/O close function
+ * @ioctx:  an I/O handler
+ * @enc:  the charset encoding if known
+ *
+ * Create a buffered parser input for the progressive parsing for the input
+ * from an I/O handler
+ *
+ * Returns the new parser input or NULL
+ */
+xmlParserInputBufferPtr
+xmlParserInputBufferCreateIO(xmlInputReadCallback   ioread,
+     xmlInputCloseCallback  ioclose, void *ioctx, xmlCharEncoding enc) {
+    xmlParserInputBufferPtr ret;
+
+    if (ioread == NULL) return(NULL);
+
+    ret = xmlAllocParserInputBuffer(enc);
+    if (ret != NULL) {
+        ret->context = (void *) ioctx;
+    ret->readcallback = ioread;
+    ret->closecallback = ioclose;
+    }
+
+    return(ret);
+}
+
+#ifdef LIBXML_OUTPUT_ENABLED
+/**
+ * xmlOutputBufferCreateIO:
+ * @iowrite:  an I/O write function
+ * @ioclose:  an I/O close function
+ * @ioctx:  an I/O handler
+ * @encoder:  the charset encoding if known
+ *
+ * Create a buffered output for the progressive saving
+ * to an I/O handler
+ *
+ * Returns the new parser output or NULL
+ */
+xmlOutputBufferPtr
+xmlOutputBufferCreateIO(xmlOutputWriteCallback   iowrite,
+     xmlOutputCloseCallback  ioclose, void *ioctx,
+     xmlCharEncodingHandlerPtr encoder) {
+    xmlOutputBufferPtr ret;
+
+    if (iowrite == NULL) return(NULL);
+
+    ret = xmlAllocOutputBuffer(encoder);
+    if (ret != NULL) {
+        ret->context = (void *) ioctx;
+    ret->writecallback = iowrite;
+    ret->closecallback = ioclose;
+    }
+
+    return(ret);
+}
+#endif /* LIBXML_OUTPUT_ENABLED */
+
+/**
+ * xmlParserInputBufferPush:
+ * @in:  a buffered parser input
+ * @len:  the size in bytes of the array.
+ * @buf:  an char array
+ *
+ * Push the content of the arry in the input buffer
+ * This routine handle the I18N transcoding to internal UTF-8
+ * This is used when operating the parser in progressive (push) mode.
+ *
+ * Returns the number of chars read and stored in the buffer, or -1
+ *         in case of error.
+ */
+int
+xmlParserInputBufferPush(xmlParserInputBufferPtr in,
+                     int len, const char *buf) {
+    int nbchars = 0;
+
+    if (len < 0) return(0);
+    if ((in == NULL) || (in->error)) return(-1);
+    if (in->encoder != NULL) {
+        unsigned int use;
+
+        /*
+     * Store the data in the incoming raw buffer
+     */
+        if (in->raw == NULL) {
+        in->raw = xmlBufferCreate();
+    }
+    xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
+
+    /*
+     * convert as much as possible to the parser reading buffer.
+     */
+    use = in->raw->use;
+    nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
+    if (nbchars < 0) {
+        xmlIOErr(XML_IO_ENCODER, NULL);
+        in->error = XML_IO_ENCODER;
+        return(-1);
+    }
+    in->rawconsumed += (use - in->raw->use);
+    } else {
+    nbchars = len;
+        xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
+    }
+#ifdef DEBUG_INPUT
+    xmlGenericError(xmlGenericErrorContext,
+        "I/O: pushed %d chars, buffer %d/%d\n",
+            nbchars, in->buffer->use, in->buffer->size);
+#endif
+    return(nbchars);
+}
+
+/**
+ * endOfInput:
+ *
+ * When reading from an Input channel indicated end of file or error
+ * don't reread from it again.
+ */
+static int
+endOfInput (
+        void* context ATTRIBUTE_UNUSED,
+        char* buffer ATTRIBUTE_UNUSED,
+        int len ATTRIBUTE_UNUSED) {
+    return(0);
+}
+
+/**
+ * xmlParserInputBufferGrow:
+ * @in:  a buffered parser input
+ * @len:  indicative value of the amount of chars to read
+ *
+ * Grow up the content of the input buffer, the old data are preserved
+ * This routine handle the I18N transcoding to internal UTF-8
+ * This routine is used when operating the parser in normal (pull) mode
+ *
+ * TODO: one should be able to remove one extra copy by copying directly
+ *       onto in->buffer or in->raw
+ *
+ * Returns the number of chars read and stored in the buffer, or -1
+ *         in case of error.
+ *
+ * OOM: possible --> sets OOM flag when returns 0
+ */
+int
+xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
+    char *buffer = NULL;
+    int res = 0;
+    int nbchars = 0;
+    int buffree;
+    unsigned int needSize;
+
+    if ((in == NULL) || (in->error)) return(-1);
+    if ((len <= MINLEN) && (len != 4))
+        len = MINLEN;
+
+    buffree = in->buffer->size - in->buffer->use;
+    if (buffree <= 0) {
+        xmlIOErr(XML_IO_BUFFER_FULL, NULL);
+        in->error = XML_IO_BUFFER_FULL;
+        return(0);
+    }
+
+    needSize = in->buffer->use + len + 1;
+    if (needSize > in->buffer->size)
+    {
+        if (!xmlBufferResize(in->buffer, needSize))
+        {
+            xmlIOErrMemory(EMBED_ERRTXT("growing input buffer"));
+            in->error = XML_ERR_NO_MEMORY;
+            return(0);
+        }
+    }
+    buffer = (char *)&in->buffer->content[in->buffer->use];
+
+    /*
+     * Call the read method for this I/O type.
+     */
+    if (in->readcallback != NULL) {
+        // TODO: Callbacks may need to notify parser about OOM or other errors
+        res = in->readcallback(in->context, &buffer[0], len);
+        if (res <= 0)
+            in->readcallback = endOfInput;
+    } else {
+        xmlIOErr(XML_IO_NO_INPUT, NULL);
+        in->error = XML_IO_NO_INPUT;
+        return(-1);
+    }
+    if (res < 0) {
+        return(-1);
+    }
+    len = res;
+    if (in->encoder != NULL) {
+        unsigned int use;
+
+        /*
+        * Store the data in the incoming raw buffer
+        */
+        if (in->raw == NULL) {
+            in->raw = xmlBufferCreate();
+            if(OOM_FLAG)
+                return 0;
+        }
+        xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
+        if(OOM_FLAG)
+            return 0;
+        /*
+        * convert as much as possible to the parser reading buffer.
+        */
+        use = in->raw->use;
+        nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
+        if(OOM_FLAG)
+            return 0;
+
+        if (nbchars < 0) {
+            xmlIOErr(XML_IO_ENCODER, NULL);
+            in->error = XML_IO_ENCODER;
+            return(-1);
+        }
+        in->rawconsumed += (use - in->raw->use);
+    } else {
+        nbchars = len;
+        in->buffer->use += nbchars;
+        buffer[nbchars] = 0;
+    }
+#ifdef DEBUG_INPUT
+    xmlGenericError(xmlGenericErrorContext,
+        "I/O: read %d chars, buffer %d/%d\n",
+            nbchars, in->buffer->use, in->buffer->size);
+#endif
+    return(nbchars);
+}
+
+/**
+ * xmlParserInputBufferRead:
+ * @in:  a buffered parser input
+ * @len:  indicative value of the amount of chars to read
+ *
+ * Refresh the content of the input buffer, the old data are considered
+ * consumed
+ * This routine handle the I18N transcoding to internal UTF-8
+ *
+ * Returns the number of chars read and stored in the buffer, or -1
+ *         in case of error.
+ */
+int
+xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
+    if ((in == NULL) || (in->error)) return(-1);
+    if (in->readcallback != NULL)
+    return(xmlParserInputBufferGrow(in, len));
+    else if ((in->buffer != NULL) &&
+             (in->buffer->alloc == XML_BUFFER_ALLOC_IMMUTABLE))
+    return(0);
+    else
+        return(-1);
+}
+
+#ifdef LIBXML_OUTPUT_ENABLED
+/**
+ * xmlOutputBufferWrite:
+ * @out:  a buffered parser output
+ * @len:  the size in bytes of the array.
+ * @buf:  an char array
+ *
+ * Write the content of the array in the output I/O buffer
+ * This routine handle the I18N transcoding from internal UTF-8
+ * The buffer is lossless, i.e. will store in case of partial
+ * or delayed writes.
+ *
+ * Returns the number of chars immediately written, or -1
+ *         in case of error.
+ */
+int
+xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
+    int nbchars = 0; /* number of chars to output to I/O */
+    int ret;         /* return from function call */
+    int written = 0; /* number of char written to I/O so far */
+    int chunk;       /* number of byte curreent processed from buf */
+
+    if ((out == NULL) || (out->error)) return(-1);
+    if (len < 0) return(0);
+    if (out->error) return(-1);
+
+    do {
+    chunk = len;
+    if (chunk > 4 * MINLEN)
+        chunk = 4 * MINLEN;
+
+    /*
+     * first handle encoding stuff.
+     */
+    if (out->encoder != NULL) {
+        /*
+         * Store the data in the incoming raw buffer
+         */
+        if (out->conv == NULL) {
+            out->conv = xmlBufferCreate();
+        }
+        xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
+
+        if ((out->buffer->use < MINLEN) && (chunk == len))
+            goto done;
+
+        /*
+         * convert as much as possible to the parser reading buffer.
+         */
+        ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
+        if ((ret < 0) && (ret != -3)) {
+            xmlIOErr(XML_IO_ENCODER, NULL);
+            out->error = XML_IO_ENCODER;
+            return(-1);
+        }
+        nbchars = out->conv->use;
+    } else {
+        xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
+        nbchars = out->buffer->use;
+    }
+    buf += chunk;
+    len -= chunk;
+
+    if ((nbchars < MINLEN) && (len <= 0))
+        goto done;
+
+    if (out->writecallback) {
+        /*
+         * second write the stuff to the I/O channel
+         */
+        if (out->encoder != NULL) {
+        ret = out->writecallback(out->context,
+                 (const char *)out->conv->content, nbchars);
+        if (ret >= 0)
+            xmlBufferShrink(out->conv, ret);
+        } else {
+        ret = out->writecallback(out->context,
+                 (const char *)out->buffer->content, nbchars);
+        if (ret >= 0)
+            xmlBufferShrink(out->buffer, ret);
+        }
+        if (ret < 0) {
+        xmlIOErr(XML_IO_WRITE, NULL);
+        out->error = XML_IO_WRITE;
+        return(ret);
+        }
+        out->written += ret;
+    }
+    written += nbchars;
+    } while (len > 0);
+
+done:
+#ifdef DEBUG_INPUT
+    xmlGenericError(xmlGenericErrorContext,
+        "I/O: wrote %d chars\n", written);
+#endif
+    return(written);
+}
+
+/**
+ * xmlEscapeContent:
+ * @out:  a pointer to an array of bytes to store the result
+ * @outlen:  the length of @out
+ * @in:  a pointer to an array of unescaped UTF-8 bytes
+ * @inlen:  the length of @in
+ *
+ * Take a block of UTF-8 chars in and escape them.
+ * Returns 0 if success, or -1 otherwise
+ * The value of @inlen after return is the number of octets consumed
+ *     if the return value is positive, else unpredictable.
+ * The value of @outlen after return is the number of octets consumed.
+ */
+static int
+xmlEscapeContent(unsigned char* out, int *outlen,
+                 const xmlChar* in, int *inlen) {
+    unsigned char* outstart = out;
+    const unsigned char* base = in;
+    unsigned char* outend = out + *outlen;
+    const unsigned char* inend;
+
+    inend = in + (*inlen);
+
+    while ((in < inend) && (out < outend)) {
+        if (*in == '<') {
+        if (outend - out < 4) break;
+        *out++ = '&';
+        *out++ = 'l';
+        *out++ = 't';
+        *out++ = ';';
+    } else if (*in == '>') {
+        if (outend - out < 4) break;
+        *out++ = '&';
+        *out++ = 'g';
+        *out++ = 't';
+        *out++ = ';';
+    } else if (*in == '&') {
+        if (outend - out < 5) break;
+        *out++ = '&';
+        *out++ = 'a';
+        *out++ = 'm';
+        *out++ = 'p';
+        *out++ = ';';
+    } else if (*in == '\r') {
+        if (outend - out < 5) break;
+        *out++ = '&';
+        *out++ = '#';
+        *out++ = '1';
+        *out++ = '3';
+        *out++ = ';';
+    } else {
+        *out++ = (unsigned char) *in;
+    }
+    ++in;
+    }
+    *outlen = out - outstart;
+    *inlen = in - base;
+    return(0);
+}
+
+/**
+ * xmlOutputBufferWriteEscape:
+ * @out:  a buffered parser output
+ * @str:  a zero terminated UTF-8 string
+ * @escaping:  an optional escaping function (or NULL)
+ *
+ * Write the content of the string in the output I/O buffer
+ * This routine escapes the caracters and then handle the I18N
+ * transcoding from internal UTF-8
+ * The buffer is lossless, i.e. will store in case of partial
+ * or delayed writes.
+ *
+ * Returns the number of chars immediately written, or -1
+ *         in case of error.
+ */
+int
+xmlOutputBufferWriteEscape(xmlOutputBufferPtr out, const xmlChar *str,
+                           xmlCharEncodingOutputFunc escaping) {
+    int nbchars = 0; /* number of chars to output to I/O */
+    int ret;         /* return from function call */
+    int written = 0; /* number of char written to I/O so far */
+    int chunk;       /* number of byte currently processed from str */
+    int len;         /* number of bytes in str */
+    int cons;        /* byte from str consumed */
+
+    if ((out == NULL) || (out->error) || (str == NULL)) return(-1);
+    len = strlen((const char *)str);
+    if (len < 0) return(0);
+    if (out->error) return(-1);
+    if (escaping == NULL) escaping = xmlEscapeContent;
+
+    do {
+        /*
+     * how many bytes to consume and how many bytes to store.
+     */
+    cons = len;
+    chunk = (out->buffer->size - out->buffer->use) - 1;
+
+    /*
+     * first handle encoding stuff.
+     */
+    if (out->encoder != NULL) {
+        /*
+         * Store the data in the incoming raw buffer
+         */
+        if (out->conv == NULL) {
+        out->conv = xmlBufferCreate();
+        }
+        ret = escaping(out->buffer->content + out->buffer->use ,
+                       &chunk, str, &cons);
+        if (ret < 0)
+            return(-1);
+        out->buffer->use += chunk;
+        out->buffer->content[out->buffer->use] = 0;
+
+        if ((out->buffer->use < MINLEN) && (cons == len))
+        goto done;
+
+        /*
+         * convert as much as possible to the output buffer.
+         */
+        ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
+        if ((ret < 0) && (ret != -3)) {
+        xmlIOErr(XML_IO_ENCODER, NULL);
+        out->error = XML_IO_ENCODER;
+        return(-1);
+        }
+        nbchars = out->conv->use;
+    } else {
+        ret = escaping(out->buffer->content + out->buffer->use ,
+                       &chunk, str, &cons);
+        if (ret < 0)
+            return(-1);
+        out->buffer->use += chunk;
+        out->buffer->content[out->buffer->use] = 0;
+        nbchars = out->buffer->use;
+    }
+    str += cons;
+    len -= cons;
+
+    if ((nbchars < MINLEN) && (len <= 0))
+        goto done;
+
+    if (out->writecallback) {
+        /*
+         * second write the stuff to the I/O channel
+         */
+        if (out->encoder != NULL) {
+        ret = out->writecallback(out->context,
+                 (const char *)out->conv->content, nbchars);
+        if (ret >= 0)
+            xmlBufferShrink(out->conv, ret);
+        } else {
+        ret = out->writecallback(out->context,
+                 (const char *)out->buffer->content, nbchars);
+        if (ret >= 0)
+            xmlBufferShrink(out->buffer, ret);
+        }
+        if (ret < 0) {
+        xmlIOErr(XML_IO_WRITE, NULL);
+        out->error = XML_IO_WRITE;
+        return(ret);
+        }
+        out->written += ret;
+    } else if (out->buffer->size - out->buffer->use < MINLEN) {
+        xmlBufferResize(out->buffer, out->buffer->size + MINLEN);
+    }
+    written += nbchars;
+    } while (len > 0);
+
+done:
+#ifdef DEBUG_INPUT
+    xmlGenericError(xmlGenericErrorContext,
+        "I/O: wrote %d chars\n", written);
+#endif
+    return(written);
+}
+
+/**
+ * xmlOutputBufferWriteString:
+ * @out:  a buffered parser output
+ * @str:  a zero terminated C string
+ *
+ * Write the content of the string in the output I/O buffer
+ * This routine handle the I18N transcoding from internal UTF-8
+ * The buffer is lossless, i.e. will store in case of partial
+ * or delayed writes.
+ *
+ * Returns the number of chars immediately written, or -1
+ *         in case of error.
+ */
+int
+xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
+    int len;
+
+    if ((out == NULL) || (out->error)) return(-1);
+    if (str == NULL)
+        return(-1);
+    len = strlen(str);
+
+    if (len > 0)
+        return(xmlOutputBufferWrite(out, len, str));
+    return(len);
+}
+
+/**
+ * xmlOutputBufferFlush:
+ * @out:  a buffered output
+ *
+ * flushes the output I/O channel
+ *
+ * Returns the number of byte written or -1 in case of error.
+ */
+int
+xmlOutputBufferFlush(xmlOutputBufferPtr out) {
+    int nbchars = 0, ret = 0;
+
+    if ((out == NULL) || (out->error)) return(-1);
+    /*
+     * first handle encoding stuff.
+     */
+    if ((out->conv != NULL) && (out->encoder != NULL)) {
+    /*
+     * convert as much as possible to the parser reading buffer.
+     */
+    nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
+    if (nbchars < 0) {
+        xmlIOErr(XML_IO_ENCODER, NULL);
+        out->error = XML_IO_ENCODER;
+        return(-1);
+    }
+    }
+
+    /*
+     * second flush the stuff to the I/O channel
+     */
+    if ((out->conv != NULL) && (out->encoder != NULL) &&
+    (out->writecallback != NULL)) {
+    ret = out->writecallback(out->context,
+               (const char *)out->conv->content, out->conv->use);
+    if (ret >= 0)
+        xmlBufferShrink(out->conv, ret);
+    } else if (out->writecallback != NULL) {
+    ret = out->writecallback(out->context,
+               (const char *)out->buffer->content, out->buffer->use);
+    if (ret >= 0)
+        xmlBufferShrink(out->buffer, ret);
+    }
+    if (ret < 0) {
+    xmlIOErr(XML_IO_FLUSH, NULL);
+    out->error = XML_IO_FLUSH;
+    return(ret);
+    }
+    out->written += ret;
+
+#ifdef DEBUG_INPUT
+    xmlGenericError(xmlGenericErrorContext,
+        "I/O: flushed %d chars\n", ret);
+#endif
+    return(ret);
+}
+#endif /* LIBXML_OUTPUT_ENABLED */
+
+/**
+ * xmlParserGetDirectory:
+ * @filename:  the path to a file
+ *
+ * lookup the directory for that file
+ *
+ * Returns a new allocated string containing the directory, or NULL.
+ */
+char *
+xmlParserGetDirectory(const char *filename) {
+    char *ret = NULL;
+    char dir[1024];
+    char *cur;
+    char sep = '/';
+
+#ifdef _WIN32_WCE  /* easy way by now ... wince does not have dirs! */
+    return NULL;
+#endif
+
+    if (xmlInputCallbackInitialized == 0)
+    xmlRegisterDefaultInputCallbacks();
+
+    if (filename == NULL) return(NULL);
+#if defined(WIN32) && !defined(__CYGWIN__)
+    sep = '\\';
+#endif
+
+    strncpy(dir, filename, 1023);
+    dir[1023] = 0;
+    cur = &dir[strlen(dir)];
+    while (cur > dir) {
+         if (*cur == sep) break;
+     cur --;
+    }
+    if (*cur == sep) {
+        if (cur == dir) dir[1] = 0;
+    else *cur = 0;
+    ret = xmlMemStrdup(dir);
+    } else {
+        if (getcwd(dir, 1024)) {
+        dir[1023] = 0;
+        ret = xmlMemStrdup(dir);
+    }
+    }
+    return(ret);
+}
+
+/****************************************************************
+ *                              *
+ *      External entities loading           *
+ *                              *
+ ****************************************************************/
+
+/**
+ * xmlCheckHTTPInput:
+ * @ctxt: an XML parser context
+ * @ret: an XML parser input
+ *
+ * Check an input in case it was created from an HTTP stream, in that
+ * case it will handle encoding and update of the base URL in case of
+ * redirection. It also checks for HTTP errors in which case the input
+ * is cleanly freed up and an appropriate error is raised in context
+ *
+ * Returns the input or NULL in case of HTTP error.
+ */
+xmlParserInputPtr
+xmlCheckHTTPInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr ret) {
+#ifdef LIBXML_HTTP_ENABLED
+    if ((ret != NULL) && (ret->buf != NULL) &&
+        (ret->buf->readcallback == xmlIOHTTPRead) &&
+        (ret->buf->context != NULL)) {
+        const char *encoding;
+        const char *redir;
+        const char *mime;
+        int code;
+
+        code = xmlNanoHTTPReturnCode(ret->buf->context);
+        if (code >= 400) {
+            /* fatal error */
+        if (ret->filename != NULL)
+        __xmlLoaderErr(ctxt, "failed to load HTTP resource \"%s\"\n",
+                         (const char *) ret->filename);
+        else
+        __xmlLoaderErr(ctxt, "failed to load HTTP resource\n", NULL);
+            xmlFreeInputStream(ret);
+            ret = NULL;
+        } else {
+
+            mime = xmlNanoHTTPMimeType(ret->buf->context);
+            if ((xmlStrstr(BAD_CAST mime, BAD_CAST "/xml")) ||
+                (xmlStrstr(BAD_CAST mime, BAD_CAST "+xml"))) {
+                encoding = xmlNanoHTTPEncoding(ret->buf->context);
+                if (encoding != NULL) {
+                    xmlCharEncodingHandlerPtr handler;
+
+                    handler = xmlFindCharEncodingHandler(encoding);
+                    if (handler != NULL) {
+                        xmlSwitchInputEncoding(ctxt, ret, handler);
+                    } else {
+                        __xmlErrEncoding(ctxt, XML_ERR_UNKNOWN_ENCODING,
+                                         "Unknown encoding %s",
+                                         BAD_CAST encoding, NULL);
+                    }
+                    if (ret->encoding == NULL)
+                        ret->encoding = xmlStrdup(BAD_CAST encoding);
+                }
+#if 0
+            } else if (xmlStrstr(BAD_CAST mime, BAD_CAST "html")) {
+#endif
+            }
+            redir = xmlNanoHTTPRedir(ret->buf->context);
+            if (redir != NULL) {
+                if (ret->filename != NULL)
+                    xmlFree((xmlChar *) ret->filename);
+                if (ret->directory != NULL) {
+                    xmlFree((xmlChar *) ret->directory);
+                    ret->directory = NULL;
+                }
+                ret->filename =
+                    (char *) xmlStrdup((const xmlChar *) redir);
+            }
+        }
+    }
+#endif
+    if(ctxt) return ret; // just to use ctx
+    return(ret);
+}
+
+static int xmlSysIDExists(const char* URL) {
+#ifdef HAVE_STAT
+    int ret;
+    struct stat info;
+    const char *path;
+
+    if (URL == NULL)
+    return(0);
+
+    if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
+#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
+    path = &URL[17];
+#else
+    path = &URL[16];
+#endif
+    else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
+#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
+    path = &URL[8];
+#else
+    path = &URL[7];
+#endif
+    } else
+    path = URL;
+    ret = stat(path, &info);
+    if (ret == 0)
+    return(1);
+#endif
+    return(0);
+}
+
+/**
+ * xmlDefaultExternalEntityLoader:
+ * @URL:  the URL for the entity to load
+ * @ID:  the System ID for the entity to load
+ * @ctxt:  the context in which the entity is called or NULL
+ *
+ * By default we don't load external entitites, yet.
+ *
+ * Returns a new allocated xmlParserInputPtr, or NULL.
+ */
+xmlParserInputPtr
+xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
+                               xmlParserCtxtPtr ctxt)
+{
+    xmlParserInputPtr ret = NULL;
+    xmlChar *resource = NULL;
+
+#ifdef LIBXML_CATALOG_ENABLED
+    xmlCatalogAllow pref;
+#endif
+
+#ifdef DEBUG_EXTERNAL_ENTITIES
+    xmlGenericError(xmlGenericErrorContext,
+                    "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
+#endif
+#ifdef LIBXML_CATALOG_ENABLED
+    if ((ctxt != NULL) && (ctxt->options & XML_PARSE_NONET)) {
+        int options = ctxt->options;
+
+    ctxt->options -= XML_PARSE_NONET;
+        ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
+    ctxt->options = options;
+    return(ret);
+    }
+
+    /*
+     * If the resource doesn't exists as a file,
+     * try to load it from the resource pointed in the catalogs
+     */
+    pref = xmlCatalogGetDefaults();
+
+    if ((pref != XML_CATA_ALLOW_NONE) && (!xmlSysIDExists(URL))) {
+        /*
+         * Do a local lookup
+         */
+        if ((ctxt->catalogs != NULL) &&
+            ((pref == XML_CATA_ALLOW_ALL) ||
+             (pref == XML_CATA_ALLOW_DOCUMENT))) {
+            resource = xmlCatalogLocalResolve(ctxt->catalogs,
+                                              (const xmlChar *) ID,
+                                              (const xmlChar *) URL);
+        }
+        /*
+         * Try a global lookup
+         */
+        if ((resource == NULL) &&
+            ((pref == XML_CATA_ALLOW_ALL) ||
+             (pref == XML_CATA_ALLOW_GLOBAL))) {
+            resource = xmlCatalogResolve((const xmlChar *) ID,
+                                         (const xmlChar *) URL);
+        }
+        if ((resource == NULL) && (URL != NULL))
+            resource = xmlStrdup((const xmlChar *) URL);
+
+        /*
+         * TODO: do an URI lookup on the reference
+         */
+        if ((resource != NULL)
+            && (!xmlSysIDExists((const char *) resource))) {
+            xmlChar *tmp = NULL;
+
+            if ((ctxt->catalogs != NULL) &&
+                ((pref == XML_CATA_ALLOW_ALL) ||
+                 (pref == XML_CATA_ALLOW_DOCUMENT))) {
+                tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
+            }
+            if ((tmp == NULL) &&
+                ((pref == XML_CATA_ALLOW_ALL) ||
+                 (pref == XML_CATA_ALLOW_GLOBAL))) {
+                tmp = xmlCatalogResolveURI(resource);
+            }
+
+            if (tmp != NULL) {
+                xmlFree(resource);
+                resource = tmp;
+            }
+        }
+    }
+#endif
+
+    if (resource == NULL)
+        resource = (xmlChar *) URL;
+
+    if (resource == NULL) {
+        if (ID == NULL)
+            ID = "NULL";
+        __xmlLoaderErr(ctxt, EMBED_ERRTXT("failed to load external entity \"%s\"\n"), ID);
+        return (NULL);
+    }
+    ret = xmlNewInputFromFile(ctxt, (const char *) resource);
+    if ((resource != NULL) && (resource != (xmlChar *) URL))
+        xmlFree(resource);
+    return (ret);
+}
+
+#ifndef XMLENGINE_EXCLUDE_UNUSED
+/**
+ * xmlSetExternalEntityLoader:
+ * @f:  the new entity resolver function
+ *
+ * Changes the defaultexternal entity resolver function for the application
+ */
+void
+xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
+    xmlCurrentExternalEntityLoader = f;
+}
+
+/**
+ * xmlGetExternalEntityLoader:
+ *
+ * Get the default external entity resolver function for the application
+ *
+ * Returns the xmlExternalEntityLoader function pointer
+ */
+xmlExternalEntityLoader
+xmlGetExternalEntityLoader(void) {
+    return(xmlCurrentExternalEntityLoader);
+}
+#endif /* ifndef XMLENGINE_EXCLUDE_UNUSED */
+
+/**
+ * xmlLoadExternalEntity:
+ * @URL:  the URL for the entity to load
+ * @ID:  the Public ID for the entity to load
+ * @ctxt:  the context in which the entity is called or NULL
+ *
+ * Load an external entity, note that the use of this function for
+ * unparsed entities may generate problems
+ * TODO: a more generic External entity API must be designed
+ *
+ * Returns the xmlParserInputPtr or NULL
+ *
+ * OOM:
+ */
+xmlParserInputPtr
+xmlLoadExternalEntity(const char *URL, const char *ID, xmlParserCtxtPtr ctxt) 
+{
+    if ((URL != NULL) && (xmlSysIDExists(URL) == 0)) {
+        char *canonicFilename;
+        xmlParserInputPtr ret;
+
+        canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL);
+        if (canonicFilename == NULL) {
+            xmlIOErrMemory(EMBED_ERRTXT("building canonical path\n"));
+            return(NULL);
+        }
+
+        ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt);
+        xmlFree(canonicFilename);
+        return(ret);
+    }
+    return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
+}
+
+/************************************************************************
+ *                                                                      *
+ *      Disabling Network access                                        *
+ *                                                                      *
+ ************************************************************************/
+
+#ifdef LIBXML_CATALOG_ENABLED
+static int
+xmlNoNetExists(const char *URL)
+{
+#ifdef HAVE_STAT
+    int ret;
+    struct stat info;
+    const char *path;
+
+    if (URL == NULL)
+        return (0);
+
+    if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
+#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
+    path = &URL[17];
+#else
+    path = &URL[16];
+#endif
+    else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
+#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
+        path = &URL[8];
+#else
+        path = &URL[7];
+#endif
+    } else
+        path = URL;
+    ret = stat(path, &info);
+    if (ret == 0)
+        return (1);
+#endif
+    return (0);
+}
+#endif
+
+/**
+ * xmlNoNetExternalEntityLoader:
+ * @URL:  the URL for the entity to load
+ * @ID:  the System ID for the entity to load
+ * @ctxt:  the context in which the entity is called or NULL
+ *
+ * A specific entity loader disabling network accesses, though still
+ * allowing local catalog accesses for resolution.
+ *
+ * Returns a new allocated xmlParserInputPtr, or NULL.
+ */
+xmlParserInputPtr
+xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
+                             xmlParserCtxtPtr ctxt) {
+    xmlParserInputPtr input = NULL;
+    xmlChar *resource = NULL;
+
+#ifdef LIBXML_CATALOG_ENABLED
+    xmlCatalogAllow pref;
+
+    /*
+     * If the resource doesn't exists as a file,
+     * try to load it from the resource pointed in the catalogs
+     */
+    pref = xmlCatalogGetDefaults();
+
+    if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
+    /*
+     * Do a local lookup
+     */
+    if ((ctxt->catalogs != NULL) &&
+        ((pref == XML_CATA_ALLOW_ALL) ||
+         (pref == XML_CATA_ALLOW_DOCUMENT))) {
+        resource = xmlCatalogLocalResolve(ctxt->catalogs,
+                          (const xmlChar *)ID,
+                          (const xmlChar *)URL);
+        }
+    /*
+     * Try a global lookup
+     */
+    if ((resource == NULL) &&
+        ((pref == XML_CATA_ALLOW_ALL) ||
+         (pref == XML_CATA_ALLOW_GLOBAL))) {
+        resource = xmlCatalogResolve((const xmlChar *)ID,
+                     (const xmlChar *)URL);
+    }
+    if ((resource == NULL) && (URL != NULL))
+        resource = xmlStrdup((const xmlChar *) URL);
+
+    /*
+     * TODO: do an URI lookup on the reference
+     */
+    if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
+        xmlChar *tmp = NULL;
+
+        if ((ctxt->catalogs != NULL) &&
+        ((pref == XML_CATA_ALLOW_ALL) ||
+         (pref == XML_CATA_ALLOW_DOCUMENT))) {
+        tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
+        }
+        if ((tmp == NULL) &&
+        ((pref == XML_CATA_ALLOW_ALL) ||
+             (pref == XML_CATA_ALLOW_GLOBAL))) {
+        tmp = xmlCatalogResolveURI(resource);
+        }
+
+        if (tmp != NULL) {
+        xmlFree(resource);
+        resource = tmp;
+        }
+    }
+    }
+#endif
+    if (resource == NULL)
+    resource = (xmlChar *) URL;
+
+    if (resource != NULL) {
+        if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
+            (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
+            xmlIOErr(XML_IO_NETWORK_ATTEMPT, (const char *) resource);
+        if (resource != (xmlChar *) URL)
+        xmlFree(resource);
+        return(NULL);
+    }
+    }
+    input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
+    if (resource != (xmlChar *) URL)
+    xmlFree(resource);
+    return(input);
+}
+
+