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