Home | History | Annotate | Download | only in src
      1 /*
      2  * xmlIO.c : implementation of the I/O interfaces used by the parser
      3  *
      4  * See Copyright for the status of this software.
      5  *
      6  * daniel (at) veillard.com
      7  *
      8  * 14 Nov 2000 ht - for VMS, truncated name of long functions to under 32 char
      9  */
     10 
     11 #define IN_LIBXML
     12 #include "libxml.h"
     13 
     14 #include <string.h>
     15 #ifdef HAVE_ERRNO_H
     16 #include <errno.h>
     17 #endif
     18 
     19 
     20 #ifdef HAVE_SYS_TYPES_H
     21 #include <sys/types.h>
     22 #endif
     23 #ifdef HAVE_SYS_STAT_H
     24 #include <sys/stat.h>
     25 #endif
     26 #ifdef HAVE_FCNTL_H
     27 #include <fcntl.h>
     28 #endif
     29 #ifdef HAVE_UNISTD_H
     30 #include <unistd.h>
     31 #endif
     32 #ifdef HAVE_STDLIB_H
     33 #include <stdlib.h>
     34 #endif
     35 #ifdef HAVE_ZLIB_H
     36 #include <zlib.h>
     37 #endif
     38 
     39 #if defined(WIN32) || defined(_WIN32)
     40 #include <windows.h>
     41 #endif
     42 
     43 #if defined(_WIN32_WCE)
     44 #include <winnls.h> /* for CP_UTF8 */
     45 #endif
     46 
     47 /* Figure a portable way to know if a file is a directory. */
     48 #ifndef HAVE_STAT
     49 #  ifdef HAVE__STAT
     50      /* MS C library seems to define stat and _stat. The definition
     51         is identical. Still, mapping them to each other causes a warning. */
     52 #    ifndef _MSC_VER
     53 #      define stat(x,y) _stat(x,y)
     54 #    endif
     55 #    define HAVE_STAT
     56 #  endif
     57 #else
     58 #  ifdef HAVE__STAT
     59 #    if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
     60 #      define stat _stat
     61 #    endif
     62 #  endif
     63 #endif
     64 #ifdef HAVE_STAT
     65 #  ifndef S_ISDIR
     66 #    ifdef _S_ISDIR
     67 #      define S_ISDIR(x) _S_ISDIR(x)
     68 #    else
     69 #      ifdef S_IFDIR
     70 #        ifndef S_IFMT
     71 #          ifdef _S_IFMT
     72 #            define S_IFMT _S_IFMT
     73 #          endif
     74 #        endif
     75 #        ifdef S_IFMT
     76 #          define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
     77 #        endif
     78 #      endif
     79 #    endif
     80 #  endif
     81 #endif
     82 
     83 #include <libxml/xmlmemory.h>
     84 #include <libxml/parser.h>
     85 #include <libxml/parserInternals.h>
     86 #include <libxml/xmlIO.h>
     87 #include <libxml/uri.h>
     88 #include <libxml/nanohttp.h>
     89 #include <libxml/nanoftp.h>
     90 #include <libxml/xmlerror.h>
     91 #ifdef LIBXML_CATALOG_ENABLED
     92 #include <libxml/catalog.h>
     93 #endif
     94 #include <libxml/globals.h>
     95 
     96 /* #define VERBOSE_FAILURE */
     97 /* #define DEBUG_EXTERNAL_ENTITIES */
     98 /* #define DEBUG_INPUT */
     99 
    100 #ifdef DEBUG_INPUT
    101 #define MINLEN 40
    102 #else
    103 #define MINLEN 4000
    104 #endif
    105 
    106 /*
    107  * Input I/O callback sets
    108  */
    109 typedef struct _xmlInputCallback {
    110     xmlInputMatchCallback matchcallback;
    111     xmlInputOpenCallback opencallback;
    112     xmlInputReadCallback readcallback;
    113     xmlInputCloseCallback closecallback;
    114 } xmlInputCallback;
    115 
    116 #define MAX_INPUT_CALLBACK 15
    117 
    118 static xmlInputCallback xmlInputCallbackTable[MAX_INPUT_CALLBACK];
    119 static int xmlInputCallbackNr = 0;
    120 static int xmlInputCallbackInitialized = 0;
    121 
    122 #ifdef LIBXML_OUTPUT_ENABLED
    123 /*
    124  * Output I/O callback sets
    125  */
    126 typedef struct _xmlOutputCallback {
    127     xmlOutputMatchCallback matchcallback;
    128     xmlOutputOpenCallback opencallback;
    129     xmlOutputWriteCallback writecallback;
    130     xmlOutputCloseCallback closecallback;
    131 } xmlOutputCallback;
    132 
    133 #define MAX_OUTPUT_CALLBACK 15
    134 
    135 static xmlOutputCallback xmlOutputCallbackTable[MAX_OUTPUT_CALLBACK];
    136 static int xmlOutputCallbackNr = 0;
    137 static int xmlOutputCallbackInitialized = 0;
    138 
    139 xmlOutputBufferPtr
    140 xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder);
    141 #endif /* LIBXML_OUTPUT_ENABLED */
    142 
    143 /************************************************************************
    144  *									*
    145  *		Tree memory error handler				*
    146  *									*
    147  ************************************************************************/
    148 
    149 static const char *IOerr[] = {
    150     "Unknown IO error",         /* UNKNOWN */
    151     "Permission denied",	/* EACCES */
    152     "Resource temporarily unavailable",/* EAGAIN */
    153     "Bad file descriptor",	/* EBADF */
    154     "Bad message",		/* EBADMSG */
    155     "Resource busy",		/* EBUSY */
    156     "Operation canceled",	/* ECANCELED */
    157     "No child processes",	/* ECHILD */
    158     "Resource deadlock avoided",/* EDEADLK */
    159     "Domain error",		/* EDOM */
    160     "File exists",		/* EEXIST */
    161     "Bad address",		/* EFAULT */
    162     "File too large",		/* EFBIG */
    163     "Operation in progress",	/* EINPROGRESS */
    164     "Interrupted function call",/* EINTR */
    165     "Invalid argument",		/* EINVAL */
    166     "Input/output error",	/* EIO */
    167     "Is a directory",		/* EISDIR */
    168     "Too many open files",	/* EMFILE */
    169     "Too many links",		/* EMLINK */
    170     "Inappropriate message buffer length",/* EMSGSIZE */
    171     "Filename too long",	/* ENAMETOOLONG */
    172     "Too many open files in system",/* ENFILE */
    173     "No such device",		/* ENODEV */
    174     "No such file or directory",/* ENOENT */
    175     "Exec format error",	/* ENOEXEC */
    176     "No locks available",	/* ENOLCK */
    177     "Not enough space",		/* ENOMEM */
    178     "No space left on device",	/* ENOSPC */
    179     "Function not implemented",	/* ENOSYS */
    180     "Not a directory",		/* ENOTDIR */
    181     "Directory not empty",	/* ENOTEMPTY */
    182     "Not supported",		/* ENOTSUP */
    183     "Inappropriate I/O control operation",/* ENOTTY */
    184     "No such device or address",/* ENXIO */
    185     "Operation not permitted",	/* EPERM */
    186     "Broken pipe",		/* EPIPE */
    187     "Result too large",		/* ERANGE */
    188     "Read-only file system",	/* EROFS */
    189     "Invalid seek",		/* ESPIPE */
    190     "No such process",		/* ESRCH */
    191     "Operation timed out",	/* ETIMEDOUT */
    192     "Improper link",		/* EXDEV */
    193     "Attempt to load network entity %s", /* XML_IO_NETWORK_ATTEMPT */
    194     "encoder error",		/* XML_IO_ENCODER */
    195     "flush error",
    196     "write error",
    197     "no input",
    198     "buffer full",
    199     "loading error",
    200     "not a socket",		/* ENOTSOCK */
    201     "already connected",	/* EISCONN */
    202     "connection refused",	/* ECONNREFUSED */
    203     "unreachable network",	/* ENETUNREACH */
    204     "adddress in use",		/* EADDRINUSE */
    205     "already in use",		/* EALREADY */
    206     "unknown address familly",	/* EAFNOSUPPORT */
    207 };
    208 
    209 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
    210 /**
    211  * __xmlIOWin32UTF8ToWChar:
    212  * @u8String:  uft-8 string
    213  *
    214  * Convert a string from utf-8 to wchar (WINDOWS ONLY!)
    215  */
    216 static wchar_t *
    217 __xmlIOWin32UTF8ToWChar(const char *u8String)
    218 {
    219     wchar_t *wString = NULL;
    220 
    221     if (u8String) {
    222         int wLen =
    223             MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, u8String,
    224                                 -1, NULL, 0);
    225         if (wLen) {
    226             wString = xmlMalloc(wLen * sizeof(wchar_t));
    227             if (wString) {
    228                 if (MultiByteToWideChar
    229                     (CP_UTF8, 0, u8String, -1, wString, wLen) == 0) {
    230                     xmlFree(wString);
    231                     wString = NULL;
    232                 }
    233             }
    234         }
    235     }
    236 
    237     return wString;
    238 }
    239 #endif
    240 
    241 /**
    242  * xmlIOErrMemory:
    243  * @extra:  extra informations
    244  *
    245  * Handle an out of memory condition
    246  */
    247 static void
    248 xmlIOErrMemory(const char *extra)
    249 {
    250     __xmlSimpleError(XML_FROM_IO, XML_ERR_NO_MEMORY, NULL, NULL, extra);
    251 }
    252 
    253 /**
    254  * __xmlIOErr:
    255  * @code:  the error number
    256  * @
    257  * @extra:  extra informations
    258  *
    259  * Handle an I/O error
    260  */
    261 void
    262 __xmlIOErr(int domain, int code, const char *extra)
    263 {
    264     unsigned int idx;
    265 
    266     if (code == 0) {
    267 #ifdef HAVE_ERRNO_H
    268 	if (errno == 0) code = 0;
    269 #ifdef EACCES
    270         else if (errno == EACCES) code = XML_IO_EACCES;
    271 #endif
    272 #ifdef EAGAIN
    273         else if (errno == EAGAIN) code = XML_IO_EAGAIN;
    274 #endif
    275 #ifdef EBADF
    276         else if (errno == EBADF) code = XML_IO_EBADF;
    277 #endif
    278 #ifdef EBADMSG
    279         else if (errno == EBADMSG) code = XML_IO_EBADMSG;
    280 #endif
    281 #ifdef EBUSY
    282         else if (errno == EBUSY) code = XML_IO_EBUSY;
    283 #endif
    284 #ifdef ECANCELED
    285         else if (errno == ECANCELED) code = XML_IO_ECANCELED;
    286 #endif
    287 #ifdef ECHILD
    288         else if (errno == ECHILD) code = XML_IO_ECHILD;
    289 #endif
    290 #ifdef EDEADLK
    291         else if (errno == EDEADLK) code = XML_IO_EDEADLK;
    292 #endif
    293 #ifdef EDOM
    294         else if (errno == EDOM) code = XML_IO_EDOM;
    295 #endif
    296 #ifdef EEXIST
    297         else if (errno == EEXIST) code = XML_IO_EEXIST;
    298 #endif
    299 #ifdef EFAULT
    300         else if (errno == EFAULT) code = XML_IO_EFAULT;
    301 #endif
    302 #ifdef EFBIG
    303         else if (errno == EFBIG) code = XML_IO_EFBIG;
    304 #endif
    305 #ifdef EINPROGRESS
    306         else if (errno == EINPROGRESS) code = XML_IO_EINPROGRESS;
    307 #endif
    308 #ifdef EINTR
    309         else if (errno == EINTR) code = XML_IO_EINTR;
    310 #endif
    311 #ifdef EINVAL
    312         else if (errno == EINVAL) code = XML_IO_EINVAL;
    313 #endif
    314 #ifdef EIO
    315         else if (errno == EIO) code = XML_IO_EIO;
    316 #endif
    317 #ifdef EISDIR
    318         else if (errno == EISDIR) code = XML_IO_EISDIR;
    319 #endif
    320 #ifdef EMFILE
    321         else if (errno == EMFILE) code = XML_IO_EMFILE;
    322 #endif
    323 #ifdef EMLINK
    324         else if (errno == EMLINK) code = XML_IO_EMLINK;
    325 #endif
    326 #ifdef EMSGSIZE
    327         else if (errno == EMSGSIZE) code = XML_IO_EMSGSIZE;
    328 #endif
    329 #ifdef ENAMETOOLONG
    330         else if (errno == ENAMETOOLONG) code = XML_IO_ENAMETOOLONG;
    331 #endif
    332 #ifdef ENFILE
    333         else if (errno == ENFILE) code = XML_IO_ENFILE;
    334 #endif
    335 #ifdef ENODEV
    336         else if (errno == ENODEV) code = XML_IO_ENODEV;
    337 #endif
    338 #ifdef ENOENT
    339         else if (errno == ENOENT) code = XML_IO_ENOENT;
    340 #endif
    341 #ifdef ENOEXEC
    342         else if (errno == ENOEXEC) code = XML_IO_ENOEXEC;
    343 #endif
    344 #ifdef ENOLCK
    345         else if (errno == ENOLCK) code = XML_IO_ENOLCK;
    346 #endif
    347 #ifdef ENOMEM
    348         else if (errno == ENOMEM) code = XML_IO_ENOMEM;
    349 #endif
    350 #ifdef ENOSPC
    351         else if (errno == ENOSPC) code = XML_IO_ENOSPC;
    352 #endif
    353 #ifdef ENOSYS
    354         else if (errno == ENOSYS) code = XML_IO_ENOSYS;
    355 #endif
    356 #ifdef ENOTDIR
    357         else if (errno == ENOTDIR) code = XML_IO_ENOTDIR;
    358 #endif
    359 #ifdef ENOTEMPTY
    360         else if (errno == ENOTEMPTY) code = XML_IO_ENOTEMPTY;
    361 #endif
    362 #ifdef ENOTSUP
    363         else if (errno == ENOTSUP) code = XML_IO_ENOTSUP;
    364 #endif
    365 #ifdef ENOTTY
    366         else if (errno == ENOTTY) code = XML_IO_ENOTTY;
    367 #endif
    368 #ifdef ENXIO
    369         else if (errno == ENXIO) code = XML_IO_ENXIO;
    370 #endif
    371 #ifdef EPERM
    372         else if (errno == EPERM) code = XML_IO_EPERM;
    373 #endif
    374 #ifdef EPIPE
    375         else if (errno == EPIPE) code = XML_IO_EPIPE;
    376 #endif
    377 #ifdef ERANGE
    378         else if (errno == ERANGE) code = XML_IO_ERANGE;
    379 #endif
    380 #ifdef EROFS
    381         else if (errno == EROFS) code = XML_IO_EROFS;
    382 #endif
    383 #ifdef ESPIPE
    384         else if (errno == ESPIPE) code = XML_IO_ESPIPE;
    385 #endif
    386 #ifdef ESRCH
    387         else if (errno == ESRCH) code = XML_IO_ESRCH;
    388 #endif
    389 #ifdef ETIMEDOUT
    390         else if (errno == ETIMEDOUT) code = XML_IO_ETIMEDOUT;
    391 #endif
    392 #ifdef EXDEV
    393         else if (errno == EXDEV) code = XML_IO_EXDEV;
    394 #endif
    395 #ifdef ENOTSOCK
    396         else if (errno == ENOTSOCK) code = XML_IO_ENOTSOCK;
    397 #endif
    398 #ifdef EISCONN
    399         else if (errno == EISCONN) code = XML_IO_EISCONN;
    400 #endif
    401 #ifdef ECONNREFUSED
    402         else if (errno == ECONNREFUSED) code = XML_IO_ECONNREFUSED;
    403 #endif
    404 #ifdef ETIMEDOUT
    405         else if (errno == ETIMEDOUT) code = XML_IO_ETIMEDOUT;
    406 #endif
    407 #ifdef ENETUNREACH
    408         else if (errno == ENETUNREACH) code = XML_IO_ENETUNREACH;
    409 #endif
    410 #ifdef EADDRINUSE
    411         else if (errno == EADDRINUSE) code = XML_IO_EADDRINUSE;
    412 #endif
    413 #ifdef EINPROGRESS
    414         else if (errno == EINPROGRESS) code = XML_IO_EINPROGRESS;
    415 #endif
    416 #ifdef EALREADY
    417         else if (errno == EALREADY) code = XML_IO_EALREADY;
    418 #endif
    419 #ifdef EAFNOSUPPORT
    420         else if (errno == EAFNOSUPPORT) code = XML_IO_EAFNOSUPPORT;
    421 #endif
    422         else code = XML_IO_UNKNOWN;
    423 #endif /* HAVE_ERRNO_H */
    424     }
    425     idx = 0;
    426     if (code >= XML_IO_UNKNOWN) idx = code - XML_IO_UNKNOWN;
    427     if (idx >= (sizeof(IOerr) / sizeof(IOerr[0]))) idx = 0;
    428 
    429     __xmlSimpleError(domain, code, NULL, IOerr[idx], extra);
    430 }
    431 
    432 /**
    433  * xmlIOErr:
    434  * @code:  the error number
    435  * @extra:  extra informations
    436  *
    437  * Handle an I/O error
    438  */
    439 static void
    440 xmlIOErr(int code, const char *extra)
    441 {
    442     __xmlIOErr(XML_FROM_IO, code, extra);
    443 }
    444 
    445 /**
    446  * __xmlLoaderErr:
    447  * @ctx: the parser context
    448  * @extra:  extra informations
    449  *
    450  * Handle a resource access error
    451  */
    452 void
    453 __xmlLoaderErr(void *ctx, const char *msg, const char *filename)
    454 {
    455     xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
    456     xmlStructuredErrorFunc schannel = NULL;
    457     xmlGenericErrorFunc channel = NULL;
    458     void *data = NULL;
    459     xmlErrorLevel level = XML_ERR_ERROR;
    460 
    461     if ((ctxt != NULL) && (ctxt->disableSAX != 0) &&
    462         (ctxt->instate == XML_PARSER_EOF))
    463 	return;
    464     if ((ctxt != NULL) && (ctxt->sax != NULL)) {
    465         if (ctxt->validate) {
    466 	    channel = ctxt->sax->error;
    467 	    level = XML_ERR_ERROR;
    468 	} else {
    469 	    channel = ctxt->sax->warning;
    470 	    level = XML_ERR_WARNING;
    471 	}
    472 	if (ctxt->sax->initialized == XML_SAX2_MAGIC)
    473 	    schannel = ctxt->sax->serror;
    474 	data = ctxt->userData;
    475     }
    476     __xmlRaiseError(schannel, channel, data, ctxt, NULL, XML_FROM_IO,
    477                     XML_IO_LOAD_ERROR, level, NULL, 0,
    478 		    filename, NULL, NULL, 0, 0,
    479 		    msg, filename);
    480 
    481 }
    482 
    483 /************************************************************************
    484  *									*
    485  *		Tree memory error handler				*
    486  *									*
    487  ************************************************************************/
    488 /**
    489  * xmlNormalizeWindowsPath:
    490  * @path: the input file path
    491  *
    492  * This function is obsolete. Please see xmlURIFromPath in uri.c for
    493  * a better solution.
    494  *
    495  * Returns a canonicalized version of the path
    496  */
    497 xmlChar *
    498 xmlNormalizeWindowsPath(const xmlChar *path)
    499 {
    500     return xmlCanonicPath(path);
    501 }
    502 
    503 /**
    504  * xmlCleanupInputCallbacks:
    505  *
    506  * clears the entire input callback table. this includes the
    507  * compiled-in I/O.
    508  */
    509 void
    510 xmlCleanupInputCallbacks(void)
    511 {
    512     int i;
    513 
    514     if (!xmlInputCallbackInitialized)
    515         return;
    516 
    517     for (i = xmlInputCallbackNr - 1; i >= 0; i--) {
    518         xmlInputCallbackTable[i].matchcallback = NULL;
    519         xmlInputCallbackTable[i].opencallback = NULL;
    520         xmlInputCallbackTable[i].readcallback = NULL;
    521         xmlInputCallbackTable[i].closecallback = NULL;
    522     }
    523 
    524     xmlInputCallbackNr = 0;
    525     xmlInputCallbackInitialized = 0;
    526 }
    527 
    528 /**
    529  * xmlPopInputCallbacks:
    530  *
    531  * Clear the top input callback from the input stack. this includes the
    532  * compiled-in I/O.
    533  *
    534  * Returns the number of input callback registered or -1 in case of error.
    535  */
    536 int
    537 xmlPopInputCallbacks(void)
    538 {
    539     if (!xmlInputCallbackInitialized)
    540         return(-1);
    541 
    542     if (xmlInputCallbackNr <= 0)
    543         return(-1);
    544 
    545     xmlInputCallbackNr--;
    546     xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = NULL;
    547     xmlInputCallbackTable[xmlInputCallbackNr].opencallback = NULL;
    548     xmlInputCallbackTable[xmlInputCallbackNr].readcallback = NULL;
    549     xmlInputCallbackTable[xmlInputCallbackNr].closecallback = NULL;
    550 
    551     return(xmlInputCallbackNr);
    552 }
    553 
    554 #ifdef LIBXML_OUTPUT_ENABLED
    555 /**
    556  * xmlCleanupOutputCallbacks:
    557  *
    558  * clears the entire output callback table. this includes the
    559  * compiled-in I/O callbacks.
    560  */
    561 void
    562 xmlCleanupOutputCallbacks(void)
    563 {
    564     int i;
    565 
    566     if (!xmlOutputCallbackInitialized)
    567         return;
    568 
    569     for (i = xmlOutputCallbackNr - 1; i >= 0; i--) {
    570         xmlOutputCallbackTable[i].matchcallback = NULL;
    571         xmlOutputCallbackTable[i].opencallback = NULL;
    572         xmlOutputCallbackTable[i].writecallback = NULL;
    573         xmlOutputCallbackTable[i].closecallback = NULL;
    574     }
    575 
    576     xmlOutputCallbackNr = 0;
    577     xmlOutputCallbackInitialized = 0;
    578 }
    579 #endif /* LIBXML_OUTPUT_ENABLED */
    580 
    581 /************************************************************************
    582  *									*
    583  *		Standard I/O for file accesses				*
    584  *									*
    585  ************************************************************************/
    586 
    587 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
    588 
    589 /**
    590  *  xmlWrapOpenUtf8:
    591  * @path:  the path in utf-8 encoding
    592  * @mode:  type of access (0 - read, 1 - write)
    593  *
    594  * function opens the file specified by @path
    595  *
    596  */
    597 static FILE*
    598 xmlWrapOpenUtf8(const char *path,int mode)
    599 {
    600     FILE *fd = NULL;
    601     wchar_t *wPath;
    602 
    603     wPath = __xmlIOWin32UTF8ToWChar(path);
    604     if(wPath)
    605     {
    606        fd = _wfopen(wPath, mode ? L"wb" : L"rb");
    607        xmlFree(wPath);
    608     }
    609     /* maybe path in native encoding */
    610     if(fd == NULL)
    611        fd = fopen(path, mode ? "wb" : "rb");
    612 
    613     return fd;
    614 }
    615 
    616 #ifdef HAVE_ZLIB_H
    617 static gzFile
    618 xmlWrapGzOpenUtf8(const char *path, const char *mode)
    619 {
    620     gzFile fd;
    621     wchar_t *wPath;
    622 
    623     fd = gzopen (path, mode);
    624     if (fd)
    625         return fd;
    626 
    627     wPath = __xmlIOWin32UTF8ToWChar(path);
    628     if(wPath)
    629     {
    630 	int d, m = (strstr(mode, "r") ? O_RDONLY : O_RDWR);
    631 #ifdef _O_BINARY
    632         m |= (strstr(mode, "b") ? _O_BINARY : 0);
    633 #endif
    634 	d = _wopen(wPath, m);
    635 	if (d >= 0)
    636 	    fd = gzdopen(d, mode);
    637         xmlFree(wPath);
    638     }
    639 
    640     return fd;
    641 }
    642 #endif
    643 
    644 /**
    645  *  xmlWrapStatUtf8:
    646  * @path:  the path in utf-8 encoding
    647  * @info:  structure that stores results
    648  *
    649  * function obtains information about the file or directory
    650  *
    651  */
    652 static int
    653 xmlWrapStatUtf8(const char *path,struct stat *info)
    654 {
    655 #ifdef HAVE_STAT
    656     int retval = -1;
    657     wchar_t *wPath;
    658 
    659     wPath = __xmlIOWin32UTF8ToWChar(path);
    660     if (wPath)
    661     {
    662        retval = _wstat(wPath,info);
    663        xmlFree(wPath);
    664     }
    665     /* maybe path in native encoding */
    666     if(retval < 0)
    667        retval = stat(path,info);
    668     return retval;
    669 #else
    670     return -1;
    671 #endif
    672 }
    673 
    674 /**
    675  *  xmlWrapOpenNative:
    676  * @path:  the path
    677  * @mode:  type of access (0 - read, 1 - write)
    678  *
    679  * function opens the file specified by @path
    680  *
    681  */
    682 static FILE*
    683 xmlWrapOpenNative(const char *path,int mode)
    684 {
    685     return fopen(path,mode ? "wb" : "rb");
    686 }
    687 
    688 /**
    689  *  xmlWrapStatNative:
    690  * @path:  the path
    691  * @info:  structure that stores results
    692  *
    693  * function obtains information about the file or directory
    694  *
    695  */
    696 static int
    697 xmlWrapStatNative(const char *path,struct stat *info)
    698 {
    699 #ifdef HAVE_STAT
    700     return stat(path,info);
    701 #else
    702     return -1;
    703 #endif
    704 }
    705 
    706 typedef int (* xmlWrapStatFunc) (const char *f, struct stat *s);
    707 static xmlWrapStatFunc xmlWrapStat = xmlWrapStatNative;
    708 typedef FILE* (* xmlWrapOpenFunc)(const char *f,int mode);
    709 static xmlWrapOpenFunc xmlWrapOpen = xmlWrapOpenNative;
    710 #ifdef HAVE_ZLIB_H
    711 typedef gzFile (* xmlWrapGzOpenFunc) (const char *f, const char *mode);
    712 static xmlWrapGzOpenFunc xmlWrapGzOpen = gzopen;
    713 #endif
    714 /**
    715  * xmlInitPlatformSpecificIo:
    716  *
    717  * Initialize platform specific features.
    718  */
    719 static void
    720 xmlInitPlatformSpecificIo(void)
    721 {
    722     static int xmlPlatformIoInitialized = 0;
    723     OSVERSIONINFO osvi;
    724 
    725     if(xmlPlatformIoInitialized)
    726       return;
    727 
    728     osvi.dwOSVersionInfoSize = sizeof(osvi);
    729 
    730     if(GetVersionEx(&osvi) && (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)) {
    731       xmlWrapStat = xmlWrapStatUtf8;
    732       xmlWrapOpen = xmlWrapOpenUtf8;
    733 #ifdef HAVE_ZLIB_H
    734       xmlWrapGzOpen = xmlWrapGzOpenUtf8;
    735 #endif
    736     } else {
    737       xmlWrapStat = xmlWrapStatNative;
    738       xmlWrapOpen = xmlWrapOpenNative;
    739 #ifdef HAVE_ZLIB_H
    740       xmlWrapGzOpen = gzopen;
    741 #endif
    742     }
    743 
    744     xmlPlatformIoInitialized = 1;
    745     return;
    746 }
    747 
    748 #endif
    749 
    750 /**
    751  * xmlCheckFilename:
    752  * @path:  the path to check
    753  *
    754  * function checks to see if @path is a valid source
    755  * (file, socket...) for XML.
    756  *
    757  * if stat is not available on the target machine,
    758  * returns 1.  if stat fails, returns 0 (if calling
    759  * stat on the filename fails, it can't be right).
    760  * if stat succeeds and the file is a directory,
    761  * returns 2.  otherwise returns 1.
    762  */
    763 
    764 int
    765 xmlCheckFilename (const char *path)
    766 {
    767 #ifdef HAVE_STAT
    768 	struct stat stat_buffer;
    769 #endif
    770 	if (path == NULL)
    771 		return(0);
    772 
    773 #ifdef HAVE_STAT
    774 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
    775     if (xmlWrapStat(path, &stat_buffer) == -1)
    776         return 0;
    777 #else
    778     if (stat(path, &stat_buffer) == -1)
    779         return 0;
    780 #endif
    781 #ifdef S_ISDIR
    782     if (S_ISDIR(stat_buffer.st_mode))
    783         return 2;
    784 #endif
    785 #endif /* HAVE_STAT */
    786     return 1;
    787 }
    788 
    789 static int
    790 xmlNop(void) {
    791     return(0);
    792 }
    793 
    794 /**
    795  * xmlFdRead:
    796  * @context:  the I/O context
    797  * @buffer:  where to drop data
    798  * @len:  number of bytes to read
    799  *
    800  * Read @len bytes to @buffer from the I/O channel.
    801  *
    802  * Returns the number of bytes written
    803  */
    804 static int
    805 xmlFdRead (void * context, char * buffer, int len) {
    806     int ret;
    807 
    808     ret = read((int) (long) context, &buffer[0], len);
    809     if (ret < 0) xmlIOErr(0, "read()");
    810     return(ret);
    811 }
    812 
    813 #ifdef LIBXML_OUTPUT_ENABLED
    814 /**
    815  * xmlFdWrite:
    816  * @context:  the I/O context
    817  * @buffer:  where to get data
    818  * @len:  number of bytes to write
    819  *
    820  * Write @len bytes from @buffer to the I/O channel.
    821  *
    822  * Returns the number of bytes written
    823  */
    824 static int
    825 xmlFdWrite (void * context, const char * buffer, int len) {
    826     int ret = 0;
    827 
    828     if (len > 0) {
    829 	ret = write((int) (long) context, &buffer[0], len);
    830 	if (ret < 0) xmlIOErr(0, "write()");
    831     }
    832     return(ret);
    833 }
    834 #endif /* LIBXML_OUTPUT_ENABLED */
    835 
    836 /**
    837  * xmlFdClose:
    838  * @context:  the I/O context
    839  *
    840  * Close an I/O channel
    841  *
    842  * Returns 0 in case of success and error code otherwise
    843  */
    844 static int
    845 xmlFdClose (void * context) {
    846     int ret;
    847     ret = close((int) (long) context);
    848     if (ret < 0) xmlIOErr(0, "close()");
    849     return(ret);
    850 }
    851 
    852 /**
    853  * xmlFileMatch:
    854  * @filename:  the URI for matching
    855  *
    856  * input from FILE *
    857  *
    858  * Returns 1 if matches, 0 otherwise
    859  */
    860 int
    861 xmlFileMatch (const char *filename ATTRIBUTE_UNUSED) {
    862     return(1);
    863 }
    864 
    865 /**
    866  * xmlFileOpen_real:
    867  * @filename:  the URI for matching
    868  *
    869  * input from FILE *, supports compressed input
    870  * if @filename is " " then the standard input is used
    871  *
    872  * Returns an I/O context or NULL in case of error
    873  */
    874 static void *
    875 xmlFileOpen_real (const char *filename) {
    876     const char *path = NULL;
    877     FILE *fd;
    878 
    879     if (filename == NULL)
    880         return(NULL);
    881 
    882     if (!strcmp(filename, "-")) {
    883 	fd = stdin;
    884 	return((void *) fd);
    885     }
    886 
    887     if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) {
    888 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
    889 	path = &filename[17];
    890 #else
    891 	path = &filename[16];
    892 #endif
    893     } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
    894 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
    895 	path = &filename[8];
    896 #else
    897 	path = &filename[7];
    898 #endif
    899     } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:/", 6)) {
    900         /* lots of generators seems to lazy to read RFC 1738 */
    901 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
    902 	path = &filename[6];
    903 #else
    904 	path = &filename[5];
    905 #endif
    906     } else
    907 	path = filename;
    908 
    909     if (path == NULL)
    910 	return(NULL);
    911     if (!xmlCheckFilename(path))
    912         return(NULL);
    913 
    914 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
    915     fd = xmlWrapOpen(path, 0);
    916 #else
    917     fd = fopen(path, "r");
    918 #endif /* WIN32 */
    919     if (fd == NULL) xmlIOErr(0, path);
    920     return((void *) fd);
    921 }
    922 
    923 /**
    924  * xmlFileOpen:
    925  * @filename:  the URI for matching
    926  *
    927  * Wrapper around xmlFileOpen_real that try it with an unescaped
    928  * version of @filename, if this fails fallback to @filename
    929  *
    930  * Returns a handler or NULL in case or failure
    931  */
    932 void *
    933 xmlFileOpen (const char *filename) {
    934     char *unescaped;
    935     void *retval;
    936 
    937     retval = xmlFileOpen_real(filename);
    938     if (retval == NULL) {
    939 	unescaped = xmlURIUnescapeString(filename, 0, NULL);
    940 	if (unescaped != NULL) {
    941 	    retval = xmlFileOpen_real(unescaped);
    942 	    xmlFree(unescaped);
    943 	}
    944     }
    945 
    946     return retval;
    947 }
    948 
    949 #ifdef LIBXML_OUTPUT_ENABLED
    950 /**
    951  * xmlFileOpenW:
    952  * @filename:  the URI for matching
    953  *
    954  * output to from FILE *,
    955  * if @filename is "-" then the standard output is used
    956  *
    957  * Returns an I/O context or NULL in case of error
    958  */
    959 static void *
    960 xmlFileOpenW (const char *filename) {
    961     const char *path = NULL;
    962     FILE *fd;
    963 
    964     if (!strcmp(filename, "-")) {
    965 	fd = stdout;
    966 	return((void *) fd);
    967     }
    968 
    969     if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
    970 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
    971 	path = &filename[17];
    972 #else
    973 	path = &filename[16];
    974 #endif
    975     else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
    976 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
    977 	path = &filename[8];
    978 #else
    979 	path = &filename[7];
    980 #endif
    981     } else
    982 	path = filename;
    983 
    984     if (path == NULL)
    985 	return(NULL);
    986 
    987 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
    988     fd = xmlWrapOpen(path, 1);
    989 #else
    990  	   fd = fopen(path, "wb");
    991 #endif /* WIN32 */
    992 
    993 	 if (fd == NULL) xmlIOErr(0, path);
    994     return((void *) fd);
    995 }
    996 #endif /* LIBXML_OUTPUT_ENABLED */
    997 
    998 /**
    999  * xmlFileRead:
   1000  * @context:  the I/O context
   1001  * @buffer:  where to drop data
   1002  * @len:  number of bytes to write
   1003  *
   1004  * Read @len bytes to @buffer from the I/O channel.
   1005  *
   1006  * Returns the number of bytes written or < 0 in case of failure
   1007  */
   1008 int
   1009 xmlFileRead (void * context, char * buffer, int len) {
   1010     int ret;
   1011     if ((context == NULL) || (buffer == NULL))
   1012         return(-1);
   1013     ret = fread(&buffer[0], 1,  len, (FILE *) context);
   1014     if (ret < 0) xmlIOErr(0, "fread()");
   1015     return(ret);
   1016 }
   1017 
   1018 #ifdef LIBXML_OUTPUT_ENABLED
   1019 /**
   1020  * xmlFileWrite:
   1021  * @context:  the I/O context
   1022  * @buffer:  where to drop data
   1023  * @len:  number of bytes to write
   1024  *
   1025  * Write @len bytes from @buffer to the I/O channel.
   1026  *
   1027  * Returns the number of bytes written
   1028  */
   1029 static int
   1030 xmlFileWrite (void * context, const char * buffer, int len) {
   1031     int items;
   1032 
   1033     if ((context == NULL) || (buffer == NULL))
   1034         return(-1);
   1035     items = fwrite(&buffer[0], len, 1, (FILE *) context);
   1036     if ((items == 0) && (ferror((FILE *) context))) {
   1037         xmlIOErr(0, "fwrite()");
   1038 	return(-1);
   1039     }
   1040     return(items * len);
   1041 }
   1042 #endif /* LIBXML_OUTPUT_ENABLED */
   1043 
   1044 /**
   1045  * xmlFileClose:
   1046  * @context:  the I/O context
   1047  *
   1048  * Close an I/O channel
   1049  *
   1050  * Returns 0 or -1 in case of error
   1051  */
   1052 int
   1053 xmlFileClose (void * context) {
   1054     FILE *fil;
   1055     int ret;
   1056 
   1057     if (context == NULL)
   1058         return(-1);
   1059     fil = (FILE *) context;
   1060     if ((fil == stdout) || (fil == stderr)) {
   1061         ret = fflush(fil);
   1062 	if (ret < 0)
   1063 	    xmlIOErr(0, "fflush()");
   1064 	return(0);
   1065     }
   1066     if (fil == stdin)
   1067 	return(0);
   1068     ret = ( fclose((FILE *) context) == EOF ) ? -1 : 0;
   1069     if (ret < 0)
   1070         xmlIOErr(0, "fclose()");
   1071     return(ret);
   1072 }
   1073 
   1074 /**
   1075  * xmlFileFlush:
   1076  * @context:  the I/O context
   1077  *
   1078  * Flush an I/O channel
   1079  */
   1080 static int
   1081 xmlFileFlush (void * context) {
   1082     int ret;
   1083 
   1084     if (context == NULL)
   1085         return(-1);
   1086     ret = ( fflush((FILE *) context) == EOF ) ? -1 : 0;
   1087     if (ret < 0)
   1088         xmlIOErr(0, "fflush()");
   1089     return(ret);
   1090 }
   1091 
   1092 #ifdef LIBXML_OUTPUT_ENABLED
   1093 /**
   1094  * xmlBufferWrite:
   1095  * @context:  the xmlBuffer
   1096  * @buffer:  the data to write
   1097  * @len:  number of bytes to write
   1098  *
   1099  * Write @len bytes from @buffer to the xml buffer
   1100  *
   1101  * Returns the number of bytes written
   1102  */
   1103 static int
   1104 xmlBufferWrite (void * context, const char * buffer, int len) {
   1105     int ret;
   1106 
   1107     ret = xmlBufferAdd((xmlBufferPtr) context, (const xmlChar *) buffer, len);
   1108     if (ret != 0)
   1109         return(-1);
   1110     return(len);
   1111 }
   1112 #endif
   1113 
   1114 #ifdef HAVE_ZLIB_H
   1115 /************************************************************************
   1116  *									*
   1117  *		I/O for compressed file accesses			*
   1118  *									*
   1119  ************************************************************************/
   1120 /**
   1121  * xmlGzfileMatch:
   1122  * @filename:  the URI for matching
   1123  *
   1124  * input from compressed file test
   1125  *
   1126  * Returns 1 if matches, 0 otherwise
   1127  */
   1128 static int
   1129 xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
   1130     return(1);
   1131 }
   1132 
   1133 /**
   1134  * xmlGzfileOpen_real:
   1135  * @filename:  the URI for matching
   1136  *
   1137  * input from compressed file open
   1138  * if @filename is " " then the standard input is used
   1139  *
   1140  * Returns an I/O context or NULL in case of error
   1141  */
   1142 static void *
   1143 xmlGzfileOpen_real (const char *filename) {
   1144     const char *path = NULL;
   1145     gzFile fd;
   1146 
   1147     if (!strcmp(filename, "-")) {
   1148         fd = gzdopen(dup(0), "rb");
   1149 	return((void *) fd);
   1150     }
   1151 
   1152     if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
   1153 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
   1154 	path = &filename[17];
   1155 #else
   1156 	path = &filename[16];
   1157 #endif
   1158     else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
   1159 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
   1160 	path = &filename[8];
   1161 #else
   1162 	path = &filename[7];
   1163 #endif
   1164     } else
   1165 	path = filename;
   1166 
   1167     if (path == NULL)
   1168 	return(NULL);
   1169     if (!xmlCheckFilename(path))
   1170         return(NULL);
   1171 
   1172 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
   1173     fd = xmlWrapGzOpen(path, "rb");
   1174 #else
   1175     fd = gzopen(path, "rb");
   1176 #endif
   1177     return((void *) fd);
   1178 }
   1179 
   1180 /**
   1181  * xmlGzfileOpen:
   1182  * @filename:  the URI for matching
   1183  *
   1184  * Wrapper around xmlGzfileOpen if the open fais, it will
   1185  * try to unescape @filename
   1186  */
   1187 static void *
   1188 xmlGzfileOpen (const char *filename) {
   1189     char *unescaped;
   1190     void *retval;
   1191 
   1192     retval = xmlGzfileOpen_real(filename);
   1193     if (retval == NULL) {
   1194 	unescaped = xmlURIUnescapeString(filename, 0, NULL);
   1195 	if (unescaped != NULL) {
   1196 	    retval = xmlGzfileOpen_real(unescaped);
   1197 	}
   1198 	xmlFree(unescaped);
   1199     }
   1200     return retval;
   1201 }
   1202 
   1203 #ifdef LIBXML_OUTPUT_ENABLED
   1204 /**
   1205  * xmlGzfileOpenW:
   1206  * @filename:  the URI for matching
   1207  * @compression:  the compression factor (0 - 9 included)
   1208  *
   1209  * input from compressed file open
   1210  * if @filename is " " then the standard input is used
   1211  *
   1212  * Returns an I/O context or NULL in case of error
   1213  */
   1214 static void *
   1215 xmlGzfileOpenW (const char *filename, int compression) {
   1216     const char *path = NULL;
   1217     char mode[15];
   1218     gzFile fd;
   1219 
   1220     snprintf(mode, sizeof(mode), "wb%d", compression);
   1221     if (!strcmp(filename, "-")) {
   1222         fd = gzdopen(dup(1), mode);
   1223 	return((void *) fd);
   1224     }
   1225 
   1226     if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
   1227 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
   1228 	path = &filename[17];
   1229 #else
   1230 	path = &filename[16];
   1231 #endif
   1232     else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
   1233 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
   1234 	path = &filename[8];
   1235 #else
   1236 	path = &filename[7];
   1237 #endif
   1238     } else
   1239 	path = filename;
   1240 
   1241     if (path == NULL)
   1242 	return(NULL);
   1243 
   1244 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
   1245     fd = xmlWrapGzOpen(path, mode);
   1246 #else
   1247     fd = gzopen(path, mode);
   1248 #endif
   1249     return((void *) fd);
   1250 }
   1251 #endif /* LIBXML_OUTPUT_ENABLED */
   1252 
   1253 /**
   1254  * xmlGzfileRead:
   1255  * @context:  the I/O context
   1256  * @buffer:  where to drop data
   1257  * @len:  number of bytes to write
   1258  *
   1259  * Read @len bytes to @buffer from the compressed I/O channel.
   1260  *
   1261  * Returns the number of bytes written
   1262  */
   1263 static int
   1264 xmlGzfileRead (void * context, char * buffer, int len) {
   1265     int ret;
   1266 
   1267     ret = gzread((gzFile) context, &buffer[0], len);
   1268     if (ret < 0) xmlIOErr(0, "gzread()");
   1269     return(ret);
   1270 }
   1271 
   1272 #ifdef LIBXML_OUTPUT_ENABLED
   1273 /**
   1274  * xmlGzfileWrite:
   1275  * @context:  the I/O context
   1276  * @buffer:  where to drop data
   1277  * @len:  number of bytes to write
   1278  *
   1279  * Write @len bytes from @buffer to the compressed I/O channel.
   1280  *
   1281  * Returns the number of bytes written
   1282  */
   1283 static int
   1284 xmlGzfileWrite (void * context, const char * buffer, int len) {
   1285     int ret;
   1286 
   1287     ret = gzwrite((gzFile) context, (char *) &buffer[0], len);
   1288     if (ret < 0) xmlIOErr(0, "gzwrite()");
   1289     return(ret);
   1290 }
   1291 #endif /* LIBXML_OUTPUT_ENABLED */
   1292 
   1293 /**
   1294  * xmlGzfileClose:
   1295  * @context:  the I/O context
   1296  *
   1297  * Close a compressed I/O channel
   1298  */
   1299 static int
   1300 xmlGzfileClose (void * context) {
   1301     int ret;
   1302 
   1303     ret =  (gzclose((gzFile) context) == Z_OK ) ? 0 : -1;
   1304     if (ret < 0) xmlIOErr(0, "gzclose()");
   1305     return(ret);
   1306 }
   1307 #endif /* HAVE_ZLIB_H */
   1308 
   1309 #ifdef LIBXML_HTTP_ENABLED
   1310 /************************************************************************
   1311  *									*
   1312  *			I/O for HTTP file accesses			*
   1313  *									*
   1314  ************************************************************************/
   1315 
   1316 #ifdef LIBXML_OUTPUT_ENABLED
   1317 typedef struct xmlIOHTTPWriteCtxt_
   1318 {
   1319     int			compression;
   1320 
   1321     char *		uri;
   1322 
   1323     void *		doc_buff;
   1324 
   1325 } xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr;
   1326 
   1327 #ifdef HAVE_ZLIB_H
   1328 
   1329 #define DFLT_WBITS		( -15 )
   1330 #define DFLT_MEM_LVL		( 8 )
   1331 #define GZ_MAGIC1		( 0x1f )
   1332 #define GZ_MAGIC2		( 0x8b )
   1333 #define LXML_ZLIB_OS_CODE	( 0x03 )
   1334 #define INIT_HTTP_BUFF_SIZE	( 32768 )
   1335 #define DFLT_ZLIB_RATIO		( 5 )
   1336 
   1337 /*
   1338 **  Data structure and functions to work with sending compressed data
   1339 **  via HTTP.
   1340 */
   1341 
   1342 typedef struct xmlZMemBuff_
   1343 {
   1344    unsigned long	size;
   1345    unsigned long	crc;
   1346 
   1347    unsigned char *	zbuff;
   1348    z_stream		zctrl;
   1349 
   1350 } xmlZMemBuff, *xmlZMemBuffPtr;
   1351 
   1352 /**
   1353  * append_reverse_ulong
   1354  * @buff:  Compressed memory buffer
   1355  * @data:  Unsigned long to append
   1356  *
   1357  * Append a unsigned long in reverse byte order to the end of the
   1358  * memory buffer.
   1359  */
   1360 static void
   1361 append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) {
   1362 
   1363     int		idx;
   1364 
   1365     if ( buff == NULL )
   1366 	return;
   1367 
   1368     /*
   1369     **  This is plagiarized from putLong in gzio.c (zlib source) where
   1370     **  the number "4" is hardcoded.  If zlib is ever patched to
   1371     **  support 64 bit file sizes, this code would need to be patched
   1372     **  as well.
   1373     */
   1374 
   1375     for ( idx = 0; idx < 4; idx++ ) {
   1376 	*buff->zctrl.next_out = ( data & 0xff );
   1377 	data >>= 8;
   1378 	buff->zctrl.next_out++;
   1379     }
   1380 
   1381     return;
   1382 }
   1383 
   1384 /**
   1385  *
   1386  * xmlFreeZMemBuff
   1387  * @buff:  The memory buffer context to clear
   1388  *
   1389  * Release all the resources associated with the compressed memory buffer.
   1390  */
   1391 static void
   1392 xmlFreeZMemBuff( xmlZMemBuffPtr buff ) {
   1393 
   1394 #ifdef DEBUG_HTTP
   1395     int z_err;
   1396 #endif
   1397 
   1398     if ( buff == NULL )
   1399 	return;
   1400 
   1401     xmlFree( buff->zbuff );
   1402 #ifdef DEBUG_HTTP
   1403     z_err = deflateEnd( &buff->zctrl );
   1404     if ( z_err != Z_OK )
   1405 	xmlGenericError( xmlGenericErrorContext,
   1406 			"xmlFreeZMemBuff:  Error releasing zlib context:  %d\n",
   1407 			z_err );
   1408 #else
   1409     deflateEnd( &buff->zctrl );
   1410 #endif
   1411 
   1412     xmlFree( buff );
   1413     return;
   1414 }
   1415 
   1416 /**
   1417  * xmlCreateZMemBuff
   1418  *@compression:	Compression value to use
   1419  *
   1420  * Create a memory buffer to hold the compressed XML document.  The
   1421  * compressed document in memory will end up being identical to what
   1422  * would be created if gzopen/gzwrite/gzclose were being used to
   1423  * write the document to disk.  The code for the header/trailer data to
   1424  * the compression is plagiarized from the zlib source files.
   1425  */
   1426 static void *
   1427 xmlCreateZMemBuff( int compression ) {
   1428 
   1429     int			z_err;
   1430     int			hdr_lgth;
   1431     xmlZMemBuffPtr	buff = NULL;
   1432 
   1433     if ( ( compression < 1 ) || ( compression > 9 ) )
   1434 	return ( NULL );
   1435 
   1436     /*  Create the control and data areas  */
   1437 
   1438     buff = xmlMalloc( sizeof( xmlZMemBuff ) );
   1439     if ( buff == NULL ) {
   1440 	xmlIOErrMemory("creating buffer context");
   1441 	return ( NULL );
   1442     }
   1443 
   1444     (void)memset( buff, 0, sizeof( xmlZMemBuff ) );
   1445     buff->size = INIT_HTTP_BUFF_SIZE;
   1446     buff->zbuff = xmlMalloc( buff->size );
   1447     if ( buff->zbuff == NULL ) {
   1448 	xmlFreeZMemBuff( buff );
   1449 	xmlIOErrMemory("creating buffer");
   1450 	return ( NULL );
   1451     }
   1452 
   1453     z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
   1454 			    DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
   1455     if ( z_err != Z_OK ) {
   1456 	xmlChar msg[500];
   1457 	xmlFreeZMemBuff( buff );
   1458 	buff = NULL;
   1459 	xmlStrPrintf(msg, 500,
   1460 		    (const xmlChar *) "xmlCreateZMemBuff:  %s %d\n",
   1461 		    "Error initializing compression context.  ZLIB error:",
   1462 		    z_err );
   1463 	xmlIOErr(XML_IO_WRITE, (const char *) msg);
   1464 	return ( NULL );
   1465     }
   1466 
   1467     /*  Set the header data.  The CRC will be needed for the trailer  */
   1468     buff->crc = crc32( 0L, NULL, 0 );
   1469     hdr_lgth = snprintf( (char *)buff->zbuff, buff->size,
   1470 			"%c%c%c%c%c%c%c%c%c%c",
   1471 			GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED,
   1472 			0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE );
   1473     buff->zctrl.next_out  = buff->zbuff + hdr_lgth;
   1474     buff->zctrl.avail_out = buff->size - hdr_lgth;
   1475 
   1476     return ( buff );
   1477 }
   1478 
   1479 /**
   1480  * xmlZMemBuffExtend
   1481  * @buff:  Buffer used to compress and consolidate data.
   1482  * @ext_amt:   Number of bytes to extend the buffer.
   1483  *
   1484  * Extend the internal buffer used to store the compressed data by the
   1485  * specified amount.
   1486  *
   1487  * Returns 0 on success or -1 on failure to extend the buffer.  On failure
   1488  * the original buffer still exists at the original size.
   1489  */
   1490 static int
   1491 xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) {
   1492 
   1493     int			rc = -1;
   1494     size_t		new_size;
   1495     size_t		cur_used;
   1496 
   1497     unsigned char *	tmp_ptr = NULL;
   1498 
   1499     if ( buff == NULL )
   1500 	return ( -1 );
   1501 
   1502     else if ( ext_amt == 0 )
   1503 	return ( 0 );
   1504 
   1505     cur_used = buff->zctrl.next_out - buff->zbuff;
   1506     new_size = buff->size + ext_amt;
   1507 
   1508 #ifdef DEBUG_HTTP
   1509     if ( cur_used > new_size )
   1510 	xmlGenericError( xmlGenericErrorContext,
   1511 			"xmlZMemBuffExtend:  %s\n%s %d bytes.\n",
   1512 			"Buffer overwrite detected during compressed memory",
   1513 			"buffer extension.  Overflowed by",
   1514 			(cur_used - new_size ) );
   1515 #endif
   1516 
   1517     tmp_ptr = xmlRealloc( buff->zbuff, new_size );
   1518     if ( tmp_ptr != NULL ) {
   1519 	rc = 0;
   1520 	buff->size  = new_size;
   1521 	buff->zbuff = tmp_ptr;
   1522 	buff->zctrl.next_out  = tmp_ptr + cur_used;
   1523 	buff->zctrl.avail_out = new_size - cur_used;
   1524     }
   1525     else {
   1526 	xmlChar msg[500];
   1527 	xmlStrPrintf(msg, 500,
   1528 		    (const xmlChar *) "xmlZMemBuffExtend:  %s %lu bytes.\n",
   1529 		    "Allocation failure extending output buffer to",
   1530 		    new_size );
   1531 	xmlIOErr(XML_IO_WRITE, (const char *) msg);
   1532     }
   1533 
   1534     return ( rc );
   1535 }
   1536 
   1537 /**
   1538  * xmlZMemBuffAppend
   1539  * @buff:  Buffer used to compress and consolidate data
   1540  * @src:   Uncompressed source content to append to buffer
   1541  * @len:   Length of source data to append to buffer
   1542  *
   1543  * Compress and append data to the internal buffer.  The data buffer
   1544  * will be expanded if needed to store the additional data.
   1545  *
   1546  * Returns the number of bytes appended to the buffer or -1 on error.
   1547  */
   1548 static int
   1549 xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) {
   1550 
   1551     int		z_err;
   1552     size_t	min_accept;
   1553 
   1554     if ( ( buff == NULL ) || ( src == NULL ) )
   1555 	return ( -1 );
   1556 
   1557     buff->zctrl.avail_in = len;
   1558     buff->zctrl.next_in  = (unsigned char *)src;
   1559     while ( buff->zctrl.avail_in > 0 ) {
   1560 	/*
   1561 	**  Extend the buffer prior to deflate call if a reasonable amount
   1562 	**  of output buffer space is not available.
   1563 	*/
   1564 	min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO;
   1565 	if ( buff->zctrl.avail_out <= min_accept ) {
   1566 	    if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
   1567 		return ( -1 );
   1568 	}
   1569 
   1570 	z_err = deflate( &buff->zctrl, Z_NO_FLUSH );
   1571 	if ( z_err != Z_OK ) {
   1572 	    xmlChar msg[500];
   1573 	    xmlStrPrintf(msg, 500,
   1574 			(const xmlChar *) "xmlZMemBuffAppend:  %s %d %s - %d",
   1575 			"Compression error while appending",
   1576 			len, "bytes to buffer.  ZLIB error", z_err );
   1577 	    xmlIOErr(XML_IO_WRITE, (const char *) msg);
   1578 	    return ( -1 );
   1579 	}
   1580     }
   1581 
   1582     buff->crc = crc32( buff->crc, (unsigned char *)src, len );
   1583 
   1584     return ( len );
   1585 }
   1586 
   1587 /**
   1588  * xmlZMemBuffGetContent
   1589  * @buff:  Compressed memory content buffer
   1590  * @data_ref:  Pointer reference to point to compressed content
   1591  *
   1592  * Flushes the compression buffers, appends gzip file trailers and
   1593  * returns the compressed content and length of the compressed data.
   1594  * NOTE:  The gzip trailer code here is plagiarized from zlib source.
   1595  *
   1596  * Returns the length of the compressed data or -1 on error.
   1597  */
   1598 static int
   1599 xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) {
   1600 
   1601     int		zlgth = -1;
   1602     int		z_err;
   1603 
   1604     if ( ( buff == NULL ) || ( data_ref == NULL ) )
   1605 	return ( -1 );
   1606 
   1607     /*  Need to loop until compression output buffers are flushed  */
   1608 
   1609     do
   1610     {
   1611 	z_err = deflate( &buff->zctrl, Z_FINISH );
   1612 	if ( z_err == Z_OK ) {
   1613 	    /*  In this case Z_OK means more buffer space needed  */
   1614 
   1615 	    if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
   1616 		return ( -1 );
   1617 	}
   1618     }
   1619     while ( z_err == Z_OK );
   1620 
   1621     /*  If the compression state is not Z_STREAM_END, some error occurred  */
   1622 
   1623     if ( z_err == Z_STREAM_END ) {
   1624 
   1625 	/*  Need to append the gzip data trailer  */
   1626 
   1627 	if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) {
   1628 	    if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 )
   1629 		return ( -1 );
   1630 	}
   1631 
   1632 	/*
   1633 	**  For whatever reason, the CRC and length data are pushed out
   1634 	**  in reverse byte order.  So a memcpy can't be used here.
   1635 	*/
   1636 
   1637 	append_reverse_ulong( buff, buff->crc );
   1638 	append_reverse_ulong( buff, buff->zctrl.total_in );
   1639 
   1640 	zlgth = buff->zctrl.next_out - buff->zbuff;
   1641 	*data_ref = (char *)buff->zbuff;
   1642     }
   1643 
   1644     else {
   1645 	xmlChar msg[500];
   1646 	xmlStrPrintf(msg, 500,
   1647 		    (const xmlChar *) "xmlZMemBuffGetContent:  %s - %d\n",
   1648 		    "Error flushing zlib buffers.  Error code", z_err );
   1649 	xmlIOErr(XML_IO_WRITE, (const char *) msg);
   1650     }
   1651 
   1652     return ( zlgth );
   1653 }
   1654 #endif /* LIBXML_OUTPUT_ENABLED */
   1655 #endif  /*  HAVE_ZLIB_H  */
   1656 
   1657 #ifdef LIBXML_OUTPUT_ENABLED
   1658 /**
   1659  * xmlFreeHTTPWriteCtxt
   1660  * @ctxt:  Context to cleanup
   1661  *
   1662  * Free allocated memory and reclaim system resources.
   1663  *
   1664  * No return value.
   1665  */
   1666 static void
   1667 xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt )
   1668 {
   1669     if ( ctxt->uri != NULL )
   1670 	xmlFree( ctxt->uri );
   1671 
   1672     if ( ctxt->doc_buff != NULL ) {
   1673 
   1674 #ifdef HAVE_ZLIB_H
   1675 	if ( ctxt->compression > 0 ) {
   1676 	    xmlFreeZMemBuff( ctxt->doc_buff );
   1677 	}
   1678 	else
   1679 #endif
   1680 	{
   1681 	    xmlOutputBufferClose( ctxt->doc_buff );
   1682 	}
   1683     }
   1684 
   1685     xmlFree( ctxt );
   1686     return;
   1687 }
   1688 #endif /* LIBXML_OUTPUT_ENABLED */
   1689 
   1690 
   1691 /**
   1692  * xmlIOHTTPMatch:
   1693  * @filename:  the URI for matching
   1694  *
   1695  * check if the URI matches an HTTP one
   1696  *
   1697  * Returns 1 if matches, 0 otherwise
   1698  */
   1699 int
   1700 xmlIOHTTPMatch (const char *filename) {
   1701     if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "http://", 7))
   1702 	return(1);
   1703     return(0);
   1704 }
   1705 
   1706 /**
   1707  * xmlIOHTTPOpen:
   1708  * @filename:  the URI for matching
   1709  *
   1710  * open an HTTP I/O channel
   1711  *
   1712  * Returns an I/O context or NULL in case of error
   1713  */
   1714 void *
   1715 xmlIOHTTPOpen (const char *filename) {
   1716     return(xmlNanoHTTPOpen(filename, NULL));
   1717 }
   1718 
   1719 #ifdef LIBXML_OUTPUT_ENABLED
   1720 /**
   1721  * xmlIOHTTPOpenW:
   1722  * @post_uri:  The destination URI for the document
   1723  * @compression:  The compression desired for the document.
   1724  *
   1725  * Open a temporary buffer to collect the document for a subsequent HTTP POST
   1726  * request.  Non-static as is called from the output buffer creation routine.
   1727  *
   1728  * Returns an I/O context or NULL in case of error.
   1729  */
   1730 
   1731 void *
   1732 xmlIOHTTPOpenW(const char *post_uri, int compression)
   1733 {
   1734 
   1735     xmlIOHTTPWriteCtxtPtr ctxt = NULL;
   1736 
   1737     if (post_uri == NULL)
   1738         return (NULL);
   1739 
   1740     ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt));
   1741     if (ctxt == NULL) {
   1742 	xmlIOErrMemory("creating HTTP output context");
   1743         return (NULL);
   1744     }
   1745 
   1746     (void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt));
   1747 
   1748     ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri);
   1749     if (ctxt->uri == NULL) {
   1750 	xmlIOErrMemory("copying URI");
   1751         xmlFreeHTTPWriteCtxt(ctxt);
   1752         return (NULL);
   1753     }
   1754 
   1755     /*
   1756      * **  Since the document length is required for an HTTP post,
   1757      * **  need to put the document into a buffer.  A memory buffer
   1758      * **  is being used to avoid pushing the data to disk and back.
   1759      */
   1760 
   1761 #ifdef HAVE_ZLIB_H
   1762     if ((compression > 0) && (compression <= 9)) {
   1763 
   1764         ctxt->compression = compression;
   1765         ctxt->doc_buff = xmlCreateZMemBuff(compression);
   1766     } else
   1767 #endif
   1768     {
   1769         /*  Any character conversions should have been done before this  */
   1770 
   1771         ctxt->doc_buff = xmlAllocOutputBufferInternal(NULL);
   1772     }
   1773 
   1774     if (ctxt->doc_buff == NULL) {
   1775         xmlFreeHTTPWriteCtxt(ctxt);
   1776         ctxt = NULL;
   1777     }
   1778 
   1779     return (ctxt);
   1780 }
   1781 #endif /* LIBXML_OUTPUT_ENABLED */
   1782 
   1783 #ifdef LIBXML_OUTPUT_ENABLED
   1784 /**
   1785  * xmlIOHTTPDfltOpenW
   1786  * @post_uri:  The destination URI for this document.
   1787  *
   1788  * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
   1789  * HTTP post command.  This function should generally not be used as
   1790  * the open callback is short circuited in xmlOutputBufferCreateFile.
   1791  *
   1792  * Returns a pointer to the new IO context.
   1793  */
   1794 static void *
   1795 xmlIOHTTPDfltOpenW( const char * post_uri ) {
   1796     return ( xmlIOHTTPOpenW( post_uri, 0 ) );
   1797 }
   1798 #endif /* LIBXML_OUTPUT_ENABLED */
   1799 
   1800 /**
   1801  * xmlIOHTTPRead:
   1802  * @context:  the I/O context
   1803  * @buffer:  where to drop data
   1804  * @len:  number of bytes to write
   1805  *
   1806  * Read @len bytes to @buffer from the I/O channel.
   1807  *
   1808  * Returns the number of bytes written
   1809  */
   1810 int
   1811 xmlIOHTTPRead(void * context, char * buffer, int len) {
   1812     if ((buffer == NULL) || (len < 0)) return(-1);
   1813     return(xmlNanoHTTPRead(context, &buffer[0], len));
   1814 }
   1815 
   1816 #ifdef LIBXML_OUTPUT_ENABLED
   1817 /**
   1818  * xmlIOHTTPWrite
   1819  * @context:  previously opened writing context
   1820  * @buffer:   data to output to temporary buffer
   1821  * @len:      bytes to output
   1822  *
   1823  * Collect data from memory buffer into a temporary file for later
   1824  * processing.
   1825  *
   1826  * Returns number of bytes written.
   1827  */
   1828 
   1829 static int
   1830 xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
   1831 
   1832     xmlIOHTTPWriteCtxtPtr	ctxt = context;
   1833 
   1834     if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
   1835 	return ( -1 );
   1836 
   1837     if ( len > 0 ) {
   1838 
   1839 	/*  Use gzwrite or fwrite as previously setup in the open call  */
   1840 
   1841 #ifdef HAVE_ZLIB_H
   1842 	if ( ctxt->compression > 0 )
   1843 	    len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len );
   1844 
   1845 	else
   1846 #endif
   1847 	    len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
   1848 
   1849 	if ( len < 0 ) {
   1850 	    xmlChar msg[500];
   1851 	    xmlStrPrintf(msg, 500,
   1852 			(const xmlChar *) "xmlIOHTTPWrite:  %s\n%s '%s'.\n",
   1853 			"Error appending to internal buffer.",
   1854 			"Error sending document to URI",
   1855 			ctxt->uri );
   1856 	    xmlIOErr(XML_IO_WRITE, (const char *) msg);
   1857 	}
   1858     }
   1859 
   1860     return ( len );
   1861 }
   1862 #endif /* LIBXML_OUTPUT_ENABLED */
   1863 
   1864 
   1865 /**
   1866  * xmlIOHTTPClose:
   1867  * @context:  the I/O context
   1868  *
   1869  * Close an HTTP I/O channel
   1870  *
   1871  * Returns 0
   1872  */
   1873 int
   1874 xmlIOHTTPClose (void * context) {
   1875     xmlNanoHTTPClose(context);
   1876     return 0;
   1877 }
   1878 
   1879 #ifdef LIBXML_OUTPUT_ENABLED
   1880 /**
   1881  * xmlIOHTTCloseWrite
   1882  * @context:  The I/O context
   1883  * @http_mthd: The HTTP method to be used when sending the data
   1884  *
   1885  * Close the transmit HTTP I/O channel and actually send the data.
   1886  */
   1887 static int
   1888 xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
   1889 
   1890     int				close_rc = -1;
   1891     int				http_rtn = 0;
   1892     int				content_lgth = 0;
   1893     xmlIOHTTPWriteCtxtPtr	ctxt = context;
   1894 
   1895     char *			http_content = NULL;
   1896     char *			content_encoding = NULL;
   1897     char *			content_type = (char *) "text/xml";
   1898     void *			http_ctxt = NULL;
   1899 
   1900     if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
   1901 	return ( -1 );
   1902 
   1903     /*  Retrieve the content from the appropriate buffer  */
   1904 
   1905 #ifdef HAVE_ZLIB_H
   1906 
   1907     if ( ctxt->compression > 0 ) {
   1908 	content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
   1909 	content_encoding = (char *) "Content-Encoding: gzip";
   1910     }
   1911     else
   1912 #endif
   1913     {
   1914 	/*  Pull the data out of the memory output buffer  */
   1915 
   1916 	xmlOutputBufferPtr	dctxt = ctxt->doc_buff;
   1917 	http_content = (char *)dctxt->buffer->content;
   1918 	content_lgth = dctxt->buffer->use;
   1919     }
   1920 
   1921     if ( http_content == NULL ) {
   1922 	xmlChar msg[500];
   1923 	xmlStrPrintf(msg, 500,
   1924 		     (const xmlChar *) "xmlIOHTTPCloseWrite:  %s '%s' %s '%s'.\n",
   1925 		     "Error retrieving content.\nUnable to",
   1926 		     http_mthd, "data to URI", ctxt->uri );
   1927 	xmlIOErr(XML_IO_WRITE, (const char *) msg);
   1928     }
   1929 
   1930     else {
   1931 
   1932 	http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
   1933 					&content_type, content_encoding,
   1934 					content_lgth );
   1935 
   1936 	if ( http_ctxt != NULL ) {
   1937 #ifdef DEBUG_HTTP
   1938 	    /*  If testing/debugging - dump reply with request content  */
   1939 
   1940 	    FILE *	tst_file = NULL;
   1941 	    char	buffer[ 4096 ];
   1942 	    char *	dump_name = NULL;
   1943 	    int		avail;
   1944 
   1945 	    xmlGenericError( xmlGenericErrorContext,
   1946 			"xmlNanoHTTPCloseWrite:  HTTP %s to\n%s returned %d.\n",
   1947 			http_mthd, ctxt->uri,
   1948 			xmlNanoHTTPReturnCode( http_ctxt ) );
   1949 
   1950 	    /*
   1951 	    **  Since either content or reply may be gzipped,
   1952 	    **  dump them to separate files instead of the
   1953 	    **  standard error context.
   1954 	    */
   1955 
   1956 	    dump_name = tempnam( NULL, "lxml" );
   1957 	    if ( dump_name != NULL ) {
   1958 		(void)snprintf( buffer, sizeof(buffer), "%s.content", dump_name );
   1959 
   1960 		tst_file = fopen( buffer, "wb" );
   1961 		if ( tst_file != NULL ) {
   1962 		    xmlGenericError( xmlGenericErrorContext,
   1963 			"Transmitted content saved in file:  %s\n", buffer );
   1964 
   1965 		    fwrite( http_content, sizeof( char ),
   1966 					content_lgth, tst_file );
   1967 		    fclose( tst_file );
   1968 		}
   1969 
   1970 		(void)snprintf( buffer, sizeof(buffer), "%s.reply", dump_name );
   1971 		tst_file = fopen( buffer, "wb" );
   1972 		if ( tst_file != NULL ) {
   1973 		    xmlGenericError( xmlGenericErrorContext,
   1974 			"Reply content saved in file:  %s\n", buffer );
   1975 
   1976 
   1977 		    while ( (avail = xmlNanoHTTPRead( http_ctxt,
   1978 					buffer, sizeof( buffer ) )) > 0 ) {
   1979 
   1980 			fwrite( buffer, sizeof( char ), avail, tst_file );
   1981 		    }
   1982 
   1983 		    fclose( tst_file );
   1984 		}
   1985 
   1986 		free( dump_name );
   1987 	    }
   1988 #endif  /*  DEBUG_HTTP  */
   1989 
   1990 	    http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
   1991 	    if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
   1992 		close_rc = 0;
   1993 	    else {
   1994                 xmlChar msg[500];
   1995                 xmlStrPrintf(msg, 500,
   1996     (const xmlChar *) "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
   1997 			    http_mthd, content_lgth,
   1998 			    "bytes to URI", ctxt->uri,
   1999 			    "failed.  HTTP return code:", http_rtn );
   2000 		xmlIOErr(XML_IO_WRITE, (const char *) msg);
   2001             }
   2002 
   2003 	    xmlNanoHTTPClose( http_ctxt );
   2004 	    xmlFree( content_type );
   2005 	}
   2006     }
   2007 
   2008     /*  Final cleanups  */
   2009 
   2010     xmlFreeHTTPWriteCtxt( ctxt );
   2011 
   2012     return ( close_rc );
   2013 }
   2014 
   2015 /**
   2016  * xmlIOHTTPClosePut
   2017  *
   2018  * @context:  The I/O context
   2019  *
   2020  * Close the transmit HTTP I/O channel and actually send data using a PUT
   2021  * HTTP method.
   2022  */
   2023 static int
   2024 xmlIOHTTPClosePut( void * ctxt ) {
   2025     return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
   2026 }
   2027 
   2028 
   2029 /**
   2030  * xmlIOHTTPClosePost
   2031  *
   2032  * @context:  The I/O context
   2033  *
   2034  * Close the transmit HTTP I/O channel and actually send data using a POST
   2035  * HTTP method.
   2036  */
   2037 static int
   2038 xmlIOHTTPClosePost( void * ctxt ) {
   2039     return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
   2040 }
   2041 #endif /* LIBXML_OUTPUT_ENABLED */
   2042 
   2043 #endif /* LIBXML_HTTP_ENABLED */
   2044 
   2045 #ifdef LIBXML_FTP_ENABLED
   2046 /************************************************************************
   2047  *									*
   2048  *			I/O for FTP file accesses			*
   2049  *									*
   2050  ************************************************************************/
   2051 /**
   2052  * xmlIOFTPMatch:
   2053  * @filename:  the URI for matching
   2054  *
   2055  * check if the URI matches an FTP one
   2056  *
   2057  * Returns 1 if matches, 0 otherwise
   2058  */
   2059 int
   2060 xmlIOFTPMatch (const char *filename) {
   2061     if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "ftp://", 6))
   2062 	return(1);
   2063     return(0);
   2064 }
   2065 
   2066 /**
   2067  * xmlIOFTPOpen:
   2068  * @filename:  the URI for matching
   2069  *
   2070  * open an FTP I/O channel
   2071  *
   2072  * Returns an I/O context or NULL in case of error
   2073  */
   2074 void *
   2075 xmlIOFTPOpen (const char *filename) {
   2076     return(xmlNanoFTPOpen(filename));
   2077 }
   2078 
   2079 /**
   2080  * xmlIOFTPRead:
   2081  * @context:  the I/O context
   2082  * @buffer:  where to drop data
   2083  * @len:  number of bytes to write
   2084  *
   2085  * Read @len bytes to @buffer from the I/O channel.
   2086  *
   2087  * Returns the number of bytes written
   2088  */
   2089 int
   2090 xmlIOFTPRead(void * context, char * buffer, int len) {
   2091     if ((buffer == NULL) || (len < 0)) return(-1);
   2092     return(xmlNanoFTPRead(context, &buffer[0], len));
   2093 }
   2094 
   2095 /**
   2096  * xmlIOFTPClose:
   2097  * @context:  the I/O context
   2098  *
   2099  * Close an FTP I/O channel
   2100  *
   2101  * Returns 0
   2102  */
   2103 int
   2104 xmlIOFTPClose (void * context) {
   2105     return ( xmlNanoFTPClose(context) );
   2106 }
   2107 #endif /* LIBXML_FTP_ENABLED */
   2108 
   2109 
   2110 /**
   2111  * xmlRegisterInputCallbacks:
   2112  * @matchFunc:  the xmlInputMatchCallback
   2113  * @openFunc:  the xmlInputOpenCallback
   2114  * @readFunc:  the xmlInputReadCallback
   2115  * @closeFunc:  the xmlInputCloseCallback
   2116  *
   2117  * Register a new set of I/O callback for handling parser input.
   2118  *
   2119  * Returns the registered handler number or -1 in case of error
   2120  */
   2121 int
   2122 xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
   2123 	xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
   2124 	xmlInputCloseCallback closeFunc) {
   2125     if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
   2126 	return(-1);
   2127     }
   2128     xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
   2129     xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
   2130     xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
   2131     xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
   2132     xmlInputCallbackInitialized = 1;
   2133     return(xmlInputCallbackNr++);
   2134 }
   2135 
   2136 #ifdef LIBXML_OUTPUT_ENABLED
   2137 /**
   2138  * xmlRegisterOutputCallbacks:
   2139  * @matchFunc:  the xmlOutputMatchCallback
   2140  * @openFunc:  the xmlOutputOpenCallback
   2141  * @writeFunc:  the xmlOutputWriteCallback
   2142  * @closeFunc:  the xmlOutputCloseCallback
   2143  *
   2144  * Register a new set of I/O callback for handling output.
   2145  *
   2146  * Returns the registered handler number or -1 in case of error
   2147  */
   2148 int
   2149 xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
   2150 	xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
   2151 	xmlOutputCloseCallback closeFunc) {
   2152     if (xmlOutputCallbackNr >= MAX_OUTPUT_CALLBACK) {
   2153 	return(-1);
   2154     }
   2155     xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
   2156     xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
   2157     xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
   2158     xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
   2159     xmlOutputCallbackInitialized = 1;
   2160     return(xmlOutputCallbackNr++);
   2161 }
   2162 #endif /* LIBXML_OUTPUT_ENABLED */
   2163 
   2164 /**
   2165  * xmlRegisterDefaultInputCallbacks:
   2166  *
   2167  * Registers the default compiled-in I/O handlers.
   2168  */
   2169 void
   2170 xmlRegisterDefaultInputCallbacks(void) {
   2171     if (xmlInputCallbackInitialized)
   2172 	return;
   2173 
   2174 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
   2175     xmlInitPlatformSpecificIo();
   2176 #endif
   2177 
   2178     xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
   2179 	                      xmlFileRead, xmlFileClose);
   2180 #ifdef HAVE_ZLIB_H
   2181     xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
   2182 	                      xmlGzfileRead, xmlGzfileClose);
   2183 #endif /* HAVE_ZLIB_H */
   2184 
   2185 #ifdef LIBXML_HTTP_ENABLED
   2186     xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
   2187 	                      xmlIOHTTPRead, xmlIOHTTPClose);
   2188 #endif /* LIBXML_HTTP_ENABLED */
   2189 
   2190 #ifdef LIBXML_FTP_ENABLED
   2191     xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
   2192 	                      xmlIOFTPRead, xmlIOFTPClose);
   2193 #endif /* LIBXML_FTP_ENABLED */
   2194     xmlInputCallbackInitialized = 1;
   2195 }
   2196 
   2197 #ifdef LIBXML_OUTPUT_ENABLED
   2198 /**
   2199  * xmlRegisterDefaultOutputCallbacks:
   2200  *
   2201  * Registers the default compiled-in I/O handlers.
   2202  */
   2203 void
   2204 xmlRegisterDefaultOutputCallbacks (void) {
   2205     if (xmlOutputCallbackInitialized)
   2206 	return;
   2207 
   2208 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
   2209     xmlInitPlatformSpecificIo();
   2210 #endif
   2211 
   2212     xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
   2213 	                      xmlFileWrite, xmlFileClose);
   2214 
   2215 #ifdef LIBXML_HTTP_ENABLED
   2216     xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
   2217 	                       xmlIOHTTPWrite, xmlIOHTTPClosePut);
   2218 #endif
   2219 
   2220 /*********************************
   2221  No way a-priori to distinguish between gzipped files from
   2222  uncompressed ones except opening if existing then closing
   2223  and saving with same compression ratio ... a pain.
   2224 
   2225 #ifdef HAVE_ZLIB_H
   2226     xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
   2227 	                       xmlGzfileWrite, xmlGzfileClose);
   2228 #endif
   2229 
   2230  Nor FTP PUT ....
   2231 #ifdef LIBXML_FTP_ENABLED
   2232     xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
   2233 	                       xmlIOFTPWrite, xmlIOFTPClose);
   2234 #endif
   2235  **********************************/
   2236     xmlOutputCallbackInitialized = 1;
   2237 }
   2238 
   2239 #ifdef LIBXML_HTTP_ENABLED
   2240 /**
   2241  * xmlRegisterHTTPPostCallbacks:
   2242  *
   2243  * By default, libxml submits HTTP output requests using the "PUT" method.
   2244  * Calling this method changes the HTTP output method to use the "POST"
   2245  * method instead.
   2246  *
   2247  */
   2248 void
   2249 xmlRegisterHTTPPostCallbacks( void ) {
   2250 
   2251     /*  Register defaults if not done previously  */
   2252 
   2253     if ( xmlOutputCallbackInitialized == 0 )
   2254 	xmlRegisterDefaultOutputCallbacks( );
   2255 
   2256     xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
   2257 	                       xmlIOHTTPWrite, xmlIOHTTPClosePost);
   2258     return;
   2259 }
   2260 #endif
   2261 #endif /* LIBXML_OUTPUT_ENABLED */
   2262 
   2263 /**
   2264  * xmlAllocParserInputBuffer:
   2265  * @enc:  the charset encoding if known
   2266  *
   2267  * Create a buffered parser input for progressive parsing
   2268  *
   2269  * Returns the new parser input or NULL
   2270  */
   2271 xmlParserInputBufferPtr
   2272 xmlAllocParserInputBuffer(xmlCharEncoding enc) {
   2273     xmlParserInputBufferPtr ret;
   2274 
   2275     ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
   2276     if (ret == NULL) {
   2277 	xmlIOErrMemory("creating input buffer");
   2278 	return(NULL);
   2279     }
   2280     memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
   2281     ret->buffer = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
   2282     if (ret->buffer == NULL) {
   2283         xmlFree(ret);
   2284 	return(NULL);
   2285     }
   2286     ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
   2287     ret->encoder = xmlGetCharEncodingHandler(enc);
   2288     if (ret->encoder != NULL)
   2289         ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
   2290     else
   2291         ret->raw = NULL;
   2292     ret->readcallback = NULL;
   2293     ret->closecallback = NULL;
   2294     ret->context = NULL;
   2295     ret->compressed = -1;
   2296     ret->rawconsumed = 0;
   2297 
   2298     return(ret);
   2299 }
   2300 
   2301 #ifdef LIBXML_OUTPUT_ENABLED
   2302 /**
   2303  * xmlAllocOutputBuffer:
   2304  * @encoder:  the encoding converter or NULL
   2305  *
   2306  * Create a buffered parser output
   2307  *
   2308  * Returns the new parser output or NULL
   2309  */
   2310 xmlOutputBufferPtr
   2311 xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
   2312     xmlOutputBufferPtr ret;
   2313 
   2314     ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
   2315     if (ret == NULL) {
   2316 	xmlIOErrMemory("creating output buffer");
   2317 	return(NULL);
   2318     }
   2319     memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
   2320     ret->buffer = xmlBufferCreate();
   2321     if (ret->buffer == NULL) {
   2322         xmlFree(ret);
   2323 	return(NULL);
   2324     }
   2325 
   2326     /* try to avoid a performance problem with Windows realloc() */
   2327     if (ret->buffer->alloc == XML_BUFFER_ALLOC_EXACT)
   2328         ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
   2329 
   2330     ret->encoder = encoder;
   2331     if (encoder != NULL) {
   2332         ret->conv = xmlBufferCreateSize(4000);
   2333 	if (ret->conv == NULL) {
   2334 	    xmlFree(ret);
   2335 	    return(NULL);
   2336 	}
   2337 
   2338 	/*
   2339 	 * This call is designed to initiate the encoder state
   2340 	 */
   2341 	xmlCharEncOutFunc(encoder, ret->conv, NULL);
   2342     } else
   2343         ret->conv = NULL;
   2344     ret->writecallback = NULL;
   2345     ret->closecallback = NULL;
   2346     ret->context = NULL;
   2347     ret->written = 0;
   2348 
   2349     return(ret);
   2350 }
   2351 
   2352 /**
   2353  * xmlAllocOutputBufferInternal:
   2354  * @encoder:  the encoding converter or NULL
   2355  *
   2356  * Create a buffered parser output
   2357  *
   2358  * Returns the new parser output or NULL
   2359  */
   2360 xmlOutputBufferPtr
   2361 xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder) {
   2362     xmlOutputBufferPtr ret;
   2363 
   2364     ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
   2365     if (ret == NULL) {
   2366 	xmlIOErrMemory("creating output buffer");
   2367 	return(NULL);
   2368     }
   2369     memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
   2370     ret->buffer = xmlBufferCreate();
   2371     if (ret->buffer == NULL) {
   2372         xmlFree(ret);
   2373 	return(NULL);
   2374     }
   2375 
   2376 
   2377     /*
   2378      * For conversion buffers we use the special IO handling
   2379      * We don't do that from the exported API to avoid confusing
   2380      * user's code.
   2381      */
   2382     ret->buffer->alloc = XML_BUFFER_ALLOC_IO;
   2383     ret->buffer->contentIO = ret->buffer->content;
   2384 
   2385     ret->encoder = encoder;
   2386     if (encoder != NULL) {
   2387         ret->conv = xmlBufferCreateSize(4000);
   2388 	if (ret->conv == NULL) {
   2389 	    xmlFree(ret);
   2390 	    return(NULL);
   2391 	}
   2392 
   2393 	/*
   2394 	 * This call is designed to initiate the encoder state
   2395 	 */
   2396 	xmlCharEncOutFunc(encoder, ret->conv, NULL);
   2397     } else
   2398         ret->conv = NULL;
   2399     ret->writecallback = NULL;
   2400     ret->closecallback = NULL;
   2401     ret->context = NULL;
   2402     ret->written = 0;
   2403 
   2404     return(ret);
   2405 }
   2406 
   2407 #endif /* LIBXML_OUTPUT_ENABLED */
   2408 
   2409 /**
   2410  * xmlFreeParserInputBuffer:
   2411  * @in:  a buffered parser input
   2412  *
   2413  * Free up the memory used by a buffered parser input
   2414  */
   2415 void
   2416 xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
   2417     if (in == NULL) return;
   2418 
   2419     if (in->raw) {
   2420         xmlBufferFree(in->raw);
   2421 	in->raw = NULL;
   2422     }
   2423     if (in->encoder != NULL) {
   2424         xmlCharEncCloseFunc(in->encoder);
   2425     }
   2426     if (in->closecallback != NULL) {
   2427 	in->closecallback(in->context);
   2428     }
   2429     if (in->buffer != NULL) {
   2430         xmlBufferFree(in->buffer);
   2431 	in->buffer = NULL;
   2432     }
   2433 
   2434     xmlFree(in);
   2435 }
   2436 
   2437 #ifdef LIBXML_OUTPUT_ENABLED
   2438 /**
   2439  * xmlOutputBufferClose:
   2440  * @out:  a buffered output
   2441  *
   2442  * flushes and close the output I/O channel
   2443  * and free up all the associated resources
   2444  *
   2445  * Returns the number of byte written or -1 in case of error.
   2446  */
   2447 int
   2448 xmlOutputBufferClose(xmlOutputBufferPtr out)
   2449 {
   2450     int written;
   2451     int err_rc = 0;
   2452 
   2453     if (out == NULL)
   2454         return (-1);
   2455     if (out->writecallback != NULL)
   2456         xmlOutputBufferFlush(out);
   2457     if (out->closecallback != NULL) {
   2458         err_rc = out->closecallback(out->context);
   2459     }
   2460     written = out->written;
   2461     if (out->conv) {
   2462         xmlBufferFree(out->conv);
   2463         out->conv = NULL;
   2464     }
   2465     if (out->encoder != NULL) {
   2466         xmlCharEncCloseFunc(out->encoder);
   2467     }
   2468     if (out->buffer != NULL) {
   2469         xmlBufferFree(out->buffer);
   2470         out->buffer = NULL;
   2471     }
   2472 
   2473     if (out->error)
   2474         err_rc = -1;
   2475     xmlFree(out);
   2476     return ((err_rc == 0) ? written : err_rc);
   2477 }
   2478 #endif /* LIBXML_OUTPUT_ENABLED */
   2479 
   2480 xmlParserInputBufferPtr
   2481 __xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
   2482     xmlParserInputBufferPtr ret;
   2483     int i = 0;
   2484     void *context = NULL;
   2485 
   2486     if (xmlInputCallbackInitialized == 0)
   2487 	xmlRegisterDefaultInputCallbacks();
   2488 
   2489     if (URI == NULL) return(NULL);
   2490 
   2491     /*
   2492      * Try to find one of the input accept method accepting that scheme
   2493      * Go in reverse to give precedence to user defined handlers.
   2494      */
   2495     if (context == NULL) {
   2496 	for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
   2497 	    if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
   2498 		(xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
   2499 		context = xmlInputCallbackTable[i].opencallback(URI);
   2500 		if (context != NULL) {
   2501 		    break;
   2502 		}
   2503 	    }
   2504 	}
   2505     }
   2506     if (context == NULL) {
   2507 	return(NULL);
   2508     }
   2509 
   2510     /*
   2511      * Allocate the Input buffer front-end.
   2512      */
   2513     ret = xmlAllocParserInputBuffer(enc);
   2514     if (ret != NULL) {
   2515 	ret->context = context;
   2516 	ret->readcallback = xmlInputCallbackTable[i].readcallback;
   2517 	ret->closecallback = xmlInputCallbackTable[i].closecallback;
   2518 #ifdef HAVE_ZLIB_H
   2519 	if ((xmlInputCallbackTable[i].opencallback == xmlGzfileOpen) &&
   2520 		(strcmp(URI, "-") != 0)) {
   2521 #if defined(ZLIB_VERNUM) && ZLIB_VERNUM >= 0x1230
   2522             ret->compressed = !gzdirect(context);
   2523 #else
   2524 	    if (((z_stream *)context)->avail_in > 4) {
   2525 	        char *cptr, buff4[4];
   2526 		cptr = (char *) ((z_stream *)context)->next_in;
   2527 		if (gzread(context, buff4, 4) == 4) {
   2528 		    if (strncmp(buff4, cptr, 4) == 0)
   2529 		        ret->compressed = 0;
   2530 		    else
   2531 		        ret->compressed = 1;
   2532 		    gzrewind(context);
   2533 		}
   2534 	    }
   2535 #endif
   2536 	}
   2537 #endif
   2538     }
   2539     else
   2540       xmlInputCallbackTable[i].closecallback (context);
   2541 
   2542     return(ret);
   2543 }
   2544 
   2545 /**
   2546  * xmlParserInputBufferCreateFilename:
   2547  * @URI:  a C string containing the URI or filename
   2548  * @enc:  the charset encoding if known
   2549  *
   2550  * Create a buffered parser input for the progressive parsing of a file
   2551  * If filename is "-' then we use stdin as the input.
   2552  * Automatic support for ZLIB/Compress compressed document is provided
   2553  * by default if found at compile-time.
   2554  * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
   2555  *
   2556  * Returns the new parser input or NULL
   2557  */
   2558 xmlParserInputBufferPtr
   2559 xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
   2560     if ((xmlParserInputBufferCreateFilenameValue)) {
   2561 		return xmlParserInputBufferCreateFilenameValue(URI, enc);
   2562 	}
   2563 	return __xmlParserInputBufferCreateFilename(URI, enc);
   2564 }
   2565 
   2566 #ifdef LIBXML_OUTPUT_ENABLED
   2567 xmlOutputBufferPtr
   2568 __xmlOutputBufferCreateFilename(const char *URI,
   2569                               xmlCharEncodingHandlerPtr encoder,
   2570                               int compression ATTRIBUTE_UNUSED) {
   2571     xmlOutputBufferPtr ret;
   2572     xmlURIPtr puri;
   2573     int i = 0;
   2574     void *context = NULL;
   2575     char *unescaped = NULL;
   2576 #ifdef HAVE_ZLIB_H
   2577     int is_file_uri = 1;
   2578 #endif
   2579 
   2580     if (xmlOutputCallbackInitialized == 0)
   2581 	xmlRegisterDefaultOutputCallbacks();
   2582 
   2583     if (URI == NULL) return(NULL);
   2584 
   2585     puri = xmlParseURI(URI);
   2586     if (puri != NULL) {
   2587 #ifdef HAVE_ZLIB_H
   2588         if ((puri->scheme != NULL) &&
   2589 	    (!xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
   2590 	    is_file_uri = 0;
   2591 #endif
   2592 	/*
   2593 	 * try to limit the damages of the URI unescaping code.
   2594 	 */
   2595 	if ((puri->scheme == NULL) ||
   2596 	    (xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
   2597 	    unescaped = xmlURIUnescapeString(URI, 0, NULL);
   2598 	xmlFreeURI(puri);
   2599     }
   2600 
   2601     /*
   2602      * Try to find one of the output accept method accepting that scheme
   2603      * Go in reverse to give precedence to user defined handlers.
   2604      * try with an unescaped version of the URI
   2605      */
   2606     if (unescaped != NULL) {
   2607 #ifdef HAVE_ZLIB_H
   2608 	if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
   2609 	    context = xmlGzfileOpenW(unescaped, compression);
   2610 	    if (context != NULL) {
   2611 		ret = xmlAllocOutputBufferInternal(encoder);
   2612 		if (ret != NULL) {
   2613 		    ret->context = context;
   2614 		    ret->writecallback = xmlGzfileWrite;
   2615 		    ret->closecallback = xmlGzfileClose;
   2616 		}
   2617 		xmlFree(unescaped);
   2618 		return(ret);
   2619 	    }
   2620 	}
   2621 #endif
   2622 	for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
   2623 	    if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
   2624 		(xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
   2625 #if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
   2626 		/*  Need to pass compression parameter into HTTP open calls  */
   2627 		if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
   2628 		    context = xmlIOHTTPOpenW(unescaped, compression);
   2629 		else
   2630 #endif
   2631 		    context = xmlOutputCallbackTable[i].opencallback(unescaped);
   2632 		if (context != NULL)
   2633 		    break;
   2634 	    }
   2635 	}
   2636 	xmlFree(unescaped);
   2637     }
   2638 
   2639     /*
   2640      * If this failed try with a non-escaped URI this may be a strange
   2641      * filename
   2642      */
   2643     if (context == NULL) {
   2644 #ifdef HAVE_ZLIB_H
   2645 	if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
   2646 	    context = xmlGzfileOpenW(URI, compression);
   2647 	    if (context != NULL) {
   2648 		ret = xmlAllocOutputBufferInternal(encoder);
   2649 		if (ret != NULL) {
   2650 		    ret->context = context;
   2651 		    ret->writecallback = xmlGzfileWrite;
   2652 		    ret->closecallback = xmlGzfileClose;
   2653 		}
   2654 		return(ret);
   2655 	    }
   2656 	}
   2657 #endif
   2658 	for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
   2659 	    if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
   2660 		(xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
   2661 #if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
   2662 		/*  Need to pass compression parameter into HTTP open calls  */
   2663 		if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
   2664 		    context = xmlIOHTTPOpenW(URI, compression);
   2665 		else
   2666 #endif
   2667 		    context = xmlOutputCallbackTable[i].opencallback(URI);
   2668 		if (context != NULL)
   2669 		    break;
   2670 	    }
   2671 	}
   2672     }
   2673 
   2674     if (context == NULL) {
   2675 	return(NULL);
   2676     }
   2677 
   2678     /*
   2679      * Allocate the Output buffer front-end.
   2680      */
   2681     ret = xmlAllocOutputBufferInternal(encoder);
   2682     if (ret != NULL) {
   2683 	ret->context = context;
   2684 	ret->writecallback = xmlOutputCallbackTable[i].writecallback;
   2685 	ret->closecallback = xmlOutputCallbackTable[i].closecallback;
   2686     }
   2687     return(ret);
   2688 }
   2689 
   2690 /**
   2691  * xmlOutputBufferCreateFilename:
   2692  * @URI:  a C string containing the URI or filename
   2693  * @encoder:  the encoding converter or NULL
   2694  * @compression:  the compression ration (0 none, 9 max).
   2695  *
   2696  * Create a buffered  output for the progressive saving of a file
   2697  * If filename is "-' then we use stdout as the output.
   2698  * Automatic support for ZLIB/Compress compressed document is provided
   2699  * by default if found at compile-time.
   2700  * TODO: currently if compression is set, the library only support
   2701  *       writing to a local file.
   2702  *
   2703  * Returns the new output or NULL
   2704  */
   2705 xmlOutputBufferPtr
   2706 xmlOutputBufferCreateFilename(const char *URI,
   2707                               xmlCharEncodingHandlerPtr encoder,
   2708                               int compression ATTRIBUTE_UNUSED) {
   2709     if ((xmlOutputBufferCreateFilenameValue)) {
   2710 		return xmlOutputBufferCreateFilenameValue(URI, encoder, compression);
   2711 	}
   2712 	return __xmlOutputBufferCreateFilename(URI, encoder, compression);
   2713 }
   2714 #endif /* LIBXML_OUTPUT_ENABLED */
   2715 
   2716 /**
   2717  * xmlParserInputBufferCreateFile:
   2718  * @file:  a FILE*
   2719  * @enc:  the charset encoding if known
   2720  *
   2721  * Create a buffered parser input for the progressive parsing of a FILE *
   2722  * buffered C I/O
   2723  *
   2724  * Returns the new parser input or NULL
   2725  */
   2726 xmlParserInputBufferPtr
   2727 xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
   2728     xmlParserInputBufferPtr ret;
   2729 
   2730     if (xmlInputCallbackInitialized == 0)
   2731 	xmlRegisterDefaultInputCallbacks();
   2732 
   2733     if (file == NULL) return(NULL);
   2734 
   2735     ret = xmlAllocParserInputBuffer(enc);
   2736     if (ret != NULL) {
   2737         ret->context = file;
   2738 	ret->readcallback = xmlFileRead;
   2739 	ret->closecallback = xmlFileFlush;
   2740     }
   2741 
   2742     return(ret);
   2743 }
   2744 
   2745 #ifdef LIBXML_OUTPUT_ENABLED
   2746 /**
   2747  * xmlOutputBufferCreateFile:
   2748  * @file:  a FILE*
   2749  * @encoder:  the encoding converter or NULL
   2750  *
   2751  * Create a buffered output for the progressive saving to a FILE *
   2752  * buffered C I/O
   2753  *
   2754  * Returns the new parser output or NULL
   2755  */
   2756 xmlOutputBufferPtr
   2757 xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
   2758     xmlOutputBufferPtr ret;
   2759 
   2760     if (xmlOutputCallbackInitialized == 0)
   2761 	xmlRegisterDefaultOutputCallbacks();
   2762 
   2763     if (file == NULL) return(NULL);
   2764 
   2765     ret = xmlAllocOutputBufferInternal(encoder);
   2766     if (ret != NULL) {
   2767         ret->context = file;
   2768 	ret->writecallback = xmlFileWrite;
   2769 	ret->closecallback = xmlFileFlush;
   2770     }
   2771 
   2772     return(ret);
   2773 }
   2774 
   2775 /**
   2776  * xmlOutputBufferCreateBuffer:
   2777  * @buffer:  a xmlBufferPtr
   2778  * @encoder:  the encoding converter or NULL
   2779  *
   2780  * Create a buffered output for the progressive saving to a xmlBuffer
   2781  *
   2782  * Returns the new parser output or NULL
   2783  */
   2784 xmlOutputBufferPtr
   2785 xmlOutputBufferCreateBuffer(xmlBufferPtr buffer,
   2786                             xmlCharEncodingHandlerPtr encoder) {
   2787     xmlOutputBufferPtr ret;
   2788 
   2789     if (buffer == NULL) return(NULL);
   2790 
   2791     ret = xmlOutputBufferCreateIO((xmlOutputWriteCallback)
   2792                                   xmlBufferWrite,
   2793                                   (xmlOutputCloseCallback)
   2794                                   NULL, (void *) buffer, encoder);
   2795 
   2796     return(ret);
   2797 }
   2798 
   2799 #endif /* LIBXML_OUTPUT_ENABLED */
   2800 
   2801 /**
   2802  * xmlParserInputBufferCreateFd:
   2803  * @fd:  a file descriptor number
   2804  * @enc:  the charset encoding if known
   2805  *
   2806  * Create a buffered parser input for the progressive parsing for the input
   2807  * from a file descriptor
   2808  *
   2809  * Returns the new parser input or NULL
   2810  */
   2811 xmlParserInputBufferPtr
   2812 xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
   2813     xmlParserInputBufferPtr ret;
   2814 
   2815     if (fd < 0) return(NULL);
   2816 
   2817     ret = xmlAllocParserInputBuffer(enc);
   2818     if (ret != NULL) {
   2819         ret->context = (void *) (long) fd;
   2820 	ret->readcallback = xmlFdRead;
   2821 	ret->closecallback = xmlFdClose;
   2822     }
   2823 
   2824     return(ret);
   2825 }
   2826 
   2827 /**
   2828  * xmlParserInputBufferCreateMem:
   2829  * @mem:  the memory input
   2830  * @size:  the length of the memory block
   2831  * @enc:  the charset encoding if known
   2832  *
   2833  * Create a buffered parser input for the progressive parsing for the input
   2834  * from a memory area.
   2835  *
   2836  * Returns the new parser input or NULL
   2837  */
   2838 xmlParserInputBufferPtr
   2839 xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
   2840     xmlParserInputBufferPtr ret;
   2841     int errcode;
   2842 
   2843     if (size <= 0) return(NULL);
   2844     if (mem == NULL) return(NULL);
   2845 
   2846     ret = xmlAllocParserInputBuffer(enc);
   2847     if (ret != NULL) {
   2848         ret->context = (void *) mem;
   2849 	ret->readcallback = (xmlInputReadCallback) xmlNop;
   2850 	ret->closecallback = NULL;
   2851 	errcode = xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size);
   2852 	if (errcode != 0) {
   2853 	    xmlFree(ret);
   2854 	    return(NULL);
   2855 	}
   2856     }
   2857 
   2858     return(ret);
   2859 }
   2860 
   2861 /**
   2862  * xmlParserInputBufferCreateStatic:
   2863  * @mem:  the memory input
   2864  * @size:  the length of the memory block
   2865  * @enc:  the charset encoding if known
   2866  *
   2867  * Create a buffered parser input for the progressive parsing for the input
   2868  * from an immutable memory area. This will not copy the memory area to
   2869  * the buffer, but the memory is expected to be available until the end of
   2870  * the parsing, this is useful for example when using mmap'ed file.
   2871  *
   2872  * Returns the new parser input or NULL
   2873  */
   2874 xmlParserInputBufferPtr
   2875 xmlParserInputBufferCreateStatic(const char *mem, int size,
   2876                                  xmlCharEncoding enc) {
   2877     xmlParserInputBufferPtr ret;
   2878 
   2879     if (size <= 0) return(NULL);
   2880     if (mem == NULL) return(NULL);
   2881 
   2882     ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
   2883     if (ret == NULL) {
   2884 	xmlIOErrMemory("creating input buffer");
   2885 	return(NULL);
   2886     }
   2887     memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
   2888     ret->buffer = xmlBufferCreateStatic((void *)mem, (size_t) size);
   2889     if (ret->buffer == NULL) {
   2890         xmlFree(ret);
   2891 	return(NULL);
   2892     }
   2893     ret->encoder = xmlGetCharEncodingHandler(enc);
   2894     if (ret->encoder != NULL)
   2895         ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
   2896     else
   2897         ret->raw = NULL;
   2898     ret->compressed = -1;
   2899     ret->context = (void *) mem;
   2900     ret->readcallback = NULL;
   2901     ret->closecallback = NULL;
   2902 
   2903     return(ret);
   2904 }
   2905 
   2906 #ifdef LIBXML_OUTPUT_ENABLED
   2907 /**
   2908  * xmlOutputBufferCreateFd:
   2909  * @fd:  a file descriptor number
   2910  * @encoder:  the encoding converter or NULL
   2911  *
   2912  * Create a buffered output for the progressive saving
   2913  * to a file descriptor
   2914  *
   2915  * Returns the new parser output or NULL
   2916  */
   2917 xmlOutputBufferPtr
   2918 xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
   2919     xmlOutputBufferPtr ret;
   2920 
   2921     if (fd < 0) return(NULL);
   2922 
   2923     ret = xmlAllocOutputBufferInternal(encoder);
   2924     if (ret != NULL) {
   2925         ret->context = (void *) (long) fd;
   2926 	ret->writecallback = xmlFdWrite;
   2927 	ret->closecallback = NULL;
   2928     }
   2929 
   2930     return(ret);
   2931 }
   2932 #endif /* LIBXML_OUTPUT_ENABLED */
   2933 
   2934 /**
   2935  * xmlParserInputBufferCreateIO:
   2936  * @ioread:  an I/O read function
   2937  * @ioclose:  an I/O close function
   2938  * @ioctx:  an I/O handler
   2939  * @enc:  the charset encoding if known
   2940  *
   2941  * Create a buffered parser input for the progressive parsing for the input
   2942  * from an I/O handler
   2943  *
   2944  * Returns the new parser input or NULL
   2945  */
   2946 xmlParserInputBufferPtr
   2947 xmlParserInputBufferCreateIO(xmlInputReadCallback   ioread,
   2948 	 xmlInputCloseCallback  ioclose, void *ioctx, xmlCharEncoding enc) {
   2949     xmlParserInputBufferPtr ret;
   2950 
   2951     if (ioread == NULL) return(NULL);
   2952 
   2953     ret = xmlAllocParserInputBuffer(enc);
   2954     if (ret != NULL) {
   2955         ret->context = (void *) ioctx;
   2956 	ret->readcallback = ioread;
   2957 	ret->closecallback = ioclose;
   2958     }
   2959 
   2960     return(ret);
   2961 }
   2962 
   2963 #ifdef LIBXML_OUTPUT_ENABLED
   2964 /**
   2965  * xmlOutputBufferCreateIO:
   2966  * @iowrite:  an I/O write function
   2967  * @ioclose:  an I/O close function
   2968  * @ioctx:  an I/O handler
   2969  * @encoder:  the charset encoding if known
   2970  *
   2971  * Create a buffered output for the progressive saving
   2972  * to an I/O handler
   2973  *
   2974  * Returns the new parser output or NULL
   2975  */
   2976 xmlOutputBufferPtr
   2977 xmlOutputBufferCreateIO(xmlOutputWriteCallback   iowrite,
   2978 	 xmlOutputCloseCallback  ioclose, void *ioctx,
   2979 	 xmlCharEncodingHandlerPtr encoder) {
   2980     xmlOutputBufferPtr ret;
   2981 
   2982     if (iowrite == NULL) return(NULL);
   2983 
   2984     ret = xmlAllocOutputBufferInternal(encoder);
   2985     if (ret != NULL) {
   2986         ret->context = (void *) ioctx;
   2987 	ret->writecallback = iowrite;
   2988 	ret->closecallback = ioclose;
   2989     }
   2990 
   2991     return(ret);
   2992 }
   2993 #endif /* LIBXML_OUTPUT_ENABLED */
   2994 
   2995 /**
   2996  * xmlParserInputBufferCreateFilenameDefault:
   2997  * @func: function pointer to the new ParserInputBufferCreateFilenameFunc
   2998  *
   2999  * Registers a callback for URI input file handling
   3000  *
   3001  * Returns the old value of the registration function
   3002  */
   3003 xmlParserInputBufferCreateFilenameFunc
   3004 xmlParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func)
   3005 {
   3006     xmlParserInputBufferCreateFilenameFunc old = xmlParserInputBufferCreateFilenameValue;
   3007     if (old == NULL) {
   3008 		old = __xmlParserInputBufferCreateFilename;
   3009 	}
   3010 
   3011     xmlParserInputBufferCreateFilenameValue = func;
   3012     return(old);
   3013 }
   3014 
   3015 /**
   3016  * xmlOutputBufferCreateFilenameDefault:
   3017  * @func: function pointer to the new OutputBufferCreateFilenameFunc
   3018  *
   3019  * Registers a callback for URI output file handling
   3020  *
   3021  * Returns the old value of the registration function
   3022  */
   3023 xmlOutputBufferCreateFilenameFunc
   3024 xmlOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func)
   3025 {
   3026     xmlOutputBufferCreateFilenameFunc old = xmlOutputBufferCreateFilenameValue;
   3027 #ifdef LIBXML_OUTPUT_ENABLED
   3028     if (old == NULL) {
   3029 		old = __xmlOutputBufferCreateFilename;
   3030 	}
   3031 #endif
   3032     xmlOutputBufferCreateFilenameValue = func;
   3033     return(old);
   3034 }
   3035 
   3036 /**
   3037  * xmlParserInputBufferPush:
   3038  * @in:  a buffered parser input
   3039  * @len:  the size in bytes of the array.
   3040  * @buf:  an char array
   3041  *
   3042  * Push the content of the arry in the input buffer
   3043  * This routine handle the I18N transcoding to internal UTF-8
   3044  * This is used when operating the parser in progressive (push) mode.
   3045  *
   3046  * Returns the number of chars read and stored in the buffer, or -1
   3047  *         in case of error.
   3048  */
   3049 int
   3050 xmlParserInputBufferPush(xmlParserInputBufferPtr in,
   3051 	                 int len, const char *buf) {
   3052     int nbchars = 0;
   3053     int ret;
   3054 
   3055     if (len < 0) return(0);
   3056     if ((in == NULL) || (in->error)) return(-1);
   3057     if (in->encoder != NULL) {
   3058         unsigned int use;
   3059 
   3060         /*
   3061 	 * Store the data in the incoming raw buffer
   3062 	 */
   3063         if (in->raw == NULL) {
   3064 	    in->raw = xmlBufferCreate();
   3065 	}
   3066 	ret = xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
   3067 	if (ret != 0)
   3068 	    return(-1);
   3069 
   3070 	/*
   3071 	 * convert as much as possible to the parser reading buffer.
   3072 	 */
   3073 	use = in->raw->use;
   3074 	nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
   3075 	if (nbchars < 0) {
   3076 	    xmlIOErr(XML_IO_ENCODER, NULL);
   3077 	    in->error = XML_IO_ENCODER;
   3078 	    return(-1);
   3079 	}
   3080 	in->rawconsumed += (use - in->raw->use);
   3081     } else {
   3082 	nbchars = len;
   3083         ret = xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
   3084 	if (ret != 0)
   3085 	    return(-1);
   3086     }
   3087 #ifdef DEBUG_INPUT
   3088     xmlGenericError(xmlGenericErrorContext,
   3089 	    "I/O: pushed %d chars, buffer %d/%d\n",
   3090             nbchars, in->buffer->use, in->buffer->size);
   3091 #endif
   3092     return(nbchars);
   3093 }
   3094 
   3095 /**
   3096  * endOfInput:
   3097  *
   3098  * When reading from an Input channel indicated end of file or error
   3099  * don't reread from it again.
   3100  */
   3101 static int
   3102 endOfInput (void * context ATTRIBUTE_UNUSED,
   3103 	    char * buffer ATTRIBUTE_UNUSED,
   3104 	    int len ATTRIBUTE_UNUSED) {
   3105     return(0);
   3106 }
   3107 
   3108 /**
   3109  * xmlParserInputBufferGrow:
   3110  * @in:  a buffered parser input
   3111  * @len:  indicative value of the amount of chars to read
   3112  *
   3113  * Grow up the content of the input buffer, the old data are preserved
   3114  * This routine handle the I18N transcoding to internal UTF-8
   3115  * This routine is used when operating the parser in normal (pull) mode
   3116  *
   3117  * TODO: one should be able to remove one extra copy by copying directly
   3118  *       onto in->buffer or in->raw
   3119  *
   3120  * Returns the number of chars read and stored in the buffer, or -1
   3121  *         in case of error.
   3122  */
   3123 int
   3124 xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
   3125     char *buffer = NULL;
   3126     int res = 0;
   3127     int nbchars = 0;
   3128     int buffree;
   3129     unsigned int needSize;
   3130 
   3131     if ((in == NULL) || (in->error)) return(-1);
   3132     if ((len <= MINLEN) && (len != 4))
   3133         len = MINLEN;
   3134 
   3135     buffree = in->buffer->size - in->buffer->use;
   3136     if (buffree <= 0) {
   3137 	xmlIOErr(XML_IO_BUFFER_FULL, NULL);
   3138 	in->error = XML_IO_BUFFER_FULL;
   3139 	return(-1);
   3140     }
   3141 
   3142     needSize = in->buffer->use + len + 1;
   3143     if (needSize > in->buffer->size){
   3144         if (!xmlBufferResize(in->buffer, needSize)){
   3145 	    xmlIOErrMemory("growing input buffer");
   3146 	    in->error = XML_ERR_NO_MEMORY;
   3147             return(-1);
   3148         }
   3149     }
   3150     buffer = (char *)&in->buffer->content[in->buffer->use];
   3151 
   3152     /*
   3153      * Call the read method for this I/O type.
   3154      */
   3155     if (in->readcallback != NULL) {
   3156 	res = in->readcallback(in->context, &buffer[0], len);
   3157 	if (res <= 0)
   3158 	    in->readcallback = endOfInput;
   3159     } else {
   3160 	xmlIOErr(XML_IO_NO_INPUT, NULL);
   3161 	in->error = XML_IO_NO_INPUT;
   3162 	return(-1);
   3163     }
   3164     if (res < 0) {
   3165 	return(-1);
   3166     }
   3167     len = res;
   3168     if (in->encoder != NULL) {
   3169         unsigned int use;
   3170 
   3171         /*
   3172 	 * Store the data in the incoming raw buffer
   3173 	 */
   3174         if (in->raw == NULL) {
   3175 	    in->raw = xmlBufferCreate();
   3176 	}
   3177 	res = xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
   3178 	if (res != 0)
   3179 	    return(-1);
   3180 
   3181 	/*
   3182 	 * convert as much as possible to the parser reading buffer.
   3183 	 */
   3184 	use = in->raw->use;
   3185 	nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
   3186 	if (nbchars < 0) {
   3187 	    xmlIOErr(XML_IO_ENCODER, NULL);
   3188 	    in->error = XML_IO_ENCODER;
   3189 	    return(-1);
   3190 	}
   3191 	in->rawconsumed += (use - in->raw->use);
   3192     } else {
   3193 	nbchars = len;
   3194    	in->buffer->use += nbchars;
   3195 	buffer[nbchars] = 0;
   3196     }
   3197 #ifdef DEBUG_INPUT
   3198     xmlGenericError(xmlGenericErrorContext,
   3199 	    "I/O: read %d chars, buffer %d/%d\n",
   3200             nbchars, in->buffer->use, in->buffer->size);
   3201 #endif
   3202     return(nbchars);
   3203 }
   3204 
   3205 /**
   3206  * xmlParserInputBufferRead:
   3207  * @in:  a buffered parser input
   3208  * @len:  indicative value of the amount of chars to read
   3209  *
   3210  * Refresh the content of the input buffer, the old data are considered
   3211  * consumed
   3212  * This routine handle the I18N transcoding to internal UTF-8
   3213  *
   3214  * Returns the number of chars read and stored in the buffer, or -1
   3215  *         in case of error.
   3216  */
   3217 int
   3218 xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
   3219     if ((in == NULL) || (in->error)) return(-1);
   3220     if (in->readcallback != NULL)
   3221 	return(xmlParserInputBufferGrow(in, len));
   3222     else if ((in->buffer != NULL) &&
   3223              (in->buffer->alloc == XML_BUFFER_ALLOC_IMMUTABLE))
   3224 	return(0);
   3225     else
   3226         return(-1);
   3227 }
   3228 
   3229 #ifdef LIBXML_OUTPUT_ENABLED
   3230 /**
   3231  * xmlOutputBufferWrite:
   3232  * @out:  a buffered parser output
   3233  * @len:  the size in bytes of the array.
   3234  * @buf:  an char array
   3235  *
   3236  * Write the content of the array in the output I/O buffer
   3237  * This routine handle the I18N transcoding from internal UTF-8
   3238  * The buffer is lossless, i.e. will store in case of partial
   3239  * or delayed writes.
   3240  *
   3241  * Returns the number of chars immediately written, or -1
   3242  *         in case of error.
   3243  */
   3244 int
   3245 xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
   3246     int nbchars = 0; /* number of chars to output to I/O */
   3247     int ret;         /* return from function call */
   3248     int written = 0; /* number of char written to I/O so far */
   3249     int chunk;       /* number of byte curreent processed from buf */
   3250 
   3251     if ((out == NULL) || (out->error)) return(-1);
   3252     if (len < 0) return(0);
   3253     if (out->error) return(-1);
   3254 
   3255     do {
   3256 	chunk = len;
   3257 	if (chunk > 4 * MINLEN)
   3258 	    chunk = 4 * MINLEN;
   3259 
   3260 	/*
   3261 	 * first handle encoding stuff.
   3262 	 */
   3263 	if (out->encoder != NULL) {
   3264 	    /*
   3265 	     * Store the data in the incoming raw buffer
   3266 	     */
   3267 	    if (out->conv == NULL) {
   3268 		out->conv = xmlBufferCreate();
   3269 	    }
   3270 	    ret = xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
   3271 	    if (ret != 0)
   3272 	        return(-1);
   3273 
   3274 	    if ((out->buffer->use < MINLEN) && (chunk == len))
   3275 		goto done;
   3276 
   3277 	    /*
   3278 	     * convert as much as possible to the parser reading buffer.
   3279 	     */
   3280 	    ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
   3281 	    if ((ret < 0) && (ret != -3)) {
   3282 		xmlIOErr(XML_IO_ENCODER, NULL);
   3283 		out->error = XML_IO_ENCODER;
   3284 		return(-1);
   3285 	    }
   3286 	    nbchars = out->conv->use;
   3287 	} else {
   3288 	    ret = xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
   3289 	    if (ret != 0)
   3290 	        return(-1);
   3291 	    nbchars = out->buffer->use;
   3292 	}
   3293 	buf += chunk;
   3294 	len -= chunk;
   3295 
   3296 	if ((nbchars < MINLEN) && (len <= 0))
   3297 	    goto done;
   3298 
   3299 	if (out->writecallback) {
   3300 	    /*
   3301 	     * second write the stuff to the I/O channel
   3302 	     */
   3303 	    if (out->encoder != NULL) {
   3304 		ret = out->writecallback(out->context,
   3305 				 (const char *)out->conv->content, nbchars);
   3306 		if (ret >= 0)
   3307 		    xmlBufferShrink(out->conv, ret);
   3308 	    } else {
   3309 		ret = out->writecallback(out->context,
   3310 				 (const char *)out->buffer->content, nbchars);
   3311 		if (ret >= 0)
   3312 		    xmlBufferShrink(out->buffer, ret);
   3313 	    }
   3314 	    if (ret < 0) {
   3315 		xmlIOErr(XML_IO_WRITE, NULL);
   3316 		out->error = XML_IO_WRITE;
   3317 		return(ret);
   3318 	    }
   3319 	    out->written += ret;
   3320 	}
   3321 	written += nbchars;
   3322     } while (len > 0);
   3323 
   3324 done:
   3325 #ifdef DEBUG_INPUT
   3326     xmlGenericError(xmlGenericErrorContext,
   3327 	    "I/O: wrote %d chars\n", written);
   3328 #endif
   3329     return(written);
   3330 }
   3331 
   3332 /**
   3333  * xmlEscapeContent:
   3334  * @out:  a pointer to an array of bytes to store the result
   3335  * @outlen:  the length of @out
   3336  * @in:  a pointer to an array of unescaped UTF-8 bytes
   3337  * @inlen:  the length of @in
   3338  *
   3339  * Take a block of UTF-8 chars in and escape them.
   3340  * Returns 0 if success, or -1 otherwise
   3341  * The value of @inlen after return is the number of octets consumed
   3342  *     if the return value is positive, else unpredictable.
   3343  * The value of @outlen after return is the number of octets consumed.
   3344  */
   3345 static int
   3346 xmlEscapeContent(unsigned char* out, int *outlen,
   3347                  const xmlChar* in, int *inlen) {
   3348     unsigned char* outstart = out;
   3349     const unsigned char* base = in;
   3350     unsigned char* outend = out + *outlen;
   3351     const unsigned char* inend;
   3352 
   3353     inend = in + (*inlen);
   3354 
   3355     while ((in < inend) && (out < outend)) {
   3356    	if (*in == '<') {
   3357 	    if (outend - out < 4) break;
   3358 	    *out++ = '&';
   3359 	    *out++ = 'l';
   3360 	    *out++ = 't';
   3361 	    *out++ = ';';
   3362 	} else if (*in == '>') {
   3363 	    if (outend - out < 4) break;
   3364 	    *out++ = '&';
   3365 	    *out++ = 'g';
   3366 	    *out++ = 't';
   3367 	    *out++ = ';';
   3368 	} else if (*in == '&') {
   3369 	    if (outend - out < 5) break;
   3370 	    *out++ = '&';
   3371 	    *out++ = 'a';
   3372 	    *out++ = 'm';
   3373 	    *out++ = 'p';
   3374 	    *out++ = ';';
   3375 	} else if (*in == '\r') {
   3376 	    if (outend - out < 5) break;
   3377 	    *out++ = '&';
   3378 	    *out++ = '#';
   3379 	    *out++ = '1';
   3380 	    *out++ = '3';
   3381 	    *out++ = ';';
   3382 	} else {
   3383 	    *out++ = (unsigned char) *in;
   3384 	}
   3385 	++in;
   3386     }
   3387     *outlen = out - outstart;
   3388     *inlen = in - base;
   3389     return(0);
   3390 }
   3391 
   3392 /**
   3393  * xmlOutputBufferWriteEscape:
   3394  * @out:  a buffered parser output
   3395  * @str:  a zero terminated UTF-8 string
   3396  * @escaping:  an optional escaping function (or NULL)
   3397  *
   3398  * Write the content of the string in the output I/O buffer
   3399  * This routine escapes the caracters and then handle the I18N
   3400  * transcoding from internal UTF-8
   3401  * The buffer is lossless, i.e. will store in case of partial
   3402  * or delayed writes.
   3403  *
   3404  * Returns the number of chars immediately written, or -1
   3405  *         in case of error.
   3406  */
   3407 int
   3408 xmlOutputBufferWriteEscape(xmlOutputBufferPtr out, const xmlChar *str,
   3409                            xmlCharEncodingOutputFunc escaping) {
   3410     int nbchars = 0; /* number of chars to output to I/O */
   3411     int ret;         /* return from function call */
   3412     int written = 0; /* number of char written to I/O so far */
   3413     int oldwritten=0;/* loop guard */
   3414     int chunk;       /* number of byte currently processed from str */
   3415     int len;         /* number of bytes in str */
   3416     int cons;        /* byte from str consumed */
   3417 
   3418     if ((out == NULL) || (out->error) || (str == NULL) ||
   3419         (out->buffer == NULL) ||
   3420 	(out->buffer->alloc == XML_BUFFER_ALLOC_IMMUTABLE)) return(-1);
   3421     len = strlen((const char *)str);
   3422     if (len < 0) return(0);
   3423     if (out->error) return(-1);
   3424     if (escaping == NULL) escaping = xmlEscapeContent;
   3425 
   3426     do {
   3427         oldwritten = written;
   3428 
   3429         /*
   3430 	 * how many bytes to consume and how many bytes to store.
   3431 	 */
   3432 	cons = len;
   3433 	chunk = (out->buffer->size - out->buffer->use) - 1;
   3434 
   3435         /*
   3436 	 * make sure we have enough room to save first, if this is
   3437 	 * not the case force a flush, but make sure we stay in the loop
   3438 	 */
   3439 	if (chunk < 40) {
   3440 	    if (xmlBufferGrow(out->buffer, out->buffer->size + 100) < 0)
   3441 	        return(-1);
   3442             oldwritten = -1;
   3443 	    continue;
   3444 	}
   3445 
   3446 	/*
   3447 	 * first handle encoding stuff.
   3448 	 */
   3449 	if (out->encoder != NULL) {
   3450 	    /*
   3451 	     * Store the data in the incoming raw buffer
   3452 	     */
   3453 	    if (out->conv == NULL) {
   3454 		out->conv = xmlBufferCreate();
   3455 	    }
   3456 	    ret = escaping(out->buffer->content + out->buffer->use ,
   3457 	                   &chunk, str, &cons);
   3458 	    if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
   3459 	        return(-1);
   3460 	    out->buffer->use += chunk;
   3461 	    out->buffer->content[out->buffer->use] = 0;
   3462 
   3463 	    if ((out->buffer->use < MINLEN) && (cons == len))
   3464 		goto done;
   3465 
   3466 	    /*
   3467 	     * convert as much as possible to the output buffer.
   3468 	     */
   3469 	    ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
   3470 	    if ((ret < 0) && (ret != -3)) {
   3471 		xmlIOErr(XML_IO_ENCODER, NULL);
   3472 		out->error = XML_IO_ENCODER;
   3473 		return(-1);
   3474 	    }
   3475 	    nbchars = out->conv->use;
   3476 	} else {
   3477 	    ret = escaping(out->buffer->content + out->buffer->use ,
   3478 	                   &chunk, str, &cons);
   3479 	    if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
   3480 	        return(-1);
   3481 	    out->buffer->use += chunk;
   3482 	    out->buffer->content[out->buffer->use] = 0;
   3483 	    nbchars = out->buffer->use;
   3484 	}
   3485 	str += cons;
   3486 	len -= cons;
   3487 
   3488 	if ((nbchars < MINLEN) && (len <= 0))
   3489 	    goto done;
   3490 
   3491 	if (out->writecallback) {
   3492 	    /*
   3493 	     * second write the stuff to the I/O channel
   3494 	     */
   3495 	    if (out->encoder != NULL) {
   3496 		ret = out->writecallback(out->context,
   3497 				 (const char *)out->conv->content, nbchars);
   3498 		if (ret >= 0)
   3499 		    xmlBufferShrink(out->conv, ret);
   3500 	    } else {
   3501 		ret = out->writecallback(out->context,
   3502 				 (const char *)out->buffer->content, nbchars);
   3503 		if (ret >= 0)
   3504 		    xmlBufferShrink(out->buffer, ret);
   3505 	    }
   3506 	    if (ret < 0) {
   3507 		xmlIOErr(XML_IO_WRITE, NULL);
   3508 		out->error = XML_IO_WRITE;
   3509 		return(ret);
   3510 	    }
   3511 	    out->written += ret;
   3512 	} else if (out->buffer->size - out->buffer->use < MINLEN) {
   3513 	    xmlBufferResize(out->buffer, out->buffer->size + MINLEN);
   3514 	}
   3515 	written += nbchars;
   3516     } while ((len > 0) && (oldwritten != written));
   3517 
   3518 done:
   3519 #ifdef DEBUG_INPUT
   3520     xmlGenericError(xmlGenericErrorContext,
   3521 	    "I/O: wrote %d chars\n", written);
   3522 #endif
   3523     return(written);
   3524 }
   3525 
   3526 /**
   3527  * xmlOutputBufferWriteString:
   3528  * @out:  a buffered parser output
   3529  * @str:  a zero terminated C string
   3530  *
   3531  * Write the content of the string in the output I/O buffer
   3532  * This routine handle the I18N transcoding from internal UTF-8
   3533  * The buffer is lossless, i.e. will store in case of partial
   3534  * or delayed writes.
   3535  *
   3536  * Returns the number of chars immediately written, or -1
   3537  *         in case of error.
   3538  */
   3539 int
   3540 xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
   3541     int len;
   3542 
   3543     if ((out == NULL) || (out->error)) return(-1);
   3544     if (str == NULL)
   3545         return(-1);
   3546     len = strlen(str);
   3547 
   3548     if (len > 0)
   3549 	return(xmlOutputBufferWrite(out, len, str));
   3550     return(len);
   3551 }
   3552 
   3553 /**
   3554  * xmlOutputBufferFlush:
   3555  * @out:  a buffered output
   3556  *
   3557  * flushes the output I/O channel
   3558  *
   3559  * Returns the number of byte written or -1 in case of error.
   3560  */
   3561 int
   3562 xmlOutputBufferFlush(xmlOutputBufferPtr out) {
   3563     int nbchars = 0, ret = 0;
   3564 
   3565     if ((out == NULL) || (out->error)) return(-1);
   3566     /*
   3567      * first handle encoding stuff.
   3568      */
   3569     if ((out->conv != NULL) && (out->encoder != NULL)) {
   3570 	/*
   3571 	 * convert as much as possible to the parser reading buffer.
   3572 	 */
   3573 	nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
   3574 	if (nbchars < 0) {
   3575 	    xmlIOErr(XML_IO_ENCODER, NULL);
   3576 	    out->error = XML_IO_ENCODER;
   3577 	    return(-1);
   3578 	}
   3579     }
   3580 
   3581     /*
   3582      * second flush the stuff to the I/O channel
   3583      */
   3584     if ((out->conv != NULL) && (out->encoder != NULL) &&
   3585 	(out->writecallback != NULL)) {
   3586 	ret = out->writecallback(out->context,
   3587 	           (const char *)out->conv->content, out->conv->use);
   3588 	if (ret >= 0)
   3589 	    xmlBufferShrink(out->conv, ret);
   3590     } else if (out->writecallback != NULL) {
   3591 	ret = out->writecallback(out->context,
   3592 	           (const char *)out->buffer->content, out->buffer->use);
   3593 	if (ret >= 0)
   3594 	    xmlBufferShrink(out->buffer, ret);
   3595     }
   3596     if (ret < 0) {
   3597 	xmlIOErr(XML_IO_FLUSH, NULL);
   3598 	out->error = XML_IO_FLUSH;
   3599 	return(ret);
   3600     }
   3601     out->written += ret;
   3602 
   3603 #ifdef DEBUG_INPUT
   3604     xmlGenericError(xmlGenericErrorContext,
   3605 	    "I/O: flushed %d chars\n", ret);
   3606 #endif
   3607     return(ret);
   3608 }
   3609 #endif /* LIBXML_OUTPUT_ENABLED */
   3610 
   3611 /**
   3612  * xmlParserGetDirectory:
   3613  * @filename:  the path to a file
   3614  *
   3615  * lookup the directory for that file
   3616  *
   3617  * Returns a new allocated string containing the directory, or NULL.
   3618  */
   3619 char *
   3620 xmlParserGetDirectory(const char *filename) {
   3621     char *ret = NULL;
   3622     char dir[1024];
   3623     char *cur;
   3624 
   3625 #ifdef _WIN32_WCE  /* easy way by now ... wince does not have dirs! */
   3626     return NULL;
   3627 #endif
   3628 
   3629     if (xmlInputCallbackInitialized == 0)
   3630 	xmlRegisterDefaultInputCallbacks();
   3631 
   3632     if (filename == NULL) return(NULL);
   3633 
   3634 #if defined(WIN32) && !defined(__CYGWIN__)
   3635 #   define IS_XMLPGD_SEP(ch) ((ch=='/')||(ch=='\\'))
   3636 #else
   3637 #   define IS_XMLPGD_SEP(ch) (ch=='/')
   3638 #endif
   3639 
   3640     strncpy(dir, filename, 1023);
   3641     dir[1023] = 0;
   3642     cur = &dir[strlen(dir)];
   3643     while (cur > dir) {
   3644          if (IS_XMLPGD_SEP(*cur)) break;
   3645 	 cur --;
   3646     }
   3647     if (IS_XMLPGD_SEP(*cur)) {
   3648         if (cur == dir) dir[1] = 0;
   3649 	else *cur = 0;
   3650 	ret = xmlMemStrdup(dir);
   3651     } else {
   3652         if (getcwd(dir, 1024) != NULL) {
   3653 	    dir[1023] = 0;
   3654 	    ret = xmlMemStrdup(dir);
   3655 	}
   3656     }
   3657     return(ret);
   3658 #undef IS_XMLPGD_SEP
   3659 }
   3660 
   3661 /****************************************************************
   3662  *								*
   3663  *		External entities loading			*
   3664  *								*
   3665  ****************************************************************/
   3666 
   3667 /**
   3668  * xmlCheckHTTPInput:
   3669  * @ctxt: an XML parser context
   3670  * @ret: an XML parser input
   3671  *
   3672  * Check an input in case it was created from an HTTP stream, in that
   3673  * case it will handle encoding and update of the base URL in case of
   3674  * redirection. It also checks for HTTP errors in which case the input
   3675  * is cleanly freed up and an appropriate error is raised in context
   3676  *
   3677  * Returns the input or NULL in case of HTTP error.
   3678  */
   3679 xmlParserInputPtr
   3680 xmlCheckHTTPInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr ret) {
   3681 #ifdef LIBXML_HTTP_ENABLED
   3682     if ((ret != NULL) && (ret->buf != NULL) &&
   3683         (ret->buf->readcallback == xmlIOHTTPRead) &&
   3684         (ret->buf->context != NULL)) {
   3685         const char *encoding;
   3686         const char *redir;
   3687         const char *mime;
   3688         int code;
   3689 
   3690         code = xmlNanoHTTPReturnCode(ret->buf->context);
   3691         if (code >= 400) {
   3692             /* fatal error */
   3693 	    if (ret->filename != NULL)
   3694 		__xmlLoaderErr(ctxt, "failed to load HTTP resource \"%s\"\n",
   3695                          (const char *) ret->filename);
   3696 	    else
   3697 		__xmlLoaderErr(ctxt, "failed to load HTTP resource\n", NULL);
   3698             xmlFreeInputStream(ret);
   3699             ret = NULL;
   3700         } else {
   3701 
   3702             mime = xmlNanoHTTPMimeType(ret->buf->context);
   3703             if ((xmlStrstr(BAD_CAST mime, BAD_CAST "/xml")) ||
   3704                 (xmlStrstr(BAD_CAST mime, BAD_CAST "+xml"))) {
   3705                 encoding = xmlNanoHTTPEncoding(ret->buf->context);
   3706                 if (encoding != NULL) {
   3707                     xmlCharEncodingHandlerPtr handler;
   3708 
   3709                     handler = xmlFindCharEncodingHandler(encoding);
   3710                     if (handler != NULL) {
   3711                         xmlSwitchInputEncoding(ctxt, ret, handler);
   3712                     } else {
   3713                         __xmlErrEncoding(ctxt, XML_ERR_UNKNOWN_ENCODING,
   3714                                          "Unknown encoding %s",
   3715                                          BAD_CAST encoding, NULL);
   3716                     }
   3717                     if (ret->encoding == NULL)
   3718                         ret->encoding = xmlStrdup(BAD_CAST encoding);
   3719                 }
   3720 #if 0
   3721             } else if (xmlStrstr(BAD_CAST mime, BAD_CAST "html")) {
   3722 #endif
   3723             }
   3724             redir = xmlNanoHTTPRedir(ret->buf->context);
   3725             if (redir != NULL) {
   3726                 if (ret->filename != NULL)
   3727                     xmlFree((xmlChar *) ret->filename);
   3728                 if (ret->directory != NULL) {
   3729                     xmlFree((xmlChar *) ret->directory);
   3730                     ret->directory = NULL;
   3731                 }
   3732                 ret->filename =
   3733                     (char *) xmlStrdup((const xmlChar *) redir);
   3734             }
   3735         }
   3736     }
   3737 #endif
   3738     return(ret);
   3739 }
   3740 
   3741 static int xmlNoNetExists(const char *URL) {
   3742     const char *path;
   3743 
   3744     if (URL == NULL)
   3745 	return(0);
   3746 
   3747     if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
   3748 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
   3749 	path = &URL[17];
   3750 #else
   3751 	path = &URL[16];
   3752 #endif
   3753     else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
   3754 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
   3755 	path = &URL[8];
   3756 #else
   3757 	path = &URL[7];
   3758 #endif
   3759     } else
   3760 	path = URL;
   3761 
   3762     return xmlCheckFilename(path);
   3763 }
   3764 
   3765 #ifdef LIBXML_CATALOG_ENABLED
   3766 
   3767 /**
   3768  * xmlResolveResourceFromCatalog:
   3769  * @URL:  the URL for the entity to load
   3770  * @ID:  the System ID for the entity to load
   3771  * @ctxt:  the context in which the entity is called or NULL
   3772  *
   3773  * Resolves the URL and ID against the appropriate catalog.
   3774  * This function is used by xmlDefaultExternalEntityLoader and
   3775  * xmlNoNetExternalEntityLoader.
   3776  *
   3777  * Returns a new allocated URL, or NULL.
   3778  */
   3779 static xmlChar *
   3780 xmlResolveResourceFromCatalog(const char *URL, const char *ID,
   3781                               xmlParserCtxtPtr ctxt) {
   3782     xmlChar *resource = NULL;
   3783     xmlCatalogAllow pref;
   3784 
   3785     /*
   3786      * If the resource doesn't exists as a file,
   3787      * try to load it from the resource pointed in the catalogs
   3788      */
   3789     pref = xmlCatalogGetDefaults();
   3790 
   3791     if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
   3792 	/*
   3793 	 * Do a local lookup
   3794 	 */
   3795 	if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
   3796 	    ((pref == XML_CATA_ALLOW_ALL) ||
   3797 	     (pref == XML_CATA_ALLOW_DOCUMENT))) {
   3798 	    resource = xmlCatalogLocalResolve(ctxt->catalogs,
   3799 					      (const xmlChar *)ID,
   3800 					      (const xmlChar *)URL);
   3801         }
   3802 	/*
   3803 	 * Try a global lookup
   3804 	 */
   3805 	if ((resource == NULL) &&
   3806 	    ((pref == XML_CATA_ALLOW_ALL) ||
   3807 	     (pref == XML_CATA_ALLOW_GLOBAL))) {
   3808 	    resource = xmlCatalogResolve((const xmlChar *)ID,
   3809 					 (const xmlChar *)URL);
   3810 	}
   3811 	if ((resource == NULL) && (URL != NULL))
   3812 	    resource = xmlStrdup((const xmlChar *) URL);
   3813 
   3814 	/*
   3815 	 * TODO: do an URI lookup on the reference
   3816 	 */
   3817 	if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
   3818 	    xmlChar *tmp = NULL;
   3819 
   3820 	    if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
   3821 		((pref == XML_CATA_ALLOW_ALL) ||
   3822 		 (pref == XML_CATA_ALLOW_DOCUMENT))) {
   3823 		tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
   3824 	    }
   3825 	    if ((tmp == NULL) &&
   3826 		((pref == XML_CATA_ALLOW_ALL) ||
   3827 	         (pref == XML_CATA_ALLOW_GLOBAL))) {
   3828 		tmp = xmlCatalogResolveURI(resource);
   3829 	    }
   3830 
   3831 	    if (tmp != NULL) {
   3832 		xmlFree(resource);
   3833 		resource = tmp;
   3834 	    }
   3835 	}
   3836     }
   3837 
   3838     return resource;
   3839 }
   3840 
   3841 #endif
   3842 
   3843 /**
   3844  * xmlDefaultExternalEntityLoader:
   3845  * @URL:  the URL for the entity to load
   3846  * @ID:  the System ID for the entity to load
   3847  * @ctxt:  the context in which the entity is called or NULL
   3848  *
   3849  * By default we don't load external entitites, yet.
   3850  *
   3851  * Returns a new allocated xmlParserInputPtr, or NULL.
   3852  */
   3853 static xmlParserInputPtr
   3854 xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
   3855                                xmlParserCtxtPtr ctxt)
   3856 {
   3857     xmlParserInputPtr ret = NULL;
   3858     xmlChar *resource = NULL;
   3859 
   3860 #ifdef DEBUG_EXTERNAL_ENTITIES
   3861     xmlGenericError(xmlGenericErrorContext,
   3862                     "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
   3863 #endif
   3864     if ((ctxt != NULL) && (ctxt->options & XML_PARSE_NONET)) {
   3865         int options = ctxt->options;
   3866 
   3867 	ctxt->options -= XML_PARSE_NONET;
   3868         ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
   3869 	ctxt->options = options;
   3870 	return(ret);
   3871     }
   3872 #ifdef LIBXML_CATALOG_ENABLED
   3873     resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
   3874 #endif
   3875 
   3876     if (resource == NULL)
   3877         resource = (xmlChar *) URL;
   3878 
   3879     if (resource == NULL) {
   3880         if (ID == NULL)
   3881             ID = "NULL";
   3882         __xmlLoaderErr(ctxt, "failed to load external entity \"%s\"\n", ID);
   3883         return (NULL);
   3884     }
   3885     ret = xmlNewInputFromFile(ctxt, (const char *) resource);
   3886     if ((resource != NULL) && (resource != (xmlChar *) URL))
   3887         xmlFree(resource);
   3888     return (ret);
   3889 }
   3890 
   3891 static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
   3892        xmlDefaultExternalEntityLoader;
   3893 
   3894 /**
   3895  * xmlSetExternalEntityLoader:
   3896  * @f:  the new entity resolver function
   3897  *
   3898  * Changes the defaultexternal entity resolver function for the application
   3899  */
   3900 void
   3901 xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
   3902     xmlCurrentExternalEntityLoader = f;
   3903 }
   3904 
   3905 /**
   3906  * xmlGetExternalEntityLoader:
   3907  *
   3908  * Get the default external entity resolver function for the application
   3909  *
   3910  * Returns the xmlExternalEntityLoader function pointer
   3911  */
   3912 xmlExternalEntityLoader
   3913 xmlGetExternalEntityLoader(void) {
   3914     return(xmlCurrentExternalEntityLoader);
   3915 }
   3916 
   3917 /**
   3918  * xmlLoadExternalEntity:
   3919  * @URL:  the URL for the entity to load
   3920  * @ID:  the Public ID for the entity to load
   3921  * @ctxt:  the context in which the entity is called or NULL
   3922  *
   3923  * Load an external entity, note that the use of this function for
   3924  * unparsed entities may generate problems
   3925  *
   3926  * Returns the xmlParserInputPtr or NULL
   3927  */
   3928 xmlParserInputPtr
   3929 xmlLoadExternalEntity(const char *URL, const char *ID,
   3930                       xmlParserCtxtPtr ctxt) {
   3931     if ((URL != NULL) && (xmlNoNetExists(URL) == 0)) {
   3932 	char *canonicFilename;
   3933 	xmlParserInputPtr ret;
   3934 
   3935 	canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL);
   3936 	if (canonicFilename == NULL) {
   3937             xmlIOErrMemory("building canonical path\n");
   3938 	    return(NULL);
   3939 	}
   3940 
   3941 	ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt);
   3942 	xmlFree(canonicFilename);
   3943 	return(ret);
   3944     }
   3945     return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
   3946 }
   3947 
   3948 /************************************************************************
   3949  *									*
   3950  *		Disabling Network access				*
   3951  *									*
   3952  ************************************************************************/
   3953 
   3954 /**
   3955  * xmlNoNetExternalEntityLoader:
   3956  * @URL:  the URL for the entity to load
   3957  * @ID:  the System ID for the entity to load
   3958  * @ctxt:  the context in which the entity is called or NULL
   3959  *
   3960  * A specific entity loader disabling network accesses, though still
   3961  * allowing local catalog accesses for resolution.
   3962  *
   3963  * Returns a new allocated xmlParserInputPtr, or NULL.
   3964  */
   3965 xmlParserInputPtr
   3966 xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
   3967                              xmlParserCtxtPtr ctxt) {
   3968     xmlParserInputPtr input = NULL;
   3969     xmlChar *resource = NULL;
   3970 
   3971 #ifdef LIBXML_CATALOG_ENABLED
   3972     resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
   3973 #endif
   3974 
   3975     if (resource == NULL)
   3976 	resource = (xmlChar *) URL;
   3977 
   3978     if (resource != NULL) {
   3979         if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
   3980             (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
   3981             xmlIOErr(XML_IO_NETWORK_ATTEMPT, (const char *) resource);
   3982 	    if (resource != (xmlChar *) URL)
   3983 		xmlFree(resource);
   3984 	    return(NULL);
   3985 	}
   3986     }
   3987     input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
   3988     if (resource != (xmlChar *) URL)
   3989 	xmlFree(resource);
   3990     return(input);
   3991 }
   3992 
   3993 #define bottom_xmlIO
   3994 #include "elfgcchack.h"
   3995