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