aboutsummaryrefslogtreecommitdiff
path: root/libxml2-2.9.10/xmlIO.c
diff options
context:
space:
mode:
Diffstat (limited to 'libxml2-2.9.10/xmlIO.c')
-rw-r--r--libxml2-2.9.10/xmlIO.c4108
1 files changed, 4108 insertions, 0 deletions
diff --git a/libxml2-2.9.10/xmlIO.c b/libxml2-2.9.10/xmlIO.c
new file mode 100644
index 0000000..752d5e0
--- /dev/null
+++ b/libxml2-2.9.10/xmlIO.c
@@ -0,0 +1,4108 @@
+/*
+ * 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>
+#include <stddef.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 LIBXML_ZLIB_ENABLED
+#include <zlib.h>
+#endif
+#ifdef LIBXML_LZMA_ENABLED
+#include <lzma.h>
+#endif
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#endif
+
+#if defined(_WIN32_WCE)
+#include <winnls.h> /* for CP_UTF8 */
+#endif
+
+#ifndef S_ISDIR
+# ifdef _S_ISDIR
+# define S_ISDIR(x) _S_ISDIR(x)
+# elif defined(S_IFDIR)
+# ifdef S_IFMT
+# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+# elif defined(_S_IFMT)
+# define S_ISDIR(m) (((m) & _S_IFMT) == S_IFDIR)
+# 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/nanohttp.h>
+#include <libxml/nanoftp.h>
+#include <libxml/xmlerror.h>
+#ifdef LIBXML_CATALOG_ENABLED
+#include <libxml/catalog.h>
+#endif
+#include <libxml/globals.h>
+
+#include "buf.h"
+#include "enc.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 */
+ "address in use", /* EADDRINUSE */
+ "already in use", /* EALREADY */
+ "unknown address family", /* 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 LIBXML_ZLIB_ENABLED
+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) {
+ 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;
+}
+
+#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
+#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
+ struct _stat stat_buffer;
+#else
+ struct stat stat_buffer;
+#endif
+#endif
+ if (path == NULL)
+ return(0);
+
+#ifdef HAVE_STAT
+#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
+ /*
+ * On Windows stat and wstat do not work with long pathname,
+ * which start with '\\?\'
+ */
+ if ((path[0] == '\\') && (path[1] == '\\') && (path[2] == '?') &&
+ (path[3] == '\\') )
+ return 1;
+
+ if (xmlWrapStatUtf8(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;
+}
+
+/**
+ * xmlInputReadCallbackNop:
+ *
+ * No Operation xmlInputReadCallback function, does nothing.
+ *
+ * Returns zero
+ */
+int
+xmlInputReadCallbackNop(void *context ATTRIBUTE_UNUSED,
+ char *buffer ATTRIBUTE_UNUSED,
+ int len ATTRIBUTE_UNUSED) {
+ 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) (ptrdiff_t) 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) (ptrdiff_t) 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) (ptrdiff_t) 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 = filename;
+ 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
+ }
+
+ /* Do not check DDNAME on zOS ! */
+#if !defined(__MVS__)
+ if (!xmlCheckFilename(path))
+ return(NULL);
+#endif
+
+#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
+ fd = xmlWrapOpenUtf8(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 = xmlWrapOpenUtf8(path, 1);
+#elif(__MVS__)
+ fd = fopen(path, "w");
+#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 LIBXML_ZLIB_ENABLED
+/************************************************************************
+ * *
+ * 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, "-")) {
+ int duped_fd = dup(fileno(stdin));
+ fd = gzdopen(duped_fd, "rb");
+ if (fd == Z_NULL && duped_fd >= 0) {
+ close(duped_fd); /* gzdOpen() does not close on failure */
+ }
+
+ 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 = xmlWrapGzOpenUtf8(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, "-")) {
+ int duped_fd = dup(fileno(stdout));
+ fd = gzdopen(duped_fd, "rb");
+ if (fd == Z_NULL && duped_fd >= 0) {
+ close(duped_fd); /* gzdOpen() does not close on failure */
+ }
+
+ 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 = xmlWrapGzOpenUtf8(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 read.
+ */
+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 /* LIBXML_ZLIB_ENABLED */
+
+#ifdef LIBXML_LZMA_ENABLED
+/************************************************************************
+ * *
+ * I/O for compressed file accesses *
+ * *
+ ************************************************************************/
+#include "xzlib.h"
+/**
+ * xmlXzfileMatch:
+ * @filename: the URI for matching
+ *
+ * input from compressed file test
+ *
+ * Returns 1 if matches, 0 otherwise
+ */
+static int
+xmlXzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
+ return(1);
+}
+
+/**
+ * xmlXzFileOpen_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 *
+xmlXzfileOpen_real (const char *filename) {
+ const char *path = NULL;
+ xzFile fd;
+
+ if (!strcmp(filename, "-")) {
+ fd = __libxml2_xzdopen(dup(fileno(stdin)), "rb");
+ return((void *) fd);
+ }
+
+ if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) {
+ path = &filename[16];
+ } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
+ path = &filename[7];
+ } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:/", 6)) {
+ /* lots of generators seems to lazy to read RFC 1738 */
+ path = &filename[5];
+ } else
+ path = filename;
+
+ if (path == NULL)
+ return(NULL);
+ if (!xmlCheckFilename(path))
+ return(NULL);
+
+ fd = __libxml2_xzopen(path, "rb");
+ return((void *) fd);
+}
+
+/**
+ * xmlXzfileOpen:
+ * @filename: the URI for matching
+ *
+ * Wrapper around xmlXzfileOpen_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
+ */
+static void *
+xmlXzfileOpen (const char *filename) {
+ char *unescaped;
+ void *retval;
+
+ retval = xmlXzfileOpen_real(filename);
+ if (retval == NULL) {
+ unescaped = xmlURIUnescapeString(filename, 0, NULL);
+ if (unescaped != NULL) {
+ retval = xmlXzfileOpen_real(unescaped);
+ }
+ xmlFree(unescaped);
+ }
+
+ return retval;
+}
+
+/**
+ * xmlXzfileRead:
+ * @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
+xmlXzfileRead (void * context, char * buffer, int len) {
+ int ret;
+
+ ret = __libxml2_xzread((xzFile) context, &buffer[0], len);
+ if (ret < 0) xmlIOErr(0, "xzread()");
+ return(ret);
+}
+
+/**
+ * xmlXzfileClose:
+ * @context: the I/O context
+ *
+ * Close a compressed I/O channel
+ */
+static int
+xmlXzfileClose (void * context) {
+ int ret;
+
+ ret = (__libxml2_xzclose((xzFile) context) == LZMA_OK ) ? 0 : -1;
+ if (ret < 0) xmlIOErr(0, "xzclose()");
+ return(ret);
+}
+#endif /* LIBXML_LZMA_ENABLED */
+
+#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 LIBXML_ZLIB_ENABLED
+
+#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,
+ "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,
+ "xmlZMemBuffExtend: %s %lu bytes.\n",
+ "Allocation failure extending output buffer to",
+ (unsigned long) 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,
+ "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,
+ "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 /* LIBXML_ZLIB_ENABLED */
+
+#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 LIBXML_ZLIB_ENABLED
+ 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 ATTRIBUTE_UNUSED)
+{
+
+ 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 LIBXML_ZLIB_ENABLED
+ 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 LIBXML_ZLIB_ENABLED
+ 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,
+ "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 LIBXML_ZLIB_ENABLED
+
+ 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 *) xmlBufContent(dctxt->buffer);
+ content_lgth = xmlBufUse(dctxt->buffer);
+ }
+
+ if ( http_content == NULL ) {
+ xmlChar msg[500];
+ xmlStrPrintf(msg, 500,
+ "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,
+ "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;
+
+ xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
+ xmlFileRead, xmlFileClose);
+#ifdef LIBXML_ZLIB_ENABLED
+ xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
+ xmlGzfileRead, xmlGzfileClose);
+#endif /* LIBXML_ZLIB_ENABLED */
+#ifdef LIBXML_LZMA_ENABLED
+ xmlRegisterInputCallbacks(xmlXzfileMatch, xmlXzfileOpen,
+ xmlXzfileRead, xmlXzfileClose);
+#endif /* LIBXML_LZMA_ENABLED */
+
+#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;
+
+ 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 LIBXML_ZLIB_ENABLED
+ 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 = xmlBufCreateSize(2 * xmlDefaultBufferSize);
+ if (ret->buffer == NULL) {
+ xmlFree(ret);
+ return(NULL);
+ }
+ xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_DOUBLEIT);
+ ret->encoder = xmlGetCharEncodingHandler(enc);
+ if (ret->encoder != NULL)
+ ret->raw = xmlBufCreateSize(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 = xmlBufCreate();
+ if (ret->buffer == NULL) {
+ xmlFree(ret);
+ return(NULL);
+ }
+
+ /* try to avoid a performance problem with Windows realloc() */
+ if (xmlBufGetAllocationScheme(ret->buffer) == XML_BUFFER_ALLOC_EXACT)
+ xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_DOUBLEIT);
+
+ ret->encoder = encoder;
+ if (encoder != NULL) {
+ ret->conv = xmlBufCreateSize(4000);
+ if (ret->conv == NULL) {
+ xmlBufFree(ret->buffer);
+ xmlFree(ret);
+ return(NULL);
+ }
+
+ /*
+ * This call is designed to initiate the encoder state
+ */
+ xmlCharEncOutput(ret, 1);
+ } 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 = xmlBufCreate();
+ if (ret->buffer == NULL) {
+ xmlFree(ret);
+ return(NULL);
+ }
+
+
+ /*
+ * For conversion buffers we use the special IO handling
+ */
+ xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_IO);
+
+ ret->encoder = encoder;
+ if (encoder != NULL) {
+ ret->conv = xmlBufCreateSize(4000);
+ if (ret->conv == NULL) {
+ xmlBufFree(ret->buffer);
+ xmlFree(ret);
+ return(NULL);
+ }
+
+ /*
+ * This call is designed to initiate the encoder state
+ */
+ xmlCharEncOutput(ret, 1);
+ } 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) {
+ xmlBufFree(in->raw);
+ in->raw = NULL;
+ }
+ if (in->encoder != NULL) {
+ xmlCharEncCloseFunc(in->encoder);
+ }
+ if (in->closecallback != NULL) {
+ in->closecallback(in->context);
+ }
+ if (in->buffer != NULL) {
+ xmlBufFree(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) {
+ xmlBufFree(out->conv);
+ out->conv = NULL;
+ }
+ if (out->encoder != NULL) {
+ xmlCharEncCloseFunc(out->encoder);
+ }
+ if (out->buffer != NULL) {
+ xmlBufFree(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 LIBXML_ZLIB_ENABLED
+ 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
+#ifdef LIBXML_LZMA_ENABLED
+ if ((xmlInputCallbackTable[i].opencallback == xmlXzfileOpen) &&
+ (strcmp(URI, "-") != 0)) {
+ ret->compressed = __libxml2_xzcompressed(context);
+ }
+#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 LIBXML_ZLIB_ENABLED
+ int is_file_uri = 1;
+#endif
+
+ if (xmlOutputCallbackInitialized == 0)
+ xmlRegisterDefaultOutputCallbacks();
+
+ if (URI == NULL) return(NULL);
+
+ puri = xmlParseURI(URI);
+ if (puri != NULL) {
+#ifdef LIBXML_ZLIB_ENABLED
+ 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 LIBXML_ZLIB_ENABLED
+ 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(LIBXML_ZLIB_ENABLED)
+ /* 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 LIBXML_ZLIB_ENABLED
+ 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(LIBXML_ZLIB_ENABLED)
+ /* 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(xmlBufferWrite, NULL, (void *) buffer,
+ encoder);
+
+ return(ret);
+}
+
+/**
+ * xmlOutputBufferGetContent:
+ * @out: an xmlOutputBufferPtr
+ *
+ * Gives a pointer to the data currently held in the output buffer
+ *
+ * Returns a pointer to the data or NULL in case of error
+ */
+const xmlChar *
+xmlOutputBufferGetContent(xmlOutputBufferPtr out) {
+ if ((out == NULL) || (out->buffer == NULL))
+ return(NULL);
+
+ return(xmlBufContent(out->buffer));
+}
+
+/**
+ * xmlOutputBufferGetSize:
+ * @out: an xmlOutputBufferPtr
+ *
+ * Gives the length of the data currently held in the output buffer
+ *
+ * Returns 0 in case or error or no data is held, the size otherwise
+ */
+size_t
+xmlOutputBufferGetSize(xmlOutputBufferPtr out) {
+ if ((out == NULL) || (out->buffer == NULL))
+ return(0);
+
+ return(xmlBufUse(out->buffer));
+}
+
+
+#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 *) (ptrdiff_t) 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 = xmlInputReadCallbackNop;
+ ret->closecallback = NULL;
+ errcode = xmlBufAdd(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 = xmlBufCreateStatic((void *)mem, (size_t) size);
+ if (ret->buffer == NULL) {
+ xmlFree(ret);
+ return(NULL);
+ }
+ ret->encoder = xmlGetCharEncodingHandler(enc);
+ if (ret->encoder != NULL)
+ ret->raw = xmlBufCreateSize(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 *) (ptrdiff_t) 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 = xmlBufCreate();
+ }
+ ret = xmlBufAdd(in->raw, (const xmlChar *) buf, len);
+ if (ret != 0)
+ return(-1);
+
+ /*
+ * convert as much as possible to the parser reading buffer.
+ */
+ use = xmlBufUse(in->raw);
+ nbchars = xmlCharEncInput(in, 1);
+ if (nbchars < 0) {
+ xmlIOErr(XML_IO_ENCODER, NULL);
+ in->error = XML_IO_ENCODER;
+ return(-1);
+ }
+ in->rawconsumed += (use - xmlBufUse(in->raw));
+ } else {
+ nbchars = len;
+ ret = xmlBufAdd(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, xmlBufUse(in->buffer), xmlBufLength(in->buffer));
+#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;
+
+ if ((in == NULL) || (in->error)) return(-1);
+ if ((len <= MINLEN) && (len != 4))
+ len = MINLEN;
+
+ if (xmlBufAvail(in->buffer) <= 0) {
+ xmlIOErr(XML_IO_BUFFER_FULL, NULL);
+ in->error = XML_IO_BUFFER_FULL;
+ return(-1);
+ }
+
+ if (xmlBufGrow(in->buffer, len + 1) < 0) {
+ xmlIOErrMemory("growing input buffer");
+ in->error = XML_ERR_NO_MEMORY;
+ return(-1);
+ }
+ buffer = (char *)xmlBufEnd(in->buffer);
+
+ /*
+ * 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);
+ }
+
+ /*
+ * try to establish compressed status of input if not done already
+ */
+ if (in->compressed == -1) {
+#ifdef LIBXML_LZMA_ENABLED
+ if (in->readcallback == xmlXzfileRead)
+ in->compressed = __libxml2_xzcompressed(in->context);
+#endif
+ }
+
+ len = res;
+ if (in->encoder != NULL) {
+ unsigned int use;
+
+ /*
+ * Store the data in the incoming raw buffer
+ */
+ if (in->raw == NULL) {
+ in->raw = xmlBufCreate();
+ }
+ res = xmlBufAdd(in->raw, (const xmlChar *) buffer, len);
+ if (res != 0)
+ return(-1);
+
+ /*
+ * convert as much as possible to the parser reading buffer.
+ */
+ use = xmlBufUse(in->raw);
+ nbchars = xmlCharEncInput(in, 1);
+ if (nbchars < 0) {
+ xmlIOErr(XML_IO_ENCODER, NULL);
+ in->error = XML_IO_ENCODER;
+ return(-1);
+ }
+ in->rawconsumed += (use - xmlBufUse(in->raw));
+ } else {
+ nbchars = len;
+ xmlBufAddLen(in->buffer, nbchars);
+ }
+#ifdef DEBUG_INPUT
+ xmlGenericError(xmlGenericErrorContext,
+ "I/O: read %d chars, buffer %d\n",
+ nbchars, xmlBufUse(in->buffer));
+#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 (xmlBufGetAllocationScheme(in->buffer) == 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 current 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 = xmlBufCreate();
+ }
+ ret = xmlBufAdd(out->buffer, (const xmlChar *) buf, chunk);
+ if (ret != 0)
+ return(-1);
+
+ if ((xmlBufUse(out->buffer) < MINLEN) && (chunk == len))
+ goto done;
+
+ /*
+ * convert as much as possible to the parser reading buffer.
+ */
+ ret = xmlCharEncOutput(out, 0);
+ if ((ret < 0) && (ret != -3)) {
+ xmlIOErr(XML_IO_ENCODER, NULL);
+ out->error = XML_IO_ENCODER;
+ return(-1);
+ }
+ if (out->writecallback)
+ nbchars = xmlBufUse(out->conv);
+ else
+ nbchars = ret;
+ } else {
+ ret = xmlBufAdd(out->buffer, (const xmlChar *) buf, chunk);
+ if (ret != 0)
+ return(-1);
+ if (out->writecallback)
+ nbchars = xmlBufUse(out->buffer);
+ else
+ nbchars = chunk;
+ }
+ buf += chunk;
+ len -= chunk;
+
+ if (out->writecallback) {
+ if ((nbchars < MINLEN) && (len <= 0))
+ goto done;
+
+ /*
+ * second write the stuff to the I/O channel
+ */
+ if (out->encoder != NULL) {
+ ret = out->writecallback(out->context,
+ (const char *)xmlBufContent(out->conv), nbchars);
+ if (ret >= 0)
+ xmlBufShrink(out->conv, ret);
+ } else {
+ ret = out->writecallback(out->context,
+ (const char *)xmlBufContent(out->buffer), nbchars);
+ if (ret >= 0)
+ xmlBufShrink(out->buffer, ret);
+ }
+ if (ret < 0) {
+ xmlIOErr(XML_IO_WRITE, NULL);
+ out->error = XML_IO_WRITE;
+ return(ret);
+ }
+ if (out->written > INT_MAX - ret)
+ out->written = INT_MAX;
+ else
+ 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 characters 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) ||
+ (xmlBufGetAllocationScheme(out->buffer) == 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 = xmlBufAvail(out->buffer) - 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 (xmlBufGrow(out->buffer, 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 = xmlBufCreate();
+ }
+ ret = escaping(xmlBufEnd(out->buffer) ,
+ &chunk, str, &cons);
+ if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
+ return(-1);
+ xmlBufAddLen(out->buffer, chunk);
+
+ if ((xmlBufUse(out->buffer) < MINLEN) && (cons == len))
+ goto done;
+
+ /*
+ * convert as much as possible to the output buffer.
+ */
+ ret = xmlCharEncOutput(out, 0);
+ if ((ret < 0) && (ret != -3)) {
+ xmlIOErr(XML_IO_ENCODER, NULL);
+ out->error = XML_IO_ENCODER;
+ return(-1);
+ }
+ if (out->writecallback)
+ nbchars = xmlBufUse(out->conv);
+ else
+ nbchars = ret;
+ } else {
+ ret = escaping(xmlBufEnd(out->buffer), &chunk, str, &cons);
+ if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
+ return(-1);
+ xmlBufAddLen(out->buffer, chunk);
+ if (out->writecallback)
+ nbchars = xmlBufUse(out->buffer);
+ else
+ nbchars = chunk;
+ }
+ str += cons;
+ len -= cons;
+
+ if (out->writecallback) {
+ if ((nbchars < MINLEN) && (len <= 0))
+ goto done;
+
+ /*
+ * second write the stuff to the I/O channel
+ */
+ if (out->encoder != NULL) {
+ ret = out->writecallback(out->context,
+ (const char *)xmlBufContent(out->conv), nbchars);
+ if (ret >= 0)
+ xmlBufShrink(out->conv, ret);
+ } else {
+ ret = out->writecallback(out->context,
+ (const char *)xmlBufContent(out->buffer), nbchars);
+ if (ret >= 0)
+ xmlBufShrink(out->buffer, ret);
+ }
+ if (ret < 0) {
+ xmlIOErr(XML_IO_WRITE, NULL);
+ out->error = XML_IO_WRITE;
+ return(ret);
+ }
+ if (out->written > INT_MAX - ret)
+ out->written = INT_MAX;
+ else
+ out->written += ret;
+ } else if (xmlBufAvail(out->buffer) < MINLEN) {
+ xmlBufGrow(out->buffer, 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 output buffer.
+ */
+ do {
+ nbchars = xmlCharEncOutput(out, 0);
+ if (nbchars < 0) {
+ xmlIOErr(XML_IO_ENCODER, NULL);
+ out->error = XML_IO_ENCODER;
+ return(-1);
+ }
+ } while (nbchars);
+ }
+
+ /*
+ * 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 *)xmlBufContent(out->conv),
+ xmlBufUse(out->conv));
+ if (ret >= 0)
+ xmlBufShrink(out->conv, ret);
+ } else if (out->writecallback != NULL) {
+ ret = out->writecallback(out->context,
+ (const char *)xmlBufContent(out->buffer),
+ xmlBufUse(out->buffer));
+ if (ret >= 0)
+ xmlBufShrink(out->buffer, ret);
+ }
+ if (ret < 0) {
+ xmlIOErr(XML_IO_FLUSH, NULL);
+ out->error = XML_IO_FLUSH;
+ return(ret);
+ }
+ if (out->written > INT_MAX - ret)
+ out->written = INT_MAX;
+ else
+ 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 entities, 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"