Edit

kc3-lang/libxml2/xmlIO.c

Branch :

  • Show log

    Commit

  • Author : Daniel Veillard
    Date : 2012-01-26 16:56:22
    Hash : adf5ec94
    Message : Cleanups of lzma support - fix inclusion of the separated file - use namespaced name for the 4 non-static routines - add padding after external structures included in-situ - add new requirement to spec file - general cleanup of code

  • xmlIO.c
  • /*
     * 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 "libxml.h"
    
    #include <string.h>
    #ifdef HAVE_ERRNO_H
    #include <errno.h>
    #endif
    
    
    #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
    #ifdef HAVE_LZMA_H
    #include <lzma.h>
    #endif
    
    #if defined(WIN32) || defined(_WIN32)
    #include <windows.h>
    #endif
    
    #if defined(_WIN32_WCE)
    #include <winnls.h> /* for CP_UTF8 */
    #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
    #else
    #  ifdef HAVE__STAT
    #    if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
    #      define stat _stat
    #    endif
    #  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 <libxml/xmlmemory.h>
    #include <libxml/parser.h>
    #include <libxml/parserInternals.h>
    #include <libxml/xmlIO.h>
    #include <libxml/uri.h>
    #include <libxml/nanohttp.h>
    #include <libxml/nanoftp.h>
    #include <libxml/xmlerror.h>
    #ifdef LIBXML_CATALOG_ENABLED
    #include <libxml/catalog.h>
    #endif
    #include <libxml/globals.h>
    
    /* #define VERBOSE_FAILURE */
    /* #define DEBUG_EXTERNAL_ENTITIES */
    /* #define DEBUG_INPUT */
    
    #ifdef DEBUG_INPUT
    #define MINLEN 40
    #else
    #define MINLEN 4000
    #endif
    
    /*
     * Input I/O callback sets
     */
    typedef struct _xmlInputCallback {
        xmlInputMatchCallback matchcallback;
        xmlInputOpenCallback opencallback;
        xmlInputReadCallback readcallback;
        xmlInputCloseCallback closecallback;
    } xmlInputCallback;
    
    #define MAX_INPUT_CALLBACK 15
    
    static xmlInputCallback xmlInputCallbackTable[MAX_INPUT_CALLBACK];
    static int xmlInputCallbackNr = 0;
    static int xmlInputCallbackInitialized = 0;
    
    #ifdef LIBXML_OUTPUT_ENABLED
    /*
     * Output I/O callback sets
     */
    typedef struct _xmlOutputCallback {
        xmlOutputMatchCallback matchcallback;
        xmlOutputOpenCallback opencallback;
        xmlOutputWriteCallback writecallback;
        xmlOutputCloseCallback closecallback;
    } xmlOutputCallback;
    
    #define MAX_OUTPUT_CALLBACK 15
    
    static xmlOutputCallback xmlOutputCallbackTable[MAX_OUTPUT_CALLBACK];
    static int xmlOutputCallbackNr = 0;
    static int xmlOutputCallbackInitialized = 0;
    
    xmlOutputBufferPtr
    xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder);
    #endif /* LIBXML_OUTPUT_ENABLED */
    
    /************************************************************************
     *									*
     *		Tree memory error handler				*
     *									*
     ************************************************************************/
    
    static const char *IOerr[] = {
        "Unknown IO error",         /* UNKNOWN */
        "Permission denied",	/* EACCES */
        "Resource temporarily unavailable",/* EAGAIN */
        "Bad file descriptor",	/* EBADF */
        "Bad message",		/* EBADMSG */
        "Resource busy",		/* EBUSY */
        "Operation canceled",	/* ECANCELED */
        "No child processes",	/* ECHILD */
        "Resource deadlock avoided",/* EDEADLK */
        "Domain error",		/* EDOM */
        "File exists",		/* EEXIST */
        "Bad address",		/* EFAULT */
        "File too large",		/* EFBIG */
        "Operation in progress",	/* EINPROGRESS */
        "Interrupted function call",/* EINTR */
        "Invalid argument",		/* EINVAL */
        "Input/output error",	/* EIO */
        "Is a directory",		/* EISDIR */
        "Too many open files",	/* EMFILE */
        "Too many links",		/* EMLINK */
        "Inappropriate message buffer length",/* EMSGSIZE */
        "Filename too long",	/* ENAMETOOLONG */
        "Too many open files in system",/* ENFILE */
        "No such device",		/* ENODEV */
        "No such file or directory",/* ENOENT */
        "Exec format error",	/* ENOEXEC */
        "No locks available",	/* ENOLCK */
        "Not enough space",		/* ENOMEM */
        "No space left on device",	/* ENOSPC */
        "Function not implemented",	/* ENOSYS */
        "Not a directory",		/* ENOTDIR */
        "Directory not empty",	/* ENOTEMPTY */
        "Not supported",		/* ENOTSUP */
        "Inappropriate I/O control operation",/* ENOTTY */
        "No such device or address",/* ENXIO */
        "Operation not permitted",	/* EPERM */
        "Broken pipe",		/* EPIPE */
        "Result too large",		/* ERANGE */
        "Read-only file system",	/* EROFS */
        "Invalid seek",		/* ESPIPE */
        "No such process",		/* ESRCH */
        "Operation timed out",	/* ETIMEDOUT */
        "Improper link",		/* EXDEV */
        "Attempt to load network entity %s", /* XML_IO_NETWORK_ATTEMPT */
        "encoder error",		/* XML_IO_ENCODER */
        "flush error",
        "write error",
        "no input",
        "buffer full",
        "loading error",
        "not a socket",		/* ENOTSOCK */
        "already connected",	/* EISCONN */
        "connection refused",	/* ECONNREFUSED */
        "unreachable network",	/* ENETUNREACH */
        "adddress in use",		/* EADDRINUSE */
        "already in use",		/* EALREADY */
        "unknown address familly",	/* EAFNOSUPPORT */
    };
    
    #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
    /**
     * __xmlIOWin32UTF8ToWChar:
     * @u8String:  uft-8 string
     *
     * Convert a string from utf-8 to wchar (WINDOWS ONLY!)
     */
    static wchar_t *
    __xmlIOWin32UTF8ToWChar(const char *u8String)
    {
        wchar_t *wString = NULL;
    
        if (u8String) {
            int wLen =
                MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, u8String,
                                    -1, NULL, 0);
            if (wLen) {
                wString = xmlMalloc(wLen * sizeof(wchar_t));
                if (wString) {
                    if (MultiByteToWideChar
                        (CP_UTF8, 0, u8String, -1, wString, wLen) == 0) {
                        xmlFree(wString);
                        wString = NULL;
                    }
                }
            }
        }
    
        return wString;
    }
    #endif
    
    /**
     * xmlIOErrMemory:
     * @extra:  extra informations
     *
     * Handle an out of memory condition
     */
    static void
    xmlIOErrMemory(const char *extra)
    {
        __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;
        if (idx >= (sizeof(IOerr) / sizeof(IOerr[0]))) idx = 0;
    
        __xmlSimpleError(domain, code, NULL, IOerr[idx], extra);
    }
    
    /**
     * 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;
    	}
    	if (ctxt->sax->initialized == XML_SAX2_MAGIC)
    	    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);
    
    }
    
    /************************************************************************
     *									*
     *		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
     */
    xmlChar *
    xmlNormalizeWindowsPath(const xmlChar *path)
    {
        return xmlCanonicPath(path);
    }
    
    /**
     * xmlCleanupInputCallbacks:
     *
     * clears the entire input callback table. this includes the
     * compiled-in I/O.
     */
    void
    xmlCleanupInputCallbacks(void)
    {
        int i;
    
        if (!xmlInputCallbackInitialized)
            return;
    
        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;
    }
    
    /**
     * xmlPopInputCallbacks:
     *
     * 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				*
     *									*
     ************************************************************************/
    
    #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
    
    /**
     *  xmlWrapOpenUtf8:
     * @path:  the path in utf-8 encoding
     * @mode:  type of access (0 - read, 1 - write)
     *
     * function opens the file specified by @path
     *
     */
    static FILE*
    xmlWrapOpenUtf8(const char *path,int mode)
    {
        FILE *fd = NULL;
        wchar_t *wPath;
    
        wPath = __xmlIOWin32UTF8ToWChar(path);
        if(wPath)
        {
           fd = _wfopen(wPath, mode ? L"wb" : L"rb");
           xmlFree(wPath);
        }
        /* maybe path in native encoding */
        if(fd == NULL)
           fd = fopen(path, mode ? "wb" : "rb");
    
        return fd;
    }
    
    #ifdef HAVE_ZLIB_H
    static gzFile
    xmlWrapGzOpenUtf8(const char *path, const char *mode)
    {
        gzFile fd;
        wchar_t *wPath;
    
        fd = gzopen (path, mode);
        if (fd)
            return fd;
    
        wPath = __xmlIOWin32UTF8ToWChar(path);
        if(wPath)
        {
    	int d, m = (strstr(mode, "r") ? O_RDONLY : O_RDWR);
    #ifdef _O_BINARY
            m |= (strstr(mode, "b") ? _O_BINARY : 0);
    #endif
    	d = _wopen(wPath, m);
    	if (d >= 0)
    	    fd = gzdopen(d, mode);
            xmlFree(wPath);
        }
    
        return fd;
    }
    #endif
    
    /**
     *  xmlWrapStatUtf8:
     * @path:  the path in utf-8 encoding
     * @info:  structure that stores results
     *
     * function obtains information about the file or directory
     *
     */
    static int
    xmlWrapStatUtf8(const char *path,struct stat *info)
    {
    #ifdef HAVE_STAT
        int retval = -1;
        wchar_t *wPath;
    
        wPath = __xmlIOWin32UTF8ToWChar(path);
        if (wPath)
        {
           retval = _wstat(wPath,info);
           xmlFree(wPath);
        }
        /* maybe path in native encoding */
        if(retval < 0)
           retval = stat(path,info);
        return retval;
    #else
        return -1;
    #endif
    }
    
    /**
     *  xmlWrapOpenNative:
     * @path:  the path
     * @mode:  type of access (0 - read, 1 - write)
     *
     * function opens the file specified by @path
     *
     */
    static FILE*
    xmlWrapOpenNative(const char *path,int mode)
    {
        return fopen(path,mode ? "wb" : "rb");
    }
    
    /**
     *  xmlWrapStatNative:
     * @path:  the path
     * @info:  structure that stores results
     *
     * function obtains information about the file or directory
     *
     */
    static int
    xmlWrapStatNative(const char *path,struct stat *info)
    {
    #ifdef HAVE_STAT
        return stat(path,info);
    #else
        return -1;
    #endif
    }
    
    typedef int (* xmlWrapStatFunc) (const char *f, struct stat *s);
    static xmlWrapStatFunc xmlWrapStat = xmlWrapStatNative;
    typedef FILE* (* xmlWrapOpenFunc)(const char *f,int mode);
    static xmlWrapOpenFunc xmlWrapOpen = xmlWrapOpenNative;
    #ifdef HAVE_ZLIB_H
    typedef gzFile (* xmlWrapGzOpenFunc) (const char *f, const char *mode);
    static xmlWrapGzOpenFunc xmlWrapGzOpen = gzopen;
    #endif
    /**
     * xmlInitPlatformSpecificIo:
     *
     * Initialize platform specific features.
     */
    static void
    xmlInitPlatformSpecificIo(void)
    {
        static int xmlPlatformIoInitialized = 0;
        OSVERSIONINFO osvi;
    
        if(xmlPlatformIoInitialized)
          return;
    
        osvi.dwOSVersionInfoSize = sizeof(osvi);
    
        if(GetVersionEx(&osvi) && (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)) {
          xmlWrapStat = xmlWrapStatUtf8;
          xmlWrapOpen = xmlWrapOpenUtf8;
    #ifdef HAVE_ZLIB_H
          xmlWrapGzOpen = xmlWrapGzOpenUtf8;
    #endif
        } else {
          xmlWrapStat = xmlWrapStatNative;
          xmlWrapOpen = xmlWrapOpenNative;
    #ifdef HAVE_ZLIB_H
          xmlWrapGzOpen = gzopen;
    #endif
        }
    
        xmlPlatformIoInitialized = 1;
        return;
    }
    
    #endif
    
    /**
     * 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.
     */
    
    int
    xmlCheckFilename (const char *path)
    {
    #ifdef HAVE_STAT
    	struct stat stat_buffer;
    #endif
    	if (path == NULL)
    		return(0);
    
    #ifdef HAVE_STAT
    #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
        if (xmlWrapStat(path, &stat_buffer) == -1)
            return 0;
    #else
        if (stat(path, &stat_buffer) == -1)
            return 0;
    #endif
    #ifdef S_ISDIR
        if (S_ISDIR(stat_buffer.st_mode))
            return 2;
    #endif
    #endif /* HAVE_STAT */
        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, "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 = 0;
    
        if (len > 0) {
    	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, "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 = NULL;
        FILE *fd;
    
        if (filename == NULL)
            return(NULL);
    
        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 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:/", 6)) {
            /* lots of generators seems to lazy to read RFC 1738 */
    #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
    	path = &filename[6];
    #else
    	path = &filename[5];
    #endif
        } else
    	path = filename;
    
        if (path == NULL)
    	return(NULL);
        if (!xmlCheckFilename(path))
            return(NULL);
    
    #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
        fd = xmlWrapOpen(path, 0);
    #else
        fd = fopen(path, "r");
    #endif /* WIN32 */
        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;
    
        retval = xmlFileOpen_real(filename);
        if (retval == NULL) {
    	unescaped = xmlURIUnescapeString(filename, 0, NULL);
    	if (unescaped != NULL) {
    	    retval = xmlFileOpen_real(unescaped);
    	    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);
    
    #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
        fd = xmlWrapOpen(path, 1);
    #else
     	   fd = fopen(path, "wb");
    #endif /* WIN32 */
    
    	 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 or < 0 in case of failure
     */
    int
    xmlFileRead (void * context, char * buffer, int len) {
        int ret;
        if ((context == NULL) || (buffer == NULL))
            return(-1);
        ret = fread(&buffer[0], 1,  len, (FILE *) context);
        if (ret < 0) xmlIOErr(0, "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;
    
        if ((context == NULL) || (buffer == NULL))
            return(-1);
        items = fwrite(&buffer[0], len, 1, (FILE *) context);
        if ((items == 0) && (ferror((FILE *) context))) {
            xmlIOErr(0, "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;
    
        if (context == NULL)
            return(-1);
        fil = (FILE *) context;
        if ((fil == stdout) || (fil == stderr)) {
            ret = fflush(fil);
    	if (ret < 0)
    	    xmlIOErr(0, "fflush()");
    	return(0);
        }
        if (fil == stdin)
    	return(0);
        ret = ( fclose((FILE *) context) == EOF ) ? -1 : 0;
        if (ret < 0)
            xmlIOErr(0, "fclose()");
        return(ret);
    }
    
    /**
     * xmlFileFlush:
     * @context:  the I/O context
     *
     * Flush an I/O channel
     */
    static int
    xmlFileFlush (void * context) {
        int ret;
    
        if (context == NULL)
            return(-1);
        ret = ( fflush((FILE *) context) == EOF ) ? -1 : 0;
        if (ret < 0)
            xmlIOErr(0, "fflush()");
        return(ret);
    }
    
    #ifdef LIBXML_OUTPUT_ENABLED
    /**
     * xmlBufferWrite:
     * @context:  the xmlBuffer
     * @buffer:  the data to write
     * @len:  number of bytes to write
     *
     * Write @len bytes from @buffer to the xml buffer
     *
     * Returns the number of bytes written
     */
    static int
    xmlBufferWrite (void * context, const char * buffer, int len) {
        int ret;
    
        ret = xmlBufferAdd((xmlBufferPtr) context, (const xmlChar *) buffer, len);
        if (ret != 0)
            return(-1);
        return(len);
    }
    #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);
    
    #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
        fd = xmlWrapGzOpen(path, "rb");
    #else
        fd = gzopen(path, "rb");
    #endif
        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);
    
    #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
        fd = xmlWrapGzOpen(path, mode);
    #else
        fd = gzopen(path, mode);
    #endif
        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, "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, "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, "gzclose()");
        return(ret);
    }
    #endif /* HAVE_ZLIB_H */
    
    #ifdef HAVE_LZMA_H
    /************************************************************************
     *									*
     *		I/O for compressed file accesses			*
     *									*
     ************************************************************************/
    #include "xzlib.h"
    /**
     * xmlXzfileMatch:
     * @filename:  the URI for matching
     *
     * input from compressed file test
     *
     * Returns 1 if matches, 0 otherwise
     */
    static int
    xmlXzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
        return(1);
    }
    
    /**
     * xmlXzFileOpen_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 *
    xmlXzfileOpen_real (const char *filename) {
        const char *path = NULL;
        xzFile fd;
    
        if (!strcmp(filename, "-")) {
            fd = __libxml2_xzdopen(dup(0), "rb");
    	return((void *) fd);
        }
    
        if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) {
    	path = &filename[16];
        } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
    	path = &filename[7];
        } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:/", 6)) {
            /* lots of generators seems to lazy to read RFC 1738 */
    	path = &filename[5];
        } else
    	path = filename;
    
        if (path == NULL)
    	return(NULL);
        if (!xmlCheckFilename(path))
            return(NULL);
    
        fd = __libxml2_xzopen(path, "rb");
        return((void *) fd);
    }
    
    /**
     * xmlXzfileOpen:
     * @filename:  the URI for matching
     *
     * Wrapper around xmlXzfileOpen_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
     */
    static void *
    xmlXzfileOpen (const char *filename) {
        char *unescaped;
        void *retval;
    
        retval = xmlXzfileOpen_real(filename);
        if (retval == NULL) {
    	unescaped = xmlURIUnescapeString(filename, 0, NULL);
    	if (unescaped != NULL) {
    	    retval = xmlXzfileOpen_real(unescaped);
    	}
    	xmlFree(unescaped);
        }
    
        return retval;
    }
    
    /**
     * xmlXzfileRead:
     * @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
    xmlXzfileRead (void * context, char * buffer, int len) {
        int ret;
    
        ret = __libxml2_xzread((xzFile) context, &buffer[0], len);
        if (ret < 0) xmlIOErr(0, "xzread()");
        return(ret);
    }
    
    /**
     * xmlXzfileClose:
     * @context:  the I/O context
     *
     * Close a compressed I/O channel
     */
    static int
    xmlXzfileClose (void * context) {
        int ret;
    
        ret =  (__libxml2_xzclose((xzFile) context) == LZMA_OK ) ? 0 : -1;
        if (ret < 0) xmlIOErr(0, "xzclose()");
        return(ret);
    }
    #endif /* HAVE_LZMA_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,
    			"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("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("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 *) "xmlCreateZMemBuff:  %s %d\n",
    		    "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, 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 *) "xmlZMemBuffExtend:  %s %lu bytes.\n",
    		    "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 *) "xmlZMemBuffAppend:  %s %d %s - %d",
    			"Compression error while appending",
    			len, "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 *) "xmlZMemBuffGetContent:  %s - %d\n",
    		    "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("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("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 = xmlAllocOutputBufferInternal(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) {
        if ((buffer == NULL) || (len < 0)) return(-1);
        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 *) "xmlIOHTTPWrite:  %s\n%s '%s'.\n",
    			"Error appending to internal buffer.",
    			"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 *) "xmlIOHTTPCloseWrite:  %s '%s' %s '%s'.\n",
    		     "Error retrieving content.\nUnable to",
    		     http_mthd, "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 *) "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
    			    http_mthd, content_lgth,
    			    "bytes to URI", ctxt->uri,
    			    "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) {
        if ((buffer == NULL) || (len < 0)) return(-1);
        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
     */
    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
     */
    int
    xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
    	xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
    	xmlOutputCloseCallback closeFunc) {
        if (xmlOutputCallbackNr >= MAX_OUTPUT_CALLBACK) {
    	return(-1);
        }
        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.
     */
    void
    xmlRegisterDefaultInputCallbacks(void) {
        if (xmlInputCallbackInitialized)
    	return;
    
    #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
        xmlInitPlatformSpecificIo();
    #endif
    
        xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
    	                      xmlFileRead, xmlFileClose);
    #ifdef HAVE_ZLIB_H
        xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
    	                      xmlGzfileRead, xmlGzfileClose);
    #endif /* HAVE_ZLIB_H */
    #ifdef HAVE_LZMA_H
        xmlRegisterInputCallbacks(xmlXzfileMatch, xmlXzfileOpen,
    	                      xmlXzfileRead, xmlXzfileClose);
    #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.
     */
    void
    xmlRegisterDefaultOutputCallbacks (void) {
        if (xmlOutputCallbackInitialized)
    	return;
    
    #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
        xmlInitPlatformSpecificIo();
    #endif
    
        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
     */
    xmlParserInputBufferPtr
    xmlAllocParserInputBuffer(xmlCharEncoding enc) {
        xmlParserInputBufferPtr ret;
    
        ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
        if (ret == NULL) {
    	xmlIOErrMemory("creating input buffer");
    	return(NULL);
        }
        memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
        ret->buffer = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
        if (ret->buffer == NULL) {
            xmlFree(ret);
    	return(NULL);
        }
        ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
        ret->encoder = xmlGetCharEncodingHandler(enc);
        if (ret->encoder != NULL)
            ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
        else
            ret->raw = NULL;
        ret->readcallback = NULL;
        ret->closecallback = NULL;
        ret->context = NULL;
        ret->compressed = -1;
        ret->rawconsumed = 0;
    
        return(ret);
    }
    
    #ifdef LIBXML_OUTPUT_ENABLED
    /**
     * xmlAllocOutputBuffer:
     * @encoder:  the encoding converter or NULL
     *
     * Create a buffered parser output
     *
     * Returns the new parser output or NULL
     */
    xmlOutputBufferPtr
    xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
        xmlOutputBufferPtr ret;
    
        ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
        if (ret == NULL) {
    	xmlIOErrMemory("creating output buffer");
    	return(NULL);
        }
        memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
        ret->buffer = xmlBufferCreate();
        if (ret->buffer == NULL) {
            xmlFree(ret);
    	return(NULL);
        }
    
        /* try to avoid a performance problem with Windows realloc() */
        if (ret->buffer->alloc == XML_BUFFER_ALLOC_EXACT)
            ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
    
        ret->encoder = encoder;
        if (encoder != NULL) {
            ret->conv = xmlBufferCreateSize(4000);
    	if (ret->conv == NULL) {
    	    xmlFree(ret);
    	    return(NULL);
    	}
    
    	/*
    	 * This call is designed to initiate the encoder state
    	 */
    	xmlCharEncOutFunc(encoder, ret->conv, NULL);
        } else
            ret->conv = NULL;
        ret->writecallback = NULL;
        ret->closecallback = NULL;
        ret->context = NULL;
        ret->written = 0;
    
        return(ret);
    }
    
    /**
     * xmlAllocOutputBufferInternal:
     * @encoder:  the encoding converter or NULL
     *
     * Create a buffered parser output
     *
     * Returns the new parser output or NULL
     */
    xmlOutputBufferPtr
    xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder) {
        xmlOutputBufferPtr ret;
    
        ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
        if (ret == NULL) {
    	xmlIOErrMemory("creating output buffer");
    	return(NULL);
        }
        memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
        ret->buffer = xmlBufferCreate();
        if (ret->buffer == NULL) {
            xmlFree(ret);
    	return(NULL);
        }
    
    
        /*
         * For conversion buffers we use the special IO handling
         * We don't do that from the exported API to avoid confusing
         * user's code.
         */
        ret->buffer->alloc = XML_BUFFER_ALLOC_IO;
        ret->buffer->contentIO = ret->buffer->content;
    
        ret->encoder = encoder;
        if (encoder != NULL) {
            ret->conv = xmlBufferCreateSize(4000);
    	if (ret->conv == NULL) {
    	    xmlFree(ret);
    	    return(NULL);
    	}
    
    	/*
    	 * This call is designed to initiate the encoder state
    	 */
    	xmlCharEncOutFunc(encoder, ret->conv, NULL);
        } 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
     */
    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;
    
        if (out == NULL)
            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 */
    
    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 defined(ZLIB_VERNUM) && ZLIB_VERNUM >= 0x1230
                ret->compressed = !gzdirect(context);
    #else
    	    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
    	}
    #endif
        }
        else
          xmlInputCallbackTable[i].closecallback (context);
    
        return(ret);
    }
    
    /**
     * 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) {
        if ((xmlParserInputBufferCreateFilenameValue)) {
    		return xmlParserInputBufferCreateFilenameValue(URI, enc);
    	}
    	return __xmlParserInputBufferCreateFilename(URI, enc);
    }
    
    #ifdef LIBXML_OUTPUT_ENABLED
    xmlOutputBufferPtr
    __xmlOutputBufferCreateFilename(const char *URI,
                                  xmlCharEncodingHandlerPtr encoder,
                                  int compression ATTRIBUTE_UNUSED) {
        xmlOutputBufferPtr ret;
        xmlURIPtr puri;
        int i = 0;
        void *context = NULL;
        char *unescaped = NULL;
    #ifdef HAVE_ZLIB_H
        int is_file_uri = 1;
    #endif
    
        if (xmlOutputCallbackInitialized == 0)
    	xmlRegisterDefaultOutputCallbacks();
    
        if (URI == NULL) return(NULL);
    
        puri = xmlParseURI(URI);
        if (puri != NULL) {
    #ifdef HAVE_ZLIB_H
            if ((puri->scheme != NULL) &&
    	    (!xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
    	    is_file_uri = 0;
    #endif
    	/*
    	 * try to limit the damages of the URI unescaping code.
    	 */
    	if ((puri->scheme == NULL) ||
    	    (xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
    	    unescaped = xmlURIUnescapeString(URI, 0, NULL);
    	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 = xmlAllocOutputBufferInternal(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 = xmlAllocOutputBufferInternal(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 = xmlAllocOutputBufferInternal(encoder);
        if (ret != NULL) {
    	ret->context = context;
    	ret->writecallback = xmlOutputCallbackTable[i].writecallback;
    	ret->closecallback = xmlOutputCallbackTable[i].closecallback;
        }
        return(ret);
    }
    
    /**
     * 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) {
        if ((xmlOutputBufferCreateFilenameValue)) {
    		return xmlOutputBufferCreateFilenameValue(URI, encoder, compression);
    	}
    	return __xmlOutputBufferCreateFilename(URI, encoder, compression);
    }
    #endif /* LIBXML_OUTPUT_ENABLED */
    
    /**
     * 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);
    }
    
    #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 = xmlAllocOutputBufferInternal(encoder);
        if (ret != NULL) {
            ret->context = file;
    	ret->writecallback = xmlFileWrite;
    	ret->closecallback = xmlFileFlush;
        }
    
        return(ret);
    }
    
    /**
     * xmlOutputBufferCreateBuffer:
     * @buffer:  a xmlBufferPtr
     * @encoder:  the encoding converter or NULL
     *
     * Create a buffered output for the progressive saving to a xmlBuffer
     *
     * Returns the new parser output or NULL
     */
    xmlOutputBufferPtr
    xmlOutputBufferCreateBuffer(xmlBufferPtr buffer,
                                xmlCharEncodingHandlerPtr encoder) {
        xmlOutputBufferPtr ret;
    
        if (buffer == NULL) return(NULL);
    
        ret = xmlOutputBufferCreateIO((xmlOutputWriteCallback)
                                      xmlBufferWrite,
                                      (xmlOutputCloseCallback)
                                      NULL, (void *) buffer, encoder);
    
        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
     */
    xmlParserInputBufferPtr
    xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
        xmlParserInputBufferPtr ret;
        int errcode;
    
        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;
    	errcode = xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size);
    	if (errcode != 0) {
    	    xmlFree(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("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 = xmlAllocOutputBufferInternal(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 = xmlAllocOutputBufferInternal(encoder);
        if (ret != NULL) {
            ret->context = (void *) ioctx;
    	ret->writecallback = iowrite;
    	ret->closecallback = ioclose;
        }
    
        return(ret);
    }
    #endif /* LIBXML_OUTPUT_ENABLED */
    
    /**
     * xmlParserInputBufferCreateFilenameDefault:
     * @func: function pointer to the new ParserInputBufferCreateFilenameFunc
     *
     * Registers a callback for URI input file handling
     *
     * Returns the old value of the registration function
     */
    xmlParserInputBufferCreateFilenameFunc
    xmlParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func)
    {
        xmlParserInputBufferCreateFilenameFunc old = xmlParserInputBufferCreateFilenameValue;
        if (old == NULL) {
    		old = __xmlParserInputBufferCreateFilename;
    	}
    
        xmlParserInputBufferCreateFilenameValue = func;
        return(old);
    }
    
    /**
     * xmlOutputBufferCreateFilenameDefault:
     * @func: function pointer to the new OutputBufferCreateFilenameFunc
     *
     * Registers a callback for URI output file handling
     *
     * Returns the old value of the registration function
     */
    xmlOutputBufferCreateFilenameFunc
    xmlOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func)
    {
        xmlOutputBufferCreateFilenameFunc old = xmlOutputBufferCreateFilenameValue;
    #ifdef LIBXML_OUTPUT_ENABLED
        if (old == NULL) {
    		old = __xmlOutputBufferCreateFilename;
    	}
    #endif
        xmlOutputBufferCreateFilenameValue = func;
        return(old);
    }
    
    /**
     * 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;
        int ret;
    
        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();
    	}
    	ret = xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
    	if (ret != 0)
    	    return(-1);
    
    	/*
    	 * 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;
            ret = xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
    	if (ret != 0)
    	    return(-1);
        }
    #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.
     */
    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(-1);
        }
    
        needSize = in->buffer->use + len + 1;
        if (needSize > in->buffer->size){
            if (!xmlBufferResize(in->buffer, needSize)){
    	    xmlIOErrMemory("growing input buffer");
    	    in->error = XML_ERR_NO_MEMORY;
                return(-1);
            }
        }
        buffer = (char *)&in->buffer->content[in->buffer->use];
    
        /*
         * Call the read method for this I/O type.
         */
        if (in->readcallback != NULL) {
    	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();
    	}
    	res = xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
    	if (res != 0)
    	    return(-1);
    
    	/*
    	 * 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;
       	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();
    	    }
    	    ret = xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
    	    if (ret != 0)
    	        return(-1);
    
    	    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 {
    	    ret = xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
    	    if (ret != 0)
    	        return(-1);
    	    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 oldwritten=0;/* loop guard */
        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) ||
            (out->buffer == NULL) ||
    	(out->buffer->alloc == XML_BUFFER_ALLOC_IMMUTABLE)) return(-1);
        len = strlen((const char *)str);
        if (len < 0) return(0);
        if (out->error) return(-1);
        if (escaping == NULL) escaping = xmlEscapeContent;
    
        do {
            oldwritten = written;
    
            /*
    	 * how many bytes to consume and how many bytes to store.
    	 */
    	cons = len;
    	chunk = (out->buffer->size - out->buffer->use) - 1;
    
            /*
    	 * make sure we have enough room to save first, if this is
    	 * not the case force a flush, but make sure we stay in the loop
    	 */
    	if (chunk < 40) {
    	    if (xmlBufferGrow(out->buffer, out->buffer->size + 100) < 0)
    	        return(-1);
                oldwritten = -1;
    	    continue;
    	}
    
    	/*
    	 * 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) || (chunk == 0)) /* chunk==0 => nothing done */
    	        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) || (chunk == 0)) /* chunk==0 => nothing done */
    	        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) && (oldwritten != written));
    
    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;
    
    #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__)
    #   define IS_XMLPGD_SEP(ch) ((ch=='/')||(ch=='\\'))
    #else
    #   define IS_XMLPGD_SEP(ch) (ch=='/')
    #endif
    
        strncpy(dir, filename, 1023);
        dir[1023] = 0;
        cur = &dir[strlen(dir)];
        while (cur > dir) {
             if (IS_XMLPGD_SEP(*cur)) break;
    	 cur --;
        }
        if (IS_XMLPGD_SEP(*cur)) {
            if (cur == dir) dir[1] = 0;
    	else *cur = 0;
    	ret = xmlMemStrdup(dir);
        } else {
            if (getcwd(dir, 1024) != NULL) {
    	    dir[1023] = 0;
    	    ret = xmlMemStrdup(dir);
    	}
        }
        return(ret);
    #undef IS_XMLPGD_SEP
    }
    
    /****************************************************************
     *								*
     *		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
        return(ret);
    }
    
    static int xmlNoNetExists(const char *URL) {
        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;
    
        return xmlCheckFilename(path);
    }
    
    #ifdef LIBXML_CATALOG_ENABLED
    
    /**
     * xmlResolveResourceFromCatalog:
     * @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
     *
     * Resolves the URL and ID against the appropriate catalog.
     * This function is used by xmlDefaultExternalEntityLoader and
     * xmlNoNetExternalEntityLoader.
     *
     * Returns a new allocated URL, or NULL.
     */
    static xmlChar *
    xmlResolveResourceFromCatalog(const char *URL, const char *ID,
                                  xmlParserCtxtPtr ctxt) {
        xmlChar *resource = NULL;
        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 != NULL) && (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 != NULL) && (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;
    	    }
    	}
        }
    
        return resource;
    }
    
    #endif
    
    /**
     * 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.
     */
    static xmlParserInputPtr
    xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
                                   xmlParserCtxtPtr ctxt)
    {
        xmlParserInputPtr ret = NULL;
        xmlChar *resource = NULL;
    
    #ifdef DEBUG_EXTERNAL_ENTITIES
        xmlGenericError(xmlGenericErrorContext,
                        "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
    #endif
        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);
        }
    #ifdef LIBXML_CATALOG_ENABLED
        resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
    #endif
    
        if (resource == NULL)
            resource = (xmlChar *) URL;
    
        if (resource == NULL) {
            if (ID == NULL)
                ID = "NULL";
            __xmlLoaderErr(ctxt, "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);
    }
    
    static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
           xmlDefaultExternalEntityLoader;
    
    /**
     * 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);
    }
    
    /**
     * 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
     *
     * Returns the xmlParserInputPtr or NULL
     */
    xmlParserInputPtr
    xmlLoadExternalEntity(const char *URL, const char *ID,
                          xmlParserCtxtPtr ctxt) {
        if ((URL != NULL) && (xmlNoNetExists(URL) == 0)) {
    	char *canonicFilename;
    	xmlParserInputPtr ret;
    
    	canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL);
    	if (canonicFilename == NULL) {
                xmlIOErrMemory("building canonical path\n");
    	    return(NULL);
    	}
    
    	ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt);
    	xmlFree(canonicFilename);
    	return(ret);
        }
        return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
    }
    
    /************************************************************************
     *									*
     *		Disabling Network access				*
     *									*
     ************************************************************************/
    
    /**
     * 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
        resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
    #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);
    }
    
    #define bottom_xmlIO
    #include "elfgcchack.h"