| /* | 
 |  * xmlIO.c : implementation of the I/O interfaces used by the parser | 
 |  * | 
 |  * See Copyright for the status of this software. | 
 |  * | 
 |  * daniel@veillard.com | 
 |  * | 
 |  * 14 Nov 2000 ht - for VMS, truncated name of long functions to under 32 char | 
 |  */ | 
 |  | 
 | #define IN_LIBXML | 
 | #include "libxml.h" | 
 |  | 
 | #include <string.h> | 
 | #ifdef HAVE_ERRNO_H | 
 | #include <errno.h> | 
 | #endif | 
 |  | 
 |  | 
 | #ifdef HAVE_SYS_TYPES_H | 
 | #include <sys/types.h> | 
 | #endif | 
 | #ifdef HAVE_SYS_STAT_H | 
 | #include <sys/stat.h> | 
 | #endif | 
 | #ifdef HAVE_FCNTL_H | 
 | #include <fcntl.h> | 
 | #endif | 
 | #ifdef HAVE_UNISTD_H | 
 | #include <unistd.h> | 
 | #endif | 
 | #ifdef HAVE_STDLIB_H | 
 | #include <stdlib.h> | 
 | #endif | 
 | #ifdef HAVE_ZLIB_H | 
 | #include <zlib.h> | 
 | #endif | 
 |  | 
 | #if defined(WIN32) || defined(_WIN32) | 
 | #include <windows.h> | 
 | #endif | 
 |  | 
 | #if defined(_WIN32_WCE) | 
 | #include <winnls.h> /* for CP_UTF8 */ | 
 | #endif | 
 |  | 
 | /* Figure a portable way to know if a file is a directory. */ | 
 | #ifndef HAVE_STAT | 
 | #  ifdef HAVE__STAT | 
 |      /* MS C library seems to define stat and _stat. The definition | 
 |         is identical. Still, mapping them to each other causes a warning. */ | 
 | #    ifndef _MSC_VER | 
 | #      define stat(x,y) _stat(x,y) | 
 | #    endif | 
 | #    define HAVE_STAT | 
 | #  endif | 
 | #else | 
 | #  ifdef HAVE__STAT | 
 | #    if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__) | 
 | #      define stat _stat | 
 | #    endif | 
 | #  endif | 
 | #endif | 
 | #ifdef HAVE_STAT | 
 | #  ifndef S_ISDIR | 
 | #    ifdef _S_ISDIR | 
 | #      define S_ISDIR(x) _S_ISDIR(x) | 
 | #    else | 
 | #      ifdef S_IFDIR | 
 | #        ifndef S_IFMT | 
 | #          ifdef _S_IFMT | 
 | #            define S_IFMT _S_IFMT | 
 | #          endif | 
 | #        endif | 
 | #        ifdef S_IFMT | 
 | #          define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) | 
 | #        endif | 
 | #      endif | 
 | #    endif | 
 | #  endif | 
 | #endif | 
 |  | 
 | #include <libxml/xmlmemory.h> | 
 | #include <libxml/parser.h> | 
 | #include <libxml/parserInternals.h> | 
 | #include <libxml/xmlIO.h> | 
 | #include <libxml/uri.h> | 
 | #include <libxml/xmlerror.h> | 
 | #ifdef LIBXML_CATALOG_ENABLED | 
 | #include <libxml/catalog.h> | 
 | #endif | 
 | #include <libxml/globals.h> | 
 |  | 
 | /* #define VERBOSE_FAILURE */ | 
 | /* #define DEBUG_EXTERNAL_ENTITIES */ | 
 | /* #define DEBUG_INPUT */ | 
 |  | 
 | #ifdef DEBUG_INPUT | 
 | #define MINLEN 40 | 
 | #else | 
 | #define MINLEN 4000 | 
 | #endif | 
 |  | 
 | /* | 
 |  * Input I/O callback sets | 
 |  */ | 
 | typedef struct _xmlInputCallback { | 
 |     xmlInputMatchCallback matchcallback; | 
 |     xmlInputOpenCallback opencallback; | 
 |     xmlInputReadCallback readcallback; | 
 |     xmlInputCloseCallback closecallback; | 
 | } xmlInputCallback; | 
 |  | 
 | #define MAX_INPUT_CALLBACK 15 | 
 |  | 
 | static xmlInputCallback xmlInputCallbackTable[MAX_INPUT_CALLBACK]; | 
 | static int xmlInputCallbackNr = 0; | 
 | static int xmlInputCallbackInitialized = 0; | 
 |  | 
 | #ifdef LIBXML_OUTPUT_ENABLED | 
 | /* | 
 |  * Output I/O callback sets | 
 |  */ | 
 | typedef struct _xmlOutputCallback { | 
 |     xmlOutputMatchCallback matchcallback; | 
 |     xmlOutputOpenCallback opencallback; | 
 |     xmlOutputWriteCallback writecallback; | 
 |     xmlOutputCloseCallback closecallback; | 
 | } xmlOutputCallback; | 
 |  | 
 | #define MAX_OUTPUT_CALLBACK 15 | 
 |  | 
 | static xmlOutputCallback xmlOutputCallbackTable[MAX_OUTPUT_CALLBACK]; | 
 | static int xmlOutputCallbackNr = 0; | 
 | static int xmlOutputCallbackInitialized = 0; | 
 |  | 
 | xmlOutputBufferPtr | 
 | xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder); | 
 | #endif /* LIBXML_OUTPUT_ENABLED */ | 
 |  | 
 | /************************************************************************ | 
 |  *									* | 
 |  *		Tree memory error handler				* | 
 |  *									* | 
 |  ************************************************************************/ | 
 |  | 
 | static const char *IOerr[] = { | 
 |     "Unknown IO error",         /* UNKNOWN */ | 
 |     "Permission denied",	/* EACCES */ | 
 |     "Resource temporarily unavailable",/* EAGAIN */ | 
 |     "Bad file descriptor",	/* EBADF */ | 
 |     "Bad message",		/* EBADMSG */ | 
 |     "Resource busy",		/* EBUSY */ | 
 |     "Operation canceled",	/* ECANCELED */ | 
 |     "No child processes",	/* ECHILD */ | 
 |     "Resource deadlock avoided",/* EDEADLK */ | 
 |     "Domain error",		/* EDOM */ | 
 |     "File exists",		/* EEXIST */ | 
 |     "Bad address",		/* EFAULT */ | 
 |     "File too large",		/* EFBIG */ | 
 |     "Operation in progress",	/* EINPROGRESS */ | 
 |     "Interrupted function call",/* EINTR */ | 
 |     "Invalid argument",		/* EINVAL */ | 
 |     "Input/output error",	/* EIO */ | 
 |     "Is a directory",		/* EISDIR */ | 
 |     "Too many open files",	/* EMFILE */ | 
 |     "Too many links",		/* EMLINK */ | 
 |     "Inappropriate message buffer length",/* EMSGSIZE */ | 
 |     "Filename too long",	/* ENAMETOOLONG */ | 
 |     "Too many open files in system",/* ENFILE */ | 
 |     "No such device",		/* ENODEV */ | 
 |     "No such file or directory",/* ENOENT */ | 
 |     "Exec format error",	/* ENOEXEC */ | 
 |     "No locks available",	/* ENOLCK */ | 
 |     "Not enough space",		/* ENOMEM */ | 
 |     "No space left on device",	/* ENOSPC */ | 
 |     "Function not implemented",	/* ENOSYS */ | 
 |     "Not a directory",		/* ENOTDIR */ | 
 |     "Directory not empty",	/* ENOTEMPTY */ | 
 |     "Not supported",		/* ENOTSUP */ | 
 |     "Inappropriate I/O control operation",/* ENOTTY */ | 
 |     "No such device or address",/* ENXIO */ | 
 |     "Operation not permitted",	/* EPERM */ | 
 |     "Broken pipe",		/* EPIPE */ | 
 |     "Result too large",		/* ERANGE */ | 
 |     "Read-only file system",	/* EROFS */ | 
 |     "Invalid seek",		/* ESPIPE */ | 
 |     "No such process",		/* ESRCH */ | 
 |     "Operation timed out",	/* ETIMEDOUT */ | 
 |     "Improper link",		/* EXDEV */ | 
 |     "Attempt to load network entity %s", /* XML_IO_NETWORK_ATTEMPT */ | 
 |     "encoder error",		/* XML_IO_ENCODER */ | 
 |     "flush error", | 
 |     "write error", | 
 |     "no input", | 
 |     "buffer full", | 
 |     "loading error", | 
 |     "not a socket",		/* ENOTSOCK */ | 
 |     "already connected",	/* EISCONN */ | 
 |     "connection refused",	/* ECONNREFUSED */ | 
 |     "unreachable network",	/* ENETUNREACH */ | 
 |     "adddress in use",		/* EADDRINUSE */ | 
 |     "already in use",		/* EALREADY */ | 
 |     "unknown address familly",	/* EAFNOSUPPORT */ | 
 | }; | 
 |  | 
 | #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__) | 
 | /** | 
 |  * __xmlIOWin32UTF8ToWChar: | 
 |  * @u8String:  uft-8 string | 
 |  * | 
 |  * Convert a string from utf-8 to wchar (WINDOWS ONLY!) | 
 |  */ | 
 | static wchar_t * | 
 | __xmlIOWin32UTF8ToWChar(const char *u8String) | 
 | { | 
 |     wchar_t *wString = NULL; | 
 |  | 
 |     if (u8String) { | 
 |         int wLen = | 
 |             MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, u8String, | 
 |                                 -1, NULL, 0); | 
 |         if (wLen) { | 
 |             wString = xmlMalloc(wLen * sizeof(wchar_t)); | 
 |             if (wString) { | 
 |                 if (MultiByteToWideChar | 
 |                     (CP_UTF8, 0, u8String, -1, wString, wLen) == 0) { | 
 |                     xmlFree(wString); | 
 |                     wString = NULL; | 
 |                 } | 
 |             } | 
 |         } | 
 |     } | 
 |  | 
 |     return wString; | 
 | } | 
 | #endif | 
 |  | 
 | /** | 
 |  * xmlIOErrMemory: | 
 |  * @extra:  extra informations | 
 |  * | 
 |  * Handle an out of memory condition | 
 |  */ | 
 | static void | 
 | xmlIOErrMemory(const char *extra) | 
 | { | 
 |     __xmlSimpleError(XML_FROM_IO, XML_ERR_NO_MEMORY, NULL, NULL, extra); | 
 | } | 
 |  | 
 | /** | 
 |  * __xmlIOErr: | 
 |  * @code:  the error number | 
 |  * @ | 
 |  * @extra:  extra informations | 
 |  * | 
 |  * Handle an I/O error | 
 |  */ | 
 | void | 
 | __xmlIOErr(int domain, int code, const char *extra) | 
 | { | 
 |     unsigned int idx; | 
 |  | 
 |     if (code == 0) { | 
 | #ifdef HAVE_ERRNO_H | 
 | 	if (errno == 0) code = 0; | 
 | #ifdef EACCES | 
 |         else if (errno == EACCES) code = XML_IO_EACCES; | 
 | #endif | 
 | #ifdef EAGAIN | 
 |         else if (errno == EAGAIN) code = XML_IO_EAGAIN; | 
 | #endif | 
 | #ifdef EBADF | 
 |         else if (errno == EBADF) code = XML_IO_EBADF; | 
 | #endif | 
 | #ifdef EBADMSG | 
 |         else if (errno == EBADMSG) code = XML_IO_EBADMSG; | 
 | #endif | 
 | #ifdef EBUSY | 
 |         else if (errno == EBUSY) code = XML_IO_EBUSY; | 
 | #endif | 
 | #ifdef ECANCELED | 
 |         else if (errno == ECANCELED) code = XML_IO_ECANCELED; | 
 | #endif | 
 | #ifdef ECHILD | 
 |         else if (errno == ECHILD) code = XML_IO_ECHILD; | 
 | #endif | 
 | #ifdef EDEADLK | 
 |         else if (errno == EDEADLK) code = XML_IO_EDEADLK; | 
 | #endif | 
 | #ifdef EDOM | 
 |         else if (errno == EDOM) code = XML_IO_EDOM; | 
 | #endif | 
 | #ifdef EEXIST | 
 |         else if (errno == EEXIST) code = XML_IO_EEXIST; | 
 | #endif | 
 | #ifdef EFAULT | 
 |         else if (errno == EFAULT) code = XML_IO_EFAULT; | 
 | #endif | 
 | #ifdef EFBIG | 
 |         else if (errno == EFBIG) code = XML_IO_EFBIG; | 
 | #endif | 
 | #ifdef EINPROGRESS | 
 |         else if (errno == EINPROGRESS) code = XML_IO_EINPROGRESS; | 
 | #endif | 
 | #ifdef EINTR | 
 |         else if (errno == EINTR) code = XML_IO_EINTR; | 
 | #endif | 
 | #ifdef EINVAL | 
 |         else if (errno == EINVAL) code = XML_IO_EINVAL; | 
 | #endif | 
 | #ifdef EIO | 
 |         else if (errno == EIO) code = XML_IO_EIO; | 
 | #endif | 
 | #ifdef EISDIR | 
 |         else if (errno == EISDIR) code = XML_IO_EISDIR; | 
 | #endif | 
 | #ifdef EMFILE | 
 |         else if (errno == EMFILE) code = XML_IO_EMFILE; | 
 | #endif | 
 | #ifdef EMLINK | 
 |         else if (errno == EMLINK) code = XML_IO_EMLINK; | 
 | #endif | 
 | #ifdef EMSGSIZE | 
 |         else if (errno == EMSGSIZE) code = XML_IO_EMSGSIZE; | 
 | #endif | 
 | #ifdef ENAMETOOLONG | 
 |         else if (errno == ENAMETOOLONG) code = XML_IO_ENAMETOOLONG; | 
 | #endif | 
 | #ifdef ENFILE | 
 |         else if (errno == ENFILE) code = XML_IO_ENFILE; | 
 | #endif | 
 | #ifdef ENODEV | 
 |         else if (errno == ENODEV) code = XML_IO_ENODEV; | 
 | #endif | 
 | #ifdef ENOENT | 
 |         else if (errno == ENOENT) code = XML_IO_ENOENT; | 
 | #endif | 
 | #ifdef ENOEXEC | 
 |         else if (errno == ENOEXEC) code = XML_IO_ENOEXEC; | 
 | #endif | 
 | #ifdef ENOLCK | 
 |         else if (errno == ENOLCK) code = XML_IO_ENOLCK; | 
 | #endif | 
 | #ifdef ENOMEM | 
 |         else if (errno == ENOMEM) code = XML_IO_ENOMEM; | 
 | #endif | 
 | #ifdef ENOSPC | 
 |         else if (errno == ENOSPC) code = XML_IO_ENOSPC; | 
 | #endif | 
 | #ifdef ENOSYS | 
 |         else if (errno == ENOSYS) code = XML_IO_ENOSYS; | 
 | #endif | 
 | #ifdef ENOTDIR | 
 |         else if (errno == ENOTDIR) code = XML_IO_ENOTDIR; | 
 | #endif | 
 | #ifdef ENOTEMPTY | 
 |         else if (errno == ENOTEMPTY) code = XML_IO_ENOTEMPTY; | 
 | #endif | 
 | #ifdef ENOTSUP | 
 |         else if (errno == ENOTSUP) code = XML_IO_ENOTSUP; | 
 | #endif | 
 | #ifdef ENOTTY | 
 |         else if (errno == ENOTTY) code = XML_IO_ENOTTY; | 
 | #endif | 
 | #ifdef ENXIO | 
 |         else if (errno == ENXIO) code = XML_IO_ENXIO; | 
 | #endif | 
 | #ifdef EPERM | 
 |         else if (errno == EPERM) code = XML_IO_EPERM; | 
 | #endif | 
 | #ifdef EPIPE | 
 |         else if (errno == EPIPE) code = XML_IO_EPIPE; | 
 | #endif | 
 | #ifdef ERANGE | 
 |         else if (errno == ERANGE) code = XML_IO_ERANGE; | 
 | #endif | 
 | #ifdef EROFS | 
 |         else if (errno == EROFS) code = XML_IO_EROFS; | 
 | #endif | 
 | #ifdef ESPIPE | 
 |         else if (errno == ESPIPE) code = XML_IO_ESPIPE; | 
 | #endif | 
 | #ifdef ESRCH | 
 |         else if (errno == ESRCH) code = XML_IO_ESRCH; | 
 | #endif | 
 | #ifdef ETIMEDOUT | 
 |         else if (errno == ETIMEDOUT) code = XML_IO_ETIMEDOUT; | 
 | #endif | 
 | #ifdef EXDEV | 
 |         else if (errno == EXDEV) code = XML_IO_EXDEV; | 
 | #endif | 
 | #ifdef ENOTSOCK | 
 |         else if (errno == ENOTSOCK) code = XML_IO_ENOTSOCK; | 
 | #endif | 
 | #ifdef EISCONN | 
 |         else if (errno == EISCONN) code = XML_IO_EISCONN; | 
 | #endif | 
 | #ifdef ECONNREFUSED | 
 |         else if (errno == ECONNREFUSED) code = XML_IO_ECONNREFUSED; | 
 | #endif | 
 | #ifdef ETIMEDOUT | 
 |         else if (errno == ETIMEDOUT) code = XML_IO_ETIMEDOUT; | 
 | #endif | 
 | #ifdef ENETUNREACH | 
 |         else if (errno == ENETUNREACH) code = XML_IO_ENETUNREACH; | 
 | #endif | 
 | #ifdef EADDRINUSE | 
 |         else if (errno == EADDRINUSE) code = XML_IO_EADDRINUSE; | 
 | #endif | 
 | #ifdef EINPROGRESS | 
 |         else if (errno == EINPROGRESS) code = XML_IO_EINPROGRESS; | 
 | #endif | 
 | #ifdef EALREADY | 
 |         else if (errno == EALREADY) code = XML_IO_EALREADY; | 
 | #endif | 
 | #ifdef EAFNOSUPPORT | 
 |         else if (errno == EAFNOSUPPORT) code = XML_IO_EAFNOSUPPORT; | 
 | #endif | 
 |         else code = XML_IO_UNKNOWN; | 
 | #endif /* HAVE_ERRNO_H */ | 
 |     } | 
 |     idx = 0; | 
 |     if (code >= XML_IO_UNKNOWN) idx = code - XML_IO_UNKNOWN; | 
 |     if (idx >= (sizeof(IOerr) / sizeof(IOerr[0]))) idx = 0; | 
 |  | 
 |     __xmlSimpleError(domain, code, NULL, IOerr[idx], extra); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlIOErr: | 
 |  * @code:  the error number | 
 |  * @extra:  extra informations | 
 |  * | 
 |  * Handle an I/O error | 
 |  */ | 
 | static void | 
 | xmlIOErr(int code, const char *extra) | 
 | { | 
 |     __xmlIOErr(XML_FROM_IO, code, extra); | 
 | } | 
 |  | 
 | /** | 
 |  * __xmlLoaderErr: | 
 |  * @ctx: the parser context | 
 |  * @extra:  extra informations | 
 |  * | 
 |  * Handle a resource access error | 
 |  */ | 
 | void | 
 | __xmlLoaderErr(void *ctx, const char *msg, const char *filename) | 
 | { | 
 |     xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; | 
 |     xmlStructuredErrorFunc schannel = NULL; | 
 |     xmlGenericErrorFunc channel = NULL; | 
 |     void *data = NULL; | 
 |     xmlErrorLevel level = XML_ERR_ERROR; | 
 |  | 
 |     if ((ctxt != NULL) && (ctxt->disableSAX != 0) && | 
 |         (ctxt->instate == XML_PARSER_EOF)) | 
 | 	return; | 
 |     if ((ctxt != NULL) && (ctxt->sax != NULL)) { | 
 |         if (ctxt->validate) { | 
 | 	    channel = ctxt->sax->error; | 
 | 	    level = XML_ERR_ERROR; | 
 | 	} else { | 
 | 	    channel = ctxt->sax->warning; | 
 | 	    level = XML_ERR_WARNING; | 
 | 	} | 
 | 	if (ctxt->sax->initialized == XML_SAX2_MAGIC) | 
 | 	    schannel = ctxt->sax->serror; | 
 | 	data = ctxt->userData; | 
 |     } | 
 |     __xmlRaiseError(schannel, channel, data, ctxt, NULL, XML_FROM_IO, | 
 |                     XML_IO_LOAD_ERROR, level, NULL, 0, | 
 | 		    filename, NULL, NULL, 0, 0, | 
 | 		    msg, filename); | 
 |  | 
 | } | 
 |  | 
 | /************************************************************************ | 
 |  *									* | 
 |  *		Tree memory error handler				* | 
 |  *									* | 
 |  ************************************************************************/ | 
 | /** | 
 |  * xmlNormalizeWindowsPath: | 
 |  * @path: the input file path | 
 |  * | 
 |  * This function is obsolete. Please see xmlURIFromPath in uri.c for | 
 |  * a better solution. | 
 |  * | 
 |  * Returns a canonicalized version of the path | 
 |  */ | 
 | xmlChar * | 
 | xmlNormalizeWindowsPath(const xmlChar *path) | 
 | { | 
 |     return xmlCanonicPath(path); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlCleanupInputCallbacks: | 
 |  * | 
 |  * clears the entire input callback table. this includes the | 
 |  * compiled-in I/O. | 
 |  */ | 
 | void | 
 | xmlCleanupInputCallbacks(void) | 
 | { | 
 |     int i; | 
 |  | 
 |     if (!xmlInputCallbackInitialized) | 
 |         return; | 
 |  | 
 |     for (i = xmlInputCallbackNr - 1; i >= 0; i--) { | 
 |         xmlInputCallbackTable[i].matchcallback = NULL; | 
 |         xmlInputCallbackTable[i].opencallback = NULL; | 
 |         xmlInputCallbackTable[i].readcallback = NULL; | 
 |         xmlInputCallbackTable[i].closecallback = NULL; | 
 |     } | 
 |  | 
 |     xmlInputCallbackNr = 0; | 
 |     xmlInputCallbackInitialized = 0; | 
 | } | 
 |  | 
 | /** | 
 |  * xmlPopInputCallbacks: | 
 |  * | 
 |  * Clear the top input callback from the input stack. this includes the | 
 |  * compiled-in I/O. | 
 |  * | 
 |  * Returns the number of input callback registered or -1 in case of error. | 
 |  */ | 
 | int | 
 | xmlPopInputCallbacks(void) | 
 | { | 
 |     if (!xmlInputCallbackInitialized) | 
 |         return(-1); | 
 |  | 
 |     if (xmlInputCallbackNr <= 0) | 
 |         return(-1); | 
 |  | 
 |     xmlInputCallbackNr--; | 
 |     xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = NULL; | 
 |     xmlInputCallbackTable[xmlInputCallbackNr].opencallback = NULL; | 
 |     xmlInputCallbackTable[xmlInputCallbackNr].readcallback = NULL; | 
 |     xmlInputCallbackTable[xmlInputCallbackNr].closecallback = NULL; | 
 |  | 
 |     return(xmlInputCallbackNr); | 
 | } | 
 |  | 
 | #ifdef LIBXML_OUTPUT_ENABLED | 
 | /** | 
 |  * xmlCleanupOutputCallbacks: | 
 |  * | 
 |  * clears the entire output callback table. this includes the | 
 |  * compiled-in I/O callbacks. | 
 |  */ | 
 | void | 
 | xmlCleanupOutputCallbacks(void) | 
 | { | 
 |     int i; | 
 |  | 
 |     if (!xmlOutputCallbackInitialized) | 
 |         return; | 
 |  | 
 |     for (i = xmlOutputCallbackNr - 1; i >= 0; i--) { | 
 |         xmlOutputCallbackTable[i].matchcallback = NULL; | 
 |         xmlOutputCallbackTable[i].opencallback = NULL; | 
 |         xmlOutputCallbackTable[i].writecallback = NULL; | 
 |         xmlOutputCallbackTable[i].closecallback = NULL; | 
 |     } | 
 |  | 
 |     xmlOutputCallbackNr = 0; | 
 |     xmlOutputCallbackInitialized = 0; | 
 | } | 
 | #endif /* LIBXML_OUTPUT_ENABLED */ | 
 |  | 
 | /************************************************************************ | 
 |  *									* | 
 |  *		Standard I/O for file accesses				* | 
 |  *									* | 
 |  ************************************************************************/ | 
 |  | 
 | #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__) | 
 |  | 
 | /** | 
 |  *  xmlWrapOpenUtf8: | 
 |  * @path:  the path in utf-8 encoding | 
 |  * @mode:  type of access (0 - read, 1 - write) | 
 |  * | 
 |  * function opens the file specified by @path | 
 |  * | 
 |  */ | 
 | static FILE* | 
 | xmlWrapOpenUtf8(const char *path,int mode) | 
 | { | 
 |     FILE *fd = NULL; | 
 |     wchar_t *wPath; | 
 |  | 
 |     wPath = __xmlIOWin32UTF8ToWChar(path); | 
 |     if(wPath) | 
 |     { | 
 |        fd = _wfopen(wPath, mode ? L"wb" : L"rb"); | 
 |        xmlFree(wPath); | 
 |     } | 
 |     /* maybe path in native encoding */ | 
 |     if(fd == NULL) | 
 |        fd = fopen(path, mode ? "wb" : "rb"); | 
 |  | 
 |     return fd; | 
 | } | 
 |  | 
 | #ifdef HAVE_ZLIB_H | 
 | static gzFile | 
 | xmlWrapGzOpenUtf8(const char *path, const char *mode) | 
 | { | 
 |     gzFile fd; | 
 |     wchar_t *wPath; | 
 |  | 
 |     fd = gzopen (path, mode); | 
 |     if (fd) | 
 |         return fd; | 
 |  | 
 |     wPath = __xmlIOWin32UTF8ToWChar(path); | 
 |     if(wPath) | 
 |     { | 
 | 	int d, m = (strstr(mode, "r") ? O_RDONLY : O_RDWR); | 
 | #ifdef _O_BINARY | 
 |         m |= (strstr(mode, "b") ? _O_BINARY : 0); | 
 | #endif | 
 | 	d = _wopen(wPath, m); | 
 | 	if (d >= 0) | 
 | 	    fd = gzdopen(d, mode); | 
 |         xmlFree(wPath); | 
 |     } | 
 |  | 
 |     return fd; | 
 | } | 
 | #endif | 
 |  | 
 | /** | 
 |  *  xmlWrapStatUtf8: | 
 |  * @path:  the path in utf-8 encoding | 
 |  * @info:  structure that stores results | 
 |  * | 
 |  * function obtains information about the file or directory | 
 |  * | 
 |  */ | 
 | static int | 
 | xmlWrapStatUtf8(const char *path,struct stat *info) | 
 | { | 
 | #ifdef HAVE_STAT | 
 |     int retval = -1; | 
 |     wchar_t *wPath; | 
 |  | 
 |     wPath = __xmlIOWin32UTF8ToWChar(path); | 
 |     if (wPath) | 
 |     { | 
 |        retval = _wstat(wPath,info); | 
 |        xmlFree(wPath); | 
 |     } | 
 |     /* maybe path in native encoding */ | 
 |     if(retval < 0) | 
 |        retval = stat(path,info); | 
 |     return retval; | 
 | #else | 
 |     return -1; | 
 | #endif | 
 | } | 
 |  | 
 | /** | 
 |  *  xmlWrapOpenNative: | 
 |  * @path:  the path | 
 |  * @mode:  type of access (0 - read, 1 - write) | 
 |  * | 
 |  * function opens the file specified by @path | 
 |  * | 
 |  */ | 
 | static FILE* | 
 | xmlWrapOpenNative(const char *path,int mode) | 
 | { | 
 |     return fopen(path,mode ? "wb" : "rb"); | 
 | } | 
 |  | 
 | /** | 
 |  *  xmlWrapStatNative: | 
 |  * @path:  the path | 
 |  * @info:  structure that stores results | 
 |  * | 
 |  * function obtains information about the file or directory | 
 |  * | 
 |  */ | 
 | static int | 
 | xmlWrapStatNative(const char *path,struct stat *info) | 
 | { | 
 | #ifdef HAVE_STAT | 
 |     return stat(path,info); | 
 | #else | 
 |     return -1; | 
 | #endif | 
 | } | 
 |  | 
 | typedef int (* xmlWrapStatFunc) (const char *f, struct stat *s); | 
 | static xmlWrapStatFunc xmlWrapStat = xmlWrapStatNative; | 
 | typedef FILE* (* xmlWrapOpenFunc)(const char *f,int mode); | 
 | static xmlWrapOpenFunc xmlWrapOpen = xmlWrapOpenNative; | 
 | #ifdef HAVE_ZLIB_H | 
 | typedef gzFile (* xmlWrapGzOpenFunc) (const char *f, const char *mode); | 
 | static xmlWrapGzOpenFunc xmlWrapGzOpen = gzopen; | 
 | #endif | 
 | /** | 
 |  * xmlInitPlatformSpecificIo: | 
 |  * | 
 |  * Initialize platform specific features. | 
 |  */ | 
 | static void | 
 | xmlInitPlatformSpecificIo(void) | 
 | { | 
 |     static int xmlPlatformIoInitialized = 0; | 
 |     OSVERSIONINFO osvi; | 
 |  | 
 |     if(xmlPlatformIoInitialized) | 
 |       return; | 
 |  | 
 |     osvi.dwOSVersionInfoSize = sizeof(osvi); | 
 |  | 
 |     if(GetVersionEx(&osvi) && (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)) { | 
 |       xmlWrapStat = xmlWrapStatUtf8; | 
 |       xmlWrapOpen = xmlWrapOpenUtf8; | 
 | #ifdef HAVE_ZLIB_H | 
 |       xmlWrapGzOpen = xmlWrapGzOpenUtf8; | 
 | #endif | 
 |     } else { | 
 |       xmlWrapStat = xmlWrapStatNative; | 
 |       xmlWrapOpen = xmlWrapOpenNative; | 
 | #ifdef HAVE_ZLIB_H | 
 |       xmlWrapGzOpen = gzopen; | 
 | #endif | 
 |     } | 
 |  | 
 |     xmlPlatformIoInitialized = 1; | 
 |     return; | 
 | } | 
 |  | 
 | #endif | 
 |  | 
 | /** | 
 |  * xmlCheckFilename: | 
 |  * @path:  the path to check | 
 |  * | 
 |  * function checks to see if @path is a valid source | 
 |  * (file, socket...) for XML. | 
 |  * | 
 |  * if stat is not available on the target machine, | 
 |  * returns 1.  if stat fails, returns 0 (if calling | 
 |  * stat on the filename fails, it can't be right). | 
 |  * if stat succeeds and the file is a directory, | 
 |  * returns 2.  otherwise returns 1. | 
 |  */ | 
 |  | 
 | int | 
 | xmlCheckFilename (const char *path) | 
 | { | 
 | #ifdef HAVE_STAT | 
 | 	struct stat stat_buffer; | 
 | #endif | 
 | 	if (path == NULL) | 
 | 		return(0); | 
 |  | 
 | #ifdef HAVE_STAT | 
 | #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__) | 
 |     if (xmlWrapStat(path, &stat_buffer) == -1) | 
 |         return 0; | 
 | #else | 
 |     if (stat(path, &stat_buffer) == -1) | 
 |         return 0; | 
 | #endif | 
 | #ifdef S_ISDIR | 
 |     if (S_ISDIR(stat_buffer.st_mode)) | 
 |         return 2; | 
 | #endif | 
 | #endif /* HAVE_STAT */ | 
 |     return 1; | 
 | } | 
 |  | 
 | static int | 
 | xmlNop(void) { | 
 |     return(0); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlFdRead: | 
 |  * @context:  the I/O context | 
 |  * @buffer:  where to drop data | 
 |  * @len:  number of bytes to read | 
 |  * | 
 |  * Read @len bytes to @buffer from the I/O channel. | 
 |  * | 
 |  * Returns the number of bytes written | 
 |  */ | 
 | static int | 
 | xmlFdRead (void * context, char * buffer, int len) { | 
 |     int ret; | 
 |  | 
 |     ret = read((int) (long) context, &buffer[0], len); | 
 |     if (ret < 0) xmlIOErr(0, "read()"); | 
 |     return(ret); | 
 | } | 
 |  | 
 | #ifdef LIBXML_OUTPUT_ENABLED | 
 | /** | 
 |  * xmlFdWrite: | 
 |  * @context:  the I/O context | 
 |  * @buffer:  where to get data | 
 |  * @len:  number of bytes to write | 
 |  * | 
 |  * Write @len bytes from @buffer to the I/O channel. | 
 |  * | 
 |  * Returns the number of bytes written | 
 |  */ | 
 | static int | 
 | xmlFdWrite (void * context, const char * buffer, int len) { | 
 |     int ret = 0; | 
 |  | 
 |     if (len > 0) { | 
 | 	ret = write((int) (long) context, &buffer[0], len); | 
 | 	if (ret < 0) xmlIOErr(0, "write()"); | 
 |     } | 
 |     return(ret); | 
 | } | 
 | #endif /* LIBXML_OUTPUT_ENABLED */ | 
 |  | 
 | /** | 
 |  * xmlFdClose: | 
 |  * @context:  the I/O context | 
 |  * | 
 |  * Close an I/O channel | 
 |  * | 
 |  * Returns 0 in case of success and error code otherwise | 
 |  */ | 
 | static int | 
 | xmlFdClose (void * context) { | 
 |     int ret; | 
 |     ret = close((int) (long) context); | 
 |     if (ret < 0) xmlIOErr(0, "close()"); | 
 |     return(ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlFileMatch: | 
 |  * @filename:  the URI for matching | 
 |  * | 
 |  * input from FILE * | 
 |  * | 
 |  * Returns 1 if matches, 0 otherwise | 
 |  */ | 
 | int | 
 | xmlFileMatch (const char *filename ATTRIBUTE_UNUSED) { | 
 |     return(1); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlFileOpen_real: | 
 |  * @filename:  the URI for matching | 
 |  * | 
 |  * input from FILE *, supports compressed input | 
 |  * if @filename is " " then the standard input is used | 
 |  * | 
 |  * Returns an I/O context or NULL in case of error | 
 |  */ | 
 | static void * | 
 | xmlFileOpen_real (const char *filename) { | 
 |     const char *path = NULL; | 
 |     FILE *fd; | 
 |  | 
 |     if (filename == NULL) | 
 |         return(NULL); | 
 |  | 
 |     if (!strcmp(filename, "-")) { | 
 | 	fd = stdin; | 
 | 	return((void *) fd); | 
 |     } | 
 |  | 
 |     if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) { | 
 | #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__) | 
 | 	path = &filename[17]; | 
 | #else | 
 | 	path = &filename[16]; | 
 | #endif | 
 |     } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) { | 
 | #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__) | 
 | 	path = &filename[8]; | 
 | #else | 
 | 	path = &filename[7]; | 
 | #endif | 
 |     } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:/", 6)) { | 
 |         /* lots of generators seems to lazy to read RFC 1738 */ | 
 | #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__) | 
 | 	path = &filename[6]; | 
 | #else | 
 | 	path = &filename[5]; | 
 | #endif | 
 |     } else | 
 | 	path = filename; | 
 |  | 
 |     if (path == NULL) | 
 | 	return(NULL); | 
 |     if (!xmlCheckFilename(path)) | 
 |         return(NULL); | 
 |  | 
 | #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__) | 
 |     fd = xmlWrapOpen(path, 0); | 
 | #else | 
 |     fd = fopen(path, "r"); | 
 | #endif /* WIN32 */ | 
 |     if (fd == NULL) xmlIOErr(0, path); | 
 |     return((void *) fd); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlFileOpen: | 
 |  * @filename:  the URI for matching | 
 |  * | 
 |  * Wrapper around xmlFileOpen_real that try it with an unescaped | 
 |  * version of @filename, if this fails fallback to @filename | 
 |  * | 
 |  * Returns a handler or NULL in case or failure | 
 |  */ | 
 | void * | 
 | xmlFileOpen (const char *filename) { | 
 |     char *unescaped; | 
 |     void *retval; | 
 |  | 
 |     retval = xmlFileOpen_real(filename); | 
 |     if (retval == NULL) { | 
 | 	unescaped = xmlURIUnescapeString(filename, 0, NULL); | 
 | 	if (unescaped != NULL) { | 
 | 	    retval = xmlFileOpen_real(unescaped); | 
 | 	    xmlFree(unescaped); | 
 | 	} | 
 |     } | 
 |  | 
 |     return retval; | 
 | } | 
 |  | 
 | #ifdef LIBXML_OUTPUT_ENABLED | 
 | /** | 
 |  * xmlFileOpenW: | 
 |  * @filename:  the URI for matching | 
 |  * | 
 |  * output to from FILE *, | 
 |  * if @filename is "-" then the standard output is used | 
 |  * | 
 |  * Returns an I/O context or NULL in case of error | 
 |  */ | 
 | static void * | 
 | xmlFileOpenW (const char *filename) { | 
 |     const char *path = NULL; | 
 |     FILE *fd; | 
 |  | 
 |     if (!strcmp(filename, "-")) { | 
 | 	fd = stdout; | 
 | 	return((void *) fd); | 
 |     } | 
 |  | 
 |     if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) | 
 | #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__) | 
 | 	path = &filename[17]; | 
 | #else | 
 | 	path = &filename[16]; | 
 | #endif | 
 |     else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) { | 
 | #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__) | 
 | 	path = &filename[8]; | 
 | #else | 
 | 	path = &filename[7]; | 
 | #endif | 
 |     } else | 
 | 	path = filename; | 
 |  | 
 |     if (path == NULL) | 
 | 	return(NULL); | 
 |  | 
 | #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__) | 
 |     fd = xmlWrapOpen(path, 1); | 
 | #else | 
 |  	   fd = fopen(path, "wb"); | 
 | #endif /* WIN32 */ | 
 |  | 
 | 	 if (fd == NULL) xmlIOErr(0, path); | 
 |     return((void *) fd); | 
 | } | 
 | #endif /* LIBXML_OUTPUT_ENABLED */ | 
 |  | 
 | /** | 
 |  * xmlFileRead: | 
 |  * @context:  the I/O context | 
 |  * @buffer:  where to drop data | 
 |  * @len:  number of bytes to write | 
 |  * | 
 |  * Read @len bytes to @buffer from the I/O channel. | 
 |  * | 
 |  * Returns the number of bytes written or < 0 in case of failure | 
 |  */ | 
 | int | 
 | xmlFileRead (void * context, char * buffer, int len) { | 
 |     int ret; | 
 |     if ((context == NULL) || (buffer == NULL)) | 
 |         return(-1); | 
 |     ret = fread(&buffer[0], 1,  len, (FILE *) context); | 
 |     if (ret < 0) xmlIOErr(0, "fread()"); | 
 |     return(ret); | 
 | } | 
 |  | 
 | #ifdef LIBXML_OUTPUT_ENABLED | 
 | /** | 
 |  * xmlFileWrite: | 
 |  * @context:  the I/O context | 
 |  * @buffer:  where to drop data | 
 |  * @len:  number of bytes to write | 
 |  * | 
 |  * Write @len bytes from @buffer to the I/O channel. | 
 |  * | 
 |  * Returns the number of bytes written | 
 |  */ | 
 | static int | 
 | xmlFileWrite (void * context, const char * buffer, int len) { | 
 |     int items; | 
 |  | 
 |     if ((context == NULL) || (buffer == NULL)) | 
 |         return(-1); | 
 |     items = fwrite(&buffer[0], len, 1, (FILE *) context); | 
 |     if ((items == 0) && (ferror((FILE *) context))) { | 
 |         xmlIOErr(0, "fwrite()"); | 
 | 	return(-1); | 
 |     } | 
 |     return(items * len); | 
 | } | 
 | #endif /* LIBXML_OUTPUT_ENABLED */ | 
 |  | 
 | /** | 
 |  * xmlFileClose: | 
 |  * @context:  the I/O context | 
 |  * | 
 |  * Close an I/O channel | 
 |  * | 
 |  * Returns 0 or -1 in case of error | 
 |  */ | 
 | int | 
 | xmlFileClose (void * context) { | 
 |     FILE *fil; | 
 |     int ret; | 
 |  | 
 |     if (context == NULL) | 
 |         return(-1); | 
 |     fil = (FILE *) context; | 
 |     if ((fil == stdout) || (fil == stderr)) { | 
 |         ret = fflush(fil); | 
 | 	if (ret < 0) | 
 | 	    xmlIOErr(0, "fflush()"); | 
 | 	return(0); | 
 |     } | 
 |     if (fil == stdin) | 
 | 	return(0); | 
 |     ret = ( fclose((FILE *) context) == EOF ) ? -1 : 0; | 
 |     if (ret < 0) | 
 |         xmlIOErr(0, "fclose()"); | 
 |     return(ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlFileFlush: | 
 |  * @context:  the I/O context | 
 |  * | 
 |  * Flush an I/O channel | 
 |  */ | 
 | static int | 
 | xmlFileFlush (void * context) { | 
 |     int ret; | 
 |  | 
 |     if (context == NULL) | 
 |         return(-1); | 
 |     ret = ( fflush((FILE *) context) == EOF ) ? -1 : 0; | 
 |     if (ret < 0) | 
 |         xmlIOErr(0, "fflush()"); | 
 |     return(ret); | 
 | } | 
 |  | 
 | #ifdef LIBXML_OUTPUT_ENABLED | 
 | /** | 
 |  * xmlBufferWrite: | 
 |  * @context:  the xmlBuffer | 
 |  * @buffer:  the data to write | 
 |  * @len:  number of bytes to write | 
 |  * | 
 |  * Write @len bytes from @buffer to the xml buffer | 
 |  * | 
 |  * Returns the number of bytes written | 
 |  */ | 
 | static int | 
 | xmlBufferWrite (void * context, const char * buffer, int len) { | 
 |     int ret; | 
 |  | 
 |     ret = xmlBufferAdd((xmlBufferPtr) context, (const xmlChar *) buffer, len); | 
 |     if (ret != 0) | 
 |         return(-1); | 
 |     return(len); | 
 | } | 
 | #endif | 
 |  | 
 | #ifdef HAVE_ZLIB_H | 
 | /************************************************************************ | 
 |  *									* | 
 |  *		I/O for compressed file accesses			* | 
 |  *									* | 
 |  ************************************************************************/ | 
 | /** | 
 |  * xmlGzfileMatch: | 
 |  * @filename:  the URI for matching | 
 |  * | 
 |  * input from compressed file test | 
 |  * | 
 |  * Returns 1 if matches, 0 otherwise | 
 |  */ | 
 | static int | 
 | xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) { | 
 |     return(1); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlGzfileOpen_real: | 
 |  * @filename:  the URI for matching | 
 |  * | 
 |  * input from compressed file open | 
 |  * if @filename is " " then the standard input is used | 
 |  * | 
 |  * Returns an I/O context or NULL in case of error | 
 |  */ | 
 | static void * | 
 | xmlGzfileOpen_real (const char *filename) { | 
 |     const char *path = NULL; | 
 |     gzFile fd; | 
 |  | 
 |     if (!strcmp(filename, "-")) { | 
 |         fd = gzdopen(dup(0), "rb"); | 
 | 	return((void *) fd); | 
 |     } | 
 |  | 
 |     if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) | 
 | #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__) | 
 | 	path = &filename[17]; | 
 | #else | 
 | 	path = &filename[16]; | 
 | #endif | 
 |     else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) { | 
 | #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__) | 
 | 	path = &filename[8]; | 
 | #else | 
 | 	path = &filename[7]; | 
 | #endif | 
 |     } else | 
 | 	path = filename; | 
 |  | 
 |     if (path == NULL) | 
 | 	return(NULL); | 
 |     if (!xmlCheckFilename(path)) | 
 |         return(NULL); | 
 |  | 
 | #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__) | 
 |     fd = xmlWrapGzOpen(path, "rb"); | 
 | #else | 
 |     fd = gzopen(path, "rb"); | 
 | #endif | 
 |     return((void *) fd); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlGzfileOpen: | 
 |  * @filename:  the URI for matching | 
 |  * | 
 |  * Wrapper around xmlGzfileOpen if the open fais, it will | 
 |  * try to unescape @filename | 
 |  */ | 
 | static void * | 
 | xmlGzfileOpen (const char *filename) { | 
 |     char *unescaped; | 
 |     void *retval; | 
 |  | 
 |     retval = xmlGzfileOpen_real(filename); | 
 |     if (retval == NULL) { | 
 | 	unescaped = xmlURIUnescapeString(filename, 0, NULL); | 
 | 	if (unescaped != NULL) { | 
 | 	    retval = xmlGzfileOpen_real(unescaped); | 
 | 	} | 
 | 	xmlFree(unescaped); | 
 |     } | 
 |     return retval; | 
 | } | 
 |  | 
 | #ifdef LIBXML_OUTPUT_ENABLED | 
 | /** | 
 |  * xmlGzfileOpenW: | 
 |  * @filename:  the URI for matching | 
 |  * @compression:  the compression factor (0 - 9 included) | 
 |  * | 
 |  * input from compressed file open | 
 |  * if @filename is " " then the standard input is used | 
 |  * | 
 |  * Returns an I/O context or NULL in case of error | 
 |  */ | 
 | static void * | 
 | xmlGzfileOpenW (const char *filename, int compression) { | 
 |     const char *path = NULL; | 
 |     char mode[15]; | 
 |     gzFile fd; | 
 |  | 
 |     snprintf(mode, sizeof(mode), "wb%d", compression); | 
 |     if (!strcmp(filename, "-")) { | 
 |         fd = gzdopen(dup(1), mode); | 
 | 	return((void *) fd); | 
 |     } | 
 |  | 
 |     if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) | 
 | #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__) | 
 | 	path = &filename[17]; | 
 | #else | 
 | 	path = &filename[16]; | 
 | #endif | 
 |     else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) { | 
 | #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__) | 
 | 	path = &filename[8]; | 
 | #else | 
 | 	path = &filename[7]; | 
 | #endif | 
 |     } else | 
 | 	path = filename; | 
 |  | 
 |     if (path == NULL) | 
 | 	return(NULL); | 
 |  | 
 | #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__) | 
 |     fd = xmlWrapGzOpen(path, mode); | 
 | #else | 
 |     fd = gzopen(path, mode); | 
 | #endif | 
 |     return((void *) fd); | 
 | } | 
 | #endif /* LIBXML_OUTPUT_ENABLED */ | 
 |  | 
 | /** | 
 |  * xmlGzfileRead: | 
 |  * @context:  the I/O context | 
 |  * @buffer:  where to drop data | 
 |  * @len:  number of bytes to write | 
 |  * | 
 |  * Read @len bytes to @buffer from the compressed I/O channel. | 
 |  * | 
 |  * Returns the number of bytes written | 
 |  */ | 
 | static int | 
 | xmlGzfileRead (void * context, char * buffer, int len) { | 
 |     int ret; | 
 |  | 
 |     ret = gzread((gzFile) context, &buffer[0], len); | 
 |     if (ret < 0) xmlIOErr(0, "gzread()"); | 
 |     return(ret); | 
 | } | 
 |  | 
 | #ifdef LIBXML_OUTPUT_ENABLED | 
 | /** | 
 |  * xmlGzfileWrite: | 
 |  * @context:  the I/O context | 
 |  * @buffer:  where to drop data | 
 |  * @len:  number of bytes to write | 
 |  * | 
 |  * Write @len bytes from @buffer to the compressed I/O channel. | 
 |  * | 
 |  * Returns the number of bytes written | 
 |  */ | 
 | static int | 
 | xmlGzfileWrite (void * context, const char * buffer, int len) { | 
 |     int ret; | 
 |  | 
 |     ret = gzwrite((gzFile) context, (char *) &buffer[0], len); | 
 |     if (ret < 0) xmlIOErr(0, "gzwrite()"); | 
 |     return(ret); | 
 | } | 
 | #endif /* LIBXML_OUTPUT_ENABLED */ | 
 |  | 
 | /** | 
 |  * xmlGzfileClose: | 
 |  * @context:  the I/O context | 
 |  * | 
 |  * Close a compressed I/O channel | 
 |  */ | 
 | static int | 
 | xmlGzfileClose (void * context) { | 
 |     int ret; | 
 |  | 
 |     ret =  (gzclose((gzFile) context) == Z_OK ) ? 0 : -1; | 
 |     if (ret < 0) xmlIOErr(0, "gzclose()"); | 
 |     return(ret); | 
 | } | 
 | #endif /* HAVE_ZLIB_H */ | 
 |  | 
 | #ifdef LIBXML_HTTP_ENABLED | 
 | /************************************************************************ | 
 |  *									* | 
 |  *			I/O for HTTP file accesses			* | 
 |  *									* | 
 |  ************************************************************************/ | 
 |  | 
 | #ifdef LIBXML_OUTPUT_ENABLED | 
 | typedef struct xmlIOHTTPWriteCtxt_ | 
 | { | 
 |     int			compression; | 
 |  | 
 |     char *		uri; | 
 |  | 
 |     void *		doc_buff; | 
 |  | 
 | } xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr; | 
 |  | 
 | #ifdef HAVE_ZLIB_H | 
 |  | 
 | #define DFLT_WBITS		( -15 ) | 
 | #define DFLT_MEM_LVL		( 8 ) | 
 | #define GZ_MAGIC1		( 0x1f ) | 
 | #define GZ_MAGIC2		( 0x8b ) | 
 | #define LXML_ZLIB_OS_CODE	( 0x03 ) | 
 | #define INIT_HTTP_BUFF_SIZE	( 32768 ) | 
 | #define DFLT_ZLIB_RATIO		( 5 ) | 
 |  | 
 | /* | 
 | **  Data structure and functions to work with sending compressed data | 
 | **  via HTTP. | 
 | */ | 
 |  | 
 | typedef struct xmlZMemBuff_ | 
 | { | 
 |    unsigned long	size; | 
 |    unsigned long	crc; | 
 |  | 
 |    unsigned char *	zbuff; | 
 |    z_stream		zctrl; | 
 |  | 
 | } xmlZMemBuff, *xmlZMemBuffPtr; | 
 |  | 
 | /** | 
 |  * append_reverse_ulong | 
 |  * @buff:  Compressed memory buffer | 
 |  * @data:  Unsigned long to append | 
 |  * | 
 |  * Append a unsigned long in reverse byte order to the end of the | 
 |  * memory buffer. | 
 |  */ | 
 | static void | 
 | append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) { | 
 |  | 
 |     int		idx; | 
 |  | 
 |     if ( buff == NULL ) | 
 | 	return; | 
 |  | 
 |     /* | 
 |     **  This is plagiarized from putLong in gzio.c (zlib source) where | 
 |     **  the number "4" is hardcoded.  If zlib is ever patched to | 
 |     **  support 64 bit file sizes, this code would need to be patched | 
 |     **  as well. | 
 |     */ | 
 |  | 
 |     for ( idx = 0; idx < 4; idx++ ) { | 
 | 	*buff->zctrl.next_out = ( data & 0xff ); | 
 | 	data >>= 8; | 
 | 	buff->zctrl.next_out++; | 
 |     } | 
 |  | 
 |     return; | 
 | } | 
 |  | 
 | /** | 
 |  * | 
 |  * xmlFreeZMemBuff | 
 |  * @buff:  The memory buffer context to clear | 
 |  * | 
 |  * Release all the resources associated with the compressed memory buffer. | 
 |  */ | 
 | static void | 
 | xmlFreeZMemBuff( xmlZMemBuffPtr buff ) { | 
 |  | 
 | #ifdef DEBUG_HTTP | 
 |     int z_err; | 
 | #endif | 
 |  | 
 |     if ( buff == NULL ) | 
 | 	return; | 
 |  | 
 |     xmlFree( buff->zbuff ); | 
 | #ifdef DEBUG_HTTP | 
 |     z_err = deflateEnd( &buff->zctrl ); | 
 |     if ( z_err != Z_OK ) | 
 | 	xmlGenericError( xmlGenericErrorContext, | 
 | 			"xmlFreeZMemBuff:  Error releasing zlib context:  %d\n", | 
 | 			z_err ); | 
 | #else | 
 |     deflateEnd( &buff->zctrl ); | 
 | #endif | 
 |  | 
 |     xmlFree( buff ); | 
 |     return; | 
 | } | 
 |  | 
 | /** | 
 |  * xmlCreateZMemBuff | 
 |  *@compression:	Compression value to use | 
 |  * | 
 |  * Create a memory buffer to hold the compressed XML document.  The | 
 |  * compressed document in memory will end up being identical to what | 
 |  * would be created if gzopen/gzwrite/gzclose were being used to | 
 |  * write the document to disk.  The code for the header/trailer data to | 
 |  * the compression is plagiarized from the zlib source files. | 
 |  */ | 
 | static void * | 
 | xmlCreateZMemBuff( int compression ) { | 
 |  | 
 |     int			z_err; | 
 |     int			hdr_lgth; | 
 |     xmlZMemBuffPtr	buff = NULL; | 
 |  | 
 |     if ( ( compression < 1 ) || ( compression > 9 ) ) | 
 | 	return ( NULL ); | 
 |  | 
 |     /*  Create the control and data areas  */ | 
 |  | 
 |     buff = xmlMalloc( sizeof( xmlZMemBuff ) ); | 
 |     if ( buff == NULL ) { | 
 | 	xmlIOErrMemory("creating buffer context"); | 
 | 	return ( NULL ); | 
 |     } | 
 |  | 
 |     (void)memset( buff, 0, sizeof( xmlZMemBuff ) ); | 
 |     buff->size = INIT_HTTP_BUFF_SIZE; | 
 |     buff->zbuff = xmlMalloc( buff->size ); | 
 |     if ( buff->zbuff == NULL ) { | 
 | 	xmlFreeZMemBuff( buff ); | 
 | 	xmlIOErrMemory("creating buffer"); | 
 | 	return ( NULL ); | 
 |     } | 
 |  | 
 |     z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED, | 
 | 			    DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY ); | 
 |     if ( z_err != Z_OK ) { | 
 | 	xmlChar msg[500]; | 
 | 	xmlFreeZMemBuff( buff ); | 
 | 	buff = NULL; | 
 | 	xmlStrPrintf(msg, 500, | 
 | 		    (const xmlChar *) "xmlCreateZMemBuff:  %s %d\n", | 
 | 		    "Error initializing compression context.  ZLIB error:", | 
 | 		    z_err ); | 
 | 	xmlIOErr(XML_IO_WRITE, (const char *) msg); | 
 | 	return ( NULL ); | 
 |     } | 
 |  | 
 |     /*  Set the header data.  The CRC will be needed for the trailer  */ | 
 |     buff->crc = crc32( 0L, NULL, 0 ); | 
 |     hdr_lgth = snprintf( (char *)buff->zbuff, buff->size, | 
 | 			"%c%c%c%c%c%c%c%c%c%c", | 
 | 			GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED, | 
 | 			0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE ); | 
 |     buff->zctrl.next_out  = buff->zbuff + hdr_lgth; | 
 |     buff->zctrl.avail_out = buff->size - hdr_lgth; | 
 |  | 
 |     return ( buff ); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlZMemBuffExtend | 
 |  * @buff:  Buffer used to compress and consolidate data. | 
 |  * @ext_amt:   Number of bytes to extend the buffer. | 
 |  * | 
 |  * Extend the internal buffer used to store the compressed data by the | 
 |  * specified amount. | 
 |  * | 
 |  * Returns 0 on success or -1 on failure to extend the buffer.  On failure | 
 |  * the original buffer still exists at the original size. | 
 |  */ | 
 | static int | 
 | xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) { | 
 |  | 
 |     int			rc = -1; | 
 |     size_t		new_size; | 
 |     size_t		cur_used; | 
 |  | 
 |     unsigned char *	tmp_ptr = NULL; | 
 |  | 
 |     if ( buff == NULL ) | 
 | 	return ( -1 ); | 
 |  | 
 |     else if ( ext_amt == 0 ) | 
 | 	return ( 0 ); | 
 |  | 
 |     cur_used = buff->zctrl.next_out - buff->zbuff; | 
 |     new_size = buff->size + ext_amt; | 
 |  | 
 | #ifdef DEBUG_HTTP | 
 |     if ( cur_used > new_size ) | 
 | 	xmlGenericError( xmlGenericErrorContext, | 
 | 			"xmlZMemBuffExtend:  %s\n%s %d bytes.\n", | 
 | 			"Buffer overwrite detected during compressed memory", | 
 | 			"buffer extension.  Overflowed by", | 
 | 			(cur_used - new_size ) ); | 
 | #endif | 
 |  | 
 |     tmp_ptr = xmlRealloc( buff->zbuff, new_size ); | 
 |     if ( tmp_ptr != NULL ) { | 
 | 	rc = 0; | 
 | 	buff->size  = new_size; | 
 | 	buff->zbuff = tmp_ptr; | 
 | 	buff->zctrl.next_out  = tmp_ptr + cur_used; | 
 | 	buff->zctrl.avail_out = new_size - cur_used; | 
 |     } | 
 |     else { | 
 | 	xmlChar msg[500]; | 
 | 	xmlStrPrintf(msg, 500, | 
 | 		    (const xmlChar *) "xmlZMemBuffExtend:  %s %lu bytes.\n", | 
 | 		    "Allocation failure extending output buffer to", | 
 | 		    new_size ); | 
 | 	xmlIOErr(XML_IO_WRITE, (const char *) msg); | 
 |     } | 
 |  | 
 |     return ( rc ); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlZMemBuffAppend | 
 |  * @buff:  Buffer used to compress and consolidate data | 
 |  * @src:   Uncompressed source content to append to buffer | 
 |  * @len:   Length of source data to append to buffer | 
 |  * | 
 |  * Compress and append data to the internal buffer.  The data buffer | 
 |  * will be expanded if needed to store the additional data. | 
 |  * | 
 |  * Returns the number of bytes appended to the buffer or -1 on error. | 
 |  */ | 
 | static int | 
 | xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) { | 
 |  | 
 |     int		z_err; | 
 |     size_t	min_accept; | 
 |  | 
 |     if ( ( buff == NULL ) || ( src == NULL ) ) | 
 | 	return ( -1 ); | 
 |  | 
 |     buff->zctrl.avail_in = len; | 
 |     buff->zctrl.next_in  = (unsigned char *)src; | 
 |     while ( buff->zctrl.avail_in > 0 ) { | 
 | 	/* | 
 | 	**  Extend the buffer prior to deflate call if a reasonable amount | 
 | 	**  of output buffer space is not available. | 
 | 	*/ | 
 | 	min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO; | 
 | 	if ( buff->zctrl.avail_out <= min_accept ) { | 
 | 	    if ( xmlZMemBuffExtend( buff, buff->size ) == -1 ) | 
 | 		return ( -1 ); | 
 | 	} | 
 |  | 
 | 	z_err = deflate( &buff->zctrl, Z_NO_FLUSH ); | 
 | 	if ( z_err != Z_OK ) { | 
 | 	    xmlChar msg[500]; | 
 | 	    xmlStrPrintf(msg, 500, | 
 | 			(const xmlChar *) "xmlZMemBuffAppend:  %s %d %s - %d", | 
 | 			"Compression error while appending", | 
 | 			len, "bytes to buffer.  ZLIB error", z_err ); | 
 | 	    xmlIOErr(XML_IO_WRITE, (const char *) msg); | 
 | 	    return ( -1 ); | 
 | 	} | 
 |     } | 
 |  | 
 |     buff->crc = crc32( buff->crc, (unsigned char *)src, len ); | 
 |  | 
 |     return ( len ); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlZMemBuffGetContent | 
 |  * @buff:  Compressed memory content buffer | 
 |  * @data_ref:  Pointer reference to point to compressed content | 
 |  * | 
 |  * Flushes the compression buffers, appends gzip file trailers and | 
 |  * returns the compressed content and length of the compressed data. | 
 |  * NOTE:  The gzip trailer code here is plagiarized from zlib source. | 
 |  * | 
 |  * Returns the length of the compressed data or -1 on error. | 
 |  */ | 
 | static int | 
 | xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) { | 
 |  | 
 |     int		zlgth = -1; | 
 |     int		z_err; | 
 |  | 
 |     if ( ( buff == NULL ) || ( data_ref == NULL ) ) | 
 | 	return ( -1 ); | 
 |  | 
 |     /*  Need to loop until compression output buffers are flushed  */ | 
 |  | 
 |     do | 
 |     { | 
 | 	z_err = deflate( &buff->zctrl, Z_FINISH ); | 
 | 	if ( z_err == Z_OK ) { | 
 | 	    /*  In this case Z_OK means more buffer space needed  */ | 
 |  | 
 | 	    if ( xmlZMemBuffExtend( buff, buff->size ) == -1 ) | 
 | 		return ( -1 ); | 
 | 	} | 
 |     } | 
 |     while ( z_err == Z_OK ); | 
 |  | 
 |     /*  If the compression state is not Z_STREAM_END, some error occurred  */ | 
 |  | 
 |     if ( z_err == Z_STREAM_END ) { | 
 |  | 
 | 	/*  Need to append the gzip data trailer  */ | 
 |  | 
 | 	if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) { | 
 | 	    if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 ) | 
 | 		return ( -1 ); | 
 | 	} | 
 |  | 
 | 	/* | 
 | 	**  For whatever reason, the CRC and length data are pushed out | 
 | 	**  in reverse byte order.  So a memcpy can't be used here. | 
 | 	*/ | 
 |  | 
 | 	append_reverse_ulong( buff, buff->crc ); | 
 | 	append_reverse_ulong( buff, buff->zctrl.total_in ); | 
 |  | 
 | 	zlgth = buff->zctrl.next_out - buff->zbuff; | 
 | 	*data_ref = (char *)buff->zbuff; | 
 |     } | 
 |  | 
 |     else { | 
 | 	xmlChar msg[500]; | 
 | 	xmlStrPrintf(msg, 500, | 
 | 		    (const xmlChar *) "xmlZMemBuffGetContent:  %s - %d\n", | 
 | 		    "Error flushing zlib buffers.  Error code", z_err ); | 
 | 	xmlIOErr(XML_IO_WRITE, (const char *) msg); | 
 |     } | 
 |  | 
 |     return ( zlgth ); | 
 | } | 
 | #endif /* LIBXML_OUTPUT_ENABLED */ | 
 | #endif  /*  HAVE_ZLIB_H  */ | 
 |  | 
 | #ifdef LIBXML_OUTPUT_ENABLED | 
 | /** | 
 |  * xmlFreeHTTPWriteCtxt | 
 |  * @ctxt:  Context to cleanup | 
 |  * | 
 |  * Free allocated memory and reclaim system resources. | 
 |  * | 
 |  * No return value. | 
 |  */ | 
 | static void | 
 | xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt ) | 
 | { | 
 |     if ( ctxt->uri != NULL ) | 
 | 	xmlFree( ctxt->uri ); | 
 |  | 
 |     if ( ctxt->doc_buff != NULL ) { | 
 |  | 
 | #ifdef HAVE_ZLIB_H | 
 | 	if ( ctxt->compression > 0 ) { | 
 | 	    xmlFreeZMemBuff( ctxt->doc_buff ); | 
 | 	} | 
 | 	else | 
 | #endif | 
 | 	{ | 
 | 	    xmlOutputBufferClose( ctxt->doc_buff ); | 
 | 	} | 
 |     } | 
 |  | 
 |     xmlFree( ctxt ); | 
 |     return; | 
 | } | 
 | #endif /* LIBXML_OUTPUT_ENABLED */ | 
 |  | 
 |  | 
 | /** | 
 |  * xmlIOHTTPMatch: | 
 |  * @filename:  the URI for matching | 
 |  * | 
 |  * check if the URI matches an HTTP one | 
 |  * | 
 |  * Returns 1 if matches, 0 otherwise | 
 |  */ | 
 | int | 
 | xmlIOHTTPMatch (const char *filename) { | 
 |     if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "http://", 7)) | 
 | 	return(1); | 
 |     return(0); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlIOHTTPOpen: | 
 |  * @filename:  the URI for matching | 
 |  * | 
 |  * open an HTTP I/O channel | 
 |  * | 
 |  * Returns an I/O context or NULL in case of error | 
 |  */ | 
 | void * | 
 | xmlIOHTTPOpen (const char *filename) { | 
 |     return(xmlNanoHTTPOpen(filename, NULL)); | 
 | } | 
 |  | 
 | #ifdef LIBXML_OUTPUT_ENABLED | 
 | /** | 
 |  * xmlIOHTTPOpenW: | 
 |  * @post_uri:  The destination URI for the document | 
 |  * @compression:  The compression desired for the document. | 
 |  * | 
 |  * Open a temporary buffer to collect the document for a subsequent HTTP POST | 
 |  * request.  Non-static as is called from the output buffer creation routine. | 
 |  * | 
 |  * Returns an I/O context or NULL in case of error. | 
 |  */ | 
 |  | 
 | void * | 
 | xmlIOHTTPOpenW(const char *post_uri, int compression) | 
 | { | 
 |  | 
 |     xmlIOHTTPWriteCtxtPtr ctxt = NULL; | 
 |  | 
 |     if (post_uri == NULL) | 
 |         return (NULL); | 
 |  | 
 |     ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt)); | 
 |     if (ctxt == NULL) { | 
 | 	xmlIOErrMemory("creating HTTP output context"); | 
 |         return (NULL); | 
 |     } | 
 |  | 
 |     (void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt)); | 
 |  | 
 |     ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri); | 
 |     if (ctxt->uri == NULL) { | 
 | 	xmlIOErrMemory("copying URI"); | 
 |         xmlFreeHTTPWriteCtxt(ctxt); | 
 |         return (NULL); | 
 |     } | 
 |  | 
 |     /* | 
 |      * **  Since the document length is required for an HTTP post, | 
 |      * **  need to put the document into a buffer.  A memory buffer | 
 |      * **  is being used to avoid pushing the data to disk and back. | 
 |      */ | 
 |  | 
 | #ifdef HAVE_ZLIB_H | 
 |     if ((compression > 0) && (compression <= 9)) { | 
 |  | 
 |         ctxt->compression = compression; | 
 |         ctxt->doc_buff = xmlCreateZMemBuff(compression); | 
 |     } else | 
 | #endif | 
 |     { | 
 |         /*  Any character conversions should have been done before this  */ | 
 |  | 
 |         ctxt->doc_buff = xmlAllocOutputBufferInternal(NULL); | 
 |     } | 
 |  | 
 |     if (ctxt->doc_buff == NULL) { | 
 |         xmlFreeHTTPWriteCtxt(ctxt); | 
 |         ctxt = NULL; | 
 |     } | 
 |  | 
 |     return (ctxt); | 
 | } | 
 | #endif /* LIBXML_OUTPUT_ENABLED */ | 
 |  | 
 | #ifdef LIBXML_OUTPUT_ENABLED | 
 | /** | 
 |  * xmlIOHTTPDfltOpenW | 
 |  * @post_uri:  The destination URI for this document. | 
 |  * | 
 |  * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent | 
 |  * HTTP post command.  This function should generally not be used as | 
 |  * the open callback is short circuited in xmlOutputBufferCreateFile. | 
 |  * | 
 |  * Returns a pointer to the new IO context. | 
 |  */ | 
 | static void * | 
 | xmlIOHTTPDfltOpenW( const char * post_uri ) { | 
 |     return ( xmlIOHTTPOpenW( post_uri, 0 ) ); | 
 | } | 
 | #endif /* LIBXML_OUTPUT_ENABLED */ | 
 |  | 
 | /** | 
 |  * xmlIOHTTPRead: | 
 |  * @context:  the I/O context | 
 |  * @buffer:  where to drop data | 
 |  * @len:  number of bytes to write | 
 |  * | 
 |  * Read @len bytes to @buffer from the I/O channel. | 
 |  * | 
 |  * Returns the number of bytes written | 
 |  */ | 
 | int | 
 | xmlIOHTTPRead(void * context, char * buffer, int len) { | 
 |     if ((buffer == NULL) || (len < 0)) return(-1); | 
 |     return(xmlNanoHTTPRead(context, &buffer[0], len)); | 
 | } | 
 |  | 
 | #ifdef LIBXML_OUTPUT_ENABLED | 
 | /** | 
 |  * xmlIOHTTPWrite | 
 |  * @context:  previously opened writing context | 
 |  * @buffer:   data to output to temporary buffer | 
 |  * @len:      bytes to output | 
 |  * | 
 |  * Collect data from memory buffer into a temporary file for later | 
 |  * processing. | 
 |  * | 
 |  * Returns number of bytes written. | 
 |  */ | 
 |  | 
 | static int | 
 | xmlIOHTTPWrite( void * context, const char * buffer, int len ) { | 
 |  | 
 |     xmlIOHTTPWriteCtxtPtr	ctxt = context; | 
 |  | 
 |     if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) ) | 
 | 	return ( -1 ); | 
 |  | 
 |     if ( len > 0 ) { | 
 |  | 
 | 	/*  Use gzwrite or fwrite as previously setup in the open call  */ | 
 |  | 
 | #ifdef HAVE_ZLIB_H | 
 | 	if ( ctxt->compression > 0 ) | 
 | 	    len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len ); | 
 |  | 
 | 	else | 
 | #endif | 
 | 	    len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer ); | 
 |  | 
 | 	if ( len < 0 ) { | 
 | 	    xmlChar msg[500]; | 
 | 	    xmlStrPrintf(msg, 500, | 
 | 			(const xmlChar *) "xmlIOHTTPWrite:  %s\n%s '%s'.\n", | 
 | 			"Error appending to internal buffer.", | 
 | 			"Error sending document to URI", | 
 | 			ctxt->uri ); | 
 | 	    xmlIOErr(XML_IO_WRITE, (const char *) msg); | 
 | 	} | 
 |     } | 
 |  | 
 |     return ( len ); | 
 | } | 
 | #endif /* LIBXML_OUTPUT_ENABLED */ | 
 |  | 
 |  | 
 | /** | 
 |  * xmlIOHTTPClose: | 
 |  * @context:  the I/O context | 
 |  * | 
 |  * Close an HTTP I/O channel | 
 |  * | 
 |  * Returns 0 | 
 |  */ | 
 | int | 
 | xmlIOHTTPClose (void * context) { | 
 |     xmlNanoHTTPClose(context); | 
 |     return 0; | 
 | } | 
 |  | 
 | #ifdef LIBXML_OUTPUT_ENABLED | 
 | /** | 
 |  * xmlIOHTTCloseWrite | 
 |  * @context:  The I/O context | 
 |  * @http_mthd: The HTTP method to be used when sending the data | 
 |  * | 
 |  * Close the transmit HTTP I/O channel and actually send the data. | 
 |  */ | 
 | static int | 
 | xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) { | 
 |  | 
 |     int				close_rc = -1; | 
 |     int				http_rtn = 0; | 
 |     int				content_lgth = 0; | 
 |     xmlIOHTTPWriteCtxtPtr	ctxt = context; | 
 |  | 
 |     char *			http_content = NULL; | 
 |     char *			content_encoding = NULL; | 
 |     char *			content_type = (char *) "text/xml"; | 
 |     void *			http_ctxt = NULL; | 
 |  | 
 |     if ( ( ctxt == NULL ) || ( http_mthd == NULL ) ) | 
 | 	return ( -1 ); | 
 |  | 
 |     /*  Retrieve the content from the appropriate buffer  */ | 
 |  | 
 | #ifdef HAVE_ZLIB_H | 
 |  | 
 |     if ( ctxt->compression > 0 ) { | 
 | 	content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content ); | 
 | 	content_encoding = (char *) "Content-Encoding: gzip"; | 
 |     } | 
 |     else | 
 | #endif | 
 |     { | 
 | 	/*  Pull the data out of the memory output buffer  */ | 
 |  | 
 | 	xmlOutputBufferPtr	dctxt = ctxt->doc_buff; | 
 | 	http_content = (char *)dctxt->buffer->content; | 
 | 	content_lgth = dctxt->buffer->use; | 
 |     } | 
 |  | 
 |     if ( http_content == NULL ) { | 
 | 	xmlChar msg[500]; | 
 | 	xmlStrPrintf(msg, 500, | 
 | 		     (const xmlChar *) "xmlIOHTTPCloseWrite:  %s '%s' %s '%s'.\n", | 
 | 		     "Error retrieving content.\nUnable to", | 
 | 		     http_mthd, "data to URI", ctxt->uri ); | 
 | 	xmlIOErr(XML_IO_WRITE, (const char *) msg); | 
 |     } | 
 |  | 
 |     else { | 
 |  | 
 | 	http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content, | 
 | 					&content_type, content_encoding, | 
 | 					content_lgth ); | 
 |  | 
 | 	if ( http_ctxt != NULL ) { | 
 | #ifdef DEBUG_HTTP | 
 | 	    /*  If testing/debugging - dump reply with request content  */ | 
 |  | 
 | 	    FILE *	tst_file = NULL; | 
 | 	    char	buffer[ 4096 ]; | 
 | 	    char *	dump_name = NULL; | 
 | 	    int		avail; | 
 |  | 
 | 	    xmlGenericError( xmlGenericErrorContext, | 
 | 			"xmlNanoHTTPCloseWrite:  HTTP %s to\n%s returned %d.\n", | 
 | 			http_mthd, ctxt->uri, | 
 | 			xmlNanoHTTPReturnCode( http_ctxt ) ); | 
 |  | 
 | 	    /* | 
 | 	    **  Since either content or reply may be gzipped, | 
 | 	    **  dump them to separate files instead of the | 
 | 	    **  standard error context. | 
 | 	    */ | 
 |  | 
 | 	    dump_name = tempnam( NULL, "lxml" ); | 
 | 	    if ( dump_name != NULL ) { | 
 | 		(void)snprintf( buffer, sizeof(buffer), "%s.content", dump_name ); | 
 |  | 
 | 		tst_file = fopen( buffer, "wb" ); | 
 | 		if ( tst_file != NULL ) { | 
 | 		    xmlGenericError( xmlGenericErrorContext, | 
 | 			"Transmitted content saved in file:  %s\n", buffer ); | 
 |  | 
 | 		    fwrite( http_content, sizeof( char ), | 
 | 					content_lgth, tst_file ); | 
 | 		    fclose( tst_file ); | 
 | 		} | 
 |  | 
 | 		(void)snprintf( buffer, sizeof(buffer), "%s.reply", dump_name ); | 
 | 		tst_file = fopen( buffer, "wb" ); | 
 | 		if ( tst_file != NULL ) { | 
 | 		    xmlGenericError( xmlGenericErrorContext, | 
 | 			"Reply content saved in file:  %s\n", buffer ); | 
 |  | 
 |  | 
 | 		    while ( (avail = xmlNanoHTTPRead( http_ctxt, | 
 | 					buffer, sizeof( buffer ) )) > 0 ) { | 
 |  | 
 | 			fwrite( buffer, sizeof( char ), avail, tst_file ); | 
 | 		    } | 
 |  | 
 | 		    fclose( tst_file ); | 
 | 		} | 
 |  | 
 | 		free( dump_name ); | 
 | 	    } | 
 | #endif  /*  DEBUG_HTTP  */ | 
 |  | 
 | 	    http_rtn = xmlNanoHTTPReturnCode( http_ctxt ); | 
 | 	    if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) ) | 
 | 		close_rc = 0; | 
 | 	    else { | 
 |                 xmlChar msg[500]; | 
 |                 xmlStrPrintf(msg, 500, | 
 |     (const xmlChar *) "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n", | 
 | 			    http_mthd, content_lgth, | 
 | 			    "bytes to URI", ctxt->uri, | 
 | 			    "failed.  HTTP return code:", http_rtn ); | 
 | 		xmlIOErr(XML_IO_WRITE, (const char *) msg); | 
 |             } | 
 |  | 
 | 	    xmlNanoHTTPClose( http_ctxt ); | 
 | 	    xmlFree( content_type ); | 
 | 	} | 
 |     } | 
 |  | 
 |     /*  Final cleanups  */ | 
 |  | 
 |     xmlFreeHTTPWriteCtxt( ctxt ); | 
 |  | 
 |     return ( close_rc ); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlIOHTTPClosePut | 
 |  * | 
 |  * @context:  The I/O context | 
 |  * | 
 |  * Close the transmit HTTP I/O channel and actually send data using a PUT | 
 |  * HTTP method. | 
 |  */ | 
 | static int | 
 | xmlIOHTTPClosePut( void * ctxt ) { | 
 |     return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) ); | 
 | } | 
 |  | 
 |  | 
 | /** | 
 |  * xmlIOHTTPClosePost | 
 |  * | 
 |  * @context:  The I/O context | 
 |  * | 
 |  * Close the transmit HTTP I/O channel and actually send data using a POST | 
 |  * HTTP method. | 
 |  */ | 
 | static int | 
 | xmlIOHTTPClosePost( void * ctxt ) { | 
 |     return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) ); | 
 | } | 
 | #endif /* LIBXML_OUTPUT_ENABLED */ | 
 |  | 
 | #endif /* LIBXML_HTTP_ENABLED */ | 
 |  | 
 | #ifdef LIBXML_FTP_ENABLED | 
 | /************************************************************************ | 
 |  *									* | 
 |  *			I/O for FTP file accesses			* | 
 |  *									* | 
 |  ************************************************************************/ | 
 | /** | 
 |  * xmlIOFTPMatch: | 
 |  * @filename:  the URI for matching | 
 |  * | 
 |  * check if the URI matches an FTP one | 
 |  * | 
 |  * Returns 1 if matches, 0 otherwise | 
 |  */ | 
 | int | 
 | xmlIOFTPMatch (const char *filename) { | 
 |     if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "ftp://", 6)) | 
 | 	return(1); | 
 |     return(0); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlIOFTPOpen: | 
 |  * @filename:  the URI for matching | 
 |  * | 
 |  * open an FTP I/O channel | 
 |  * | 
 |  * Returns an I/O context or NULL in case of error | 
 |  */ | 
 | void * | 
 | xmlIOFTPOpen (const char *filename) { | 
 |     return(xmlNanoFTPOpen(filename)); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlIOFTPRead: | 
 |  * @context:  the I/O context | 
 |  * @buffer:  where to drop data | 
 |  * @len:  number of bytes to write | 
 |  * | 
 |  * Read @len bytes to @buffer from the I/O channel. | 
 |  * | 
 |  * Returns the number of bytes written | 
 |  */ | 
 | int | 
 | xmlIOFTPRead(void * context, char * buffer, int len) { | 
 |     if ((buffer == NULL) || (len < 0)) return(-1); | 
 |     return(xmlNanoFTPRead(context, &buffer[0], len)); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlIOFTPClose: | 
 |  * @context:  the I/O context | 
 |  * | 
 |  * Close an FTP I/O channel | 
 |  * | 
 |  * Returns 0 | 
 |  */ | 
 | int | 
 | xmlIOFTPClose (void * context) { | 
 |     return ( xmlNanoFTPClose(context) ); | 
 | } | 
 | #endif /* LIBXML_FTP_ENABLED */ | 
 |  | 
 |  | 
 | /** | 
 |  * xmlRegisterInputCallbacks: | 
 |  * @matchFunc:  the xmlInputMatchCallback | 
 |  * @openFunc:  the xmlInputOpenCallback | 
 |  * @readFunc:  the xmlInputReadCallback | 
 |  * @closeFunc:  the xmlInputCloseCallback | 
 |  * | 
 |  * Register a new set of I/O callback for handling parser input. | 
 |  * | 
 |  * Returns the registered handler number or -1 in case of error | 
 |  */ | 
 | int | 
 | xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc, | 
 | 	xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc, | 
 | 	xmlInputCloseCallback closeFunc) { | 
 |     if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) { | 
 | 	return(-1); | 
 |     } | 
 |     xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc; | 
 |     xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc; | 
 |     xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc; | 
 |     xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc; | 
 |     xmlInputCallbackInitialized = 1; | 
 |     return(xmlInputCallbackNr++); | 
 | } | 
 |  | 
 | #ifdef LIBXML_OUTPUT_ENABLED | 
 | /** | 
 |  * xmlRegisterOutputCallbacks: | 
 |  * @matchFunc:  the xmlOutputMatchCallback | 
 |  * @openFunc:  the xmlOutputOpenCallback | 
 |  * @writeFunc:  the xmlOutputWriteCallback | 
 |  * @closeFunc:  the xmlOutputCloseCallback | 
 |  * | 
 |  * Register a new set of I/O callback for handling output. | 
 |  * | 
 |  * Returns the registered handler number or -1 in case of error | 
 |  */ | 
 | int | 
 | xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc, | 
 | 	xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc, | 
 | 	xmlOutputCloseCallback closeFunc) { | 
 |     if (xmlOutputCallbackNr >= MAX_OUTPUT_CALLBACK) { | 
 | 	return(-1); | 
 |     } | 
 |     xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc; | 
 |     xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc; | 
 |     xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc; | 
 |     xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc; | 
 |     xmlOutputCallbackInitialized = 1; | 
 |     return(xmlOutputCallbackNr++); | 
 | } | 
 | #endif /* LIBXML_OUTPUT_ENABLED */ | 
 |  | 
 | /** | 
 |  * xmlRegisterDefaultInputCallbacks: | 
 |  * | 
 |  * Registers the default compiled-in I/O handlers. | 
 |  */ | 
 | void | 
 | xmlRegisterDefaultInputCallbacks(void) { | 
 |     if (xmlInputCallbackInitialized) | 
 | 	return; | 
 |  | 
 | #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__) | 
 |     xmlInitPlatformSpecificIo(); | 
 | #endif | 
 |  | 
 |     xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen, | 
 | 	                      xmlFileRead, xmlFileClose); | 
 | #ifdef HAVE_ZLIB_H | 
 |     xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen, | 
 | 	                      xmlGzfileRead, xmlGzfileClose); | 
 | #endif /* HAVE_ZLIB_H */ | 
 |  | 
 | #ifdef LIBXML_HTTP_ENABLED | 
 |     xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen, | 
 | 	                      xmlIOHTTPRead, xmlIOHTTPClose); | 
 | #endif /* LIBXML_HTTP_ENABLED */ | 
 |  | 
 | #ifdef LIBXML_FTP_ENABLED | 
 |     xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen, | 
 | 	                      xmlIOFTPRead, xmlIOFTPClose); | 
 | #endif /* LIBXML_FTP_ENABLED */ | 
 |     xmlInputCallbackInitialized = 1; | 
 | } | 
 |  | 
 | #ifdef LIBXML_OUTPUT_ENABLED | 
 | /** | 
 |  * xmlRegisterDefaultOutputCallbacks: | 
 |  * | 
 |  * Registers the default compiled-in I/O handlers. | 
 |  */ | 
 | void | 
 | xmlRegisterDefaultOutputCallbacks (void) { | 
 |     if (xmlOutputCallbackInitialized) | 
 | 	return; | 
 |  | 
 | #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__) | 
 |     xmlInitPlatformSpecificIo(); | 
 | #endif | 
 |  | 
 |     xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW, | 
 | 	                      xmlFileWrite, xmlFileClose); | 
 |  | 
 | #ifdef LIBXML_HTTP_ENABLED | 
 |     xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW, | 
 | 	                       xmlIOHTTPWrite, xmlIOHTTPClosePut); | 
 | #endif | 
 |  | 
 | /********************************* | 
 |  No way a-priori to distinguish between gzipped files from | 
 |  uncompressed ones except opening if existing then closing | 
 |  and saving with same compression ratio ... a pain. | 
 |  | 
 | #ifdef HAVE_ZLIB_H | 
 |     xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen, | 
 | 	                       xmlGzfileWrite, xmlGzfileClose); | 
 | #endif | 
 |  | 
 |  Nor FTP PUT .... | 
 | #ifdef LIBXML_FTP_ENABLED | 
 |     xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen, | 
 | 	                       xmlIOFTPWrite, xmlIOFTPClose); | 
 | #endif | 
 |  **********************************/ | 
 |     xmlOutputCallbackInitialized = 1; | 
 | } | 
 |  | 
 | #ifdef LIBXML_HTTP_ENABLED | 
 | /** | 
 |  * xmlRegisterHTTPPostCallbacks: | 
 |  * | 
 |  * By default, libxml submits HTTP output requests using the "PUT" method. | 
 |  * Calling this method changes the HTTP output method to use the "POST" | 
 |  * method instead. | 
 |  * | 
 |  */ | 
 | void | 
 | xmlRegisterHTTPPostCallbacks( void ) { | 
 |  | 
 |     /*  Register defaults if not done previously  */ | 
 |  | 
 |     if ( xmlOutputCallbackInitialized == 0 ) | 
 | 	xmlRegisterDefaultOutputCallbacks( ); | 
 |  | 
 |     xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW, | 
 | 	                       xmlIOHTTPWrite, xmlIOHTTPClosePost); | 
 |     return; | 
 | } | 
 | #endif | 
 | #endif /* LIBXML_OUTPUT_ENABLED */ | 
 |  | 
 | /** | 
 |  * xmlAllocParserInputBuffer: | 
 |  * @enc:  the charset encoding if known | 
 |  * | 
 |  * Create a buffered parser input for progressive parsing | 
 |  * | 
 |  * Returns the new parser input or NULL | 
 |  */ | 
 | xmlParserInputBufferPtr | 
 | xmlAllocParserInputBuffer(xmlCharEncoding enc) { | 
 |     xmlParserInputBufferPtr ret; | 
 |  | 
 |     ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer)); | 
 |     if (ret == NULL) { | 
 | 	xmlIOErrMemory("creating input buffer"); | 
 | 	return(NULL); | 
 |     } | 
 |     memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer)); | 
 |     ret->buffer = xmlBufferCreateSize(2 * xmlDefaultBufferSize); | 
 |     if (ret->buffer == NULL) { | 
 |         xmlFree(ret); | 
 | 	return(NULL); | 
 |     } | 
 |     ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT; | 
 |     ret->encoder = xmlGetCharEncodingHandler(enc); | 
 |     if (ret->encoder != NULL) | 
 |         ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize); | 
 |     else | 
 |         ret->raw = NULL; | 
 |     ret->readcallback = NULL; | 
 |     ret->closecallback = NULL; | 
 |     ret->context = NULL; | 
 |     ret->compressed = -1; | 
 |     ret->rawconsumed = 0; | 
 |  | 
 |     return(ret); | 
 | } | 
 |  | 
 | #ifdef LIBXML_OUTPUT_ENABLED | 
 | /** | 
 |  * xmlAllocOutputBuffer: | 
 |  * @encoder:  the encoding converter or NULL | 
 |  * | 
 |  * Create a buffered parser output | 
 |  * | 
 |  * Returns the new parser output or NULL | 
 |  */ | 
 | xmlOutputBufferPtr | 
 | xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) { | 
 |     xmlOutputBufferPtr ret; | 
 |  | 
 |     ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer)); | 
 |     if (ret == NULL) { | 
 | 	xmlIOErrMemory("creating output buffer"); | 
 | 	return(NULL); | 
 |     } | 
 |     memset(ret, 0, (size_t) sizeof(xmlOutputBuffer)); | 
 |     ret->buffer = xmlBufferCreate(); | 
 |     if (ret->buffer == NULL) { | 
 |         xmlFree(ret); | 
 | 	return(NULL); | 
 |     } | 
 |  | 
 |     /* try to avoid a performance problem with Windows realloc() */ | 
 |     if (ret->buffer->alloc == XML_BUFFER_ALLOC_EXACT) | 
 |         ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT; | 
 |  | 
 |     ret->encoder = encoder; | 
 |     if (encoder != NULL) { | 
 |         ret->conv = xmlBufferCreateSize(4000); | 
 | 	if (ret->conv == NULL) { | 
 | 	    xmlFree(ret); | 
 | 	    return(NULL); | 
 | 	} | 
 |  | 
 | 	/* | 
 | 	 * This call is designed to initiate the encoder state | 
 | 	 */ | 
 | 	xmlCharEncOutFunc(encoder, ret->conv, NULL); | 
 |     } else | 
 |         ret->conv = NULL; | 
 |     ret->writecallback = NULL; | 
 |     ret->closecallback = NULL; | 
 |     ret->context = NULL; | 
 |     ret->written = 0; | 
 |  | 
 |     return(ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlAllocOutputBufferInternal: | 
 |  * @encoder:  the encoding converter or NULL | 
 |  * | 
 |  * Create a buffered parser output | 
 |  * | 
 |  * Returns the new parser output or NULL | 
 |  */ | 
 | xmlOutputBufferPtr | 
 | xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder) { | 
 |     xmlOutputBufferPtr ret; | 
 |  | 
 |     ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer)); | 
 |     if (ret == NULL) { | 
 | 	xmlIOErrMemory("creating output buffer"); | 
 | 	return(NULL); | 
 |     } | 
 |     memset(ret, 0, (size_t) sizeof(xmlOutputBuffer)); | 
 |     ret->buffer = xmlBufferCreate(); | 
 |     if (ret->buffer == NULL) { | 
 |         xmlFree(ret); | 
 | 	return(NULL); | 
 |     } | 
 |  | 
 |  | 
 |     /* | 
 |      * For conversion buffers we use the special IO handling | 
 |      * We don't do that from the exported API to avoid confusing | 
 |      * user's code. | 
 |      */ | 
 |     ret->buffer->alloc = XML_BUFFER_ALLOC_IO; | 
 |     ret->buffer->contentIO = ret->buffer->content; | 
 |  | 
 |     ret->encoder = encoder; | 
 |     if (encoder != NULL) { | 
 |         ret->conv = xmlBufferCreateSize(4000); | 
 | 	if (ret->conv == NULL) { | 
 | 	    xmlFree(ret); | 
 | 	    return(NULL); | 
 | 	} | 
 |  | 
 | 	/* | 
 | 	 * This call is designed to initiate the encoder state | 
 | 	 */ | 
 | 	xmlCharEncOutFunc(encoder, ret->conv, NULL); | 
 |     } else | 
 |         ret->conv = NULL; | 
 |     ret->writecallback = NULL; | 
 |     ret->closecallback = NULL; | 
 |     ret->context = NULL; | 
 |     ret->written = 0; | 
 |  | 
 |     return(ret); | 
 | } | 
 |  | 
 | #endif /* LIBXML_OUTPUT_ENABLED */ | 
 |  | 
 | /** | 
 |  * xmlFreeParserInputBuffer: | 
 |  * @in:  a buffered parser input | 
 |  * | 
 |  * Free up the memory used by a buffered parser input | 
 |  */ | 
 | void | 
 | xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) { | 
 |     if (in == NULL) return; | 
 |  | 
 |     if (in->raw) { | 
 |         xmlBufferFree(in->raw); | 
 | 	in->raw = NULL; | 
 |     } | 
 |     if (in->encoder != NULL) { | 
 |         xmlCharEncCloseFunc(in->encoder); | 
 |     } | 
 |     if (in->closecallback != NULL) { | 
 | 	in->closecallback(in->context); | 
 |     } | 
 |     if (in->buffer != NULL) { | 
 |         xmlBufferFree(in->buffer); | 
 | 	in->buffer = NULL; | 
 |     } | 
 |  | 
 |     xmlFree(in); | 
 | } | 
 |  | 
 | #ifdef LIBXML_OUTPUT_ENABLED | 
 | /** | 
 |  * xmlOutputBufferClose: | 
 |  * @out:  a buffered output | 
 |  * | 
 |  * flushes and close the output I/O channel | 
 |  * and free up all the associated resources | 
 |  * | 
 |  * Returns the number of byte written or -1 in case of error. | 
 |  */ | 
 | int | 
 | xmlOutputBufferClose(xmlOutputBufferPtr out) | 
 | { | 
 |     int written; | 
 |     int err_rc = 0; | 
 |  | 
 |     if (out == NULL) | 
 |         return (-1); | 
 |     if (out->writecallback != NULL) | 
 |         xmlOutputBufferFlush(out); | 
 |     if (out->closecallback != NULL) { | 
 |         err_rc = out->closecallback(out->context); | 
 |     } | 
 |     written = out->written; | 
 |     if (out->conv) { | 
 |         xmlBufferFree(out->conv); | 
 |         out->conv = NULL; | 
 |     } | 
 |     if (out->encoder != NULL) { | 
 |         xmlCharEncCloseFunc(out->encoder); | 
 |     } | 
 |     if (out->buffer != NULL) { | 
 |         xmlBufferFree(out->buffer); | 
 |         out->buffer = NULL; | 
 |     } | 
 |  | 
 |     if (out->error) | 
 |         err_rc = -1; | 
 |     xmlFree(out); | 
 |     return ((err_rc == 0) ? written : err_rc); | 
 | } | 
 | #endif /* LIBXML_OUTPUT_ENABLED */ | 
 |  | 
 | xmlParserInputBufferPtr | 
 | __xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) { | 
 |     xmlParserInputBufferPtr ret; | 
 |     int i = 0; | 
 |     void *context = NULL; | 
 |  | 
 |     if (xmlInputCallbackInitialized == 0) | 
 | 	xmlRegisterDefaultInputCallbacks(); | 
 |  | 
 |     if (URI == NULL) return(NULL); | 
 |  | 
 |     /* | 
 |      * Try to find one of the input accept method accepting that scheme | 
 |      * Go in reverse to give precedence to user defined handlers. | 
 |      */ | 
 |     if (context == NULL) { | 
 | 	for (i = xmlInputCallbackNr - 1;i >= 0;i--) { | 
 | 	    if ((xmlInputCallbackTable[i].matchcallback != NULL) && | 
 | 		(xmlInputCallbackTable[i].matchcallback(URI) != 0)) { | 
 | 		context = xmlInputCallbackTable[i].opencallback(URI); | 
 | 		if (context != NULL) { | 
 | 		    break; | 
 | 		} | 
 | 	    } | 
 | 	} | 
 |     } | 
 |     if (context == NULL) { | 
 | 	return(NULL); | 
 |     } | 
 |  | 
 |     /* | 
 |      * Allocate the Input buffer front-end. | 
 |      */ | 
 |     ret = xmlAllocParserInputBuffer(enc); | 
 |     if (ret != NULL) { | 
 | 	ret->context = context; | 
 | 	ret->readcallback = xmlInputCallbackTable[i].readcallback; | 
 | 	ret->closecallback = xmlInputCallbackTable[i].closecallback; | 
 | #ifdef HAVE_ZLIB_H | 
 | 	if ((xmlInputCallbackTable[i].opencallback == xmlGzfileOpen) && | 
 | 		(strcmp(URI, "-") != 0)) { | 
 | #if defined(ZLIB_VERNUM) && ZLIB_VERNUM >= 0x1230 | 
 |             ret->compressed = !gzdirect(context); | 
 | #else | 
 | 	    if (((z_stream *)context)->avail_in > 4) { | 
 | 	        char *cptr, buff4[4]; | 
 | 		cptr = (char *) ((z_stream *)context)->next_in; | 
 | 		if (gzread(context, buff4, 4) == 4) { | 
 | 		    if (strncmp(buff4, cptr, 4) == 0) | 
 | 		        ret->compressed = 0; | 
 | 		    else | 
 | 		        ret->compressed = 1; | 
 | 		    gzrewind(context); | 
 | 		} | 
 | 	    } | 
 | #endif | 
 | 	} | 
 | #endif | 
 |     } | 
 |     else | 
 |       xmlInputCallbackTable[i].closecallback (context); | 
 |  | 
 |     return(ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlParserInputBufferCreateFilename: | 
 |  * @URI:  a C string containing the URI or filename | 
 |  * @enc:  the charset encoding if known | 
 |  * | 
 |  * Create a buffered parser input for the progressive parsing of a file | 
 |  * If filename is "-' then we use stdin as the input. | 
 |  * Automatic support for ZLIB/Compress compressed document is provided | 
 |  * by default if found at compile-time. | 
 |  * Do an encoding check if enc == XML_CHAR_ENCODING_NONE | 
 |  * | 
 |  * Returns the new parser input or NULL | 
 |  */ | 
 | xmlParserInputBufferPtr | 
 | xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) { | 
 |     if ((xmlParserInputBufferCreateFilenameValue)) { | 
 | 		return xmlParserInputBufferCreateFilenameValue(URI, enc); | 
 | 	} | 
 | 	return __xmlParserInputBufferCreateFilename(URI, enc); | 
 | } | 
 |  | 
 | #ifdef LIBXML_OUTPUT_ENABLED | 
 | xmlOutputBufferPtr | 
 | __xmlOutputBufferCreateFilename(const char *URI, | 
 |                               xmlCharEncodingHandlerPtr encoder, | 
 |                               int compression ATTRIBUTE_UNUSED) { | 
 |     xmlOutputBufferPtr ret; | 
 |     xmlURIPtr puri; | 
 |     int i = 0; | 
 |     void *context = NULL; | 
 |     char *unescaped = NULL; | 
 | #ifdef HAVE_ZLIB_H | 
 |     int is_file_uri = 1; | 
 | #endif | 
 |  | 
 |     if (xmlOutputCallbackInitialized == 0) | 
 | 	xmlRegisterDefaultOutputCallbacks(); | 
 |  | 
 |     if (URI == NULL) return(NULL); | 
 |  | 
 |     puri = xmlParseURI(URI); | 
 |     if (puri != NULL) { | 
 | #ifdef HAVE_ZLIB_H | 
 |         if ((puri->scheme != NULL) && | 
 | 	    (!xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file"))) | 
 | 	    is_file_uri = 0; | 
 | #endif | 
 | 	/* | 
 | 	 * try to limit the damages of the URI unescaping code. | 
 | 	 */ | 
 | 	if ((puri->scheme == NULL) || | 
 | 	    (xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file"))) | 
 | 	    unescaped = xmlURIUnescapeString(URI, 0, NULL); | 
 | 	xmlFreeURI(puri); | 
 |     } | 
 |  | 
 |     /* | 
 |      * Try to find one of the output accept method accepting that scheme | 
 |      * Go in reverse to give precedence to user defined handlers. | 
 |      * try with an unescaped version of the URI | 
 |      */ | 
 |     if (unescaped != NULL) { | 
 | #ifdef HAVE_ZLIB_H | 
 | 	if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) { | 
 | 	    context = xmlGzfileOpenW(unescaped, compression); | 
 | 	    if (context != NULL) { | 
 | 		ret = xmlAllocOutputBufferInternal(encoder); | 
 | 		if (ret != NULL) { | 
 | 		    ret->context = context; | 
 | 		    ret->writecallback = xmlGzfileWrite; | 
 | 		    ret->closecallback = xmlGzfileClose; | 
 | 		} | 
 | 		xmlFree(unescaped); | 
 | 		return(ret); | 
 | 	    } | 
 | 	} | 
 | #endif | 
 | 	for (i = xmlOutputCallbackNr - 1;i >= 0;i--) { | 
 | 	    if ((xmlOutputCallbackTable[i].matchcallback != NULL) && | 
 | 		(xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) { | 
 | #if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H) | 
 | 		/*  Need to pass compression parameter into HTTP open calls  */ | 
 | 		if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch) | 
 | 		    context = xmlIOHTTPOpenW(unescaped, compression); | 
 | 		else | 
 | #endif | 
 | 		    context = xmlOutputCallbackTable[i].opencallback(unescaped); | 
 | 		if (context != NULL) | 
 | 		    break; | 
 | 	    } | 
 | 	} | 
 | 	xmlFree(unescaped); | 
 |     } | 
 |  | 
 |     /* | 
 |      * If this failed try with a non-escaped URI this may be a strange | 
 |      * filename | 
 |      */ | 
 |     if (context == NULL) { | 
 | #ifdef HAVE_ZLIB_H | 
 | 	if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) { | 
 | 	    context = xmlGzfileOpenW(URI, compression); | 
 | 	    if (context != NULL) { | 
 | 		ret = xmlAllocOutputBufferInternal(encoder); | 
 | 		if (ret != NULL) { | 
 | 		    ret->context = context; | 
 | 		    ret->writecallback = xmlGzfileWrite; | 
 | 		    ret->closecallback = xmlGzfileClose; | 
 | 		} | 
 | 		return(ret); | 
 | 	    } | 
 | 	} | 
 | #endif | 
 | 	for (i = xmlOutputCallbackNr - 1;i >= 0;i--) { | 
 | 	    if ((xmlOutputCallbackTable[i].matchcallback != NULL) && | 
 | 		(xmlOutputCallbackTable[i].matchcallback(URI) != 0)) { | 
 | #if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H) | 
 | 		/*  Need to pass compression parameter into HTTP open calls  */ | 
 | 		if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch) | 
 | 		    context = xmlIOHTTPOpenW(URI, compression); | 
 | 		else | 
 | #endif | 
 | 		    context = xmlOutputCallbackTable[i].opencallback(URI); | 
 | 		if (context != NULL) | 
 | 		    break; | 
 | 	    } | 
 | 	} | 
 |     } | 
 |  | 
 |     if (context == NULL) { | 
 | 	return(NULL); | 
 |     } | 
 |  | 
 |     /* | 
 |      * Allocate the Output buffer front-end. | 
 |      */ | 
 |     ret = xmlAllocOutputBufferInternal(encoder); | 
 |     if (ret != NULL) { | 
 | 	ret->context = context; | 
 | 	ret->writecallback = xmlOutputCallbackTable[i].writecallback; | 
 | 	ret->closecallback = xmlOutputCallbackTable[i].closecallback; | 
 |     } | 
 |     return(ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlOutputBufferCreateFilename: | 
 |  * @URI:  a C string containing the URI or filename | 
 |  * @encoder:  the encoding converter or NULL | 
 |  * @compression:  the compression ration (0 none, 9 max). | 
 |  * | 
 |  * Create a buffered  output for the progressive saving of a file | 
 |  * If filename is "-' then we use stdout as the output. | 
 |  * Automatic support for ZLIB/Compress compressed document is provided | 
 |  * by default if found at compile-time. | 
 |  * TODO: currently if compression is set, the library only support | 
 |  *       writing to a local file. | 
 |  * | 
 |  * Returns the new output or NULL | 
 |  */ | 
 | xmlOutputBufferPtr | 
 | xmlOutputBufferCreateFilename(const char *URI, | 
 |                               xmlCharEncodingHandlerPtr encoder, | 
 |                               int compression ATTRIBUTE_UNUSED) { | 
 |     if ((xmlOutputBufferCreateFilenameValue)) { | 
 | 		return xmlOutputBufferCreateFilenameValue(URI, encoder, compression); | 
 | 	} | 
 | 	return __xmlOutputBufferCreateFilename(URI, encoder, compression); | 
 | } | 
 | #endif /* LIBXML_OUTPUT_ENABLED */ | 
 |  | 
 | /** | 
 |  * xmlParserInputBufferCreateFile: | 
 |  * @file:  a FILE* | 
 |  * @enc:  the charset encoding if known | 
 |  * | 
 |  * Create a buffered parser input for the progressive parsing of a FILE * | 
 |  * buffered C I/O | 
 |  * | 
 |  * Returns the new parser input or NULL | 
 |  */ | 
 | xmlParserInputBufferPtr | 
 | xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) { | 
 |     xmlParserInputBufferPtr ret; | 
 |  | 
 |     if (xmlInputCallbackInitialized == 0) | 
 | 	xmlRegisterDefaultInputCallbacks(); | 
 |  | 
 |     if (file == NULL) return(NULL); | 
 |  | 
 |     ret = xmlAllocParserInputBuffer(enc); | 
 |     if (ret != NULL) { | 
 |         ret->context = file; | 
 | 	ret->readcallback = xmlFileRead; | 
 | 	ret->closecallback = xmlFileFlush; | 
 |     } | 
 |  | 
 |     return(ret); | 
 | } | 
 |  | 
 | #ifdef LIBXML_OUTPUT_ENABLED | 
 | /** | 
 |  * xmlOutputBufferCreateFile: | 
 |  * @file:  a FILE* | 
 |  * @encoder:  the encoding converter or NULL | 
 |  * | 
 |  * Create a buffered output for the progressive saving to a FILE * | 
 |  * buffered C I/O | 
 |  * | 
 |  * Returns the new parser output or NULL | 
 |  */ | 
 | xmlOutputBufferPtr | 
 | xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) { | 
 |     xmlOutputBufferPtr ret; | 
 |  | 
 |     if (xmlOutputCallbackInitialized == 0) | 
 | 	xmlRegisterDefaultOutputCallbacks(); | 
 |  | 
 |     if (file == NULL) return(NULL); | 
 |  | 
 |     ret = xmlAllocOutputBufferInternal(encoder); | 
 |     if (ret != NULL) { | 
 |         ret->context = file; | 
 | 	ret->writecallback = xmlFileWrite; | 
 | 	ret->closecallback = xmlFileFlush; | 
 |     } | 
 |  | 
 |     return(ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlOutputBufferCreateBuffer: | 
 |  * @buffer:  a xmlBufferPtr | 
 |  * @encoder:  the encoding converter or NULL | 
 |  * | 
 |  * Create a buffered output for the progressive saving to a xmlBuffer | 
 |  * | 
 |  * Returns the new parser output or NULL | 
 |  */ | 
 | xmlOutputBufferPtr | 
 | xmlOutputBufferCreateBuffer(xmlBufferPtr buffer, | 
 |                             xmlCharEncodingHandlerPtr encoder) { | 
 |     xmlOutputBufferPtr ret; | 
 |  | 
 |     if (buffer == NULL) return(NULL); | 
 |  | 
 |     ret = xmlOutputBufferCreateIO((xmlOutputWriteCallback) | 
 |                                   xmlBufferWrite, | 
 |                                   (xmlOutputCloseCallback) | 
 |                                   NULL, (void *) buffer, encoder); | 
 |  | 
 |     return(ret); | 
 | } | 
 |  | 
 | #endif /* LIBXML_OUTPUT_ENABLED */ | 
 |  | 
 | /** | 
 |  * xmlParserInputBufferCreateFd: | 
 |  * @fd:  a file descriptor number | 
 |  * @enc:  the charset encoding if known | 
 |  * | 
 |  * Create a buffered parser input for the progressive parsing for the input | 
 |  * from a file descriptor | 
 |  * | 
 |  * Returns the new parser input or NULL | 
 |  */ | 
 | xmlParserInputBufferPtr | 
 | xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) { | 
 |     xmlParserInputBufferPtr ret; | 
 |  | 
 |     if (fd < 0) return(NULL); | 
 |  | 
 |     ret = xmlAllocParserInputBuffer(enc); | 
 |     if (ret != NULL) { | 
 |         ret->context = (void *) (long) fd; | 
 | 	ret->readcallback = xmlFdRead; | 
 | 	ret->closecallback = xmlFdClose; | 
 |     } | 
 |  | 
 |     return(ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlParserInputBufferCreateMem: | 
 |  * @mem:  the memory input | 
 |  * @size:  the length of the memory block | 
 |  * @enc:  the charset encoding if known | 
 |  * | 
 |  * Create a buffered parser input for the progressive parsing for the input | 
 |  * from a memory area. | 
 |  * | 
 |  * Returns the new parser input or NULL | 
 |  */ | 
 | xmlParserInputBufferPtr | 
 | xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) { | 
 |     xmlParserInputBufferPtr ret; | 
 |     int errcode; | 
 |  | 
 |     if (size <= 0) return(NULL); | 
 |     if (mem == NULL) return(NULL); | 
 |  | 
 |     ret = xmlAllocParserInputBuffer(enc); | 
 |     if (ret != NULL) { | 
 |         ret->context = (void *) mem; | 
 | 	ret->readcallback = (xmlInputReadCallback) xmlNop; | 
 | 	ret->closecallback = NULL; | 
 | 	errcode = xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size); | 
 | 	if (errcode != 0) { | 
 | 	    xmlFree(ret); | 
 | 	    return(NULL); | 
 | 	} | 
 |     } | 
 |  | 
 |     return(ret); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlParserInputBufferCreateStatic: | 
 |  * @mem:  the memory input | 
 |  * @size:  the length of the memory block | 
 |  * @enc:  the charset encoding if known | 
 |  * | 
 |  * Create a buffered parser input for the progressive parsing for the input | 
 |  * from an immutable memory area. This will not copy the memory area to | 
 |  * the buffer, but the memory is expected to be available until the end of | 
 |  * the parsing, this is useful for example when using mmap'ed file. | 
 |  * | 
 |  * Returns the new parser input or NULL | 
 |  */ | 
 | xmlParserInputBufferPtr | 
 | xmlParserInputBufferCreateStatic(const char *mem, int size, | 
 |                                  xmlCharEncoding enc) { | 
 |     xmlParserInputBufferPtr ret; | 
 |  | 
 |     if (size <= 0) return(NULL); | 
 |     if (mem == NULL) return(NULL); | 
 |  | 
 |     ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer)); | 
 |     if (ret == NULL) { | 
 | 	xmlIOErrMemory("creating input buffer"); | 
 | 	return(NULL); | 
 |     } | 
 |     memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer)); | 
 |     ret->buffer = xmlBufferCreateStatic((void *)mem, (size_t) size); | 
 |     if (ret->buffer == NULL) { | 
 |         xmlFree(ret); | 
 | 	return(NULL); | 
 |     } | 
 |     ret->encoder = xmlGetCharEncodingHandler(enc); | 
 |     if (ret->encoder != NULL) | 
 |         ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize); | 
 |     else | 
 |         ret->raw = NULL; | 
 |     ret->compressed = -1; | 
 |     ret->context = (void *) mem; | 
 |     ret->readcallback = NULL; | 
 |     ret->closecallback = NULL; | 
 |  | 
 |     return(ret); | 
 | } | 
 |  | 
 | #ifdef LIBXML_OUTPUT_ENABLED | 
 | /** | 
 |  * xmlOutputBufferCreateFd: | 
 |  * @fd:  a file descriptor number | 
 |  * @encoder:  the encoding converter or NULL | 
 |  * | 
 |  * Create a buffered output for the progressive saving | 
 |  * to a file descriptor | 
 |  * | 
 |  * Returns the new parser output or NULL | 
 |  */ | 
 | xmlOutputBufferPtr | 
 | xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) { | 
 |     xmlOutputBufferPtr ret; | 
 |  | 
 |     if (fd < 0) return(NULL); | 
 |  | 
 |     ret = xmlAllocOutputBufferInternal(encoder); | 
 |     if (ret != NULL) { | 
 |         ret->context = (void *) (long) fd; | 
 | 	ret->writecallback = xmlFdWrite; | 
 | 	ret->closecallback = NULL; | 
 |     } | 
 |  | 
 |     return(ret); | 
 | } | 
 | #endif /* LIBXML_OUTPUT_ENABLED */ | 
 |  | 
 | /** | 
 |  * xmlParserInputBufferCreateIO: | 
 |  * @ioread:  an I/O read function | 
 |  * @ioclose:  an I/O close function | 
 |  * @ioctx:  an I/O handler | 
 |  * @enc:  the charset encoding if known | 
 |  * | 
 |  * Create a buffered parser input for the progressive parsing for the input | 
 |  * from an I/O handler | 
 |  * | 
 |  * Returns the new parser input or NULL | 
 |  */ | 
 | xmlParserInputBufferPtr | 
 | xmlParserInputBufferCreateIO(xmlInputReadCallback   ioread, | 
 | 	 xmlInputCloseCallback  ioclose, void *ioctx, xmlCharEncoding enc) { | 
 |     xmlParserInputBufferPtr ret; | 
 |  | 
 |     if (ioread == NULL) return(NULL); | 
 |  | 
 |     ret = xmlAllocParserInputBuffer(enc); | 
 |     if (ret != NULL) { | 
 |         ret->context = (void *) ioctx; | 
 | 	ret->readcallback = ioread; | 
 | 	ret->closecallback = ioclose; | 
 |     } | 
 |  | 
 |     return(ret); | 
 | } | 
 |  | 
 | #ifdef LIBXML_OUTPUT_ENABLED | 
 | /** | 
 |  * xmlOutputBufferCreateIO: | 
 |  * @iowrite:  an I/O write function | 
 |  * @ioclose:  an I/O close function | 
 |  * @ioctx:  an I/O handler | 
 |  * @encoder:  the charset encoding if known | 
 |  * | 
 |  * Create a buffered output for the progressive saving | 
 |  * to an I/O handler | 
 |  * | 
 |  * Returns the new parser output or NULL | 
 |  */ | 
 | xmlOutputBufferPtr | 
 | xmlOutputBufferCreateIO(xmlOutputWriteCallback   iowrite, | 
 | 	 xmlOutputCloseCallback  ioclose, void *ioctx, | 
 | 	 xmlCharEncodingHandlerPtr encoder) { | 
 |     xmlOutputBufferPtr ret; | 
 |  | 
 |     if (iowrite == NULL) return(NULL); | 
 |  | 
 |     ret = xmlAllocOutputBufferInternal(encoder); | 
 |     if (ret != NULL) { | 
 |         ret->context = (void *) ioctx; | 
 | 	ret->writecallback = iowrite; | 
 | 	ret->closecallback = ioclose; | 
 |     } | 
 |  | 
 |     return(ret); | 
 | } | 
 | #endif /* LIBXML_OUTPUT_ENABLED */ | 
 |  | 
 | /** | 
 |  * xmlParserInputBufferCreateFilenameDefault: | 
 |  * @func: function pointer to the new ParserInputBufferCreateFilenameFunc | 
 |  * | 
 |  * Registers a callback for URI input file handling | 
 |  * | 
 |  * Returns the old value of the registration function | 
 |  */ | 
 | xmlParserInputBufferCreateFilenameFunc | 
 | xmlParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func) | 
 | { | 
 |     xmlParserInputBufferCreateFilenameFunc old = xmlParserInputBufferCreateFilenameValue; | 
 |     if (old == NULL) { | 
 | 		old = __xmlParserInputBufferCreateFilename; | 
 | 	} | 
 |  | 
 |     xmlParserInputBufferCreateFilenameValue = func; | 
 |     return(old); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlOutputBufferCreateFilenameDefault: | 
 |  * @func: function pointer to the new OutputBufferCreateFilenameFunc | 
 |  * | 
 |  * Registers a callback for URI output file handling | 
 |  * | 
 |  * Returns the old value of the registration function | 
 |  */ | 
 | xmlOutputBufferCreateFilenameFunc | 
 | xmlOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func) | 
 | { | 
 |     xmlOutputBufferCreateFilenameFunc old = xmlOutputBufferCreateFilenameValue; | 
 | #ifdef LIBXML_OUTPUT_ENABLED | 
 |     if (old == NULL) { | 
 | 		old = __xmlOutputBufferCreateFilename; | 
 | 	} | 
 | #endif | 
 |     xmlOutputBufferCreateFilenameValue = func; | 
 |     return(old); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlParserInputBufferPush: | 
 |  * @in:  a buffered parser input | 
 |  * @len:  the size in bytes of the array. | 
 |  * @buf:  an char array | 
 |  * | 
 |  * Push the content of the arry in the input buffer | 
 |  * This routine handle the I18N transcoding to internal UTF-8 | 
 |  * This is used when operating the parser in progressive (push) mode. | 
 |  * | 
 |  * Returns the number of chars read and stored in the buffer, or -1 | 
 |  *         in case of error. | 
 |  */ | 
 | int | 
 | xmlParserInputBufferPush(xmlParserInputBufferPtr in, | 
 | 	                 int len, const char *buf) { | 
 |     int nbchars = 0; | 
 |     int ret; | 
 |  | 
 |     if (len < 0) return(0); | 
 |     if ((in == NULL) || (in->error)) return(-1); | 
 |     if (in->encoder != NULL) { | 
 |         unsigned int use; | 
 |  | 
 |         /* | 
 | 	 * Store the data in the incoming raw buffer | 
 | 	 */ | 
 |         if (in->raw == NULL) { | 
 | 	    in->raw = xmlBufferCreate(); | 
 | 	} | 
 | 	ret = xmlBufferAdd(in->raw, (const xmlChar *) buf, len); | 
 | 	if (ret != 0) | 
 | 	    return(-1); | 
 |  | 
 | 	/* | 
 | 	 * convert as much as possible to the parser reading buffer. | 
 | 	 */ | 
 | 	use = in->raw->use; | 
 | 	nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw); | 
 | 	if (nbchars < 0) { | 
 | 	    xmlIOErr(XML_IO_ENCODER, NULL); | 
 | 	    in->error = XML_IO_ENCODER; | 
 | 	    return(-1); | 
 | 	} | 
 | 	in->rawconsumed += (use - in->raw->use); | 
 |     } else { | 
 | 	nbchars = len; | 
 |         ret = xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars); | 
 | 	if (ret != 0) | 
 | 	    return(-1); | 
 |     } | 
 | #ifdef DEBUG_INPUT | 
 |     xmlGenericError(xmlGenericErrorContext, | 
 | 	    "I/O: pushed %d chars, buffer %d/%d\n", | 
 |             nbchars, in->buffer->use, in->buffer->size); | 
 | #endif | 
 |     return(nbchars); | 
 | } | 
 |  | 
 | /** | 
 |  * endOfInput: | 
 |  * | 
 |  * When reading from an Input channel indicated end of file or error | 
 |  * don't reread from it again. | 
 |  */ | 
 | static int | 
 | endOfInput (void * context ATTRIBUTE_UNUSED, | 
 | 	    char * buffer ATTRIBUTE_UNUSED, | 
 | 	    int len ATTRIBUTE_UNUSED) { | 
 |     return(0); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlParserInputBufferGrow: | 
 |  * @in:  a buffered parser input | 
 |  * @len:  indicative value of the amount of chars to read | 
 |  * | 
 |  * Grow up the content of the input buffer, the old data are preserved | 
 |  * This routine handle the I18N transcoding to internal UTF-8 | 
 |  * This routine is used when operating the parser in normal (pull) mode | 
 |  * | 
 |  * TODO: one should be able to remove one extra copy by copying directly | 
 |  *       onto in->buffer or in->raw | 
 |  * | 
 |  * Returns the number of chars read and stored in the buffer, or -1 | 
 |  *         in case of error. | 
 |  */ | 
 | int | 
 | xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) { | 
 |     char *buffer = NULL; | 
 |     int res = 0; | 
 |     int nbchars = 0; | 
 |     int buffree; | 
 |     unsigned int needSize; | 
 |  | 
 |     if ((in == NULL) || (in->error)) return(-1); | 
 |     if ((len <= MINLEN) && (len != 4)) | 
 |         len = MINLEN; | 
 |  | 
 |     buffree = in->buffer->size - in->buffer->use; | 
 |     if (buffree <= 0) { | 
 | 	xmlIOErr(XML_IO_BUFFER_FULL, NULL); | 
 | 	in->error = XML_IO_BUFFER_FULL; | 
 | 	return(-1); | 
 |     } | 
 |  | 
 |     needSize = in->buffer->use + len + 1; | 
 |     if (needSize > in->buffer->size){ | 
 |         if (!xmlBufferResize(in->buffer, needSize)){ | 
 | 	    xmlIOErrMemory("growing input buffer"); | 
 | 	    in->error = XML_ERR_NO_MEMORY; | 
 |             return(-1); | 
 |         } | 
 |     } | 
 |     buffer = (char *)&in->buffer->content[in->buffer->use]; | 
 |  | 
 |     /* | 
 |      * Call the read method for this I/O type. | 
 |      */ | 
 |     if (in->readcallback != NULL) { | 
 | 	res = in->readcallback(in->context, &buffer[0], len); | 
 | 	if (res <= 0) | 
 | 	    in->readcallback = endOfInput; | 
 |     } else { | 
 | 	xmlIOErr(XML_IO_NO_INPUT, NULL); | 
 | 	in->error = XML_IO_NO_INPUT; | 
 | 	return(-1); | 
 |     } | 
 |     if (res < 0) { | 
 | 	return(-1); | 
 |     } | 
 |     len = res; | 
 |     if (in->encoder != NULL) { | 
 |         unsigned int use; | 
 |  | 
 |         /* | 
 | 	 * Store the data in the incoming raw buffer | 
 | 	 */ | 
 |         if (in->raw == NULL) { | 
 | 	    in->raw = xmlBufferCreate(); | 
 | 	} | 
 | 	res = xmlBufferAdd(in->raw, (const xmlChar *) buffer, len); | 
 | 	if (res != 0) | 
 | 	    return(-1); | 
 |  | 
 | 	/* | 
 | 	 * convert as much as possible to the parser reading buffer. | 
 | 	 */ | 
 | 	use = in->raw->use; | 
 | 	nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw); | 
 | 	if (nbchars < 0) { | 
 | 	    xmlIOErr(XML_IO_ENCODER, NULL); | 
 | 	    in->error = XML_IO_ENCODER; | 
 | 	    return(-1); | 
 | 	} | 
 | 	in->rawconsumed += (use - in->raw->use); | 
 |     } else { | 
 | 	nbchars = len; | 
 |    	in->buffer->use += nbchars; | 
 | 	buffer[nbchars] = 0; | 
 |     } | 
 | #ifdef DEBUG_INPUT | 
 |     xmlGenericError(xmlGenericErrorContext, | 
 | 	    "I/O: read %d chars, buffer %d/%d\n", | 
 |             nbchars, in->buffer->use, in->buffer->size); | 
 | #endif | 
 |     return(nbchars); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlParserInputBufferRead: | 
 |  * @in:  a buffered parser input | 
 |  * @len:  indicative value of the amount of chars to read | 
 |  * | 
 |  * Refresh the content of the input buffer, the old data are considered | 
 |  * consumed | 
 |  * This routine handle the I18N transcoding to internal UTF-8 | 
 |  * | 
 |  * Returns the number of chars read and stored in the buffer, or -1 | 
 |  *         in case of error. | 
 |  */ | 
 | int | 
 | xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) { | 
 |     if ((in == NULL) || (in->error)) return(-1); | 
 |     if (in->readcallback != NULL) | 
 | 	return(xmlParserInputBufferGrow(in, len)); | 
 |     else if ((in->buffer != NULL) && | 
 |              (in->buffer->alloc == XML_BUFFER_ALLOC_IMMUTABLE)) | 
 | 	return(0); | 
 |     else | 
 |         return(-1); | 
 | } | 
 |  | 
 | #ifdef LIBXML_OUTPUT_ENABLED | 
 | /** | 
 |  * xmlOutputBufferWrite: | 
 |  * @out:  a buffered parser output | 
 |  * @len:  the size in bytes of the array. | 
 |  * @buf:  an char array | 
 |  * | 
 |  * Write the content of the array in the output I/O buffer | 
 |  * This routine handle the I18N transcoding from internal UTF-8 | 
 |  * The buffer is lossless, i.e. will store in case of partial | 
 |  * or delayed writes. | 
 |  * | 
 |  * Returns the number of chars immediately written, or -1 | 
 |  *         in case of error. | 
 |  */ | 
 | int | 
 | xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) { | 
 |     int nbchars = 0; /* number of chars to output to I/O */ | 
 |     int ret;         /* return from function call */ | 
 |     int written = 0; /* number of char written to I/O so far */ | 
 |     int chunk;       /* number of byte curreent processed from buf */ | 
 |  | 
 |     if ((out == NULL) || (out->error)) return(-1); | 
 |     if (len < 0) return(0); | 
 |     if (out->error) return(-1); | 
 |  | 
 |     do { | 
 | 	chunk = len; | 
 | 	if (chunk > 4 * MINLEN) | 
 | 	    chunk = 4 * MINLEN; | 
 |  | 
 | 	/* | 
 | 	 * first handle encoding stuff. | 
 | 	 */ | 
 | 	if (out->encoder != NULL) { | 
 | 	    /* | 
 | 	     * Store the data in the incoming raw buffer | 
 | 	     */ | 
 | 	    if (out->conv == NULL) { | 
 | 		out->conv = xmlBufferCreate(); | 
 | 	    } | 
 | 	    ret = xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk); | 
 | 	    if (ret != 0) | 
 | 	        return(-1); | 
 |  | 
 | 	    if ((out->buffer->use < MINLEN) && (chunk == len)) | 
 | 		goto done; | 
 |  | 
 | 	    /* | 
 | 	     * convert as much as possible to the parser reading buffer. | 
 | 	     */ | 
 | 	    ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer); | 
 | 	    if ((ret < 0) && (ret != -3)) { | 
 | 		xmlIOErr(XML_IO_ENCODER, NULL); | 
 | 		out->error = XML_IO_ENCODER; | 
 | 		return(-1); | 
 | 	    } | 
 | 	    nbchars = out->conv->use; | 
 | 	} else { | 
 | 	    ret = xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk); | 
 | 	    if (ret != 0) | 
 | 	        return(-1); | 
 | 	    nbchars = out->buffer->use; | 
 | 	} | 
 | 	buf += chunk; | 
 | 	len -= chunk; | 
 |  | 
 | 	if ((nbchars < MINLEN) && (len <= 0)) | 
 | 	    goto done; | 
 |  | 
 | 	if (out->writecallback) { | 
 | 	    /* | 
 | 	     * second write the stuff to the I/O channel | 
 | 	     */ | 
 | 	    if (out->encoder != NULL) { | 
 | 		ret = out->writecallback(out->context, | 
 | 				 (const char *)out->conv->content, nbchars); | 
 | 		if (ret >= 0) | 
 | 		    xmlBufferShrink(out->conv, ret); | 
 | 	    } else { | 
 | 		ret = out->writecallback(out->context, | 
 | 				 (const char *)out->buffer->content, nbchars); | 
 | 		if (ret >= 0) | 
 | 		    xmlBufferShrink(out->buffer, ret); | 
 | 	    } | 
 | 	    if (ret < 0) { | 
 | 		xmlIOErr(XML_IO_WRITE, NULL); | 
 | 		out->error = XML_IO_WRITE; | 
 | 		return(ret); | 
 | 	    } | 
 | 	    out->written += ret; | 
 | 	} | 
 | 	written += nbchars; | 
 |     } while (len > 0); | 
 |  | 
 | done: | 
 | #ifdef DEBUG_INPUT | 
 |     xmlGenericError(xmlGenericErrorContext, | 
 | 	    "I/O: wrote %d chars\n", written); | 
 | #endif | 
 |     return(written); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlEscapeContent: | 
 |  * @out:  a pointer to an array of bytes to store the result | 
 |  * @outlen:  the length of @out | 
 |  * @in:  a pointer to an array of unescaped UTF-8 bytes | 
 |  * @inlen:  the length of @in | 
 |  * | 
 |  * Take a block of UTF-8 chars in and escape them. | 
 |  * Returns 0 if success, or -1 otherwise | 
 |  * The value of @inlen after return is the number of octets consumed | 
 |  *     if the return value is positive, else unpredictable. | 
 |  * The value of @outlen after return is the number of octets consumed. | 
 |  */ | 
 | static int | 
 | xmlEscapeContent(unsigned char* out, int *outlen, | 
 |                  const xmlChar* in, int *inlen) { | 
 |     unsigned char* outstart = out; | 
 |     const unsigned char* base = in; | 
 |     unsigned char* outend = out + *outlen; | 
 |     const unsigned char* inend; | 
 |  | 
 |     inend = in + (*inlen); | 
 |  | 
 |     while ((in < inend) && (out < outend)) { | 
 |    	if (*in == '<') { | 
 | 	    if (outend - out < 4) break; | 
 | 	    *out++ = '&'; | 
 | 	    *out++ = 'l'; | 
 | 	    *out++ = 't'; | 
 | 	    *out++ = ';'; | 
 | 	} else if (*in == '>') { | 
 | 	    if (outend - out < 4) break; | 
 | 	    *out++ = '&'; | 
 | 	    *out++ = 'g'; | 
 | 	    *out++ = 't'; | 
 | 	    *out++ = ';'; | 
 | 	} else if (*in == '&') { | 
 | 	    if (outend - out < 5) break; | 
 | 	    *out++ = '&'; | 
 | 	    *out++ = 'a'; | 
 | 	    *out++ = 'm'; | 
 | 	    *out++ = 'p'; | 
 | 	    *out++ = ';'; | 
 | 	} else if (*in == '\r') { | 
 | 	    if (outend - out < 5) break; | 
 | 	    *out++ = '&'; | 
 | 	    *out++ = '#'; | 
 | 	    *out++ = '1'; | 
 | 	    *out++ = '3'; | 
 | 	    *out++ = ';'; | 
 | 	} else { | 
 | 	    *out++ = (unsigned char) *in; | 
 | 	} | 
 | 	++in; | 
 |     } | 
 |     *outlen = out - outstart; | 
 |     *inlen = in - base; | 
 |     return(0); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlOutputBufferWriteEscape: | 
 |  * @out:  a buffered parser output | 
 |  * @str:  a zero terminated UTF-8 string | 
 |  * @escaping:  an optional escaping function (or NULL) | 
 |  * | 
 |  * Write the content of the string in the output I/O buffer | 
 |  * This routine escapes the caracters and then handle the I18N | 
 |  * transcoding from internal UTF-8 | 
 |  * The buffer is lossless, i.e. will store in case of partial | 
 |  * or delayed writes. | 
 |  * | 
 |  * Returns the number of chars immediately written, or -1 | 
 |  *         in case of error. | 
 |  */ | 
 | int | 
 | xmlOutputBufferWriteEscape(xmlOutputBufferPtr out, const xmlChar *str, | 
 |                            xmlCharEncodingOutputFunc escaping) { | 
 |     int nbchars = 0; /* number of chars to output to I/O */ | 
 |     int ret;         /* return from function call */ | 
 |     int written = 0; /* number of char written to I/O so far */ | 
 |     int oldwritten=0;/* loop guard */ | 
 |     int chunk;       /* number of byte currently processed from str */ | 
 |     int len;         /* number of bytes in str */ | 
 |     int cons;        /* byte from str consumed */ | 
 |  | 
 |     if ((out == NULL) || (out->error) || (str == NULL) || | 
 |         (out->buffer == NULL) || | 
 | 	(out->buffer->alloc == XML_BUFFER_ALLOC_IMMUTABLE)) return(-1); | 
 |     len = strlen((const char *)str); | 
 |     if (len < 0) return(0); | 
 |     if (out->error) return(-1); | 
 |     if (escaping == NULL) escaping = xmlEscapeContent; | 
 |  | 
 |     do { | 
 |         oldwritten = written; | 
 |  | 
 |         /* | 
 | 	 * how many bytes to consume and how many bytes to store. | 
 | 	 */ | 
 | 	cons = len; | 
 | 	chunk = (out->buffer->size - out->buffer->use) - 1; | 
 |  | 
 |         /* | 
 | 	 * make sure we have enough room to save first, if this is | 
 | 	 * not the case force a flush, but make sure we stay in the loop | 
 | 	 */ | 
 | 	if (chunk < 40) { | 
 | 	    if (xmlBufferGrow(out->buffer, out->buffer->size + 100) < 0) | 
 | 	        return(-1); | 
 |             oldwritten = -1; | 
 | 	    continue; | 
 | 	} | 
 |  | 
 | 	/* | 
 | 	 * first handle encoding stuff. | 
 | 	 */ | 
 | 	if (out->encoder != NULL) { | 
 | 	    /* | 
 | 	     * Store the data in the incoming raw buffer | 
 | 	     */ | 
 | 	    if (out->conv == NULL) { | 
 | 		out->conv = xmlBufferCreate(); | 
 | 	    } | 
 | 	    ret = escaping(out->buffer->content + out->buffer->use , | 
 | 	                   &chunk, str, &cons); | 
 | 	    if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */ | 
 | 	        return(-1); | 
 | 	    out->buffer->use += chunk; | 
 | 	    out->buffer->content[out->buffer->use] = 0; | 
 |  | 
 | 	    if ((out->buffer->use < MINLEN) && (cons == len)) | 
 | 		goto done; | 
 |  | 
 | 	    /* | 
 | 	     * convert as much as possible to the output buffer. | 
 | 	     */ | 
 | 	    ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer); | 
 | 	    if ((ret < 0) && (ret != -3)) { | 
 | 		xmlIOErr(XML_IO_ENCODER, NULL); | 
 | 		out->error = XML_IO_ENCODER; | 
 | 		return(-1); | 
 | 	    } | 
 | 	    nbchars = out->conv->use; | 
 | 	} else { | 
 | 	    ret = escaping(out->buffer->content + out->buffer->use , | 
 | 	                   &chunk, str, &cons); | 
 | 	    if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */ | 
 | 	        return(-1); | 
 | 	    out->buffer->use += chunk; | 
 | 	    out->buffer->content[out->buffer->use] = 0; | 
 | 	    nbchars = out->buffer->use; | 
 | 	} | 
 | 	str += cons; | 
 | 	len -= cons; | 
 |  | 
 | 	if ((nbchars < MINLEN) && (len <= 0)) | 
 | 	    goto done; | 
 |  | 
 | 	if (out->writecallback) { | 
 | 	    /* | 
 | 	     * second write the stuff to the I/O channel | 
 | 	     */ | 
 | 	    if (out->encoder != NULL) { | 
 | 		ret = out->writecallback(out->context, | 
 | 				 (const char *)out->conv->content, nbchars); | 
 | 		if (ret >= 0) | 
 | 		    xmlBufferShrink(out->conv, ret); | 
 | 	    } else { | 
 | 		ret = out->writecallback(out->context, | 
 | 				 (const char *)out->buffer->content, nbchars); | 
 | 		if (ret >= 0) | 
 | 		    xmlBufferShrink(out->buffer, ret); | 
 | 	    } | 
 | 	    if (ret < 0) { | 
 | 		xmlIOErr(XML_IO_WRITE, NULL); | 
 | 		out->error = XML_IO_WRITE; | 
 | 		return(ret); | 
 | 	    } | 
 | 	    out->written += ret; | 
 | 	} else if (out->buffer->size - out->buffer->use < MINLEN) { | 
 | 	    xmlBufferResize(out->buffer, out->buffer->size + MINLEN); | 
 | 	} | 
 | 	written += nbchars; | 
 |     } while ((len > 0) && (oldwritten != written)); | 
 |  | 
 | done: | 
 | #ifdef DEBUG_INPUT | 
 |     xmlGenericError(xmlGenericErrorContext, | 
 | 	    "I/O: wrote %d chars\n", written); | 
 | #endif | 
 |     return(written); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlOutputBufferWriteString: | 
 |  * @out:  a buffered parser output | 
 |  * @str:  a zero terminated C string | 
 |  * | 
 |  * Write the content of the string in the output I/O buffer | 
 |  * This routine handle the I18N transcoding from internal UTF-8 | 
 |  * The buffer is lossless, i.e. will store in case of partial | 
 |  * or delayed writes. | 
 |  * | 
 |  * Returns the number of chars immediately written, or -1 | 
 |  *         in case of error. | 
 |  */ | 
 | int | 
 | xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) { | 
 |     int len; | 
 |  | 
 |     if ((out == NULL) || (out->error)) return(-1); | 
 |     if (str == NULL) | 
 |         return(-1); | 
 |     len = strlen(str); | 
 |  | 
 |     if (len > 0) | 
 | 	return(xmlOutputBufferWrite(out, len, str)); | 
 |     return(len); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlOutputBufferFlush: | 
 |  * @out:  a buffered output | 
 |  * | 
 |  * flushes the output I/O channel | 
 |  * | 
 |  * Returns the number of byte written or -1 in case of error. | 
 |  */ | 
 | int | 
 | xmlOutputBufferFlush(xmlOutputBufferPtr out) { | 
 |     int nbchars = 0, ret = 0; | 
 |  | 
 |     if ((out == NULL) || (out->error)) return(-1); | 
 |     /* | 
 |      * first handle encoding stuff. | 
 |      */ | 
 |     if ((out->conv != NULL) && (out->encoder != NULL)) { | 
 | 	/* | 
 | 	 * convert as much as possible to the parser reading buffer. | 
 | 	 */ | 
 | 	nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer); | 
 | 	if (nbchars < 0) { | 
 | 	    xmlIOErr(XML_IO_ENCODER, NULL); | 
 | 	    out->error = XML_IO_ENCODER; | 
 | 	    return(-1); | 
 | 	} | 
 |     } | 
 |  | 
 |     /* | 
 |      * second flush the stuff to the I/O channel | 
 |      */ | 
 |     if ((out->conv != NULL) && (out->encoder != NULL) && | 
 | 	(out->writecallback != NULL)) { | 
 | 	ret = out->writecallback(out->context, | 
 | 	           (const char *)out->conv->content, out->conv->use); | 
 | 	if (ret >= 0) | 
 | 	    xmlBufferShrink(out->conv, ret); | 
 |     } else if (out->writecallback != NULL) { | 
 | 	ret = out->writecallback(out->context, | 
 | 	           (const char *)out->buffer->content, out->buffer->use); | 
 | 	if (ret >= 0) | 
 | 	    xmlBufferShrink(out->buffer, ret); | 
 |     } | 
 |     if (ret < 0) { | 
 | 	xmlIOErr(XML_IO_FLUSH, NULL); | 
 | 	out->error = XML_IO_FLUSH; | 
 | 	return(ret); | 
 |     } | 
 |     out->written += ret; | 
 |  | 
 | #ifdef DEBUG_INPUT | 
 |     xmlGenericError(xmlGenericErrorContext, | 
 | 	    "I/O: flushed %d chars\n", ret); | 
 | #endif | 
 |     return(ret); | 
 | } | 
 | #endif /* LIBXML_OUTPUT_ENABLED */ | 
 |  | 
 | /** | 
 |  * xmlParserGetDirectory: | 
 |  * @filename:  the path to a file | 
 |  * | 
 |  * lookup the directory for that file | 
 |  * | 
 |  * Returns a new allocated string containing the directory, or NULL. | 
 |  */ | 
 | char * | 
 | xmlParserGetDirectory(const char *filename) { | 
 |     char *ret = NULL; | 
 |     char dir[1024]; | 
 |     char *cur; | 
 |  | 
 | #ifdef _WIN32_WCE  /* easy way by now ... wince does not have dirs! */ | 
 |     return NULL; | 
 | #endif | 
 |  | 
 |     if (xmlInputCallbackInitialized == 0) | 
 | 	xmlRegisterDefaultInputCallbacks(); | 
 |  | 
 |     if (filename == NULL) return(NULL); | 
 |  | 
 | #if defined(WIN32) && !defined(__CYGWIN__) | 
 | #   define IS_XMLPGD_SEP(ch) ((ch=='/')||(ch=='\\')) | 
 | #else | 
 | #   define IS_XMLPGD_SEP(ch) (ch=='/') | 
 | #endif | 
 |  | 
 |     strncpy(dir, filename, 1023); | 
 |     dir[1023] = 0; | 
 |     cur = &dir[strlen(dir)]; | 
 |     while (cur > dir) { | 
 |          if (IS_XMLPGD_SEP(*cur)) break; | 
 | 	 cur --; | 
 |     } | 
 |     if (IS_XMLPGD_SEP(*cur)) { | 
 |         if (cur == dir) dir[1] = 0; | 
 | 	else *cur = 0; | 
 | 	ret = xmlMemStrdup(dir); | 
 |     } else { | 
 |         if (getcwd(dir, 1024) != NULL) { | 
 | 	    dir[1023] = 0; | 
 | 	    ret = xmlMemStrdup(dir); | 
 | 	} | 
 |     } | 
 |     return(ret); | 
 | #undef IS_XMLPGD_SEP | 
 | } | 
 |  | 
 | /**************************************************************** | 
 |  *								* | 
 |  *		External entities loading			* | 
 |  *								* | 
 |  ****************************************************************/ | 
 |  | 
 | /** | 
 |  * xmlCheckHTTPInput: | 
 |  * @ctxt: an XML parser context | 
 |  * @ret: an XML parser input | 
 |  * | 
 |  * Check an input in case it was created from an HTTP stream, in that | 
 |  * case it will handle encoding and update of the base URL in case of | 
 |  * redirection. It also checks for HTTP errors in which case the input | 
 |  * is cleanly freed up and an appropriate error is raised in context | 
 |  * | 
 |  * Returns the input or NULL in case of HTTP error. | 
 |  */ | 
 | xmlParserInputPtr | 
 | xmlCheckHTTPInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr ret) { | 
 | #ifdef LIBXML_HTTP_ENABLED | 
 |     if ((ret != NULL) && (ret->buf != NULL) && | 
 |         (ret->buf->readcallback == xmlIOHTTPRead) && | 
 |         (ret->buf->context != NULL)) { | 
 |         const char *encoding; | 
 |         const char *redir; | 
 |         const char *mime; | 
 |         int code; | 
 |  | 
 |         code = xmlNanoHTTPReturnCode(ret->buf->context); | 
 |         if (code >= 400) { | 
 |             /* fatal error */ | 
 | 	    if (ret->filename != NULL) | 
 | 		__xmlLoaderErr(ctxt, "failed to load HTTP resource \"%s\"\n", | 
 |                          (const char *) ret->filename); | 
 | 	    else | 
 | 		__xmlLoaderErr(ctxt, "failed to load HTTP resource\n", NULL); | 
 |             xmlFreeInputStream(ret); | 
 |             ret = NULL; | 
 |         } else { | 
 |  | 
 |             mime = xmlNanoHTTPMimeType(ret->buf->context); | 
 |             if ((xmlStrstr(BAD_CAST mime, BAD_CAST "/xml")) || | 
 |                 (xmlStrstr(BAD_CAST mime, BAD_CAST "+xml"))) { | 
 |                 encoding = xmlNanoHTTPEncoding(ret->buf->context); | 
 |                 if (encoding != NULL) { | 
 |                     xmlCharEncodingHandlerPtr handler; | 
 |  | 
 |                     handler = xmlFindCharEncodingHandler(encoding); | 
 |                     if (handler != NULL) { | 
 |                         xmlSwitchInputEncoding(ctxt, ret, handler); | 
 |                     } else { | 
 |                         __xmlErrEncoding(ctxt, XML_ERR_UNKNOWN_ENCODING, | 
 |                                          "Unknown encoding %s", | 
 |                                          BAD_CAST encoding, NULL); | 
 |                     } | 
 |                     if (ret->encoding == NULL) | 
 |                         ret->encoding = xmlStrdup(BAD_CAST encoding); | 
 |                 } | 
 | #if 0 | 
 |             } else if (xmlStrstr(BAD_CAST mime, BAD_CAST "html")) { | 
 | #endif | 
 |             } | 
 |             redir = xmlNanoHTTPRedir(ret->buf->context); | 
 |             if (redir != NULL) { | 
 |                 if (ret->filename != NULL) | 
 |                     xmlFree((xmlChar *) ret->filename); | 
 |                 if (ret->directory != NULL) { | 
 |                     xmlFree((xmlChar *) ret->directory); | 
 |                     ret->directory = NULL; | 
 |                 } | 
 |                 ret->filename = | 
 |                     (char *) xmlStrdup((const xmlChar *) redir); | 
 |             } | 
 |         } | 
 |     } | 
 | #endif | 
 |     return(ret); | 
 | } | 
 |  | 
 | static int xmlNoNetExists(const char *URL) { | 
 |     const char *path; | 
 |  | 
 |     if (URL == NULL) | 
 | 	return(0); | 
 |  | 
 |     if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17)) | 
 | #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__) | 
 | 	path = &URL[17]; | 
 | #else | 
 | 	path = &URL[16]; | 
 | #endif | 
 |     else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) { | 
 | #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__) | 
 | 	path = &URL[8]; | 
 | #else | 
 | 	path = &URL[7]; | 
 | #endif | 
 |     } else | 
 | 	path = URL; | 
 |  | 
 |     return xmlCheckFilename(path); | 
 | } | 
 |  | 
 | #ifdef LIBXML_CATALOG_ENABLED | 
 |  | 
 | /** | 
 |  * xmlResolveResourceFromCatalog: | 
 |  * @URL:  the URL for the entity to load | 
 |  * @ID:  the System ID for the entity to load | 
 |  * @ctxt:  the context in which the entity is called or NULL | 
 |  * | 
 |  * Resolves the URL and ID against the appropriate catalog. | 
 |  * This function is used by xmlDefaultExternalEntityLoader and | 
 |  * xmlNoNetExternalEntityLoader. | 
 |  * | 
 |  * Returns a new allocated URL, or NULL. | 
 |  */ | 
 | static xmlChar * | 
 | xmlResolveResourceFromCatalog(const char *URL, const char *ID, | 
 |                               xmlParserCtxtPtr ctxt) { | 
 |     xmlChar *resource = NULL; | 
 |     xmlCatalogAllow pref; | 
 |  | 
 |     /* | 
 |      * If the resource doesn't exists as a file, | 
 |      * try to load it from the resource pointed in the catalogs | 
 |      */ | 
 |     pref = xmlCatalogGetDefaults(); | 
 |  | 
 |     if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) { | 
 | 	/* | 
 | 	 * Do a local lookup | 
 | 	 */ | 
 | 	if ((ctxt != NULL) && (ctxt->catalogs != NULL) && | 
 | 	    ((pref == XML_CATA_ALLOW_ALL) || | 
 | 	     (pref == XML_CATA_ALLOW_DOCUMENT))) { | 
 | 	    resource = xmlCatalogLocalResolve(ctxt->catalogs, | 
 | 					      (const xmlChar *)ID, | 
 | 					      (const xmlChar *)URL); | 
 |         } | 
 | 	/* | 
 | 	 * Try a global lookup | 
 | 	 */ | 
 | 	if ((resource == NULL) && | 
 | 	    ((pref == XML_CATA_ALLOW_ALL) || | 
 | 	     (pref == XML_CATA_ALLOW_GLOBAL))) { | 
 | 	    resource = xmlCatalogResolve((const xmlChar *)ID, | 
 | 					 (const xmlChar *)URL); | 
 | 	} | 
 | 	if ((resource == NULL) && (URL != NULL)) | 
 | 	    resource = xmlStrdup((const xmlChar *) URL); | 
 |  | 
 | 	/* | 
 | 	 * TODO: do an URI lookup on the reference | 
 | 	 */ | 
 | 	if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) { | 
 | 	    xmlChar *tmp = NULL; | 
 |  | 
 | 	    if ((ctxt != NULL) && (ctxt->catalogs != NULL) && | 
 | 		((pref == XML_CATA_ALLOW_ALL) || | 
 | 		 (pref == XML_CATA_ALLOW_DOCUMENT))) { | 
 | 		tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource); | 
 | 	    } | 
 | 	    if ((tmp == NULL) && | 
 | 		((pref == XML_CATA_ALLOW_ALL) || | 
 | 	         (pref == XML_CATA_ALLOW_GLOBAL))) { | 
 | 		tmp = xmlCatalogResolveURI(resource); | 
 | 	    } | 
 |  | 
 | 	    if (tmp != NULL) { | 
 | 		xmlFree(resource); | 
 | 		resource = tmp; | 
 | 	    } | 
 | 	} | 
 |     } | 
 |  | 
 |     return resource; | 
 | } | 
 |  | 
 | #endif | 
 |  | 
 | /** | 
 |  * xmlDefaultExternalEntityLoader: | 
 |  * @URL:  the URL for the entity to load | 
 |  * @ID:  the System ID for the entity to load | 
 |  * @ctxt:  the context in which the entity is called or NULL | 
 |  * | 
 |  * By default we don't load external entitites, yet. | 
 |  * | 
 |  * Returns a new allocated xmlParserInputPtr, or NULL. | 
 |  */ | 
 | static xmlParserInputPtr | 
 | xmlDefaultExternalEntityLoader(const char *URL, const char *ID, | 
 |                                xmlParserCtxtPtr ctxt) | 
 | { | 
 |     xmlParserInputPtr ret = NULL; | 
 |     xmlChar *resource = NULL; | 
 |  | 
 | #ifdef DEBUG_EXTERNAL_ENTITIES | 
 |     xmlGenericError(xmlGenericErrorContext, | 
 |                     "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL); | 
 | #endif | 
 |     if ((ctxt != NULL) && (ctxt->options & XML_PARSE_NONET)) { | 
 |         int options = ctxt->options; | 
 |  | 
 | 	ctxt->options -= XML_PARSE_NONET; | 
 |         ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt); | 
 | 	ctxt->options = options; | 
 | 	return(ret); | 
 |     } | 
 | #ifdef LIBXML_CATALOG_ENABLED | 
 |     resource = xmlResolveResourceFromCatalog(URL, ID, ctxt); | 
 | #endif | 
 |  | 
 |     if (resource == NULL) | 
 |         resource = (xmlChar *) URL; | 
 |  | 
 |     if (resource == NULL) { | 
 |         if (ID == NULL) | 
 |             ID = "NULL"; | 
 |         __xmlLoaderErr(ctxt, "failed to load external entity \"%s\"\n", ID); | 
 |         return (NULL); | 
 |     } | 
 |     ret = xmlNewInputFromFile(ctxt, (const char *) resource); | 
 |     if ((resource != NULL) && (resource != (xmlChar *) URL)) | 
 |         xmlFree(resource); | 
 |     return (ret); | 
 | } | 
 |  | 
 | static xmlExternalEntityLoader xmlCurrentExternalEntityLoader = | 
 |        xmlDefaultExternalEntityLoader; | 
 |  | 
 | /** | 
 |  * xmlSetExternalEntityLoader: | 
 |  * @f:  the new entity resolver function | 
 |  * | 
 |  * Changes the defaultexternal entity resolver function for the application | 
 |  */ | 
 | void | 
 | xmlSetExternalEntityLoader(xmlExternalEntityLoader f) { | 
 |     xmlCurrentExternalEntityLoader = f; | 
 | } | 
 |  | 
 | /** | 
 |  * xmlGetExternalEntityLoader: | 
 |  * | 
 |  * Get the default external entity resolver function for the application | 
 |  * | 
 |  * Returns the xmlExternalEntityLoader function pointer | 
 |  */ | 
 | xmlExternalEntityLoader | 
 | xmlGetExternalEntityLoader(void) { | 
 |     return(xmlCurrentExternalEntityLoader); | 
 | } | 
 |  | 
 | /** | 
 |  * xmlLoadExternalEntity: | 
 |  * @URL:  the URL for the entity to load | 
 |  * @ID:  the Public ID for the entity to load | 
 |  * @ctxt:  the context in which the entity is called or NULL | 
 |  * | 
 |  * Load an external entity, note that the use of this function for | 
 |  * unparsed entities may generate problems | 
 |  * | 
 |  * Returns the xmlParserInputPtr or NULL | 
 |  */ | 
 | xmlParserInputPtr | 
 | xmlLoadExternalEntity(const char *URL, const char *ID, | 
 |                       xmlParserCtxtPtr ctxt) { | 
 |     if ((URL != NULL) && (xmlNoNetExists(URL) == 0)) { | 
 | 	char *canonicFilename; | 
 | 	xmlParserInputPtr ret; | 
 |  | 
 | 	canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL); | 
 | 	if (canonicFilename == NULL) { | 
 |             xmlIOErrMemory("building canonical path\n"); | 
 | 	    return(NULL); | 
 | 	} | 
 |  | 
 | 	ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt); | 
 | 	xmlFree(canonicFilename); | 
 | 	return(ret); | 
 |     } | 
 |     return(xmlCurrentExternalEntityLoader(URL, ID, ctxt)); | 
 | } | 
 |  | 
 | /************************************************************************ | 
 |  *									* | 
 |  *		Disabling Network access				* | 
 |  *									* | 
 |  ************************************************************************/ | 
 |  | 
 | /** | 
 |  * xmlNoNetExternalEntityLoader: | 
 |  * @URL:  the URL for the entity to load | 
 |  * @ID:  the System ID for the entity to load | 
 |  * @ctxt:  the context in which the entity is called or NULL | 
 |  * | 
 |  * A specific entity loader disabling network accesses, though still | 
 |  * allowing local catalog accesses for resolution. | 
 |  * | 
 |  * Returns a new allocated xmlParserInputPtr, or NULL. | 
 |  */ | 
 | xmlParserInputPtr | 
 | xmlNoNetExternalEntityLoader(const char *URL, const char *ID, | 
 |                              xmlParserCtxtPtr ctxt) { | 
 |     xmlParserInputPtr input = NULL; | 
 |     xmlChar *resource = NULL; | 
 |  | 
 | #ifdef LIBXML_CATALOG_ENABLED | 
 |     resource = xmlResolveResourceFromCatalog(URL, ID, ctxt); | 
 | #endif | 
 |  | 
 |     if (resource == NULL) | 
 | 	resource = (xmlChar *) URL; | 
 |  | 
 |     if (resource != NULL) { | 
 |         if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) || | 
 |             (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) { | 
 |             xmlIOErr(XML_IO_NETWORK_ATTEMPT, (const char *) resource); | 
 | 	    if (resource != (xmlChar *) URL) | 
 | 		xmlFree(resource); | 
 | 	    return(NULL); | 
 | 	} | 
 |     } | 
 |     input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt); | 
 |     if (resource != (xmlChar *) URL) | 
 | 	xmlFree(resource); | 
 |     return(input); | 
 | } | 
 |  | 
 | #define bottom_xmlIO | 
 | #include "elfgcchack.h" |