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