mirror of
				https://gitlab.gnome.org/GNOME/libxml2.git
				synced 2025-10-24 13:33:01 +03:00 
			
		
		
		
	On 64-bit Windows, `long` is 32 bits wide and can't hold a pointer. Switch to ptrdiff_t instead which should be the same size as a pointer on every somewhat sane platform without requiring C99 types like intptr_t. Fixes bug 788312. Thanks to J. Peter Mugaas for the report and initial patch.
		
			
				
	
	
		
			4193 lines
		
	
	
		
			104 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			4193 lines
		
	
	
		
			104 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * 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 HAVE_ZLIB_H
 | |
| #include <zlib.h>
 | |
| #endif
 | |
| #ifdef HAVE_LZMA_H
 | |
| #include <lzma.h>
 | |
| #endif
 | |
| 
 | |
| #if defined(WIN32) || defined(_WIN32)
 | |
| #include <windows.h>
 | |
| #endif
 | |
| 
 | |
| #if defined(_WIN32_WCE)
 | |
| #include <winnls.h> /* for CP_UTF8 */
 | |
| #endif
 | |
| 
 | |
| /* Figure a portable way to know if a file is a directory. */
 | |
| #ifndef HAVE_STAT
 | |
| #  ifdef HAVE__STAT
 | |
|      /* MS C library seems to define stat and _stat. The definition
 | |
|         is identical. Still, mapping them to each other causes a warning. */
 | |
| #    ifndef _MSC_VER
 | |
| #      define stat(x,y) _stat(x,y)
 | |
| #    endif
 | |
| #    define HAVE_STAT
 | |
| #  endif
 | |
| #else
 | |
| #  ifdef HAVE__STAT
 | |
| #    if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
 | |
| #      define stat _stat
 | |
| #    endif
 | |
| #  endif
 | |
| #endif
 | |
| #ifdef HAVE_STAT
 | |
| #  ifndef S_ISDIR
 | |
| #    ifdef _S_ISDIR
 | |
| #      define S_ISDIR(x) _S_ISDIR(x)
 | |
| #    else
 | |
| #      ifdef S_IFDIR
 | |
| #        ifndef S_IFMT
 | |
| #          ifdef _S_IFMT
 | |
| #            define S_IFMT _S_IFMT
 | |
| #          endif
 | |
| #        endif
 | |
| #        ifdef S_IFMT
 | |
| #          define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
 | |
| #        endif
 | |
| #      endif
 | |
| #    endif
 | |
| #  endif
 | |
| #endif
 | |
| 
 | |
| #include <libxml/xmlmemory.h>
 | |
| #include <libxml/parser.h>
 | |
| #include <libxml/parserInternals.h>
 | |
| #include <libxml/xmlIO.h>
 | |
| #include <libxml/uri.h>
 | |
| #include <libxml/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 */
 | |
|     "adddress in use",		/* EADDRINUSE */
 | |
|     "already in use",		/* EALREADY */
 | |
|     "unknown address familly",	/* EAFNOSUPPORT */
 | |
| };
 | |
| 
 | |
| #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
 | |
| /**
 | |
|  * __xmlIOWin32UTF8ToWChar:
 | |
|  * @u8String:  uft-8 string
 | |
|  *
 | |
|  * Convert a string from utf-8 to wchar (WINDOWS ONLY!)
 | |
|  */
 | |
| static wchar_t *
 | |
| __xmlIOWin32UTF8ToWChar(const char *u8String)
 | |
