diff -r 000000000000 -r e35f40988205 xml/libxml2libs/src/libxml2/libxml2_xmlio.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xml/libxml2libs/src/libxml2/libxml2_xmlio.c Thu Dec 17 09:29:21 2009 +0200 @@ -0,0 +1,3723 @@ +/* + * libxml2_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 + * Portion Copyright © 2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. + */ + +#define IN_LIBXML +#include "xmlenglibxml.h" + +#include + +#ifdef HAVE_ERRNO_H +#include +#endif + +#include + +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_STAT_H +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_ZLIB_H +#include +#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 +#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 +#include "libxml2_errencoding.h" +#include "libxml2_xmlerror2.h" +#include + +#ifdef LIBXML_CATALOG_ENABLED +#include "libxml2_catalog.h" +#endif + +#include + +/* #define VERBOSE_FAILURE */ +/* #define DEBUG_EXTERNAL_ENTITIES */ +/* #define DEBUG_INPUT */ + +#ifdef DEBUG_INPUT +#define MINLEN 40 +#else +#define MINLEN 4000 +#endif + + +/************************************************************************ + * * + * Tree memory error handler * + * * + ************************************************************************/ + +#ifndef XMLENGINE_EXCLUDE_EMBED_MSG +const char * const IOerr[] = { + EMBED_ERRTXT("Unknown IO error"), /* UNKNOWN */ + EMBED_ERRTXT("Permission denied"), /* EACCES */ + EMBED_ERRTXT("Resource temporarily unavailable"), /* EAGAIN */ + EMBED_ERRTXT("Bad file descriptor"), /* EBADF */ + EMBED_ERRTXT("Bad message"), /* EBADMSG */ + EMBED_ERRTXT("Resource busy"), /* EBUSY */ + EMBED_ERRTXT("Operation canceled"), /* ECANCELED */ + EMBED_ERRTXT("No child processes"), /* ECHILD */ + EMBED_ERRTXT("Resource deadlock avoided"), /* EDEADLK */ + EMBED_ERRTXT("Domain error"), /* EDOM */ + EMBED_ERRTXT("File exists"), /* EEXIST */ + EMBED_ERRTXT("Bad address"), /* EFAULT */ + EMBED_ERRTXT("File too large"), /* EFBIG */ + EMBED_ERRTXT("Operation in progress"), /* EINPROGRESS */ + EMBED_ERRTXT("Interrupted function call"), /* EINTR */ + EMBED_ERRTXT("Invalid argument"), /* EINVAL */ + EMBED_ERRTXT("Input/output error"), /* EIO */ + EMBED_ERRTXT("Is a directory"), /* EISDIR */ + EMBED_ERRTXT("Too many open files"), /* EMFILE */ + EMBED_ERRTXT("Too many links"), /* EMLINK */ + EMBED_ERRTXT("Inappropriate message buffer length"),/* EMSGSIZE */ + EMBED_ERRTXT("Filename too long"), /* ENAMETOOLONG */ + EMBED_ERRTXT("Too many open files in system"), /* ENFILE */ + EMBED_ERRTXT("No such device"), /* ENODEV */ + EMBED_ERRTXT("No such file or directory"), /* ENOENT */ + EMBED_ERRTXT("Exec format error"), /* ENOEXEC */ + EMBED_ERRTXT("No locks available"), /* ENOLCK */ + EMBED_ERRTXT("Not enough space"), /* ENOMEM */ + EMBED_ERRTXT("No space left on device"), /* ENOSPC */ + EMBED_ERRTXT("Function not implemented"), /* ENOSYS */ + EMBED_ERRTXT("Not a directory"), /* ENOTDIR */ + EMBED_ERRTXT("Directory not empty"), /* ENOTEMPTY */ + EMBED_ERRTXT("Not supported"), /* ENOTSUP */ + EMBED_ERRTXT("Inappropriate I/O control operation"),/* ENOTTY */ + EMBED_ERRTXT("No such device or address"), /* ENXIO */ + EMBED_ERRTXT("Operation not permitted"), /* EPERM */ + EMBED_ERRTXT("Broken pipe"), /* EPIPE */ + EMBED_ERRTXT("Result too large"), /* ERANGE */ + EMBED_ERRTXT("Read-only file system"), /* EROFS */ + EMBED_ERRTXT("Invalid seek"), /* ESPIPE */ + EMBED_ERRTXT("No such process"), /* ESRCH */ + EMBED_ERRTXT("Operation timed out"), /* ETIMEDOUT */ + EMBED_ERRTXT("Improper link"), /* EXDEV */ + EMBED_ERRTXT("Attempt to load network entity %s"), /* XML_IO_NETWORK_ATTEMPT */ + EMBED_ERRTXT("encoder error"), /* XML_IO_ENCODER */ + EMBED_ERRTXT("flush error"), + EMBED_ERRTXT("write error"), + EMBED_ERRTXT("no input"), + EMBED_ERRTXT("buffer full"), + EMBED_ERRTXT("loading error"), + EMBED_ERRTXT("not a socket"), /* ENOTSOCK */ + EMBED_ERRTXT("already connected"), /* EISCONN */ + EMBED_ERRTXT("connection refuxed"), /* ECONNREFUSED */ + EMBED_ERRTXT("unreachable network"), /* ENETUNREACH */ + EMBED_ERRTXT("adddress in use"), /* EADDRINUSE */ + EMBED_ERRTXT("already in use"), /* EALREADY */ + EMBED_ERRTXT("unknown address familly") /* EAFNOSUPPORT */ +}; +#endif /* ! XMLENGINE_EXCLUDE_EMBED_MSG */ + +/** + * xmlIOErrMemory: + * @param 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: + * @param code the error number + * @ + * @param extra extra informations + * + * Handle an I/O error + */ +void +__xmlIOErr(int domain, int code, const char *extra) +{ + // Note: on Symbian 'errno' is a macro for function call + int _errno = errno; + 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 */ + } + +#if defined(LIBXML_OUTPUT_ENABLED) && !defined(XMLENGINE_EXCLUDE_EMBED_MSG) + { + unsigned int idx = 0; + if (code >= XML_IO_UNKNOWN) idx = code - XML_IO_UNKNOWN; + + // DONE: disable this branch if error messages are stripped from sources (and then disable IOerr array too) + if (idx >= (sizeof(IOerr) / sizeof(IOerr[0]))) + idx = 0; + __xmlSimpleError(domain, code, NULL, IOerr[idx], extra); + } +#else + // No error messages used.. + __xmlSimpleError(domain, code, NULL, EMBED_ERRTXT("IOError"), extra); +#endif /* LIBXML_OUTPUT_ENABLED */ +} + +/** + * xmlIOErr: + * @param code the error number + * @param extra extra informations + * + * Handle an I/O error + */ +static void +xmlIOErr(int code, const char *extra) +{ + __xmlIOErr(XML_FROM_IO, code, extra); +} + +/** + * __xmlLoaderErr: + * @param ctx the parser context + * @param 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; + } + 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 * + * * + ************************************************************************/ + +/** + * xmlCleanupInputCallbacks: + * + * clears the entire input callback table. this includes the + * compiled-in I/O. + * + * OOM: never + */ +XMLPUBFUNEXPORT void +xmlCleanupInputCallbacks(void) +{ + LOAD_GS_DIRECT + 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; +} + +/** + * xmlPopInputCallback: + * + * 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. + */ +XMLPUBFUNEXPORT int +xmlPopInputCallbacks(void) +{ + LOAD_GS_DIRECT + 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. + */ +XMLPUBFUNEXPORT void +xmlCleanupOutputCallbacks(void) +{ + LOAD_GS_DIRECT + 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 * + * * + ************************************************************************/ + +/** + * xmlCheckFilename: + * @param 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. + */ +#include +XMLPUBFUNEXPORT int +xmlCheckFilename (const char* path) +{ +#ifdef HAVE_STAT + struct stat stat_buffer; + + if (stat(path, &stat_buffer) == -1) + return 0; + +#ifdef S_ISDIR + if (S_ISDIR(stat_buffer.st_mode)) { + return 2; + } +#endif +#endif + return 1; +} + +static int +xmlNop(void) { + return(0); +} + +/** + * xmlFdRead: + * @param context the I/O context + * @param buffer where to drop data + * @param len number of bytes to read + * + * Read len bytes to buffer from the I/O channel. + * + * Returns the number of bytes written + */ +static int +xmlFdRead (void * context, char * buffer, int len) { + int ret; + + ret = read((int) (long) context, &buffer[0], len); + if (ret < 0) xmlIOErr(0, EMBED_ERRTXT("read()")); + return(ret); +} + +#ifdef LIBXML_OUTPUT_ENABLED +/** + * xmlFdWrite: + * @param context the I/O context + * @param buffer where to get data + * @param 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; + + ret = write((int) (long) context, &buffer[0], len); + if (ret < 0) xmlIOErr(0, "write()"); + return(ret); +} +#endif /* LIBXML_OUTPUT_ENABLED */ + +/** + * xmlFdClose: + * @param context the I/O context + * + * Close an I/O channel + * + * Returns 0 in case of success and error code otherwise + */ +static int +xmlFdClose (void * context) { + int ret; + ret = close((int) (long) context); + if (ret < 0) xmlIOErr(0, EMBED_ERRTXT("close()")); + return(ret); +} + +/** + * xmlFileMatch: + * @param filename the URI for matching + * + * input from FILE * + * + * Returns 1 if matches, 0 otherwise + */ +XMLPUBFUNEXPORT int +xmlFileMatch (const char* filename ATTRIBUTE_UNUSED) { + return(1); +} + +// XMLENGINE: NEW CODE: xmlFileOpen_common +// --> common method extracted from xmlFileOpenW and xmlFileOpen_real; +// --> Slashes-handling code added for Symbian UREL builds +/* + * + * + */ +static void* +xmlFileOpen_common(const char* filename, const char* mode) +{ + FILE* fd; + char* p; + char* rpath; + const char* path = filename; + + if (!path) + return(NULL); + + if(filename[0] == 'f' && filename[1] == 'i') + { + if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) + path = &filename[17]; + else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) + path = &filename[8]; + } + + // Convert all slashes into backslashes + + path = rpath = p = (char*) xmlStrdup((const xmlChar*) path); + if(!p) + return NULL; + + for(; *p; p++){ + if(*p == '/') + *p = '\\'; + } + + fd = fopen(path, mode); + CHECK_ERRNO; + + if (!fd){ + xmlIOErr(0, path); + } + + xmlFree(rpath); + return((void*) fd); +} + +/** + * xmlFileOpen_real: + * @param 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 + * + * OOM: possible --> OOM flag is set + */ +void* +xmlFileOpen_real (const char* filename) +{ + if (filename && filename[0] == '-' && !filename[1]) + return((void *) stdin); + else + return xmlFileOpen_common(filename, "r"); // Symbian case is here, right ? +} + +/** + * xmlFileOpen: + * @param 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 + */ +XMLPUBFUNEXPORT void* +xmlFileOpen (const char* filename) { + char* unescaped; + void* retval; + + unescaped = xmlURIUnescapeString(filename, 0, NULL); + retval = xmlFileOpen_real(unescaped ? unescaped : filename); + + if(unescaped) + xmlFree(unescaped); + return retval; +} + +#ifdef LIBXML_OUTPUT_ENABLED +/** + * xmlFileOpenW: + * @param 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 + * + * OOM: possible --> OOM flag is set + */ +static void* +xmlFileOpenW (const char* filename) +{ + if (filename && filename[0] == '-' && !filename[1]) + return((void*) stdout); + else + return xmlFileOpen_common(filename, "wb"); +} +#endif /* LIBXML_OUTPUT_ENABLED */ + + +/** + * xmlFileRead: + * @param context the I/O context + * @param buffer where to drop data + * @param len number of bytes to write + * + * Read len bytes to buffer from the I/O channel. + * + * Returns the number of bytes written + */ +XMLPUBFUNEXPORT int +xmlFileRead (void* context, char* buffer, int len) +{ + int ret = fread(&buffer[0], 1, len, (FILE*) context); + if (ret < 0) { + CHECK_ERRNO; + xmlIOErr(0, EMBED_ERRTXT("fread()")); + } + return(ret); +} + + +#ifdef LIBXML_OUTPUT_ENABLED +/** + * xmlFileWrite: + * @param context the I/O context + * @param buffer where to drop data + * @param 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 = fwrite(&buffer[0], len, 1, (FILE*) context); + + if (items == EOF || + (items == 0 && ferror((FILE*) context))) + { + CHECK_ERRNO; + xmlIOErr(0, EMBED_ERRTXT("fwrite()")); + return(-1); + } + return(items * len); +} +#endif /* LIBXML_OUTPUT_ENABLED */ + + + +/** + * xmlFileClose: + * @param context the I/O context + * + * Close an I/O channel + * + * Returns 0 or -1 in case of error + */ +XMLPUBFUNEXPORT int +xmlFileClose (void* context) +{ + FILE* fil; + int ret; + + fil = (FILE*) context; + if ((fil == stdout) || (fil == stderr)) { + ret = fflush(fil); + if (ret < 0){ + CHECK_ERRNO; + xmlIOErr(0, EMBED_ERRTXT("fflush()")); + } + return(0); + } + if (fil == stdin) + return(0); + ret = ( fclose((FILE*) context) == EOF ) ? -1 : 0; + if (ret < 0){ + CHECK_ERRNO; + xmlIOErr(0, EMBED_ERRTXT("fclose()")); + } + return(ret); +} + +/** + * xmlFileFlush: + * @param context the I/O context + * + * Flush an I/O channel + */ +static int +xmlFileFlush (void * context) +{ + int ret = (fflush((FILE *) context) == EOF) ? -1 : 0; + if (ret < 0){ + CHECK_ERRNO; + xmlIOErr(0, EMBED_ERRTXT("fflush()")); + } + return(ret); +} + + +#ifdef HAVE_ZLIB_H +/************************************************************************ + * * + * I/O for compressed file accesses * + * * + ************************************************************************/ +/** + * xmlGzfileMatch: + * @param 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: + * @param filename the URI for matching + * + * input from compressed file open + * if filename is " " then the standard input is used + * + * Returns an I/O context or NULL in case of error + */ +static void* +xmlGzfileOpen_real (const char *filename) +{ + const char *path = NULL; + gzFile fd; + + if (!strcmp(filename, "-")) { + fd = gzdopen(dup(0), "rb"); + return((void *) fd); + } + + if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) + path = &filename[17]; + else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) { + path = &filename[8]; + } else + path = filename; + + if (path == NULL) + return(NULL); + if (!xmlCheckFilename(path)) + return(NULL); + + fd = gzopen(path, "rb"); + return((void *) fd); +} + +/** + * xmlGzfileOpen: + * @param 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: + * @param filename the URI for matching + * @param compression the compression factor (0 - 9 included) + * + * input from compressed file open + * if filename is " " then the standard input is used + * + * Returns an I/O context or NULL in case of error + */ +static void* +xmlGzfileOpenW (const char *filename, int compression) +{ + const char* path = NULL; + char mode[15]; + gzFile fd; + + snprintf(mode, sizeof(mode), "wb%d", compression); + if (!strcmp(filename, "-")) { + fd = gzdopen(dup(1), mode); + return((void *) fd); + } + + if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) + path = &filename[17]; + else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) { + path = &filename[8]; + } else + path = filename; + + if (path == NULL) + return(NULL); + + fd = gzopen(path, mode); + return((void *) fd); +} +#endif /* LIBXML_OUTPUT_ENABLED */ + +/** + * xmlGzfileRead: + * @param context the I/O context + * @param buffer where to drop data + * @param len number of bytes to write + * + * Read len bytes to buffer from the compressed I/O channel. + * + * Returns the number of bytes written + */ +static int +xmlGzfileRead (void * context, char * buffer, int len) +{ + int ret; + + ret = gzread((gzFile) context, &buffer[0], len); + if (ret < 0) xmlIOErr(0, EMBED_ERRTXT("gzread()")); + return(ret); +} + +#ifdef LIBXML_OUTPUT_ENABLED +/** + * xmlGzfileWrite: + * @param context the I/O context + * @param buffer where to drop data + * @param 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, EMBED_ERRTXT("gzwrite()")); + return(ret); +} +#endif /* LIBXML_OUTPUT_ENABLED */ + +/** + * xmlGzfileClose: + * @param 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, EMBED_ERRTXT("gzclose()")); + return(ret); +} +#endif /* HAVE_ZLIB_H */ + +#ifdef LIBXML_HTTP_ENABLED +/************************************************************************ + * * + * I/O for HTTP file accesses * + * * + ************************************************************************/ + +#ifdef LIBXML_OUTPUT_ENABLED +typedef struct xmlIOHTTPWriteCtxt_ +{ + int compression; + char * uri; + void * doc_buff; +} xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr; + +#ifdef HAVE_ZLIB_H + +#define DFLT_WBITS ( -15 ) +#define DFLT_MEM_LVL ( 8 ) +#define GZ_MAGIC1 ( 0x1f ) +#define GZ_MAGIC2 ( 0x8b ) +#define LXML_ZLIB_OS_CODE ( 0x03 ) +#define INIT_HTTP_BUFF_SIZE ( 32768 ) +#define DFLT_ZLIB_RATIO ( 5 ) + +/* +** Data structure and functions to work with sending compressed data +** via HTTP. +*/ + +typedef struct xmlZMemBuff_ +{ + unsigned long size; + unsigned long crc; + unsigned char * zbuff; + z_stream zctrl; + +} xmlZMemBuff, *xmlZMemBuffPtr; + +/** + * append_reverse_ulong + * @param buff Compressed memory buffer + * @param 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 + * @param 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, + EMBED_ERRTXT("xmlFreeZMemBuff: Error releasing zlib context: %d\n"), + z_err ); +#else + deflateEnd( &buff->zctrl ); +#endif + + xmlFree( buff ); + return; +} + +/** + * xmlCreateZMemBuff + *@param 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(EMBED_ERRTXT("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(EMBED_ERRTXT("creating buffer")); + return ( NULL ); + } + + z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED, + DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY ); + if ( z_err != Z_OK ) { + xmlChar msg[500]; + xmlFreeZMemBuff( buff ); + buff = NULL; + xmlStrPrintf(msg, 500, + (const xmlChar *) EMBED_ERRTXT("xmlCreateZMemBuff: %s %d\n"), + EMBED_ERRTXT("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, Z_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 + * @param buff Buffer used to compress and consolidate data. + * @param ext_amt Number of bytes to extend the buffer. + * + * Extend the internal buffer used to store the compressed data by the + * specified amount. + * + * Returns 0 on success or -1 on failure to extend the buffer. On failure + * the original buffer still exists at the original size. + */ +static int +xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) +{ + int rc = -1; + size_t new_size; + size_t cur_used; + + unsigned char * tmp_ptr = NULL; + + if ( buff == NULL ) + return ( -1 ); + + else if ( ext_amt == 0 ) + return ( 0 ); + + cur_used = buff->zctrl.next_out - buff->zbuff; + new_size = buff->size + ext_amt; + +#ifdef DEBUG_HTTP + if ( cur_used > new_size ) + xmlGenericError( xmlGenericErrorContext, + "xmlZMemBuffExtend: %s\n%s %d bytes.\n", + "Buffer overwrite detected during compressed memory", + "buffer extension. Overflowed by", + (cur_used - new_size ) ); +#endif + + tmp_ptr = xmlRealloc( buff->zbuff, new_size ); + if ( tmp_ptr != NULL ) { + rc = 0; + buff->size = new_size; + buff->zbuff = tmp_ptr; + buff->zctrl.next_out = tmp_ptr + cur_used; + buff->zctrl.avail_out = new_size - cur_used; + } + else { + xmlChar msg[500]; + xmlStrPrintf(msg, 500, + (const xmlChar *) EMBED_ERRTXT("xmlZMemBuffExtend: %s %lu bytes.\n"), + EMBED_ERRTXT("Allocation failure extending output buffer to"), + new_size ); + xmlIOErr(XML_IO_WRITE, (const char *) msg); + } + + return ( rc ); +} + +/** + * xmlZMemBuffAppend + * @param buff Buffer used to compress and consolidate data + * @param src Uncompressed source content to append to buffer + * @param len Length of source data to append to buffer + * + * Compress and append data to the internal buffer. The data buffer + * will be expanded if needed to store the additional data. + * + * Returns the number of bytes appended to the buffer or -1 on error. + */ +static int +xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) +{ + int z_err; + size_t min_accept; + + if ( ( buff == NULL ) || ( src == NULL ) ) + return ( -1 ); + + buff->zctrl.avail_in = len; + buff->zctrl.next_in = (unsigned char *)src; + while ( buff->zctrl.avail_in > 0 ) { + /* + ** Extend the buffer prior to deflate call if a reasonable amount + ** of output buffer space is not available. + */ + min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO; + if ( buff->zctrl.avail_out <= min_accept ) { + if ( xmlZMemBuffExtend( buff, buff->size ) == -1 ) + return ( -1 ); + } + + z_err = deflate( &buff->zctrl, Z_NO_FLUSH ); + if ( z_err != Z_OK ) { + xmlChar msg[500]; + xmlStrPrintf(msg, 500, + (const xmlChar *) EMBED_ERRTXT("xmlZMemBuffAppend: %s %d %s - %d"), + EMBED_ERRTXT("Compression error while appending"), + len, EMBED_ERRTXT("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 + * @param buff Compressed memory content buffer + * @param data_ref Pointer reference to point to compressed content + * + * Flushes the compression buffers, appends gzip file trailers and + * returns the compressed content and length of the compressed data. + * NOTE: The gzip trailer code here is plagiarized from zlib source. + * + * Returns the length of the compressed data or -1 on error. + */ +static int +xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) +{ + int zlgth = -1; + int z_err; + + if ( ( buff == NULL ) || ( data_ref == NULL ) ) + return ( -1 ); + + /* Need to loop until compression output buffers are flushed */ + + do + { + z_err = deflate( &buff->zctrl, Z_FINISH ); + if ( z_err == Z_OK ) { + /* In this case Z_OK means more buffer space needed */ + + if ( xmlZMemBuffExtend( buff, buff->size ) == -1 ) + return ( -1 ); + } + } + while ( z_err == Z_OK ); + + /* If the compression state is not Z_STREAM_END, some error occurred */ + + if ( z_err == Z_STREAM_END ) { + + /* Need to append the gzip data trailer */ + + if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) { + if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 ) + return ( -1 ); + } + + /* + ** For whatever reason, the CRC and length data are pushed out + ** in reverse byte order. So a memcpy can't be used here. + */ + + append_reverse_ulong( buff, buff->crc ); + append_reverse_ulong( buff, buff->zctrl.total_in ); + + zlgth = buff->zctrl.next_out - buff->zbuff; + *data_ref = (char *)buff->zbuff; + } + + else { + xmlChar msg[500]; + xmlStrPrintf(msg, 500, + (const xmlChar *) EMBED_ERRTXT("xmlZMemBuffGetContent: %s - %d\n"), + EMBED_ERRTXT("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 + * @param 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: + * @param 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: + * @param 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: + * @param post_uri The destination URI for the document + * @param compression The compression desired for the document. + * + * Open a temporary buffer to collect the document for a subsequent HTTP POST + * request. Non-static as is called from the output buffer creation routine. + * + * Returns an I/O context or NULL in case of error. + */ + +void * +xmlIOHTTPOpenW(const char *post_uri, int compression) +{ + + xmlIOHTTPWriteCtxtPtr ctxt = NULL; + + if (post_uri == NULL) + return (NULL); + + ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt)); + if (ctxt == NULL) { + xmlIOErrMemory(EMBED_ERRTXT("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(EMBED_ERRTXT("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 = xmlAllocOutputBuffer(NULL); + } + + if (ctxt->doc_buff == NULL) { + xmlFreeHTTPWriteCtxt(ctxt); + ctxt = NULL; + } + + return (ctxt); +} +#endif /* LIBXML_OUTPUT_ENABLED */ + +#ifdef LIBXML_OUTPUT_ENABLED +/** + * xmlIOHTTPDfltOpenW + * @param 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: + * @param context the I/O context + * @param buffer where to drop data + * @param 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) +{ + return(xmlNanoHTTPRead(context, &buffer[0], len)); +} + +#ifdef LIBXML_OUTPUT_ENABLED +/** + * xmlIOHTTPWrite + * @param context previously opened writing context + * @param buffer data to output to temporary buffer + * @param len bytes to output + * + * Collect data from memory buffer into a temporary file for later + * processing. + * + * Returns number of bytes written. + */ + +static int +xmlIOHTTPWrite( void * context, const char * buffer, int len ) +{ + xmlIOHTTPWriteCtxtPtr ctxt = context; + + if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) ) + return ( -1 ); + + if ( len > 0 ) { + + /* Use gzwrite or fwrite as previously setup in the open call */ + +#ifdef HAVE_ZLIB_H + if ( ctxt->compression > 0 ) + len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len ); + + else +#endif + len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer ); + + if ( len < 0 ) { + xmlChar msg[500]; + xmlStrPrintf(msg, 500, + (const xmlChar *) EMBED_ERRTXT("xmlIOHTTPWrite: %s\n%s '%s'.\n"), + EMBED_ERRTXT("Error appending to internal buffer."), + EMBED_ERRTXT("Error sending document to URI"), + ctxt->uri ); + xmlIOErr(XML_IO_WRITE, (const char *) msg); + } + } + + return ( len ); +} +#endif /* LIBXML_OUTPUT_ENABLED */ + + +/** + * xmlIOHTTPClose: + * @param 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 + * @param context The I/O context + * @param http_mthd The HTTP method to be used when sending the data + * + * Close the transmit HTTP I/O channel and actually send the data. + */ +static int +xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) +{ + int close_rc = -1; + int http_rtn = 0; + int content_lgth = 0; + xmlIOHTTPWriteCtxtPtr ctxt = context; + + char * http_content = NULL; + char * content_encoding = NULL; + char * content_type = (char *) "text/xml"; + void * http_ctxt = NULL; + + if ( ( ctxt == NULL ) || ( http_mthd == NULL ) ) + return ( -1 ); + + /* Retrieve the content from the appropriate buffer */ + +#ifdef HAVE_ZLIB_H + + if ( ctxt->compression > 0 ) { + content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content ); + content_encoding = (char *) "Content-Encoding: gzip"; + } + else +#endif + { + /* Pull the data out of the memory output buffer */ + + xmlOutputBufferPtr dctxt = ctxt->doc_buff; + http_content = (char *)dctxt->buffer->content; + content_lgth = dctxt->buffer->use; + } + + if ( http_content == NULL ) { + xmlChar msg[500]; + xmlStrPrintf(msg, 500, + (const xmlChar *) EMBED_ERRTXT("xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n"), + EMBED_ERRTXT("Error retrieving content.\nUnable to"), + http_mthd, EMBED_ERRTXT("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" ); + CHECK_ERRNO; + + if ( tst_file != NULL ) { + xmlGenericError( xmlGenericErrorContext, + "Transmitted content saved in file: %s\n", buffer ); + + fwrite( http_content, sizeof( char ), + content_lgth, tst_file ); + CHECK_ERRNO; + fclose( tst_file ); + } + + (void)snprintf( buffer, sizeof(buffer), "%s.reply", dump_name ); + tst_file = fopen( buffer, "wb" ); + CHECK_ERRNO; + + if ( tst_file != NULL ) { + xmlGenericError( xmlGenericErrorContext, + "Reply content saved in file: %s\n", buffer ); + + + while ( (avail = xmlNanoHTTPRead( http_ctxt, + buffer, sizeof( buffer ) )) > 0 ) { + + fwrite( buffer, sizeof( char ), avail, tst_file ); + } + + fclose( tst_file ); + } + + free( dump_name ); + } +#endif /* DEBUG_HTTP */ + + http_rtn = xmlNanoHTTPReturnCode( http_ctxt ); + if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) ) + close_rc = 0; + else { + xmlChar msg[500]; + xmlStrPrintf(msg, 500, + (const xmlChar *) EMBED_ERRTXT("xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n"), + http_mthd, content_lgth, + EMBED_ERRTXT("bytes to URI"), ctxt->uri, + EMBED_ERRTXT("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 + * + * @param 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 + * + * @param 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: + * @param 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: + * @param 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: + * @param context the I/O context + * @param buffer where to drop data + * @param 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) +{ + return(xmlNanoFTPRead(context, &buffer[0], len)); +} + +/** + * xmlIOFTPClose: + * @param 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: + * @param matchFunc the xmlInputMatchCallback + * @param openFunc the xmlInputOpenCallback + * @param readFunc the xmlInputReadCallback + * @param 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 + * + * OOM: never + */ +XMLPUBFUNEXPORT int +xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc, + xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc, + xmlInputCloseCallback closeFunc) +{ + LOAD_GS_DIRECT + 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: + * @param matchFunc the xmlOutputMatchCallback + * @param openFunc the xmlOutputOpenCallback + * @param writeFunc the xmlOutputWriteCallback + * @param 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 + * + * OOM: never + */ +XMLPUBFUNEXPORT int +xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc, + xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc, + xmlOutputCloseCallback closeFunc) +{ + LOAD_GS_DIRECT + if (xmlOutputCallbackNr >= MAX_INPUT_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. + * + * OOM: never + */ +XMLPUBFUNEXPORT void +xmlRegisterDefaultInputCallbacks(void) +{ + LOAD_GS_DIRECT + if (xmlInputCallbackInitialized){ + + return; + } + + xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen, + xmlFileRead, xmlFileClose); +#ifdef HAVE_ZLIB_H + xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen, + xmlGzfileRead, xmlGzfileClose); +#endif /* HAVE_ZLIB_H */ + + xmlInputCallbackInitialized = 1; +} + +#ifdef LIBXML_OUTPUT_ENABLED +/** + * xmlRegisterDefaultOutputCallbacks: + * + * Registers the default compiled-in I/O handlers. + * + * OOM: never (at least as far as initial size of table is enough) + */ +XMLPUBFUNEXPORT void +xmlRegisterDefaultOutputCallbacks(void) +{ + LOAD_GS_DIRECT + if (xmlOutputCallbackInitialized) + return; + + xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW, + xmlFileWrite, xmlFileClose); + +#ifdef LIBXML_HTTP_ENABLED + xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW, + xmlIOHTTPWrite, xmlIOHTTPClosePut); +#endif + +/********************************* + No way a-priori to distinguish between gzipped files from + uncompressed ones except opening if existing then closing + and saving with same compression ratio ... a pain. + +#ifdef 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: + * @param enc the charset encoding if known + * + * Create a buffered parser input for progressive parsing + * + * Returns the new parser input or NULL + * + * OOM: possible --> NULL returned and OOM flag is set + */ +XMLPUBFUNEXPORT xmlParserInputBufferPtr +xmlAllocParserInputBuffer(xmlCharEncoding enc) +{ + LOAD_GS_DIRECT + xmlParserInputBufferPtr ret; + + ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer)); + if (!ret) { + xmlIOErrMemory(EMBED_ERRTXT("creating input buffer")); + return(NULL); + } + memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer)); + ret->buffer = xmlBufferCreateSize(2 * xmlDefaultBufferSize); + if (!ret->buffer) + goto OOM; + + + ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT; + ret->encoder = xmlGetCharEncodingHandler(enc); + + if(OOM_FLAG) + goto OOM; + + if (ret->encoder){ + ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize); // sets OOM flag + if(!ret->raw) + goto OOM; + }else{ + ret->raw = NULL; + } + ret->readcallback = NULL; + ret->closecallback = NULL; + ret->context = NULL; + ret->compressed = -1; + ret->rawconsumed = 0; + + return(ret); +//------------------- +OOM: + xmlFreeParserInputBuffer(ret); + return NULL; +} + +#ifdef LIBXML_OUTPUT_ENABLED +/** + * xmlAllocOutputBuffer: + * @param encoder the encoding converter or NULL + * + * Create a buffered parser output + * + * Returns the new parser output or NULL + * + * OOM: possible --> NULL is returned && OOM flag is set + * + */ +XMLPUBFUNEXPORT xmlOutputBufferPtr +xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) +{ + xmlOutputBufferPtr ret; + + ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer)); + if (ret == NULL) { + xmlIOErrMemory(EMBED_ERRTXT("creating output buffer")); + return(NULL); + } + memset(ret, 0, (size_t) sizeof(xmlOutputBuffer)); + ret->buffer = xmlBufferCreate(); + if (ret->buffer == NULL) { + xmlFree(ret); + return(NULL); + } + ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT; + ret->encoder = encoder; + if (encoder != NULL) { + ret->conv = xmlBufferCreateSize(4000); + /* + * This call is designed to initiate the encoder state + */ + xmlCharEncOutFunc(encoder, ret->conv, NULL); // may set OOM flag + } //else { + //ret->conv = NULL; // unneeded -- it's NULL after memset() above + //} + ret->writecallback = NULL; + ret->closecallback = NULL; + ret->context = NULL; + ret->written = 0; + + return(ret); +} +#endif /* LIBXML_OUTPUT_ENABLED */ + +/** + * xmlFreeParserInputBuffer: + * @param in a buffered parser input + * + * Free up the memory used by a buffered parser input + * + * OOM: never + */ +XMLPUBFUNEXPORT void +xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) +{ + if (in == NULL) return; + + if (in->raw) { + xmlBufferFree(in->raw); + in->raw = NULL; + } + if (in->encoder) { + xmlCharEncCloseFunc(in->encoder); + } + if (in->closecallback) { + in->closecallback(in->context); + } + if (in->buffer) { + xmlBufferFree(in->buffer); + in->buffer = NULL; + } + + xmlFree(in); +} + +#ifdef LIBXML_OUTPUT_ENABLED +/** + * xmlOutputBufferClose: + * @param 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. + */ +XMLPUBFUNEXPORT int +xmlOutputBufferClose(xmlOutputBufferPtr out) +{ + int written; + int err_rc = 0; + + if (!out) + return (-1); + if (out->writecallback != NULL) + xmlOutputBufferFlush(out); + if (out->closecallback != NULL) { + err_rc = out->closecallback(out->context); + } + written = out->written; + if (out->conv) { + xmlBufferFree(out->conv); + out->conv = NULL; + } + if (out->encoder != NULL) { + xmlCharEncCloseFunc(out->encoder); + } + if (out->buffer != NULL) { + xmlBufferFree(out->buffer); + out->buffer = NULL; + } + + if (out->error) + err_rc = -1; + xmlFree(out); + return ((err_rc == 0) ? written : err_rc); +} +#endif /* LIBXML_OUTPUT_ENABLED */ + +/** + * xmlParserInputBufferCreateFilename: + * @param URI a C string containing the URI or filename + * @param 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 + */ +XMLPUBFUNEXPORT xmlParserInputBufferPtr +xmlParserInputBufferCreateFilename(const char* URI, xmlCharEncoding enc) +{ + LOAD_GS_DIRECT + xmlParserInputBufferPtr ret; + int i = 0; + void* context = NULL; + + if (!URI) + return(NULL); + + if (xmlInputCallbackInitialized == 0) + xmlRegisterDefaultInputCallbacks(); + + /* + * Try to find one of the input accept method accepting that scheme + * Go in reverse to give precedence to user defined handlers. + */ + if (!context) { + for (i = xmlInputCallbackNr - 1;i >= 0;i--) + if (xmlInputCallbackTable[i].matchcallback && + xmlInputCallbackTable[i].matchcallback(URI) != 0) + { + context = xmlInputCallbackTable[i].opencallback(URI); + if (context) + break; + } + } + if (!context) { + return(NULL); + } + + /* + * Allocate the Input buffer front-end. + */ + ret = xmlAllocParserInputBuffer(enc); + if (ret) + { + 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 (((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 + } + return(ret); +} + +#ifdef LIBXML_OUTPUT_ENABLED +/** + * xmlOutputBufferCreateFilename: + * @param URI a C string containing the URI or filename + * @param encoder the encoding converter or NULL + * @param 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. + * currently if compression is set, the library only support + * writing to a local file. + * + * Returns the new output or NULL + */ +XMLPUBFUNEXPORT xmlOutputBufferPtr +xmlOutputBufferCreateFilename(const char *URI, + xmlCharEncodingHandlerPtr encoder, + int compression ATTRIBUTE_UNUSED) +{ + LOAD_GS_DIRECT + xmlOutputBufferPtr ret; + xmlURIPtr puri; + int i = 0; + void* context = NULL; + char* unescaped = NULL; +#ifdef HAVE_ZLIB_H + int is_file_uri = 1; // Used only in ZLIB-enabled parts +#endif + + if (xmlOutputCallbackInitialized == 0) + xmlRegisterDefaultOutputCallbacks(); + if (!URI) + return(NULL); + + puri = xmlParseURI(URI); + if (!puri) + return NULL; +#ifdef HAVE_ZLIB_H + if (puri->scheme && + !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) + { + 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) { +#ifdef HAVE_ZLIB_H + if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) { + context = xmlGzfileOpenW(unescaped, compression); + if (context) { + ret = xmlAllocOutputBuffer(encoder); + if (ret) { + 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 && + 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) + break; + } + } + xmlFree(unescaped); + } // end if(unescaped) + + /* + * If this failed try with a non-escaped URI this may be a strange + * filename + */ + if (!context) { +#ifdef HAVE_ZLIB_H + if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) + { + context = xmlGzfileOpenW(URI, compression); + if (context) { + ret = xmlAllocOutputBuffer(encoder); + if (ret) { + ret->context = context; + ret->writecallback = xmlGzfileWrite; + ret->closecallback = xmlGzfileClose; + } + return(ret); + } + } +#endif + for (i = xmlOutputCallbackNr - 1;i >= 0;i--) + { + if (xmlOutputCallbackTable[i].matchcallback && + 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) + break; + } + } + } + + if (!context) { + return(NULL); + } + + /* + * Allocate the Output buffer front-end. + */ + ret = xmlAllocOutputBuffer(encoder); + if (ret) { + ret->context = context; + ret->writecallback = xmlOutputCallbackTable[i].writecallback; + ret->closecallback = xmlOutputCallbackTable[i].closecallback; + } + return(ret); +} +#endif /* LIBXML_OUTPUT_ENABLED */ + +#ifndef XMLENGINE_EXCLUDE_FILE_FUNC +/** + * xmlParserInputBufferCreateFile: + * @param file a FILE* + * @param 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 + */ +XMLPUBFUNEXPORT xmlParserInputBufferPtr +xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) +{ + xmlParserInputBufferPtr ret; + + if (xmlInputCallbackInitialized == 0) + xmlRegisterDefaultInputCallbacks(); + + if (!file) + return(NULL); + + ret = xmlAllocParserInputBuffer(enc); + if (ret) { + ret->context = file; + ret->readcallback = xmlFileRead; + ret->closecallback = xmlFileFlush; + } + + return(ret); +} +#endif + +#ifdef LIBXML_OUTPUT_ENABLED +/** + * xmlOutputBufferCreateFile: + * @param file a FILE* + * @param 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 in OOM + * OOM: possible --> NULL is returned + */ +XMLPUBFUNEXPORT xmlOutputBufferPtr +xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) +{ + LOAD_GS_DIRECT + xmlOutputBufferPtr ret; + + if (xmlOutputCallbackInitialized == 0) + xmlRegisterDefaultOutputCallbacks(); + + if (file == NULL) return(NULL); + + ret = xmlAllocOutputBuffer(encoder); + + if(ret){ + ret->context = file; + ret->writecallback = xmlFileWrite; + ret->closecallback = xmlFileFlush; + } + return(ret); +} +#endif /* LIBXML_OUTPUT_ENABLED */ + + +/** + * xmlParserInputBufferCreateFd: + * @param fd a file descriptor number + * @param 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 + */ +XMLPUBFUNEXPORT xmlParserInputBufferPtr +xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) +{ + xmlParserInputBufferPtr ret; + + if (fd < 0) return(NULL); + + ret = xmlAllocParserInputBuffer(enc); + if (ret != NULL) { + ret->context = (void *) (long) fd; + ret->readcallback = xmlFdRead; + ret->closecallback = xmlFdClose; + } + + return(ret); +} + +/** + * xmlParserInputBufferCreateMem: + * @param mem the memory input + * @param size the length of the memory block + * @param 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 + * + * OOM: possible --> sets OOM flag, returns NULL for mem!=NULL && size>0 + */ +XMLPUBFUNEXPORT xmlParserInputBufferPtr +xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) +{ + LOAD_GS_DIRECT + xmlParserInputBufferPtr ret; + + 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; + xmlBufferAdd(ret->buffer, (const xmlChar*) mem, size); + if(OOM_FLAG){ + xmlFreeParserInputBuffer(ret); + return NULL; + } + } + + return(ret); +} + +/** + * xmlParserInputBufferCreateStatic: + * @param mem the memory input + * @param size the length of the memory block + * @param 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 + */ +XMLPUBFUNEXPORT xmlParserInputBufferPtr +xmlParserInputBufferCreateStatic(const char *mem, int size, xmlCharEncoding enc) +{ + LOAD_GS_DIRECT + xmlParserInputBufferPtr ret; + + if (size <= 0) return(NULL); + if (mem == NULL) return(NULL); + + ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer)); + if (ret == NULL) { + xmlIOErrMemory(EMBED_ERRTXT("creating input buffer")); + return(NULL); + } + memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer)); + ret->buffer = xmlBufferCreateStatic((void *)mem, (size_t) size); + if (ret->buffer == NULL) { + xmlFree(ret); + return(NULL); + } + ret->encoder = xmlGetCharEncodingHandler(enc); + if (ret->encoder != NULL) + ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize); + else + ret->raw = NULL; + ret->compressed = -1; + ret->context = (void *) mem; + ret->readcallback = NULL; + ret->closecallback = NULL; + + return(ret); +} + +#ifdef LIBXML_OUTPUT_ENABLED +/** + * xmlOutputBufferCreateFd: + * @param fd a file descriptor number + * @param 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 + */ +XMLPUBFUNEXPORT xmlOutputBufferPtr +xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) +{ + xmlOutputBufferPtr ret; + + if (fd < 0) return(NULL); + + ret = xmlAllocOutputBuffer(encoder); + if (ret != NULL) { + ret->context = (void *) (long) fd; + ret->writecallback = xmlFdWrite; + ret->closecallback = NULL; + } + + return(ret); +} +#endif /* LIBXML_OUTPUT_ENABLED */ + +/** + * xmlParserInputBufferCreateIO: + * @param ioread an I/O read function + * @param ioclose an I/O close function + * @param ioctx an I/O handler + * @param 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 + */ +XMLPUBFUNEXPORT 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: + * @param iowrite an I/O write function + * @param ioclose an I/O close function + * @param ioctx an I/O handler + * @param 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 + */ +XMLPUBFUNEXPORT xmlOutputBufferPtr +xmlOutputBufferCreateIO( + xmlOutputWriteCallback iowrite, + xmlOutputCloseCallback ioclose, + void *ioctx, + xmlCharEncodingHandlerPtr encoder) +{ + xmlOutputBufferPtr ret; + + if (iowrite == NULL) return(NULL); + + ret = xmlAllocOutputBuffer(encoder); + if (ret != NULL) { + ret->context = (void*) ioctx; + ret->writecallback = iowrite; + ret->closecallback = ioclose; + } + + return(ret); +} +#endif /* LIBXML_OUTPUT_ENABLED */ + +/** + * xmlParserInputBufferPush: + * @param in a buffered parser input + * @param len the size in bytes of the array. + * @param buf an char array + * + * Push the content of the array 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. + * + * OOM: possible --> + */ +XMLPUBFUNEXPORT int +xmlParserInputBufferPush(xmlParserInputBufferPtr in, + int len, const char* buf) +{ + int nbchars; // initialization was unnecessary: = 0; + + if (len < 0) return(0); + + if (!in || in->error) + return(-1); + + if (in->encoder) + { + unsigned int use; + + /* + * Store the data in the incoming raw buffer + */ + if (!in->raw) { + in->raw = xmlBufferCreate(); + } + xmlBufferAdd(in->raw, (const xmlChar*) buf, len); + + /* + * convert as much as possible to the parser reading buffer. + */ + use = in->raw->use; + nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw); + if (nbchars < 0) { + xmlIOErr(XML_IO_ENCODER, NULL); + in->error = XML_IO_ENCODER; + return(-1); + } + in->rawconsumed += (use - in->raw->use); + } else { + nbchars = len; + xmlBufferAdd(in->buffer, (xmlChar*) buf, nbchars); + } +#ifdef DEBUG_INPUT + xmlGenericError(xmlGenericErrorContext, + "I/O: pushed %d chars, buffer %d/%d\n", + nbchars, in->buffer->use, in->buffer->size); +#endif + return(nbchars); +} + +/** + * endOfInput: + * + * When reading from an Input channel indicated end of file or error + * don't reread from it again. + */ +static int +endOfInput ( + void* context ATTRIBUTE_UNUSED, + char* buffer ATTRIBUTE_UNUSED, + int len ATTRIBUTE_UNUSED) +{ + return(0); +} + +/** + * xmlParserInputBufferGrow: + * @param in a buffered parser input + * @param 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 + * + * + * + * + * Returns the number of chars read and stored in the buffer, or -1 + * in case of error. + * + * OOM: possible --> sets OOM flag when returns 0 + */ +XMLPUBFUNEXPORT int +xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) +{ + LOAD_GS_DIRECT + char *buffer = NULL; + int res = 0; + int nbchars = 0; + int buffree; + unsigned int needSize; + + if ((in == NULL) || (in->error)) return(-1); + if ((len <= MINLEN) && (len != 4)) + len = MINLEN; + + buffree = in->buffer->size - in->buffer->use; + if (buffree <= 0) { + xmlIOErr(XML_IO_BUFFER_FULL, NULL); + in->error = XML_IO_BUFFER_FULL; + return(0); + } + + needSize = in->buffer->use + len + 1; + if (needSize > in->buffer->size) + { + if (!xmlBufferResize(in->buffer, needSize)) + { + xmlIOErrMemory(EMBED_ERRTXT("growing input buffer")); + in->error = XML_ERR_NO_MEMORY; + return(0); + } + } + buffer = (char*)&in->buffer->content[in->buffer->use]; + + /* + * Call the read method for this I/O type. + */ + if (in->readcallback != NULL) { + + res = in->readcallback(in->context, &buffer[0], len); + if (res <= 0) + in->readcallback = endOfInput; + } else { + xmlIOErr(XML_IO_NO_INPUT, NULL); + in->error = XML_IO_NO_INPUT; + return(-1); + } + if (res < 0) { + return(-1); + } + len = res; + if (in->encoder != NULL) { + unsigned int use; + + /* + * Store the data in the incoming raw buffer + */ + if (in->raw == NULL) { + in->raw = xmlBufferCreate(); + if(OOM_FLAG) + return 0; + } + xmlBufferAdd(in->raw, (const xmlChar *) buffer, len); + if(OOM_FLAG) + return 0; + /* + * convert as much as possible to the parser reading buffer. + */ + use = in->raw->use; + nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw); + if(OOM_FLAG) + return 0; + + if (nbchars < 0) { + xmlIOErr(XML_IO_ENCODER, NULL); + in->error = XML_IO_ENCODER; + return(-1); + } + in->rawconsumed += (use - in->raw->use); + } else { + nbchars = len; + in->buffer->use += nbchars; + buffer[nbchars] = 0; + } +#ifdef DEBUG_INPUT + xmlGenericError(xmlGenericErrorContext, + "I/O: read %d chars, buffer %d/%d\n", + nbchars, in->buffer->use, in->buffer->size); +#endif + return(nbchars); +} + +/** + * xmlParserInputBufferRead: + * @param in a buffered parser input + * @param 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. + */ +XMLPUBFUNEXPORT int +xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) +{ + if ((in == NULL) || (in->error)) return(-1); + if (in->readcallback != NULL) + return(xmlParserInputBufferGrow(in, len)); + else if ((in->buffer != NULL) && + (in->buffer->alloc == XML_BUFFER_ALLOC_IMMUTABLE)) + return(0); + else + return(-1); +} + +#ifdef LIBXML_OUTPUT_ENABLED +/** + * xmlOutputBufferWrite: + * @param out a buffered parser output + * @param len the size in bytes of the array. + * @param 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. + */ +XMLPUBFUNEXPORT 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 || 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) { + /* + * Store the data in the incoming raw buffer + */ + if (!out->conv) { + out->conv = xmlBufferCreate(); + } + xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk); + + if ((out->buffer->use < MINLEN) && (chunk == len)) + goto done; + + /* + * convert as much as possible to the parser reading buffer. + */ + ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer); + if ((ret < 0) && (ret != -3)) { + xmlIOErr(XML_IO_ENCODER, NULL); + out->error = XML_IO_ENCODER; + return(-1); + } + nbchars = out->conv->use; + } else { + xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk); + nbchars = out->buffer->use; + } + buf += chunk; + len -= chunk; + + if ((nbchars < MINLEN) && (len <= 0)) + goto done; + + if (out->writecallback) { + /* + * second write the stuff to the I/O channel + */ + if (out->encoder != NULL) { + ret = out->writecallback(out->context, + (const char *)out->conv->content, nbchars); + if (ret >= 0) + xmlBufferShrink(out->conv, ret); + } else { + ret = out->writecallback(out->context, + (const char *)out->buffer->content, nbchars); + if (ret >= 0) + xmlBufferShrink(out->buffer, ret); + } + if (ret < 0) { + xmlIOErr(XML_IO_WRITE, NULL); + out->error = XML_IO_WRITE; + return(ret); + } + out->written += ret; + } + written += nbchars; + } while (len > 0); + +done: +#ifdef DEBUG_INPUT + xmlGenericError(xmlGenericErrorContext, + "I/O: wrote %d chars\n", written); +#endif + return(written); +} + +/** + * xmlEscapeContent: + * @param out a pointer to an array of bytes to store the result + * @param outlen the length of out + * @param in a pointer to an array of unescaped UTF-8 bytes + * @param 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: + * @param out a buffered parser output + * @param str a zero terminated UTF-8 string + * @param 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. + */ +XMLPUBFUNEXPORT 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 chunk; /* number of byte currently processed from str */ + int len; /* number of bytes in str */ + int cons; /* byte from str consumed */ + + if (!out || out->error || !str) + return(-1); + len = strlen((const char*)str); + if (len < 0) + return(0); + if (out->error) + return(-1); + if (!escaping) + escaping = xmlEscapeContent; + + do { + /* + * how many bytes to consume and how many bytes to store. + */ + cons = len; + chunk = (out->buffer->size - out->buffer->use) - 1; + + /* + * first handle encoding stuff. + */ + if (out->encoder != NULL) { + /* + * Store the data in the incoming raw buffer + */ + if (out->conv == NULL) { + out->conv = xmlBufferCreate(); + } + ret = escaping(out->buffer->content + out->buffer->use , + &chunk, str, &cons); + if (ret < 0) + return(-1); + out->buffer->use += chunk; + out->buffer->content[out->buffer->use] = 0; + + if ((out->buffer->use < MINLEN) && (cons == len)) + goto done; + + /* + * convert as much as possible to the output buffer. + */ + ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer); + if ((ret < 0) && (ret != -3)) { + xmlIOErr(XML_IO_ENCODER, NULL); + out->error = XML_IO_ENCODER; + return(-1); + } + nbchars = out->conv->use; + } else { + ret = escaping(out->buffer->content + out->buffer->use , + &chunk, str, &cons); + if (ret < 0) + return(-1); + out->buffer->use += chunk; + out->buffer->content[out->buffer->use] = 0; + nbchars = out->buffer->use; + } + str += cons; + len -= cons; + + if ((nbchars < MINLEN) && (len <= 0)) + goto done; + + if (out->writecallback) { + /* + * second write the stuff to the I/O channel + */ + if (out->encoder != NULL) { + ret = out->writecallback(out->context, + (const char *)out->conv->content, nbchars); + if (ret >= 0) + xmlBufferShrink(out->conv, ret); + } else { + ret = out->writecallback(out->context, + (const char *)out->buffer->content, nbchars); + if (ret >= 0) + xmlBufferShrink(out->buffer, ret); + } + if (ret < 0) { + xmlIOErr(XML_IO_WRITE, NULL); + out->error = XML_IO_WRITE; + return(ret); + } + out->written += ret; + } else if (out->buffer->size - out->buffer->use < MINLEN) { + if (!xmlBufferResize(out->buffer, out->buffer->size + MINLEN)) + { + chunk = out->buffer->size - out->buffer->use - 1; + if(chunk <= 0) + { + /* can't proceed without more buffer */ + out->error = XML_ERR_NO_MEMORY; + return(-1); + } + + } + } + written += nbchars; + } while (len > 0); + +done: +#ifdef DEBUG_INPUT + xmlGenericError(xmlGenericErrorContext, "I/O: wrote %d chars\n", written); +#endif + return(written); +} + +/** + * xmlOutputBufferWriteString: + * @param out a buffered parser output + * @param 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. + * + * OOM: possible + */ +XMLPUBFUNEXPORT int +xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) +{ + int len; + + if (!out || out->error || !str) + return(-1); + len = strlen(str); + + if (len > 0) + return(xmlOutputBufferWrite(out, len, str)); + return(len); +} + +/** + * xmlOutputBufferFlush: + * @param out a buffered output + * + * flushes the output I/O channel + * + * Returns the number of byte written or -1 in case of error. + */ +XMLPUBFUNEXPORT int +xmlOutputBufferFlush(xmlOutputBufferPtr out) +{ + int ret = 0; + + if (!out || out->error) + return(-1); + +// XMLENGINE: Replaced code +/* + if (out->conv && out->encoder) + { + int nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer); + if (nbchars < 0) { + xmlIOErr(XML_IO_ENCODER, NULL); + out->error = XML_IO_ENCODER; + return(-1); + } + } + + if (out->conv) && + out->encoder && + out->writecallback) + { + ret = out->writecallback( + out->context, + (const char *)out->conv->content, + out->conv->use); + if (ret >= 0) + xmlBufferShrink(out->conv, ret); + } else if (out->writecallback != NULL) { + ret = out->writecallback( + out->context, + (const char*) out->buffer->content, + out->buffer->use); + if (ret >= 0) + xmlBufferShrink(out->buffer, ret); + } +*/ +// ----------- + if (out->writecallback) + { + xmlBufferPtr buffer; + + /* + * first handle encoding stuff. + */ + if (out->conv && out->encoder) + { + /* + * convert as much as possible to the parser reading buffer. + */ + int nbchars; + + buffer = out->conv; + nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer); + if (nbchars < 0) { + xmlIOErr(XML_IO_ENCODER, NULL); + out->error = XML_IO_ENCODER; + return(-1); + } + } else { + buffer = out->buffer; + } + + /* + * second flush the stuff to the I/O channel + */ + ret = out->writecallback( + out->context, + (const char*) buffer->content, + buffer->use); + if (ret >= 0) + xmlBufferShrink(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: + * @param filename the path to a file + * + * lookup the directory for that file + * + * Returns a new allocated string containing the directory, or NULL. + */ +XMLPUBFUNEXPORT char* +xmlParserGetDirectory(const char* filename) +{ + LOAD_GS_DIRECT + char* ret = NULL; + char dir[1024]; + char* cur; + char sep; + + if (!filename) + return(NULL); + + if (xmlInputCallbackInitialized == 0) + xmlRegisterDefaultInputCallbacks(); + + + sep = '\\'; // NOTE: All backslashes are converted to slashes + // when converting all local paths to URIs; + // Later they are converted to backslashes.. + // Seems inefficient, but works for now... + + strncpy(dir, filename, 1023); + dir[1023] = 0; + cur = &dir[strlen(dir)]; + while (cur > dir) { + if (*cur == sep) + break; + cur --; + } + if (*cur == sep) { + if (cur == dir) + dir[1] = 0; + else + *cur = 0; + ret = xmlMemStrdup(dir); + } else { + if (getcwd(dir, 1024)) { + dir[1023] = 0; + ret = xmlMemStrdup(dir); + } + } + return(ret); +} + +/**************************************************************** + * * + * External entities loading * + * * + ****************************************************************/ + +/** + * xmlCheckHTTPInput: + * @param ctxt an XML parser context + * @param 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. + */ +XMLPUBFUNEXPORT 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 xmlSysIDExists(const char* URL) +{ +#ifdef HAVE_STAT + int ret; + struct stat info; + const char *path; + + if (URL == NULL) + return(0); + + if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17)) + path = &URL[17]; + else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) { + path = &URL[8]; + } else { + path = URL; + } + + ret = stat(path, &info); + if (ret == 0) + return(1); +#endif + return(0); +} + +/** + * xmlDefaultExternalEntityLoader: + * @param URL the URL for the entity to load + * @param ID the System ID for the entity to load + * @param 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. + */ +xmlParserInputPtr +xmlDefaultExternalEntityLoader(const char *URL, const char *ID, xmlParserCtxtPtr ctxt) +{ + xmlParserInputPtr ret = NULL; + xmlChar *resource = NULL; + +#ifdef LIBXML_CATALOG_ENABLED + xmlCatalogAllow pref; +#endif + +#ifdef DEBUG_EXTERNAL_ENTITIES + xmlGenericError(xmlGenericErrorContext, + "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL); +#endif +#ifdef LIBXML_CATALOG_ENABLED + 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); + } + + /* + * 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) && (!xmlSysIDExists(URL))) { + /* + * Do a local lookup + */ + if ((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); + + /* + * + */ + if ((resource != NULL) + && (!xmlSysIDExists((const char *) resource))) { + xmlChar *tmp = NULL; + + if ((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) { + xmlFree(resource); + resource = tmp; + } + } + } +#endif + + if (!resource) + resource = (xmlChar*) URL; + + if (!resource) { + if (!ID) + ID = "NULL"; + __xmlLoaderErr(ctxt, EMBED_ERRTXT("failed to load external entity \"%s\"\n"), ID); + return (NULL); + } + ret = xmlNewInputFromFile(ctxt, (const char*) resource); + if (resource && resource != (xmlChar*)URL) + xmlFree(resource); + return (ret); +} + +#ifndef XMLENGINE_EXCLUDE_UNUSED +/** + * xmlSetExternalEntityLoader: + * @param 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); +} +#endif /* ifndef XMLENGINE_EXCLUDE_UNUSED */ + +/** + * xmlLoadExternalEntity: + * @param URL the URL for the entity to load + * @param ID the Public ID for the entity to load + * @param 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 + * + * OOM: + */ +XMLPUBFUNEXPORT xmlParserInputPtr +xmlLoadExternalEntity(const char *URL, const char *ID, xmlParserCtxtPtr ctxt) +{ + LOAD_GS_DIRECT + if (URL && (xmlSysIDExists(URL) == 0)) { + char* canonicFilename; + xmlParserInputPtr ret; + + canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL); + if (!canonicFilename) { + xmlIOErrMemory(EMBED_ERRTXT("building canonical path\n")); + return(NULL); + } + + ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt); + xmlFree(canonicFilename); + return(ret); + } + return(xmlCurrentExternalEntityLoader(URL, ID, ctxt)); +} + +/************************************************************************ + * * + * Disabling Network access * + * * + ************************************************************************/ + +#ifdef LIBXML_CATALOG_ENABLED +static int +xmlNoNetExists(const char *URL) +{ +#ifdef HAVE_STAT + int ret; + struct stat info; + const char *path; + + if (!URL) + return (0); + + if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17)) + path = &URL[17]; + else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) { + path = &URL[8]; + } else + path = URL; + ret = stat(path, &info); + if (ret == 0) + return (1); +#endif + return (0); +} +#endif + +/** + * xmlNoNetExternalEntityLoader: + * @param URL the URL for the entity to load + * @param ID the System ID for the entity to load + * @param 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. + */ +XMLPUBFUNEXPORT xmlParserInputPtr +xmlNoNetExternalEntityLoader(const char *URL, const char *ID, xmlParserCtxtPtr ctxt) +{ + xmlParserInputPtr input = NULL; + xmlChar *resource = NULL; + +#ifdef LIBXML_CATALOG_ENABLED + 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->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); + + /* + * + */ + if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) { + xmlChar *tmp = NULL; + + if ((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; + } + } + } +#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); +} +