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