| {
 | |
|     wchar_t *wString = NULL;
 | |
| 
 | |
|     if (u8String) {
 | |
|         int wLen =
 | |
|             MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, u8String,
 | |
|                                 -1, NULL, 0);
 | |
|         if (wLen) {
 | |
|             wString = xmlMalloc(wLen * sizeof(wchar_t));
 | |
|             if (wString) {
 | |
|                 if (MultiByteToWideChar
 | |
|                     (CP_UTF8, 0, u8String, -1, wString, wLen) == 0) {
 | |
|                     xmlFree(wString);
 | |
|                     wString = NULL;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     return wString;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /**
 | |
|  * xmlIOErrMemory:
 | |
|  * @extra:  extra informations
 | |
|  *
 | |
|  * Handle an out of memory condition
 | |
|  */
 | |
| static void
 | |
| xmlIOErrMemory(const char *extra)
 | |
| {
 | |
|     __xmlSimpleError(XML_FROM_IO, XML_ERR_NO_MEMORY, NULL, NULL, extra);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * __xmlIOErr:
 | |
|  * @code:  the error number
 | |
|  * @
 | |
|  * @extra:  extra informations
 | |
|  *
 | |
|  * Handle an I/O error
 | |
|  */
 | |
| void
 | |
| __xmlIOErr(int domain, int code, const char *extra)
 | |
| {
 | |
|     unsigned int idx;
 | |
| 
 | |
|     if (code == 0) {
 | |
| #ifdef HAVE_ERRNO_H
 | |
| 	if (errno == 0) code = 0;
 | |
| #ifdef EACCES
 | |
|         else if (errno == EACCES) code = XML_IO_EACCES;
 | |
| #endif
 | |
| #ifdef EAGAIN
 | |
|         else if (errno == EAGAIN) code = XML_IO_EAGAIN;
 | |
| #endif
 | |
| #ifdef EBADF
 | |
|         else if (errno == EBADF) code = XML_IO_EBADF;
 | |
| #endif
 | |
| #ifdef EBADMSG
 | |
|         else if (errno == EBADMSG) code = XML_IO_EBADMSG;
 | |
| #endif
 | |
| #ifdef EBUSY
 | |
|         else if (errno == EBUSY) code = XML_IO_EBUSY;
 | |
| #endif
 | |
| #ifdef ECANCELED
 | |
|         else if (errno == ECANCELED) code = XML_IO_ECANCELED;
 | |
| #endif
 | |
| #ifdef ECHILD
 | |
|         else if (errno == ECHILD) code = XML_IO_ECHILD;
 | |
| #endif
 | |
| #ifdef EDEADLK
 | |
|         else if (errno == EDEADLK) code = XML_IO_EDEADLK;
 | |
| #endif
 | |
| #ifdef EDOM
 | |
|         else if (errno == EDOM) code = XML_IO_EDOM;
 | |
| #endif
 | |
| #ifdef EEXIST
 | |
|         else if (errno == EEXIST) code = XML_IO_EEXIST;
 | |
| #endif
 | |
| #ifdef EFAULT
 | |
|         else if (errno == EFAULT) code = XML_IO_EFAULT;
 | |
| #endif
 | |
| #ifdef EFBIG
 | |
|         else if (errno == EFBIG) code = XML_IO_EFBIG;
 | |
| #endif
 | |
| #ifdef EINPROGRESS
 | |
|         else if (errno == EINPROGRESS) code = XML_IO_EINPROGRESS;
 | |
| #endif
 | |
| #ifdef EINTR
 | |
|         else if (errno == EINTR) code = XML_IO_EINTR;
 | |
| #endif
 | |
| #ifdef EINVAL
 | |
|         else if (errno == EINVAL) code = XML_IO_EINVAL;
 | |
| #endif
 | |
| #ifdef EIO
 | |
|         else if (errno == EIO) code = XML_IO_EIO;
 | |
| #endif
 | |
| #ifdef EISDIR
 | |
|         else if (errno == EISDIR) code = XML_IO_EISDIR;
 | |
| #endif
 | |
| #ifdef EMFILE
 | |
|         else if (errno == EMFILE) code = XML_IO_EMFILE;
 | |
| #endif
 | |
| #ifdef EMLINK
 | |
|         else if (errno == EMLINK) code = XML_IO_EMLINK;
 | |
| #endif
 | |
| #ifdef EMSGSIZE
 | |
|         else if (errno == EMSGSIZE) code = XML_IO_EMSGSIZE;
 | |
| #endif
 | |
| #ifdef ENAMETOOLONG
 | |
|         else if (errno == ENAMETOOLONG) code = XML_IO_ENAMETOOLONG;
 | |
| #endif
 | |
| #ifdef ENFILE
 | |
|         else if (errno == ENFILE) code = XML_IO_ENFILE;
 | |
| #endif
 | |
| #ifdef ENODEV
 | |
|         else if (errno == ENODEV) code = XML_IO_ENODEV;
 | |
| #endif
 | |
| #ifdef ENOENT
 | |
|         else if (errno == ENOENT) code = XML_IO_ENOENT;
 | |
| #endif
 | |
| #ifdef ENOEXEC
 | |
|         else if (errno == ENOEXEC) code = XML_IO_ENOEXEC;
 | |
| #endif
 | |
| #ifdef ENOLCK
 | |
|         else if (errno == ENOLCK) code = XML_IO_ENOLCK;
 | |
| #endif
 | |
| #ifdef ENOMEM
 | |
|         else if (errno == ENOMEM) code = XML_IO_ENOMEM;
 | |
| #endif
 | |
| #ifdef ENOSPC
 | |
|         else if (errno == ENOSPC) code = XML_IO_ENOSPC;
 | |
| #endif
 | |
| #ifdef ENOSYS
 | |
|         else if (errno == ENOSYS) code = XML_IO_ENOSYS;
 | |
| #endif
 | |
| #ifdef ENOTDIR
 | |
|         else if (errno == ENOTDIR) code = XML_IO_ENOTDIR;
 | |
| #endif
 | |
| #ifdef ENOTEMPTY
 | |
|         else if (errno == ENOTEMPTY) code = XML_IO_ENOTEMPTY;
 | |
| #endif
 | |
| #ifdef ENOTSUP
 | |
|         else if (errno == ENOTSUP) code = XML_IO_ENOTSUP;
 | |
| #endif
 | |
| #ifdef ENOTTY
 | |
|         else if (errno == ENOTTY) code = XML_IO_ENOTTY;
 | |
| #endif
 | |
| #ifdef ENXIO
 | |
|         else if (errno == ENXIO) code = XML_IO_ENXIO;
 | |
| #endif
 | |
| #ifdef EPERM
 | |
|         else if (errno == EPERM) code = XML_IO_EPERM;
 | |
| #endif
 | |
| #ifdef EPIPE
 | |
|         else if (errno == EPIPE) code = XML_IO_EPIPE;
 | |
| #endif
 | |
| #ifdef ERANGE
 | |
|         else if (errno == ERANGE) code = XML_IO_ERANGE;
 | |
| #endif
 | |
| #ifdef EROFS
 | |
|         else if (errno == EROFS) code = XML_IO_EROFS;
 | |
| #endif
 | |
| #ifdef ESPIPE
 | |
|         else if (errno == ESPIPE) code = XML_IO_ESPIPE;
 | |
| #endif
 | |
| #ifdef ESRCH
 | |
|         else if (errno == ESRCH) code = XML_IO_ESRCH;
 | |
| #endif
 | |
| #ifdef ETIMEDOUT
 | |
|         else if (errno == ETIMEDOUT) code = XML_IO_ETIMEDOUT;
 | |
| #endif
 | |
| #ifdef EXDEV
 | |
|         else if (errno == EXDEV) code = XML_IO_EXDEV;
 | |
| #endif
 | |
| #ifdef ENOTSOCK
 | |
|         else if (errno == ENOTSOCK) code = XML_IO_ENOTSOCK;
 | |
| #endif
 | |
| #ifdef EISCONN
 | |
|         else if (errno == EISCONN) code = XML_IO_EISCONN;
 | |
| #endif
 | |
| #ifdef ECONNREFUSED
 | |
|         else if (errno == ECONNREFUSED) code = XML_IO_ECONNREFUSED;
 | |
| #endif
 | |
| #ifdef ETIMEDOUT
 | |
|         else if (errno == ETIMEDOUT) code = XML_IO_ETIMEDOUT;
 | |
| #endif
 | |
| #ifdef ENETUNREACH
 | |
|         else if (errno == ENETUNREACH) code = XML_IO_ENETUNREACH;
 | |
| #endif
 | |
| #ifdef EADDRINUSE
 | |
|         else if (errno == EADDRINUSE) code = XML_IO_EADDRINUSE;
 | |
| #endif
 | |
| #ifdef EINPROGRESS
 | |
|         else if (errno == EINPROGRESS) code = XML_IO_EINPROGRESS;
 | |
| #endif
 | |
| #ifdef EALREADY
 | |
|         else if (errno == EALREADY) code = XML_IO_EALREADY;
 | |
| #endif
 | |
| #ifdef EAFNOSUPPORT
 | |
|         else if (errno == EAFNOSUPPORT) code = XML_IO_EAFNOSUPPORT;
 | |
| #endif
 | |
|         else code = XML_IO_UNKNOWN;
 | |
| #endif /* HAVE_ERRNO_H */
 | |
|     }
 | |
|     idx = 0;
 | |
|     if (code >= XML_IO_UNKNOWN) idx = code - XML_IO_UNKNOWN;
 | |
|     if (idx >= (sizeof(IOerr) / sizeof(IOerr[0]))) idx = 0;
 | |
| 
 | |
|     __xmlSimpleError(domain, code, NULL, IOerr[idx], extra);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * xmlIOErr:
 | |
|  * @code:  the error number
 | |
|  * @extra:  extra informations
 | |
|  *
 | |
|  * Handle an I/O error
 | |
|  */
 | |
| static void
 | |
| xmlIOErr(int code, const char *extra)
 | |
| {
 | |
|     __xmlIOErr(XML_FROM_IO, code, extra);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * __xmlLoaderErr:
 | |
|  * @ctx: the parser context
 | |
|  * @extra:  extra informations
 | |
|  *
 | |
|  * Handle a resource access error
 | |
|  */
 | |
| void
 | |
| __xmlLoaderErr(void *ctx, const char *msg, const char *filename)
 | |
| {
 | |
|     xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
 | |
|     xmlStructuredErrorFunc schannel = NULL;
 | |
|     xmlGenericErrorFunc channel = NULL;
 | |
|     void *data = NULL;
 | |
|     xmlErrorLevel level = XML_ERR_ERROR;
 | |
| 
 | |
|     if ((ctxt != NULL) && (ctxt->disableSAX != 0) &&
 | |
|         (ctxt->instate == XML_PARSER_EOF))
 | |
| 	return;
 | |
|     if ((ctxt != NULL) && (ctxt->sax != NULL)) {
 | |
|         if (ctxt->validate) {
 | |
| 	    channel = ctxt->sax->error;
 | |
| 	    level = XML_ERR_ERROR;
 | |
| 	} else {
 | |
| 	    channel = ctxt->sax->warning;
 | |
| 	    level = XML_ERR_WARNING;
 | |
| 	}
 | |
| 	if (ctxt->sax->initialized == XML_SAX2_MAGIC)
 | |
| 	    schannel = ctxt->sax->serror;
 | |
| 	data = ctxt->userData;
 | |
|     }
 | |
|     __xmlRaiseError(schannel, channel, data, ctxt, NULL, XML_FROM_IO,
 | |
|                     XML_IO_LOAD_ERROR, level, NULL, 0,
 | |
| 		    filename, NULL, NULL, 0, 0,
 | |
| 		    msg, filename);
 | |
| 
 | |
| }
 | |
| 
 | |
| /************************************************************************
 | |
|  *									*
 | |
|  *		Tree memory error handler				*
 | |
|  *									*
 | |
|  ************************************************************************/
 | |
| /**
 | |
|  * xmlNormalizeWindowsPath:
 | |
|  * @path: the input file path
 | |
|  *
 | |
|  * This function is obsolete. Please see xmlURIFromPath in uri.c for
 | |
|  * a better solution.
 | |
|  *
 | |
|  * Returns a canonicalized version of the path
 | |
|  */
 | |
| xmlChar *
 | |
| xmlNormalizeWindowsPath(const xmlChar *path)
 | |
| {
 | |
|     return xmlCanonicPath(path);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * xmlCleanupInputCallbacks:
 | |
|  *
 | |
|  * clears the entire input callback table. this includes the
 | |
|  * compiled-in I/O.
 | |
|  */
 | |
| void
 | |
| xmlCleanupInputCallbacks(void)
 | |
| {
 | |
|     int i;
 | |
| 
 | |
|     if (!xmlInputCallbackInitialized)
 | |
|         return;
 | |
| 
 | |
|     for (i = xmlInputCallbackNr - 1; i >= 0; i--) {
 | |
|         xmlInputCallbackTable[i].matchcallback = NULL;
 | |
|         xmlInputCallbackTable[i].opencallback = NULL;
 | |
|         xmlInputCallbackTable[i].readcallback = NULL;
 | |
|         xmlInputCallbackTable[i].closecallback = NULL;
 | |
|     }
 | |
| 
 | |
|     xmlInputCallbackNr = 0;
 | |
|     xmlInputCallbackInitialized = 0;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * xmlPopInputCallbacks:
 | |
|  *
 | |
|  * Clear the top input callback from the input stack. this includes the
 | |
|  * compiled-in I/O.
 | |
|  *
 | |
|  * Returns the number of input callback registered or -1 in case of error.
 | |
|  */
 | |
| int
 | |
| xmlPopInputCallbacks(void)
 | |
| {
 | |
|     if (!xmlInputCallbackInitialized)
 | |
|         return(-1);
 | |
| 
 | |
|     if (xmlInputCallbackNr <= 0)
 | |
|         return(-1);
 | |
| 
 | |
|     xmlInputCallbackNr--;
 | |
|     xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = NULL;
 | |
|     xmlInputCallbackTable[xmlInputCallbackNr].opencallback = NULL;
 | |
|     xmlInputCallbackTable[xmlInputCallbackNr].readcallback = NULL;
 | |
|     xmlInputCallbackTable[xmlInputCallbackNr].closecallback = NULL;
 | |
| 
 | |
|     return(xmlInputCallbackNr);
 | |
| }
 | |
| 
 | |
| #ifdef LIBXML_OUTPUT_ENABLED
 | |
| /**
 | |
|  * xmlCleanupOutputCallbacks:
 | |
|  *
 | |
|  * clears the entire output callback table. this includes the
 | |
|  * compiled-in I/O callbacks.
 | |
|  */
 | |
| void
 | |
| xmlCleanupOutputCallbacks(void)
 | |
| {
 | |
|     int i;
 | |
| 
 | |
|     if (!xmlOutputCallbackInitialized)
 | |
|         return;
 | |
| 
 | |
|     for (i = xmlOutputCallbackNr - 1; i >= 0; i--) {
 | |
|         xmlOutputCallbackTable[i].matchcallback = NULL;
 | |
|         xmlOutputCallbackTable[i].opencallback = NULL;
 | |
|         xmlOutputCallbackTable[i].writecallback = NULL;
 | |
|         xmlOutputCallbackTable[i].closecallback = NULL;
 | |
|     }
 | |
| 
 | |
|     xmlOutputCallbackNr = 0;
 | |
|     xmlOutputCallbackInitialized = 0;
 | |
| }
 | |
| #endif /* LIBXML_OUTPUT_ENABLED */
 | |
| 
 | |
| /************************************************************************
 | |
|  *									*
 | |
|  *		Standard I/O for file accesses				*
 | |
|  *									*
 | |
|  ************************************************************************/
 | |
| 
 | |
| #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
 | |
| 
 | |
| /**
 | |
|  *  xmlWrapOpenUtf8:
 | |
|  * @path:  the path in utf-8 encoding
 | |
|  * @mode:  type of access (0 - read, 1 - write)
 | |
|  *
 | |
|  * function opens the file specified by @path
 | |
|  *
 | |
|  */
 | |
| static FILE*
 | |
| xmlWrapOpenUtf8(const char *path,int mode)
 | |
| {
 | |
|     FILE *fd = NULL;
 | |
|     wchar_t *wPath;
 | |
| 
 | |
|     wPath = __xmlIOWin32UTF8ToWChar(path);
 | |
|     if(wPath)
 | |
|     {
 | |
|        fd = _wfopen(wPath, mode ? L"wb" : L"rb");
 | |
|        xmlFree(wPath);
 | |
|     }
 | |
|     /* maybe path in native encoding */
 | |
|     if(fd == NULL)
 | |
|        fd = fopen(path, mode ? "wb" : "rb");
 | |
| 
 | |
|     return fd;
 | |
| }
 | |
| 
 | |
| #ifdef HAVE_ZLIB_H
 | |
| static gzFile
 | |
| xmlWrapGzOpenUtf8(const char *path, const char *mode)
 | |
| {
 | |
|     gzFile fd;
 | |
|     wchar_t *wPath;
 | |
| 
 | |
|     fd = gzopen (path, mode);
 | |
|     if (fd)
 | |
|         return fd;
 | |
| 
 | |
|     wPath = __xmlIOWin32UTF8ToWChar(path);
 | |
|     if(wPath)
 | |
|     {
 | |
| 	int d, m = (strstr(mode, "r") ? O_RDONLY : O_RDWR);
 | |
| #ifdef _O_BINARY
 | |
|         m |= (strstr(mode, "b") ? _O_BINARY : 0);
 | |
| #endif
 | |
| 	d = _wopen(wPath, m);
 | |
| 	if (d >= 0)
 | |
| 	    fd = gzdopen(d, mode);
 | |
|         xmlFree(wPath);
 | |
|     }
 | |
| 
 | |
|     return fd;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /**
 | |
|  *  xmlWrapStatUtf8:
 | |
|  * @path:  the path in utf-8 encoding
 | |
|  * @info:  structure that stores results
 | |
|  *
 | |
|  * function obtains information about the file or directory
 | |
|  *
 | |
|  */
 | |
| static int
 | |
| xmlWrapStatUtf8(const char *path,struct stat *info)
 | |
| {
 | |
| #ifdef HAVE_STAT
 | |
|     int retval = -1;
 | |
|     wchar_t *wPath;
 | |
| 
 | |
|     wPath = __xmlIOWin32UTF8ToWChar(path);
 | |
|     if (wPath)
 | |
|     {
 | |
|        retval = _wstat(wPath,info);
 | |
|        xmlFree(wPath);
 | |
|     }
 | |
|     /* maybe path in native encoding */
 | |
|     if(retval < 0)
 | |
|        retval = stat(path,info);
 | |
|     return retval;
 | |
| #else
 | |
|     return -1;
 | |
| #endif
 | |
| }
 | |
| 
 | |
| /**
 | |
|  *  xmlWrapOpenNative:
 | |
|  * @path:  the path
 | |
|  * @mode:  type of access (0 - read, 1 - write)
 | |
|  *
 | |
|  * function opens the file specified by @path
 | |
|  *
 | |
|  */
 | |
| static FILE*
 | |
| xmlWrapOpenNative(const char *path,int mode)
 | |
| {
 | |
|     return fopen(path,mode ? "wb" : "rb");
 | |
| }
 | |
| 
 | |
| /**
 | |
|  *  xmlWrapStatNative:
 | |
|  * @path:  the path
 | |
|  * @info:  structure that stores results
 | |
|  *
 | |
|  * function obtains information about the file or directory
 | |
|  *
 | |
|  */
 | |
| static int
 | |
| xmlWrapStatNative(const char *path,struct stat *info)
 | |
| {
 | |
| #ifdef HAVE_STAT
 | |
|     return stat(path,info);
 | |
| #else
 | |
|     return -1;
 | |
| #endif
 | |
| }
 | |
| 
 | |
| typedef int (* xmlWrapStatFunc) (const char *f, struct stat *s);
 | |
| static xmlWrapStatFunc xmlWrapStat = xmlWrapStatNative;
 | |
| typedef FILE* (* xmlWrapOpenFunc)(const char *f,int mode);
 | |
| static xmlWrapOpenFunc xmlWrapOpen = xmlWrapOpenNative;
 | |
| #ifdef HAVE_ZLIB_H
 | |
| typedef gzFile (* xmlWrapGzOpenFunc) (const char *f, const char *mode);
 | |
| static xmlWrapGzOpenFunc xmlWrapGzOpen = gzopen;
 | |
| #endif
 | |
| /**
 | |
|  * xmlInitPlatformSpecificIo:
 | |
|  *
 | |
|  * Initialize platform specific features.
 | |
|  */
 | |
| static void
 | |
| xmlInitPlatformSpecificIo(void)
 | |
| {
 | |
|     static int xmlPlatformIoInitialized = 0;
 | |
|     OSVERSIONINFO osvi;
 | |
| 
 | |
|     if(xmlPlatformIoInitialized)
 | |
|       return;
 | |
| 
 | |
|     osvi.dwOSVersionInfoSize = sizeof(osvi);
 | |
| 
 | |
|     if(GetVersionEx(&osvi) && (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)) {
 | |
|       xmlWrapStat = xmlWrapStatUtf8;
 | |
|       xmlWrapOpen = xmlWrapOpenUtf8;
 | |
| #ifdef HAVE_ZLIB_H
 | |
|       xmlWrapGzOpen = xmlWrapGzOpenUtf8;
 | |
| #endif
 | |
|     } else {
 | |
|       xmlWrapStat = xmlWrapStatNative;
 | |
|       xmlWrapOpen = xmlWrapOpenNative;
 | |
| #ifdef HAVE_ZLIB_H
 | |
|       xmlWrapGzOpen = gzopen;
 | |
| #endif
 | |
|     }
 | |
| 
 | |
|     xmlPlatformIoInitialized = 1;
 | |
|     return;
 | |
| }
 | |
| 
 | |
| #endif
 | |
| 
 | |
| /**
 | |
|  * xmlCheckFilename:
 | |
|  * @path:  the path to check
 | |
|  *
 | |
|  * function checks to see if @path is a valid source
 | |
|  * (file, socket...) for XML.
 | |
|  *
 | |
|  * if stat is not available on the target machine,
 | |
|  * returns 1.  if stat fails, returns 0 (if calling
 | |
|  * stat on the filename fails, it can't be right).
 | |
|  * if stat succeeds and the file is a directory,
 | |
|  * returns 2.  otherwise returns 1.
 | |
|  */
 | |
| 
 | |
| int
 | |
| xmlCheckFilename (const char *path)
 | |
| {
 | |
| #ifdef HAVE_STAT
 | |
|     struct stat stat_buffer;
 | |
| #endif
 | |
|     if (path == NULL)
 | |
| 	return(0);
 | |
| 
 | |
| #ifdef HAVE_STAT
 | |
| #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
 | |
|     /*
 | |
|      * 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 (xmlWrapStat(path, &stat_buffer) == -1)
 | |
|         return 0;
 | |
| #else
 | |
|     if (stat(path, &stat_buffer) == -1)
 | |
|         return 0;
 | |
| #endif
 | |
| #ifdef S_ISDIR
 | |
|     if (S_ISDIR(stat_buffer.st_mode))
 | |
|         return 2;
 | |
| #endif
 | |
| #endif /* HAVE_STAT */
 | |
|     return 1;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * xmlNop:
 | |
|  *
 | |
|  * No Operation function, does nothing, no input
 | |
|  *
 | |
|  * Returns zero
 | |
|  */
 | |
| int
 | |
| xmlNop(void) {
 | |
|     return(0);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * xmlFdRead:
 | |
|  * @context:  the I/O context
 | |
|  * @buffer:  where to drop data
 | |
|  * @len:  number of bytes to read
 | |
|  *
 | |
|  * Read @len bytes to @buffer from the I/O channel.
 | |
|  *
 | |
|  * Returns the number of bytes written
 | |
|  */
 | |
| static int
 | |
| xmlFdRead (void * context, char * buffer, int len) {
 | |
|     int ret;
 | |
| 
 | |
|     ret = read((int) (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 = xmlWrapOpen(path, 0);
 | |
| #else
 | |
|     fd = fopen(path, "r");
 | |
| #endif /* WIN32 */
 | |
|     if (fd == NULL) xmlIOErr(0, path);
 | |
|     return((void *) fd);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * xmlFileOpen:
 | |
|  * @filename:  the URI for matching
 | |
|  *
 | |
|  * Wrapper around xmlFileOpen_real that try it with an unescaped
 | |
|  * version of @filename, if this fails fallback to @filename
 | |
|  *
 | |
|  * Returns a handler or NULL in case or failure
 | |
|  */
 | |
| void *
 | |
| xmlFileOpen (const char *filename) {
 | |
|     char *unescaped;
 | |
|     void *retval;
 | |
| 
 | |
|     retval = xmlFileOpen_real(filename);
 | |
|     if (retval == NULL) {
 | |
| 	unescaped = xmlURIUnescapeString(filename, 0, NULL);
 | |
| 	if (unescaped != NULL) {
 | |
| 	    retval = xmlFileOpen_real(unescaped);
 | |
| 	    xmlFree(unescaped);
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|     return retval;
 | |
| }
 | |
| 
 | |
| #ifdef LIBXML_OUTPUT_ENABLED
 | |
| /**
 | |
|  * xmlFileOpenW:
 | |
|  * @filename:  the URI for matching
 | |
|  *
 | |
|  * output to from FILE *,
 | |
|  * if @filename is "-" then the standard output is used
 | |
|  *
 | |
|  * Returns an I/O context or NULL in case of error
 | |
|  */
 | |
| static void *
 | |
| xmlFileOpenW (const char *filename) {
 | |
|     const char *path = NULL;
 | |
|     FILE *fd;
 | |
| 
 | |
|     if (!strcmp(filename, "-")) {
 | |
| 	fd = stdout;
 | |
| 	return((void *) fd);
 | |
|     }
 | |
| 
 | |
|     if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
 | |
| #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
 | |
| 	path = &filename[17];
 | |
| #else
 | |
| 	path = &filename[16];
 | |
| #endif
 | |
|     else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
 | |
| #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
 | |
| 	path = &filename[8];
 | |
| #else
 | |
| 	path = &filename[7];
 | |
| #endif
 | |
|     } else
 | |
| 	path = filename;
 | |
| 
 | |
|     if (path == NULL)
 | |
| 	return(NULL);
 | |
| 
 | |
| #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
 | |
|     fd = xmlWrapOpen(path, 1);
 | |
| #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 HAVE_ZLIB_H
 | |
| /************************************************************************
 | |
|  *									*
 | |
|  *		I/O for compressed file accesses			*
 | |
|  *									*
 | |
|  ************************************************************************/
 | |
| /**
 | |
|  * xmlGzfileMatch:
 | |
|  * @filename:  the URI for matching
 | |
|  *
 | |
|  * input from compressed file test
 | |
|  *
 | |
|  * Returns 1 if matches, 0 otherwise
 | |
|  */
 | |
| static int
 | |
| xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
 | |
|     return(1);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * xmlGzfileOpen_real:
 | |
|  * @filename:  the URI for matching
 | |
|  *
 | |
|  * input from compressed file open
 | |
|  * if @filename is " " then the standard input is used
 | |
|  *
 | |
|  * Returns an I/O context or NULL in case of error
 | |
|  */
 | |
| static void *
 | |
| xmlGzfileOpen_real (const char *filename) {
 | |
|     const char *path = NULL;
 | |
|     gzFile fd;
 | |
| 
 | |
|     if (!strcmp(filename, "-")) {
 | |
|         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 = xmlWrapGzOpen(path, "rb");
 | |
| #else
 | |
|     fd = gzopen(path, "rb");
 | |
| #endif
 | |
|     return((void *) fd);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * xmlGzfileOpen:
 | |
|  * @filename:  the URI for matching
 | |
|  *
 | |
|  * Wrapper around xmlGzfileOpen if the open fais, it will
 | |
|  * try to unescape @filename
 | |
|  */
 | |
| static void *
 | |
| xmlGzfileOpen (const char *filename) {
 | |
|     char *unescaped;
 | |
|     void *retval;
 | |
| 
 | |
|     retval = xmlGzfileOpen_real(filename);
 | |
|     if (retval == NULL) {
 | |
| 	unescaped = xmlURIUnescapeString(filename, 0, NULL);
 | |
| 	if (unescaped != NULL) {
 | |
| 	    retval = xmlGzfileOpen_real(unescaped);
 | |
| 	}
 | |
| 	xmlFree(unescaped);
 | |
|     }
 | |
|     return retval;
 | |
| }
 | |
| 
 | |
| #ifdef LIBXML_OUTPUT_ENABLED
 | |
| /**
 | |
|  * xmlGzfileOpenW:
 | |
|  * @filename:  the URI for matching
 | |
|  * @compression:  the compression factor (0 - 9 included)
 | |
|  *
 | |
|  * input from compressed file open
 | |
|  * if @filename is " " then the standard input is used
 | |
|  *
 | |
|  * Returns an I/O context or NULL in case of error
 | |
|  */
 | |
| static void *
 | |
| xmlGzfileOpenW (const char *filename, int compression) {
 | |
|     const char *path = NULL;
 | |
|     char mode[15];
 | |
|     gzFile fd;
 | |
| 
 | |
|     snprintf(mode, sizeof(mode), "wb%d", compression);
 | |
|     if (!strcmp(filename, "-")) {
 | |
|         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 = xmlWrapGzOpen(path, mode);
 | |
| #else
 | |
|     fd = gzopen(path, mode);
 | |
| #endif
 | |
|     return((void *) fd);
 | |
| }
 | |
| #endif /* LIBXML_OUTPUT_ENABLED */
 | |
| 
 | |
| /**
 | |
|  * xmlGzfileRead:
 | |
|  * @context:  the I/O context
 | |
|  * @buffer:  where to drop data
 | |
|  * @len:  number of bytes to write
 | |
|  *
 | |
|  * Read @len bytes to @buffer from the compressed I/O channel.
 | |
|  *
 | |
|  * Returns the number of bytes 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 /* HAVE_ZLIB_H */
 | |
| 
 | |
| #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 HAVE_ZLIB_H
 | |
| 
 | |
| #define DFLT_WBITS		( -15 )
 | |
| #define DFLT_MEM_LVL		( 8 )
 | |
| #define GZ_MAGIC1		( 0x1f )
 | |
| #define GZ_MAGIC2		( 0x8b )
 | |
| #define LXML_ZLIB_OS_CODE	( 0x03 )
 | |
| #define INIT_HTTP_BUFF_SIZE	( 32768 )
 | |
| #define DFLT_ZLIB_RATIO		( 5 )
 | |
| 
 | |
| /*
 | |
| **  Data structure and functions to work with sending compressed data
 | |
| **  via HTTP.
 | |
| */
 | |
| 
 | |
| typedef struct xmlZMemBuff_
 | |
| {
 | |
|    unsigned long	size;
 | |
|    unsigned long	crc;
 | |
| 
 | |
|    unsigned char *	zbuff;
 | |
|    z_stream		zctrl;
 | |
| 
 | |
| } xmlZMemBuff, *xmlZMemBuffPtr;
 | |
| 
 | |
| /**
 | |
|  * append_reverse_ulong
 | |
|  * @buff:  Compressed memory buffer
 | |
|  * @data:  Unsigned long to append
 | |
|  *
 | |
|  * Append a unsigned long in reverse byte order to the end of the
 | |
|  * memory buffer.
 | |
|  */
 | |
| static void
 | |
| append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) {
 | |
| 
 | |
|     int		idx;
 | |
| 
 | |
|     if ( buff == NULL )
 | |
| 	return;
 | |
| 
 | |
|     /*
 | |
|     **  This is plagiarized from putLong in gzio.c (zlib source) where
 | |
|     **  the number "4" is hardcoded.  If zlib is ever patched to
 | |
|     **  support 64 bit file sizes, this code would need to be patched
 | |
|     **  as well.
 | |
|     */
 | |
| 
 | |
|     for ( idx = 0; idx < 4; idx++ ) {
 | |
| 	*buff->zctrl.next_out = ( data & 0xff );
 | |
| 	data >>= 8;
 | |
| 	buff->zctrl.next_out++;
 | |
|     }
 | |
| 
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  *
 | |
|  * xmlFreeZMemBuff
 | |
|  * @buff:  The memory buffer context to clear
 | |
|  *
 | |
|  * Release all the resources associated with the compressed memory buffer.
 | |
|  */
 | |
| static void
 | |
| xmlFreeZMemBuff( xmlZMemBuffPtr buff ) {
 | |
| 
 | |
| #ifdef DEBUG_HTTP
 | |
|     int z_err;
 | |
| #endif
 | |
| 
 | |
|     if ( buff == NULL )
 | |
| 	return;
 | |
| 
 | |
|     xmlFree( buff->zbuff );
 | |
| #ifdef DEBUG_HTTP
 | |
|     z_err = deflateEnd( &buff->zctrl );
 | |
|     if ( z_err != Z_OK )
 | |
| 	xmlGenericError( xmlGenericErrorContext,
 | |
| 			"xmlFreeZMemBuff:  Error releasing zlib context:  %d\n",
 | |
| 			z_err );
 | |
| #else
 | |
|     deflateEnd( &buff->zctrl );
 | |
| #endif
 | |
| 
 | |
|     xmlFree( buff );
 | |
|     return;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * xmlCreateZMemBuff
 | |
|  *@compression:	Compression value to use
 | |
|  *
 | |
|  * Create a memory buffer to hold the compressed XML document.  The
 | |
|  * compressed document in memory will end up being identical to what
 | |
|  * would be created if gzopen/gzwrite/gzclose were being used to
 | |
|  * write the document to disk.  The code for the header/trailer data to
 | |
|  * the compression is plagiarized from the zlib source files.
 | |
|  */
 | |
| static void *
 | |
| xmlCreateZMemBuff( int compression ) {
 | |
| 
 | |
|     int			z_err;
 | |
|     int			hdr_lgth;
 | |
|     xmlZMemBuffPtr	buff = NULL;
 | |
| 
 | |
|     if ( ( compression < 1 ) || ( compression > 9 ) )
 | |
| 	return ( NULL );
 | |
| 
 | |
|     /*  Create the control and data areas  */
 | |
| 
 | |
|     buff = xmlMalloc( sizeof( xmlZMemBuff ) );
 | |
|     if ( buff == NULL ) {
 | |
| 	xmlIOErrMemory("creating buffer context");
 | |
| 	return ( NULL );
 | |
|     }
 | |
| 
 | |
|     (void)memset( buff, 0, sizeof( xmlZMemBuff ) );
 | |
|     buff->size = INIT_HTTP_BUFF_SIZE;
 | |
|     buff->zbuff = xmlMalloc( buff->size );
 | |
|     if ( buff->zbuff == NULL ) {
 | |
| 	xmlFreeZMemBuff( buff );
 | |
| 	xmlIOErrMemory("creating buffer");
 | |
| 	return ( NULL );
 | |
|     }
 | |
| 
 | |
|     z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
 | |
| 			    DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
 | |
|     if ( z_err != Z_OK ) {
 | |
| 	xmlChar msg[500];
 | |
| 	xmlFreeZMemBuff( buff );
 | |
| 	buff = NULL;
 | |
| 	xmlStrPrintf(msg, 500,
 | |
| 		    "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  /*  HAVE_ZLIB_H  */
 | |
| 
 | |
| #ifdef LIBXML_OUTPUT_ENABLED
 | |
| /**
 | |
|  * xmlFreeHTTPWriteCtxt
 | |
|  * @ctxt:  Context to cleanup
 | |
|  *
 | |
|  * Free allocated memory and reclaim system resources.
 | |
|  *
 | |
|  * No return value.
 | |
|  */
 | |
| static void
 | |
| xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt )
 | |
| {
 | |
|     if ( ctxt->uri != NULL )
 | |
| 	xmlFree( ctxt->uri );
 | |
| 
 | |
|     if ( ctxt->doc_buff != NULL ) {
 | |
| 
 | |
| #ifdef HAVE_ZLIB_H
 | |
| 	if ( ctxt->compression > 0 ) {
 | |
| 	    xmlFreeZMemBuff( ctxt->doc_buff );
 | |
| 	}
 | |
| 	else
 | |
| #endif
 | |
| 	{
 | |
| 	    xmlOutputBufferClose( ctxt->doc_buff );
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|     xmlFree( ctxt );
 | |
|     return;
 | |
| }
 | |
| #endif /* LIBXML_OUTPUT_ENABLED */
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * xmlIOHTTPMatch:
 | |
|  * @filename:  the URI for matching
 | |
|  *
 | |
|  * check if the URI matches an HTTP one
 | |
|  *
 | |
|  * Returns 1 if matches, 0 otherwise
 | |
|  */
 | |
| int
 | |
| xmlIOHTTPMatch (const char *filename) {
 | |
|     if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "http://", 7))
 | |
| 	return(1);
 | |
|     return(0);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * xmlIOHTTPOpen:
 | |
|  * @filename:  the URI for matching
 | |
|  *
 | |
|  * open an HTTP I/O channel
 | |
|  *
 | |
|  * Returns an I/O context or NULL in case of error
 | |
|  */
 | |
| void *
 | |
| xmlIOHTTPOpen (const char *filename) {
 | |
|     return(xmlNanoHTTPOpen(filename, NULL));
 | |
| }
 | |
| 
 | |
| #ifdef LIBXML_OUTPUT_ENABLED
 | |
| /**
 | |
|  * xmlIOHTTPOpenW:
 | |
|  * @post_uri:  The destination URI for the document
 | |
|  * @compression:  The compression desired for the document.
 | |
|  *
 | |
|  * Open a temporary buffer to collect the document for a subsequent HTTP POST
 | |
|  * request.  Non-static as is called from the output buffer creation routine.
 | |
|  *
 | |
|  * Returns an I/O context or NULL in case of error.
 | |
|  */
 | |
| 
 | |
| void *
 | |
| xmlIOHTTPOpenW(const char *post_uri, int compression 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 HAVE_ZLIB_H
 | |
|     if ((compression > 0) && (compression <= 9)) {
 | |
| 
 | |
|         ctxt->compression = compression;
 | |
|         ctxt->doc_buff = xmlCreateZMemBuff(compression);
 | |
|     } else
 | |
| #endif
 | |
|     {
 | |
|         /*  Any character conversions should have been done before this  */
 | |
| 
 | |
|         ctxt->doc_buff = xmlAllocOutputBufferInternal(NULL);
 | |
|     }
 | |
| 
 | |
|     if (ctxt->doc_buff == NULL) {
 | |
|         xmlFreeHTTPWriteCtxt(ctxt);
 | |
|         ctxt = NULL;
 | |
|     }
 | |
| 
 | |
|     return (ctxt);
 | |
| }
 | |
| #endif /* LIBXML_OUTPUT_ENABLED */
 | |
| 
 | |
| #ifdef LIBXML_OUTPUT_ENABLED
 | |
| /**
 | |
|  * xmlIOHTTPDfltOpenW
 | |
|  * @post_uri:  The destination URI for this document.
 | |
|  *
 | |
|  * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
 | |
|  * HTTP post command.  This function should generally not be used as
 | |
|  * the open callback is short circuited in xmlOutputBufferCreateFile.
 | |
|  *
 | |
|  * Returns a pointer to the new IO context.
 | |
|  */
 | |
| static void *
 | |
| xmlIOHTTPDfltOpenW( const char * post_uri ) {
 | |
|     return ( xmlIOHTTPOpenW( post_uri, 0 ) );
 | |
| }
 | |
| #endif /* LIBXML_OUTPUT_ENABLED */
 | |
| 
 | |
| /**
 | |
|  * xmlIOHTTPRead:
 | |
|  * @context:  the I/O context
 | |
|  * @buffer:  where to drop data
 | |
|  * @len:  number of bytes to write
 | |
|  *
 | |
|  * Read @len bytes to @buffer from the I/O channel.
 | |
|  *
 | |
|  * Returns the number of bytes written
 | |
|  */
 | |
| int
 | |
| xmlIOHTTPRead(void * context, char * buffer, int len) {
 | |
|     if ((buffer == NULL) || (len < 0)) return(-1);
 | |
|     return(xmlNanoHTTPRead(context, &buffer[0], len));
 | |
| }
 | |
| 
 | |
| #ifdef LIBXML_OUTPUT_ENABLED
 | |
| /**
 | |
|  * xmlIOHTTPWrite
 | |
|  * @context:  previously opened writing context
 | |
|  * @buffer:   data to output to temporary buffer
 | |
|  * @len:      bytes to output
 | |
|  *
 | |
|  * Collect data from memory buffer into a temporary file for later
 | |
|  * processing.
 | |
|  *
 | |
|  * Returns number of bytes written.
 | |
|  */
 | |
| 
 | |
| static int
 | |
| xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
 | |
| 
 | |
|     xmlIOHTTPWriteCtxtPtr	ctxt = context;
 | |
| 
 | |
|     if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
 | |
| 	return ( -1 );
 | |
| 
 | |
|     if ( len > 0 ) {
 | |
| 
 | |
| 	/*  Use gzwrite or fwrite as previously setup in the open call  */
 | |
| 
 | |
| #ifdef HAVE_ZLIB_H
 | |
| 	if ( ctxt->compression > 0 )
 | |
| 	    len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len );
 | |
| 
 | |
| 	else
 | |
| #endif
 | |
| 	    len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
 | |
| 
 | |
| 	if ( len < 0 ) {
 | |
| 	    xmlChar msg[500];
 | |
| 	    xmlStrPrintf(msg, 500,
 | |
| 			"xmlIOHTTPWrite:  %s\n%s '%s'.\n",
 | |
| 			"Error appending to internal buffer.",
 | |
| 			"Error sending document to URI",
 | |
| 			ctxt->uri );
 | |
| 	    xmlIOErr(XML_IO_WRITE, (const char *) msg);
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|     return ( len );
 | |
| }
 | |
| #endif /* LIBXML_OUTPUT_ENABLED */
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * xmlIOHTTPClose:
 | |
|  * @context:  the I/O context
 | |
|  *
 | |
|  * Close an HTTP I/O channel
 | |
|  *
 | |
|  * Returns 0
 | |
|  */
 | |
| int
 | |
| xmlIOHTTPClose (void * context) {
 | |
|     xmlNanoHTTPClose(context);
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| #ifdef LIBXML_OUTPUT_ENABLED
 | |
| /**
 | |
|  * xmlIOHTTCloseWrite
 | |
|  * @context:  The I/O context
 | |
|  * @http_mthd: The HTTP method to be used when sending the data
 | |
|  *
 | |
|  * Close the transmit HTTP I/O channel and actually send the data.
 | |
|  */
 | |
| static int
 | |
| xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
 | |
| 
 | |
|     int				close_rc = -1;
 | |
|     int				http_rtn = 0;
 | |
|     int				content_lgth = 0;
 | |
|     xmlIOHTTPWriteCtxtPtr	ctxt = context;
 | |
| 
 | |
|     char *			http_content = NULL;
 | |
|     char *			content_encoding = NULL;
 | |
|     char *			content_type = (char *) "text/xml";
 | |
|     void *			http_ctxt = NULL;
 | |
| 
 | |
|     if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
 | |
| 	return ( -1 );
 | |
| 
 | |
|     /*  Retrieve the content from the appropriate buffer  */
 | |
| 
 | |
| #ifdef HAVE_ZLIB_H
 | |
| 
 | |
|     if ( ctxt->compression > 0 ) {
 | |
| 	content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
 | |
| 	content_encoding = (char *) "Content-Encoding: gzip";
 | |
|     }
 | |
|     else
 | |
| #endif
 | |
|     {
 | |
| 	/*  Pull the data out of the memory output buffer  */
 | |
| 
 | |
| 	xmlOutputBufferPtr	dctxt = ctxt->doc_buff;
 | |
| 	http_content = (char *) 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;
 | |
| 
 | |
| #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
 | |
|     xmlInitPlatformSpecificIo();
 | |
| #endif
 | |
| 
 | |
|     xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
 | |
| 	                      xmlFileRead, xmlFileClose);
 | |
| #ifdef HAVE_ZLIB_H
 | |
|     xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
 | |
| 	                      xmlGzfileRead, xmlGzfileClose);
 | |
| #endif /* HAVE_ZLIB_H */
 | |
| #ifdef LIBXML_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;
 | |
| 
 | |
| #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
 | |
|     xmlInitPlatformSpecificIo();
 | |
| #endif
 | |
| 
 | |
|     xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
 | |
| 	                      xmlFileWrite, xmlFileClose);
 | |
| 
 | |
| #ifdef LIBXML_HTTP_ENABLED
 | |
|     xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
 | |
| 	                       xmlIOHTTPWrite, xmlIOHTTPClosePut);
 | |
| #endif
 | |
| 
 | |
| /*********************************
 | |
|  No way a-priori to distinguish between gzipped files from
 | |
|  uncompressed ones except opening if existing then closing
 | |
|  and saving with same compression ratio ... a pain.
 | |
| 
 | |
| #ifdef HAVE_ZLIB_H
 | |
|     xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
 | |
| 	                       xmlGzfileWrite, xmlGzfileClose);
 | |
| #endif
 | |
| 
 | |
|  Nor FTP PUT ....
 | |
| #ifdef LIBXML_FTP_ENABLED
 | |
|     xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
 | |
| 	                       xmlIOFTPWrite, xmlIOFTPClose);
 | |
| #endif
 | |
|  **********************************/
 | |
|     xmlOutputCallbackInitialized = 1;
 | |
| }
 | |
| 
 | |
| #ifdef LIBXML_HTTP_ENABLED
 | |
| /**
 | |
|  * xmlRegisterHTTPPostCallbacks:
 | |
|  *
 | |
|  * By default, libxml submits HTTP output requests using the "PUT" method.
 | |
|  * Calling this method changes the HTTP output method to use the "POST"
 | |
|  * method instead.
 | |
|  *
 | |
|  */
 | |
| void
 | |
| xmlRegisterHTTPPostCallbacks( void ) {
 | |
| 
 | |
|     /*  Register defaults if not done previously  */
 | |
| 
 | |
|     if ( xmlOutputCallbackInitialized == 0 )
 | |
| 	xmlRegisterDefaultOutputCallbacks( );
 | |
| 
 | |
|     xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
 | |
| 	                       xmlIOHTTPWrite, xmlIOHTTPClosePost);
 | |
|     return;
 | |
| }
 | |
| #endif
 | |
| #endif /* LIBXML_OUTPUT_ENABLED */
 | |
| 
 | |
| /**
 | |
|  * xmlAllocParserInputBuffer:
 | |
|  * @enc:  the charset encoding if known
 | |
|  *
 | |
|  * Create a buffered parser input for progressive parsing
 | |
|  *
 | |
|  * Returns the new parser input or NULL
 | |
|  */
 | |
| xmlParserInputBufferPtr
 | |
| xmlAllocParserInputBuffer(xmlCharEncoding enc) {
 | |
|     xmlParserInputBufferPtr ret;
 | |
| 
 | |
|     ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
 | |
|     if (ret == NULL) {
 | |
| 	xmlIOErrMemory("creating input buffer");
 | |
| 	return(NULL);
 | |
|     }
 | |
|     memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
 | |
|     ret->buffer = 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) {
 | |
| 	    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) {
 | |
| 	    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 HAVE_ZLIB_H
 | |
| 	if ((xmlInputCallbackTable[i].opencallback == xmlGzfileOpen) &&
 | |
| 		(strcmp(URI, "-") != 0)) {
 | |
| #if defined(ZLIB_VERNUM) && ZLIB_VERNUM >= 0x1230
 | |
|             ret->compressed = !gzdirect(context);
 | |
| #else
 | |
| 	    if (((z_stream *)context)->avail_in > 4) {
 | |
| 	        char *cptr, buff4[4];
 | |
| 		cptr = (char *) ((z_stream *)context)->next_in;
 | |
| 		if (gzread(context, buff4, 4) == 4) {
 | |
| 		    if (strncmp(buff4, cptr, 4) == 0)
 | |
| 		        ret->compressed = 0;
 | |
| 		    else
 | |
| 		        ret->compressed = 1;
 | |
| 		    gzrewind(context);
 | |
| 		}
 | |
| 	    }
 | |
| #endif
 | |
| 	}
 | |
| #endif
 | |
| #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 HAVE_ZLIB_H
 | |
|     int is_file_uri = 1;
 | |
| #endif
 | |
| 
 | |
|     if (xmlOutputCallbackInitialized == 0)
 | |
| 	xmlRegisterDefaultOutputCallbacks();
 | |
| 
 | |
|     if (URI == NULL) return(NULL);
 | |
| 
 | |
|     puri = xmlParseURI(URI);
 | |
|     if (puri != NULL) {
 | |
| #ifdef HAVE_ZLIB_H
 | |
|         if ((puri->scheme != NULL) &&
 | |
| 	    (!xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
 | |
| 	    is_file_uri = 0;
 | |
| #endif
 | |
| 	/*
 | |
| 	 * try to limit the damages of the URI unescaping code.
 | |
| 	 */
 | |
| 	if ((puri->scheme == NULL) ||
 | |
| 	    (xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
 | |
| 	    unescaped = xmlURIUnescapeString(URI, 0, NULL);
 | |
| 	xmlFreeURI(puri);
 | |
|     }
 | |
| 
 | |
|     /*
 | |
|      * Try to find one of the output accept method accepting that scheme
 | |
|      * Go in reverse to give precedence to user defined handlers.
 | |
|      * try with an unescaped version of the URI
 | |
|      */
 | |
|     if (unescaped != NULL) {
 | |
| #ifdef HAVE_ZLIB_H
 | |
| 	if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
 | |
| 	    context = xmlGzfileOpenW(unescaped, compression);
 | |
| 	    if (context != NULL) {
 | |
| 		ret = xmlAllocOutputBufferInternal(encoder);
 | |
| 		if (ret != NULL) {
 | |
| 		    ret->context = context;
 | |
| 		    ret->writecallback = xmlGzfileWrite;
 | |
| 		    ret->closecallback = xmlGzfileClose;
 | |
| 		}
 | |
| 		xmlFree(unescaped);
 | |
| 		return(ret);
 | |
| 	    }
 | |
| 	}
 | |
| #endif
 | |
| 	for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
 | |
| 	    if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
 | |
| 		(xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
 | |
| #if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
 | |
| 		/*  Need to pass compression parameter into HTTP open calls  */
 | |
| 		if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
 | |
| 		    context = xmlIOHTTPOpenW(unescaped, compression);
 | |
| 		else
 | |
| #endif
 | |
| 		    context = xmlOutputCallbackTable[i].opencallback(unescaped);
 | |
| 		if (context != NULL)
 | |
| 		    break;
 | |
| 	    }
 | |
| 	}
 | |
| 	xmlFree(unescaped);
 | |
|     }
 | |
| 
 | |
|     /*
 | |
|      * If this failed try with a non-escaped URI this may be a strange
 | |
|      * filename
 | |
|      */
 | |
|     if (context == NULL) {
 | |
| #ifdef HAVE_ZLIB_H
 | |
| 	if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
 | |
| 	    context = xmlGzfileOpenW(URI, compression);
 | |
| 	    if (context != NULL) {
 | |
| 		ret = xmlAllocOutputBufferInternal(encoder);
 | |
| 		if (ret != NULL) {
 | |
| 		    ret->context = context;
 | |
| 		    ret->writecallback = xmlGzfileWrite;
 | |
| 		    ret->closecallback = xmlGzfileClose;
 | |
| 		}
 | |
| 		return(ret);
 | |
| 	    }
 | |
| 	}
 | |
| #endif
 | |
| 	for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
 | |
| 	    if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
 | |
| 		(xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
 | |
| #if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
 | |
| 		/*  Need to pass compression parameter into HTTP open calls  */
 | |
| 		if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
 | |
| 		    context = xmlIOHTTPOpenW(URI, compression);
 | |
| 		else
 | |
| #endif
 | |
| 		    context = xmlOutputCallbackTable[i].opencallback(URI);
 | |
| 		if (context != NULL)
 | |
| 		    break;
 | |
| 	    }
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|     if (context == NULL) {
 | |
| 	return(NULL);
 | |
|     }
 | |
| 
 | |
|     /*
 | |
|      * Allocate the Output buffer front-end.
 | |
|      */
 | |
|     ret = xmlAllocOutputBufferInternal(encoder);
 | |
|     if (ret != NULL) {
 | |
| 	ret->context = context;
 | |
| 	ret->writecallback = xmlOutputCallbackTable[i].writecallback;
 | |
| 	ret->closecallback = xmlOutputCallbackTable[i].closecallback;
 | |
|     }
 | |
|     return(ret);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * xmlOutputBufferCreateFilename:
 | |
|  * @URI:  a C string containing the URI or filename
 | |
|  * @encoder:  the encoding converter or NULL
 | |
|  * @compression:  the compression ration (0 none, 9 max).
 | |
|  *
 | |
|  * Create a buffered  output for the progressive saving of a file
 | |
|  * If filename is "-' then we use stdout as the output.
 | |
|  * Automatic support for ZLIB/Compress compressed document is provided
 | |
|  * by default if found at compile-time.
 | |
|  * TODO: currently if compression is set, the library only support
 | |
|  *       writing to a local file.
 | |
|  *
 | |
|  * Returns the new output or NULL
 | |
|  */
 | |
| xmlOutputBufferPtr
 | |
| xmlOutputBufferCreateFilename(const char *URI,
 | |
|                               xmlCharEncodingHandlerPtr encoder,
 | |
|                               int compression ATTRIBUTE_UNUSED) {
 | |
|     if ((xmlOutputBufferCreateFilenameValue)) {
 | |
| 		return xmlOutputBufferCreateFilenameValue(URI, encoder, compression);
 | |
| 	}
 | |
| 	return __xmlOutputBufferCreateFilename(URI, encoder, compression);
 | |
| }
 | |
| #endif /* LIBXML_OUTPUT_ENABLED */
 | |
| 
 | |
| /**
 | |
|  * xmlParserInputBufferCreateFile:
 | |
|  * @file:  a FILE*
 | |
|  * @enc:  the charset encoding if known
 | |
|  *
 | |
|  * Create a buffered parser input for the progressive parsing of a FILE *
 | |
|  * buffered C I/O
 | |
|  *
 | |
|  * Returns the new parser input or NULL
 | |
|  */
 | |
| xmlParserInputBufferPtr
 | |
| xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
 | |
|     xmlParserInputBufferPtr ret;
 | |
| 
 | |
|     if (xmlInputCallbackInitialized == 0)
 | |
| 	xmlRegisterDefaultInputCallbacks();
 | |
| 
 | |
|     if (file == NULL) return(NULL);
 | |
| 
 | |
|     ret = xmlAllocParserInputBuffer(enc);
 | |
|     if (ret != NULL) {
 | |
|         ret->context = file;
 | |
| 	ret->readcallback = xmlFileRead;
 | |
| 	ret->closecallback = xmlFileFlush;
 | |
|     }
 | |
| 
 | |
|     return(ret);
 | |
| }
 | |
| 
 | |
| #ifdef LIBXML_OUTPUT_ENABLED
 | |
| /**
 | |
|  * xmlOutputBufferCreateFile:
 | |
|  * @file:  a FILE*
 | |
|  * @encoder:  the encoding converter or NULL
 | |
|  *
 | |
|  * Create a buffered output for the progressive saving to a FILE *
 | |
|  * buffered C I/O
 | |
|  *
 | |
|  * Returns the new parser output or NULL
 | |
|  */
 | |
| xmlOutputBufferPtr
 | |
| xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
 | |
|     xmlOutputBufferPtr ret;
 | |
| 
 | |
|     if (xmlOutputCallbackInitialized == 0)
 | |
| 	xmlRegisterDefaultOutputCallbacks();
 | |
| 
 | |
|     if (file == NULL) return(NULL);
 | |
| 
 | |
|     ret = xmlAllocOutputBufferInternal(encoder);
 | |
|     if (ret != NULL) {
 | |
|         ret->context = file;
 | |
| 	ret->writecallback = xmlFileWrite;
 | |
| 	ret->closecallback = xmlFileFlush;
 | |
|     }
 | |
| 
 | |
|     return(ret);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * xmlOutputBufferCreateBuffer:
 | |
|  * @buffer:  a xmlBufferPtr
 | |
|  * @encoder:  the encoding converter or NULL
 | |
|  *
 | |
|  * Create a buffered output for the progressive saving to a xmlBuffer
 | |
|  *
 | |
|  * Returns the new parser output or NULL
 | |
|  */
 | |
| xmlOutputBufferPtr
 | |
| xmlOutputBufferCreateBuffer(xmlBufferPtr buffer,
 | |
|                             xmlCharEncodingHandlerPtr encoder) {
 | |
|     xmlOutputBufferPtr ret;
 | |
| 
 | |
|     if (buffer == NULL) return(NULL);
 | |
| 
 | |
|     ret = xmlOutputBufferCreateIO((xmlOutputWriteCallback)
 | |
|                                   xmlBufferWrite,
 | |
|                                   (xmlOutputCloseCallback)
 | |
|                                   NULL, (void *) buffer, encoder);
 | |
| 
 | |
|     return(ret);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * 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 = (xmlInputReadCallback) xmlNop;
 | |
| 	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 curreent processed from buf */
 | |
| 
 | |
|     if ((out == NULL) || (out->error)) return(-1);
 | |
|     if (len < 0) return(0);
 | |
|     if (out->error) return(-1);
 | |
| 
 | |
|     do {
 | |
| 	chunk = len;
 | |
| 	if (chunk > 4 * MINLEN)
 | |
| 	    chunk = 4 * MINLEN;
 | |
| 
 | |
| 	/*
 | |
| 	 * first handle encoding stuff.
 | |
| 	 */
 | |
| 	if (out->encoder != NULL) {
 | |
| 	    /*
 | |
| 	     * Store the data in the incoming raw buffer
 | |
| 	     */
 | |
| 	    if (out->conv == NULL) {
 | |
| 		out->conv = 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);
 | |
| 	    }
 | |
| 	    nbchars = xmlBufUse(out->conv);
 | |
| 	} else {
 | |
| 	    ret = xmlBufAdd(out->buffer, (const xmlChar *) buf, chunk);
 | |
| 	    if (ret != 0)
 | |
| 	        return(-1);
 | |
| 	    nbchars = xmlBufUse(out->buffer);
 | |
| 	}
 | |
| 	buf += chunk;
 | |
| 	len -= chunk;
 | |
| 
 | |
| 	if ((nbchars < MINLEN) && (len <= 0))
 | |
| 	    goto done;
 | |
| 
 | |
| 	if (out->writecallback) {
 | |
| 	    /*
 | |
| 	     * second write the stuff to the I/O channel
 | |
| 	     */
 | |
| 	    if (out->encoder != NULL) {
 | |
| 		ret = out->writecallback(out->context,
 | |
|                            (const char *)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);
 | |
| 	    }
 | |
| 	    out->written += ret;
 | |
| 	}
 | |
| 	written += nbchars;
 | |
|     } while (len > 0);
 | |
| 
 | |
| done:
 | |
| #ifdef DEBUG_INPUT
 | |
|     xmlGenericError(xmlGenericErrorContext,
 | |
| 	    "I/O: wrote %d chars\n", written);
 | |
| #endif
 | |
|     return(written);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * xmlEscapeContent:
 | |
|  * @out:  a pointer to an array of bytes to store the result
 | |
|  * @outlen:  the length of @out
 | |
|  * @in:  a pointer to an array of unescaped UTF-8 bytes
 | |
|  * @inlen:  the length of @in
 | |
|  *
 | |
|  * Take a block of UTF-8 chars in and escape them.
 | |
|  * Returns 0 if success, or -1 otherwise
 | |
|  * The value of @inlen after return is the number of octets consumed
 | |
|  *     if the return value is positive, else unpredictable.
 | |
|  * The value of @outlen after return is the number of octets consumed.
 | |
|  */
 | |
| static int
 | |
| xmlEscapeContent(unsigned char* out, int *outlen,
 | |
|                  const xmlChar* in, int *inlen) {
 | |
|     unsigned char* outstart = out;
 | |
|     const unsigned char* base = in;
 | |
|     unsigned char* outend = out + *outlen;
 | |
|     const unsigned char* inend;
 | |
| 
 | |
|     inend = in + (*inlen);
 | |
| 
 | |
|     while ((in < inend) && (out < outend)) {
 | |
| 	if (*in == '<') {
 | |
| 	    if (outend - out < 4) break;
 | |
| 	    *out++ = '&';
 | |
| 	    *out++ = 'l';
 | |
| 	    *out++ = 't';
 | |
| 	    *out++ = ';';
 | |
| 	} else if (*in == '>') {
 | |
| 	    if (outend - out < 4) break;
 | |
| 	    *out++ = '&';
 | |
| 	    *out++ = 'g';
 | |
| 	    *out++ = 't';
 | |
| 	    *out++ = ';';
 | |
| 	} else if (*in == '&') {
 | |
| 	    if (outend - out < 5) break;
 | |
| 	    *out++ = '&';
 | |
| 	    *out++ = 'a';
 | |
| 	    *out++ = 'm';
 | |
| 	    *out++ = 'p';
 | |
| 	    *out++ = ';';
 | |
| 	} else if (*in == '\r') {
 | |
| 	    if (outend - out < 5) break;
 | |
| 	    *out++ = '&';
 | |
| 	    *out++ = '#';
 | |
| 	    *out++ = '1';
 | |
| 	    *out++ = '3';
 | |
| 	    *out++ = ';';
 | |
| 	} else {
 | |
| 	    *out++ = (unsigned char) *in;
 | |
| 	}
 | |
| 	++in;
 | |
|     }
 | |
|     *outlen = out - outstart;
 | |
|     *inlen = in - base;
 | |
|     return(0);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * xmlOutputBufferWriteEscape:
 | |
|  * @out:  a buffered parser output
 | |
|  * @str:  a zero terminated UTF-8 string
 | |
|  * @escaping:  an optional escaping function (or NULL)
 | |
|  *
 | |
|  * Write the content of the string in the output I/O buffer
 | |
|  * This routine escapes the caracters and then handle the I18N
 | |
|  * transcoding from internal UTF-8
 | |
|  * The buffer is lossless, i.e. will store in case of partial
 | |
|  * or delayed writes.
 | |
|  *
 | |
|  * Returns the number of chars immediately written, or -1
 | |
|  *         in case of error.
 | |
|  */
 | |
| int
 | |
| xmlOutputBufferWriteEscape(xmlOutputBufferPtr out, const xmlChar *str,
 | |
|                            xmlCharEncodingOutputFunc escaping) {
 | |
|     int nbchars = 0; /* number of chars to output to I/O */
 | |
|     int ret;         /* return from function call */
 | |
|     int written = 0; /* number of char written to I/O so far */
 | |
|     int oldwritten=0;/* loop guard */
 | |
|     int chunk;       /* number of byte currently processed from str */
 | |
|     int len;         /* number of bytes in str */
 | |
|     int cons;        /* byte from str consumed */
 | |
| 
 | |
|     if ((out == NULL) || (out->error) || (str == NULL) ||
 | |
|         (out->buffer == NULL) ||
 | |
| 	(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);
 | |
| 	    }
 | |
| 	    nbchars = xmlBufUse(out->conv);
 | |
| 	} else {
 | |
| 	    ret = escaping(xmlBufEnd(out->buffer), &chunk, str, &cons);
 | |
| 	    if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
 | |
| 	        return(-1);
 | |
|             xmlBufAddLen(out->buffer, chunk);
 | |
| 	    nbchars = xmlBufUse(out->buffer);
 | |
| 	}
 | |
| 	str += cons;
 | |
| 	len -= cons;
 | |
| 
 | |
| 	if ((nbchars < MINLEN) && (len <= 0))
 | |
| 	    goto done;
 | |
| 
 | |
| 	if (out->writecallback) {
 | |
| 	    /*
 | |
| 	     * second write the stuff to the I/O channel
 | |
| 	     */
 | |
| 	    if (out->encoder != NULL) {
 | |
| 		ret = out->writecallback(out->context,
 | |
|                            (const char *)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);
 | |
| 	    }
 | |
| 	    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);
 | |
|     }
 | |
|     out->written += ret;
 | |
| 
 | |
| #ifdef DEBUG_INPUT
 | |
|     xmlGenericError(xmlGenericErrorContext,
 | |
| 	    "I/O: flushed %d chars\n", ret);
 | |
| #endif
 | |
|     return(ret);
 | |
| }
 | |
| #endif /* LIBXML_OUTPUT_ENABLED */
 | |
| 
 | |
| /**
 | |
|  * xmlParserGetDirectory:
 | |
|  * @filename:  the path to a file
 | |
|  *
 | |
|  * lookup the directory for that file
 | |
|  *
 | |
|  * Returns a new allocated string containing the directory, or NULL.
 | |
|  */
 | |
| char *
 | |
| xmlParserGetDirectory(const char *filename) {
 | |
|     char *ret = NULL;
 | |
|     char dir[1024];
 | |
|     char *cur;
 | |
| 
 | |
| #ifdef _WIN32_WCE  /* easy way by now ... wince does not have dirs! */
 | |
|     return NULL;
 | |
| #endif
 | |
| 
 | |
|     if (xmlInputCallbackInitialized == 0)
 | |
| 	xmlRegisterDefaultInputCallbacks();
 | |
| 
 | |
|     if (filename == NULL) return(NULL);
 | |
| 
 | |
| #if defined(WIN32) && !defined(__CYGWIN__)
 | |
| #   define IS_XMLPGD_SEP(ch) ((ch=='/')||(ch=='\\'))
 | |
| #else
 | |
| #   define IS_XMLPGD_SEP(ch) (ch=='/')
 | |
| #endif
 | |
| 
 | |
|     strncpy(dir, filename, 1023);
 | |
|     dir[1023] = 0;
 | |
|     cur = &dir[strlen(dir)];
 | |
|     while (cur > dir) {
 | |
|          if (IS_XMLPGD_SEP(*cur)) break;
 | |
| 	 cur --;
 | |
|     }
 | |
|     if (IS_XMLPGD_SEP(*cur)) {
 | |
|         if (cur == dir) dir[1] = 0;
 | |
| 	else *cur = 0;
 | |
| 	ret = xmlMemStrdup(dir);
 | |
|     } else {
 | |
|         if (getcwd(dir, 1024) != NULL) {
 | |
| 	    dir[1023] = 0;
 | |
| 	    ret = xmlMemStrdup(dir);
 | |
| 	}
 | |
|     }
 | |
|     return(ret);
 | |
| #undef IS_XMLPGD_SEP
 | |
| }
 | |
| 
 | |
| /****************************************************************
 | |
|  *								*
 | |
|  *		External entities loading			*
 | |
|  *								*
 | |
|  ****************************************************************/
 | |
| 
 | |
| /**
 | |
|  * xmlCheckHTTPInput:
 | |
|  * @ctxt: an XML parser context
 | |
|  * @ret: an XML parser input
 | |
|  *
 | |
|  * Check an input in case it was created from an HTTP stream, in that
 | |
|  * case it will handle encoding and update of the base URL in case of
 | |
|  * redirection. It also checks for HTTP errors in which case the input
 | |
|  * is cleanly freed up and an appropriate error is raised in context
 | |
|  *
 | |
|  * Returns the input or NULL in case of HTTP error.
 | |
|  */
 | |
| xmlParserInputPtr
 | |
| xmlCheckHTTPInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr ret) {
 | |
| #ifdef LIBXML_HTTP_ENABLED
 | |
|     if ((ret != NULL) && (ret->buf != NULL) &&
 | |
|         (ret->buf->readcallback == xmlIOHTTPRead) &&
 | |
|         (ret->buf->context != NULL)) {
 | |
|         const char *encoding;
 | |
|         const char *redir;
 | |
|         const char *mime;
 | |
|         int code;
 | |
| 
 | |
|         code = xmlNanoHTTPReturnCode(ret->buf->context);
 | |
|         if (code >= 400) {
 | |
|             /* fatal error */
 | |
| 	    if (ret->filename != NULL)
 | |
| 		__xmlLoaderErr(ctxt, "failed to load HTTP resource \"%s\"\n",
 | |
|                          (const char *) ret->filename);
 | |
| 	    else
 | |
| 		__xmlLoaderErr(ctxt, "failed to load HTTP resource\n", NULL);
 | |
|             xmlFreeInputStream(ret);
 | |
|             ret = NULL;
 | |
|         } else {
 | |
| 
 | |
|             mime = xmlNanoHTTPMimeType(ret->buf->context);
 | |
|             if ((xmlStrstr(BAD_CAST mime, BAD_CAST "/xml")) ||
 | |
|                 (xmlStrstr(BAD_CAST mime, BAD_CAST "+xml"))) {
 | |
|                 encoding = xmlNanoHTTPEncoding(ret->buf->context);
 | |
|                 if (encoding != NULL) {
 | |
|                     xmlCharEncodingHandlerPtr handler;
 | |
| 
 | |
|                     handler = xmlFindCharEncodingHandler(encoding);
 | |
|                     if (handler != NULL) {
 | |
|                         xmlSwitchInputEncoding(ctxt, ret, handler);
 | |
|                     } else {
 | |
|                         __xmlErrEncoding(ctxt, XML_ERR_UNKNOWN_ENCODING,
 | |
|                                          "Unknown encoding %s",
 | |
|                                          BAD_CAST encoding, NULL);
 | |
|                     }
 | |
|                     if (ret->encoding == NULL)
 | |
|                         ret->encoding = xmlStrdup(BAD_CAST encoding);
 | |
|                 }
 | |
| #if 0
 | |
|             } else if (xmlStrstr(BAD_CAST mime, BAD_CAST "html")) {
 | |
| #endif
 | |
|             }
 | |
|             redir = xmlNanoHTTPRedir(ret->buf->context);
 | |
|             if (redir != NULL) {
 | |
|                 if (ret->filename != NULL)
 | |
|                     xmlFree((xmlChar *) ret->filename);
 | |
|                 if (ret->directory != NULL) {
 | |
|                     xmlFree((xmlChar *) ret->directory);
 | |
|                     ret->directory = NULL;
 | |
|                 }
 | |
|                 ret->filename =
 | |
|                     (char *) xmlStrdup((const xmlChar *) redir);
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| #endif
 | |
|     return(ret);
 | |
| }
 | |
| 
 | |
| static int xmlNoNetExists(const char *URL) {
 | |
|     const char *path;
 | |
| 
 | |
|     if (URL == NULL)
 | |
| 	return(0);
 | |
| 
 | |
|     if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
 | |
| #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
 | |
| 	path = &URL[17];
 | |
| #else
 | |
| 	path = &URL[16];
 | |
| #endif
 | |
|     else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
 | |
| #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
 | |
| 	path = &URL[8];
 | |
| #else
 | |
| 	path = &URL[7];
 | |
| #endif
 | |
|     } else
 | |
| 	path = URL;
 | |
| 
 | |
|     return xmlCheckFilename(path);
 | |
| }
 | |
| 
 | |
| #ifdef LIBXML_CATALOG_ENABLED
 | |
| 
 | |
| /**
 | |
|  * xmlResolveResourceFromCatalog:
 | |
|  * @URL:  the URL for the entity to load
 | |
|  * @ID:  the System ID for the entity to load
 | |
|  * @ctxt:  the context in which the entity is called or NULL
 | |
|  *
 | |
|  * Resolves the URL and ID against the appropriate catalog.
 | |
|  * This function is used by xmlDefaultExternalEntityLoader and
 | |
|  * xmlNoNetExternalEntityLoader.
 | |
|  *
 | |
|  * Returns a new allocated URL, or NULL.
 | |
|  */
 | |
| static xmlChar *
 | |
| xmlResolveResourceFromCatalog(const char *URL, const char *ID,
 | |
|                               xmlParserCtxtPtr ctxt) {
 | |
|     xmlChar *resource = NULL;
 | |
|     xmlCatalogAllow pref;
 | |
| 
 | |
|     /*
 | |
|      * If the resource doesn't exists as a file,
 | |
|      * try to load it from the resource pointed in the catalogs
 | |
|      */
 | |
|     pref = xmlCatalogGetDefaults();
 | |
| 
 | |
|     if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
 | |
| 	/*
 | |
| 	 * Do a local lookup
 | |
| 	 */
 | |
| 	if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
 | |
| 	    ((pref == XML_CATA_ALLOW_ALL) ||
 | |
| 	     (pref == XML_CATA_ALLOW_DOCUMENT))) {
 | |
| 	    resource = xmlCatalogLocalResolve(ctxt->catalogs,
 | |
| 					      (const xmlChar *)ID,
 | |
| 					      (const xmlChar *)URL);
 | |
|         }
 | |
| 	/*
 | |
| 	 * Try a global lookup
 | |
| 	 */
 | |
| 	if ((resource == NULL) &&
 | |
| 	    ((pref == XML_CATA_ALLOW_ALL) ||
 | |
| 	     (pref == XML_CATA_ALLOW_GLOBAL))) {
 | |
| 	    resource = xmlCatalogResolve((const xmlChar *)ID,
 | |
| 					 (const xmlChar *)URL);
 | |
| 	}
 | |
| 	if ((resource == NULL) && (URL != NULL))
 | |
| 	    resource = xmlStrdup((const xmlChar *) URL);
 | |
| 
 | |
| 	/*
 | |
| 	 * TODO: do an URI lookup on the reference
 | |
| 	 */
 | |
| 	if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
 | |
| 	    xmlChar *tmp = NULL;
 | |
| 
 | |
| 	    if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
 | |
| 		((pref == XML_CATA_ALLOW_ALL) ||
 | |
| 		 (pref == XML_CATA_ALLOW_DOCUMENT))) {
 | |
| 		tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
 | |
| 	    }
 | |
| 	    if ((tmp == NULL) &&
 | |
| 		((pref == XML_CATA_ALLOW_ALL) ||
 | |
| 	         (pref == XML_CATA_ALLOW_GLOBAL))) {
 | |
| 		tmp = xmlCatalogResolveURI(resource);
 | |
| 	    }
 | |
| 
 | |
| 	    if (tmp != NULL) {
 | |
| 		xmlFree(resource);
 | |
| 		resource = tmp;
 | |
| 	    }
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|     return resource;
 | |
| }
 | |
| 
 | |
| #endif
 | |
| 
 | |
| /**
 | |
|  * xmlDefaultExternalEntityLoader:
 | |
|  * @URL:  the URL for the entity to load
 | |
|  * @ID:  the System ID for the entity to load
 | |
|  * @ctxt:  the context in which the entity is called or NULL
 | |
|  *
 | |
|  * By default we don't load external entitites, yet.
 | |
|  *
 | |
|  * Returns a new allocated xmlParserInputPtr, or NULL.
 | |
|  */
 | |
| static xmlParserInputPtr
 | |
| xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
 | |
|                                xmlParserCtxtPtr ctxt)
 | |
| {
 | |
|     xmlParserInputPtr ret = NULL;
 | |
|     xmlChar *resource = NULL;
 | |
| 
 | |
| #ifdef DEBUG_EXTERNAL_ENTITIES
 | |
|     xmlGenericError(xmlGenericErrorContext,
 | |
|                     "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
 | |
| #endif
 | |
|     if ((ctxt != NULL) && (ctxt->options & XML_PARSE_NONET)) {
 | |
|         int options = ctxt->options;
 | |
| 
 | |
| 	ctxt->options -= XML_PARSE_NONET;
 | |
|         ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
 | |
| 	ctxt->options = options;
 | |
| 	return(ret);
 | |
|     }
 | |
| #ifdef LIBXML_CATALOG_ENABLED
 | |
|     resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
 | |
| #endif
 | |
| 
 | |
|     if (resource == NULL)
 | |
|         resource = (xmlChar *) URL;
 | |
| 
 | |
|     if (resource == NULL) {
 | |
|         if (ID == NULL)
 | |
|             ID = "NULL";
 | |
|         __xmlLoaderErr(ctxt, "failed to load external entity \"%s\"\n", ID);
 | |
|         return (NULL);
 | |
|     }
 | |
|     ret = xmlNewInputFromFile(ctxt, (const char *) resource);
 | |
|     if ((resource != NULL) && (resource != (xmlChar *) URL))
 | |
|         xmlFree(resource);
 | |
|     return (ret);
 | |
| }
 | |
| 
 | |
| static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
 | |
|        xmlDefaultExternalEntityLoader;
 | |
| 
 | |
| /**
 | |
|  * xmlSetExternalEntityLoader:
 | |
|  * @f:  the new entity resolver function
 | |
|  *
 | |
|  * Changes the defaultexternal entity resolver function for the application
 | |
|  */
 | |
| void
 | |
| xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
 | |
|     xmlCurrentExternalEntityLoader = f;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * xmlGetExternalEntityLoader:
 | |
|  *
 | |
|  * Get the default external entity resolver function for the application
 | |
|  *
 | |
|  * Returns the xmlExternalEntityLoader function pointer
 | |
|  */
 | |
| xmlExternalEntityLoader
 | |
| xmlGetExternalEntityLoader(void) {
 | |
|     return(xmlCurrentExternalEntityLoader);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * xmlLoadExternalEntity:
 | |
|  * @URL:  the URL for the entity to load
 | |
|  * @ID:  the Public ID for the entity to load
 | |
|  * @ctxt:  the context in which the entity is called or NULL
 | |
|  *
 | |
|  * Load an external entity, note that the use of this function for
 | |
|  * unparsed entities may generate problems
 | |
|  *
 | |
|  * Returns the xmlParserInputPtr or NULL
 | |
|  */
 | |
| xmlParserInputPtr
 | |
| xmlLoadExternalEntity(const char *URL, const char *ID,
 | |
|                       xmlParserCtxtPtr ctxt) {
 | |
|     if ((URL != NULL) && (xmlNoNetExists(URL) == 0)) {
 | |
| 	char *canonicFilename;
 | |
| 	xmlParserInputPtr ret;
 | |
| 
 | |
| 	canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL);
 | |
| 	if (canonicFilename == NULL) {
 | |
|             xmlIOErrMemory("building canonical path\n");
 | |
| 	    return(NULL);
 | |
| 	}
 | |
| 
 | |
| 	ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt);
 | |
| 	xmlFree(canonicFilename);
 | |
| 	return(ret);
 | |
|     }
 | |
|     return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
 | |
| }
 | |
| 
 | |
| /************************************************************************
 | |
|  *									*
 | |
|  *		Disabling Network access				*
 | |
|  *									*
 | |
|  ************************************************************************/
 | |
| 
 | |
| /**
 | |
|  * xmlNoNetExternalEntityLoader:
 | |
|  * @URL:  the URL for the entity to load
 | |
|  * @ID:  the System ID for the entity to load
 | |
|  * @ctxt:  the context in which the entity is called or NULL
 | |
|  *
 | |
|  * A specific entity loader disabling network accesses, though still
 | |
|  * allowing local catalog accesses for resolution.
 | |
|  *
 | |
|  * Returns a new allocated xmlParserInputPtr, or NULL.
 | |
|  */
 | |
| xmlParserInputPtr
 | |
| xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
 | |
|                              xmlParserCtxtPtr ctxt) {
 | |
|     xmlParserInputPtr input = NULL;
 | |
|     xmlChar *resource = NULL;
 | |
| 
 | |
| #ifdef LIBXML_CATALOG_ENABLED
 | |
|     resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
 | |
| #endif
 | |
| 
 | |
|     if (resource == NULL)
 | |
| 	resource = (xmlChar *) URL;
 | |
| 
 | |
|     if (resource != NULL) {
 | |
|         if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
 | |
|             (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
 | |
|             xmlIOErr(XML_IO_NETWORK_ATTEMPT, (const char *) resource);
 | |
| 	    if (resource != (xmlChar *) URL)
 | |
| 		xmlFree(resource);
 | |
| 	    return(NULL);
 | |
| 	}
 | |
|     }
 | |
|     input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
 | |
|     if (resource != (xmlChar *) URL)
 | |
| 	xmlFree(resource);
 | |
|     return(input);
 | |
| }
 | |
| 
 | |
| #define bottom_xmlIO
 | |
| #include "elfgcchack.h"
 |