#define IN_LIBXML
#include "libxml.h"
#include <string.h>
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_ZLIB_H
#include <zlib.h>
#endif
#ifndef HAVE_STAT
# ifdef HAVE__STAT
# 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 <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>
#ifdef DEBUG_INPUT
#define MINLEN 40
#else
#define MINLEN 4000
#endif
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;
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;
xmlChar *
xmlNormalizeWindowsPath(const xmlChar *path)
{
return xmlCanonicPath(path);
}
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;
}
xmlInputCallbackInitialized = 0;
xmlInputCallbackNr = 0;
xmlInputCallbackInitialized = 0;
}
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;
}
xmlOutputCallbackInitialized = 0;
xmlOutputCallbackNr = 0;
xmlOutputCallbackInitialized = 0;
}
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);
}
static int
xmlFdRead (void * context, char * buffer, int len) {
return(read((int) (long) context, &buffer[0], len));
}
static int
xmlFdWrite (void * context, const char * buffer, int len) {
return(write((int) (long) context, &buffer[0], len));
}
static int
xmlFdClose (void * context) {
return ( close((int) (long) context) );
}
int
xmlFileMatch (const char *filename ATTRIBUTE_UNUSED) {
return(1);
}
static void *
xmlFileOpen_real (const char *filename) {
const char *path = NULL;
FILE *fd;
if (!strcmp(filename, "-")) {
fd = stdin;
return((void *) fd);
}
if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
#if defined (_WIN32) && !defined(__CYGWIN__)
path = &filename[17];
#else
path = &filename[16];
#endif
else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
#if defined (_WIN32) && !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 (__CYGWIN__)
fd = fopen(path, "rb");
#else
fd = fopen(path, "r");
#endif
return((void *) fd);
}
void *
xmlFileOpen (const char *filename) {
char *unescaped;
void *retval;
unescaped = xmlURIUnescapeString(filename, 0, NULL);
if (unescaped != NULL) {
retval = xmlFileOpen_real(unescaped);
} else {
retval = xmlFileOpen_real(filename);
}
xmlFree(unescaped);
return retval;
}
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(__CYGWIN__)
path = &filename[17];
#else
path = &filename[16];
#endif
else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
#if defined (_WIN32) && !defined(__CYGWIN__)
path = &filename[8];
#else
path = &filename[7];
#endif
} else
path = filename;
if (path == NULL)
return(NULL);
fd = fopen(path, "w");
return((void *) fd);
}
int
xmlFileRead (void * context, char * buffer, int len) {
return(fread(&buffer[0], 1, len, (FILE *) context));
}
static int
xmlFileWrite (void * context, const char * buffer, int len) {
int items;
items = fwrite(&buffer[0], len, 1, (FILE *) context);
return(items * len);
}
int
xmlFileClose (void * context) {
FILE *fil;
fil = (FILE *) context;
if (fil == stdin)
return(0);
if (fil == stdout)
return(0);
if (fil == stderr)
return(0);
return ( ( fclose((FILE *) context) == EOF ) ? -1 : 0 );
}
static int
xmlFileFlush (void * context) {
return ( ( fflush((FILE *) context) == EOF ) ? -1 : 0 );
}
#ifdef HAVE_ZLIB_H
static int
xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
return(1);
}
static void *
xmlGzfileOpen_real (const char *filename) {
const char *path = NULL;
gzFile fd;
if (!strcmp(filename, "-")) {
fd = gzdopen(dup(0), "rb");
return((void *) fd);
}
if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
#if defined (_WIN32) && !defined(__CYGWIN__)
path = &filename[17];
#else
path = &filename[16];
#endif
else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
#if defined (_WIN32) && !defined(__CYGWIN__)
path = &filename[8];
#else
path = &filename[7];
#endif
} else
path = filename;
if (path == NULL)
return(NULL);
if (!xmlCheckFilename(path))
return(NULL);
fd = gzopen(path, "rb");
return((void *) fd);
}
static void *
xmlGzfileOpen (const char *filename) {
char *unescaped;
void *retval;
unescaped = xmlURIUnescapeString(filename, 0, NULL);
if (unescaped != NULL) {
retval = xmlGzfileOpen_real(unescaped);
} else {
retval = xmlGzfileOpen_real(filename);
}
xmlFree(unescaped);
return retval;
}
static void *
xmlGzfileOpenW (const char *filename, int compression) {
const char *path = NULL;
char mode[15];
gzFile fd;
snprintf(mode, sizeof(mode), "wb%d", compression);
if (!strcmp(filename, "-")) {
fd = gzdopen(dup(1), mode);
return((void *) fd);
}
if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
#if defined (_WIN32) && !defined(__CYGWIN__)
path = &filename[17];
#else
path = &filename[16];
#endif
else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
#if defined (_WIN32) && !defined(__CYGWIN__)
path = &filename[8];
#else
path = &filename[7];
#endif
} else
path = filename;
if (path == NULL)
return(NULL);
fd = gzopen(path, mode);
return((void *) fd);
}
static int
xmlGzfileRead (void * context, char * buffer, int len) {
return(gzread((gzFile) context, &buffer[0], len));
}
static int
xmlGzfileWrite (void * context, const char * buffer, int len) {
return(gzwrite((gzFile) context, (char *) &buffer[0], len));
}
static int
xmlGzfileClose (void * context) {
return ( ( gzclose((gzFile) context) == Z_OK ) ? 0 : -1 );
}
#endif
#ifdef LIBXML_HTTP_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 )
typedef struct xmlZMemBuff_
{
unsigned long size;
unsigned long crc;
unsigned char * zbuff;
z_stream zctrl;
} xmlZMemBuff, *xmlZMemBuffPtr;
static void
append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) {
int idx;
if ( buff == NULL )
return;
for ( idx = 0; idx < 4; idx++ ) {
*buff->zctrl.next_out = ( data & 0xff );
data >>= 8;
buff->zctrl.next_out++;
}
return;
}
static void
xmlFreeZMemBuff( xmlZMemBuffPtr buff ) {
int z_err;
if ( buff == NULL )
return;
xmlFree( buff->zbuff );
z_err = deflateEnd( &buff->zctrl );
#ifdef DEBUG_HTTP
if ( z_err != Z_OK )
xmlGenericError( xmlGenericErrorContext,
"xmlFreeZMemBuff: Error releasing zlib context: %d\n",
z_err );
#endif
xmlFree( buff );
return;
}
static void *
xmlCreateZMemBuff( int compression ) {
int z_err;
int hdr_lgth;
xmlZMemBuffPtr buff = NULL;
if ( ( compression < 1 ) || ( compression > 9 ) )
return ( NULL );
buff = xmlMalloc( sizeof( xmlZMemBuff ) );
if ( buff == NULL ) {
xmlGenericError( xmlGenericErrorContext,
"xmlCreateZMemBuff: %s\n",
"Failure allocating 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 );
xmlGenericError( xmlGenericErrorContext,
"xmlCreateZMemBuff: %s\n",
"Failure allocating data buffer." );
return ( NULL );
}
z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
if ( z_err != Z_OK ) {
xmlFreeZMemBuff( buff );
buff = NULL;
xmlGenericError( xmlGenericErrorContext,
"xmlCreateZMemBuff: %s %d\n",
"Error initializing compression context. ZLIB error:",
z_err );
return ( NULL );
}
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 );
}
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 {
xmlGenericError( xmlGenericErrorContext,
"xmlZMemBuffExtend: %s %lu bytes.\n",
"Allocation failure extending output buffer to",
new_size );
}
return ( rc );
}
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 ) {
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 ) {
xmlGenericError( xmlGenericErrorContext,
"xmlZMemBuffAppend: %s %d %s - %d",
"Compression error while appending",
len, "bytes to buffer. ZLIB error", z_err );
return ( -1 );
}
}
buff->crc = crc32( buff->crc, (unsigned char *)src, len );
return ( len );
}
static int
xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) {
int zlgth = -1;
int z_err;
if ( ( buff == NULL ) || ( data_ref == NULL ) )
return ( -1 );
do
{
z_err = deflate( &buff->zctrl, Z_FINISH );
if ( z_err == Z_OK ) {
if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
return ( -1 );
}
}
while ( z_err == Z_OK );
if ( z_err == Z_STREAM_END ) {
if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) {
if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 )
return ( -1 );
}
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
xmlGenericError( xmlGenericErrorContext,
"xmlZMemBuffGetContent: %s - %d\n",
"Error flushing zlib buffers. Error code", z_err );
return ( zlgth );
}
#endif
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;
}
int
xmlIOHTTPMatch (const char *filename) {
if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "http://", 7))
return(1);
return(0);
}
void *
xmlIOHTTPOpen (const char *filename) {
return(xmlNanoHTTPOpen(filename, NULL));
}
void *
xmlIOHTTPOpenW(const char *post_uri, int compression)
{
xmlIOHTTPWriteCtxtPtr ctxt = NULL;
if (post_uri == NULL)
return (NULL);
ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt));
if (ctxt == NULL) {
xmlGenericError(xmlGenericErrorContext,
"xmlIOHTTPOpenW: Failed to create output HTTP context.\n");
return (NULL);
}
(void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt));
ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri);
if (ctxt->uri == NULL) {
xmlGenericError(xmlGenericErrorContext,
"xmlIOHTTPOpenW: Failed to duplicate destination URI.\n");
xmlFreeHTTPWriteCtxt(ctxt);
return (NULL);
}
#ifdef HAVE_ZLIB_H
if ((compression > 0) && (compression <= 9)) {
ctxt->compression = compression;
ctxt->doc_buff = xmlCreateZMemBuff(compression);
} else
#endif
{
ctxt->doc_buff = xmlAllocOutputBuffer(NULL);
}
if (ctxt->doc_buff == NULL) {
xmlFreeHTTPWriteCtxt(ctxt);
ctxt = NULL;
}
return (ctxt);
}
static void *
xmlIOHTTPDfltOpenW( const char * post_uri ) {
return ( xmlIOHTTPOpenW( post_uri, 0 ) );
}
int
xmlIOHTTPRead(void * context, char * buffer, int len) {
return(xmlNanoHTTPRead(context, &buffer[0], len));
}
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 ) {
#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 ) {
xmlGenericError( xmlGenericErrorContext,
"xmlIOHTTPWrite: %s\n%s '%s'.\n",
"Error appending to internal buffer.",
"Error sending document to URI",
ctxt->uri );
}
}
return ( len );
}
int
xmlIOHTTPClose (void * context) {
xmlNanoHTTPClose(context);
return 0;
}
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 );
#ifdef HAVE_ZLIB_H
if ( ctxt->compression > 0 ) {
content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
content_encoding = (char *) "Content-Encoding: gzip";
}
else
#endif
{
xmlOutputBufferPtr dctxt = ctxt->doc_buff;
http_content = (char *)dctxt->buffer->content;
content_lgth = dctxt->buffer->use;
}
if ( http_content == NULL ) {
xmlGenericError( xmlGenericErrorContext,
"xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
"Error retrieving content.\nUnable to",
http_mthd, "data to URI", ctxt->uri );
}
else {
http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
&content_type, content_encoding,
content_lgth );
if ( http_ctxt != NULL ) {
#ifdef DEBUG_HTTP
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 ) );
dump_name = tempnam( NULL, "lxml" );
if ( dump_name != NULL ) {
(void)snprintf( buffer, sizeof(buffer), "%s.content", dump_name );
tst_file = fopen( buffer, "w" );
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, "w" );
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
http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
close_rc = 0;
else
xmlGenericError( xmlGenericErrorContext,
"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 );
xmlNanoHTTPClose( http_ctxt );
xmlFree( content_type );
}
}
xmlFreeHTTPWriteCtxt( ctxt );
return ( close_rc );
}
static int
xmlIOHTTPClosePut( void * ctxt ) {
return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
}
static int
xmlIOHTTPClosePost( void * ctxt ) {
return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
}
#endif
#ifdef LIBXML_FTP_ENABLED
int
xmlIOFTPMatch (const char *filename) {
if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "ftp://", 6))
return(1);
return(0);
}
void *
xmlIOFTPOpen (const char *filename) {
return(xmlNanoFTPOpen(filename));
}
int
xmlIOFTPRead(void * context, char * buffer, int len) {
return(xmlNanoFTPRead(context, &buffer[0], len));
}
int
xmlIOFTPClose (void * context) {
return ( xmlNanoFTPClose(context) );
}
#endif
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;
return(xmlInputCallbackNr++);
}
int
xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
xmlOutputCloseCallback closeFunc) {
if (xmlOutputCallbackNr >= MAX_INPUT_CALLBACK) {
return(-1);
}
xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
return(xmlOutputCallbackNr++);
}
void
xmlRegisterDefaultInputCallbacks
(void) {
if (xmlInputCallbackInitialized)
return;
xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
xmlFileRead, xmlFileClose);
#ifdef HAVE_ZLIB_H
xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
xmlGzfileRead, xmlGzfileClose);
#endif
#ifdef LIBXML_HTTP_ENABLED
xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
xmlIOHTTPRead, xmlIOHTTPClose);
#endif
#ifdef LIBXML_FTP_ENABLED
xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
xmlIOFTPRead, xmlIOFTPClose);
#endif
xmlInputCallbackInitialized = 1;
}
void
xmlRegisterDefaultOutputCallbacks
(void) {
if (xmlOutputCallbackInitialized)
return;
xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
xmlFileWrite, xmlFileClose);
#ifdef LIBXML_HTTP_ENABLED
xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
xmlIOHTTPWrite, xmlIOHTTPClosePut);
#endif
xmlOutputCallbackInitialized = 1;
}
#ifdef LIBXML_HTTP_ENABLED
void
xmlRegisterHTTPPostCallbacks( void ) {
if ( xmlOutputCallbackInitialized == 0 )
xmlRegisterDefaultOutputCallbacks( );
xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
xmlIOHTTPWrite, xmlIOHTTPClosePost);
return;
}
#endif
xmlParserInputBufferPtr
xmlAllocParserInputBuffer(xmlCharEncoding enc) {
xmlParserInputBufferPtr ret;
ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
if (ret == NULL) {
xmlGenericError(xmlGenericErrorContext,
"xmlAllocParserInputBuffer : out of memory!\n");
return(NULL);
}
memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
ret->buffer = xmlBufferCreate();
if (ret->buffer == NULL) {
xmlFree(ret);
return(NULL);
}
ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
ret->encoder = xmlGetCharEncodingHandler(enc);
if (ret->encoder != NULL)
ret->raw = xmlBufferCreate();
else
ret->raw = NULL;
ret->readcallback = NULL;
ret->closecallback = NULL;
ret->context = NULL;
return(ret);
}
xmlOutputBufferPtr
xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
xmlOutputBufferPtr ret;
ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
if (ret == NULL) {
xmlGenericError(xmlGenericErrorContext,
"xmlAllocOutputBuffer : out of memory!\n");
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);
xmlCharEncOutFunc(encoder, ret->conv, NULL);
} else
ret->conv = NULL;
ret->writecallback = NULL;
ret->closecallback = NULL;
ret->context = NULL;
ret->written = 0;
return(ret);
}
void
xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
if (in->raw) {
xmlBufferFree(in->raw);
in->raw = NULL;
}
if (in->encoder != NULL) {
xmlCharEncCloseFunc(in->encoder);
}
if (in->closecallback != NULL) {
in->closecallback(in->context);
}
if (in->buffer != NULL) {
xmlBufferFree(in->buffer);
in->buffer = NULL;
}
xmlFree(in);
}
int
xmlOutputBufferClose(xmlOutputBufferPtr out) {
int written;
int err_rc = 0;
if (out == NULL)
return(-1);
if (out->writecallback != NULL)
xmlOutputBufferFlush(out);
if (out->closecallback != NULL) {
err_rc = out->closecallback(out->context);
}
written = out->written;
if (out->conv) {
xmlBufferFree(out->conv);
out->conv = NULL;
}
if (out->encoder != NULL) {
xmlCharEncCloseFunc(out->encoder);
}
if (out->buffer != NULL) {
xmlBufferFree(out->buffer);
out->buffer = NULL;
}
xmlFree(out);
return( ( err_rc == 0 ) ? written : err_rc );
}
xmlParserInputBufferPtr
xmlParserInputBufferCreateFilename
(const char *URI, xmlCharEncoding enc) {
xmlParserInputBufferPtr ret;
int i = 0;
void *context = NULL;
if (xmlInputCallbackInitialized == 0)
xmlRegisterDefaultInputCallbacks();
if (URI == NULL) return(NULL);
#ifdef LIBXML_CATALOG_ENABLED
#endif
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);
}
ret = xmlAllocParserInputBuffer(enc);
if (ret != NULL) {
ret->context = context;
ret->readcallback = xmlInputCallbackTable[i].readcallback;
ret->closecallback = xmlInputCallbackTable[i].closecallback;
}
return(ret);
}
xmlOutputBufferPtr
xmlOutputBufferCreateFilename(const char *URI,
xmlCharEncodingHandlerPtr encoder,
int compression) {
xmlOutputBufferPtr ret;
int i = 0;
void *context = NULL;
char *unescaped;
int is_http_uri = 0;
if (xmlOutputCallbackInitialized == 0)
xmlRegisterDefaultOutputCallbacks();
if (URI == NULL) return(NULL);
#ifdef LIBXML_HTTP_ENABLED
is_http_uri = xmlIOHTTPMatch( URI );
#endif
unescaped = xmlURIUnescapeString(URI, 0, NULL);
if (unescaped != NULL) {
#ifdef HAVE_ZLIB_H
if ((compression > 0) && (compression <= 9) && (is_http_uri == 0)) {
context = xmlGzfileOpenW(unescaped, compression);
if (context != NULL) {
ret = xmlAllocOutputBuffer(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)
if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
context = xmlIOHTTPOpenW(unescaped, compression);
else
#endif
context = xmlOutputCallbackTable[i].opencallback(unescaped);
if (context != NULL)
break;
}
}
xmlFree(unescaped);
}
if (context == NULL) {
#ifdef HAVE_ZLIB_H
if ((compression > 0) && (compression <= 9) && (is_http_uri == 0)) {
context = xmlGzfileOpenW(URI, compression);
if (context != NULL) {
ret = xmlAllocOutputBuffer(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)
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);
}
ret = xmlAllocOutputBuffer(encoder);
if (ret != NULL) {
ret->context = context;
ret->writecallback = xmlOutputCallbackTable[i].writecallback;
ret->closecallback = xmlOutputCallbackTable[i].closecallback;
}
return(ret);
}
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);
}
xmlOutputBufferPtr
xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
xmlOutputBufferPtr ret;
if (xmlOutputCallbackInitialized == 0)
xmlRegisterDefaultOutputCallbacks();
if (file == NULL) return(NULL);
ret = xmlAllocOutputBuffer(encoder);
if (ret != NULL) {
ret->context = file;
ret->writecallback = xmlFileWrite;
ret->closecallback = xmlFileFlush;
}
return(ret);
}
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);
}
xmlParserInputBufferPtr
xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
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);
}
return(ret);
}
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);
}
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);
}
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);
}
int
xmlParserInputBufferPush(xmlParserInputBufferPtr in,
int len, const char *buf) {
int nbchars = 0;
if (len < 0) return(0);
if (in->encoder != NULL) {
if (in->raw == NULL) {
in->raw = xmlBufferCreate();
}
xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
if (nbchars < 0) {
xmlGenericError(xmlGenericErrorContext,
"xmlParserInputBufferPush: encoder error\n");
return(-1);
}
} 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);
}
static int
endOfInput (void * context ATTRIBUTE_UNUSED,
char * buffer ATTRIBUTE_UNUSED,
int len ATTRIBUTE_UNUSED) {
return(0);
}
int
xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
char *buffer = NULL;
int res = 0;
int nbchars = 0;
int buffree;
unsigned int needSize;
if ((len <= MINLEN) && (len != 4))
len = MINLEN;
buffree = in->buffer->size - in->buffer->use;
if (buffree <= 0) {
xmlGenericError(xmlGenericErrorContext,
"xmlParserInputBufferGrow : buffer full !\n");
return(0);
}
if (len > buffree)
len = buffree;
needSize = in->buffer->use + len + 1;
if (needSize > in->buffer->size){
if (!xmlBufferResize(in->buffer, needSize)){
xmlGenericError(xmlGenericErrorContext,
"xmlBufferAdd : out of memory!\n");
return(0);
}
}
buffer = (char *)&in->buffer->content[in->buffer->use];
if (in->readcallback != NULL) {
res = in->readcallback(in->context, &buffer[0], len);
if (res <= 0)
in->readcallback = endOfInput;
} else {
xmlGenericError(xmlGenericErrorContext,
"xmlParserInputBufferGrow : no input !\n");
return(-1);
}
if (res < 0) {
return(-1);
}
len = res;
if (in->encoder != NULL) {
if (in->raw == NULL) {
in->raw = xmlBufferCreate();
}
xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
if (nbchars < 0) {
xmlGenericError(xmlGenericErrorContext,
"xmlParserInputBufferGrow: encoder error\n");
return(-1);
}
} 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);
}
int
xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
if (in->readcallback != NULL)
return(xmlParserInputBufferGrow(in, len));
else
return(-1);
}
int
xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
int nbchars = 0;
int ret;
int written = 0;
int chunk;
if (len < 0) return(0);
do {
chunk = len;
if (chunk > 4 * MINLEN)
chunk = 4 * MINLEN;
if (out->encoder != NULL) {
if (out->conv == NULL) {
out->conv = xmlBufferCreate();
}
xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
if ((out->buffer->use < MINLEN) && (chunk == len))
goto done;
ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
if ((ret < 0) && (ret != -3)) {
xmlGenericError(xmlGenericErrorContext,
"xmlOutputBufferWrite: encoder error\n");
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) {
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) {
xmlGenericError(xmlGenericErrorContext,
"I/O: error %d writing %d bytes\n", ret, nbchars);
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);
}
int
xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
int len;
if (str == NULL)
return(-1);
len = strlen(str);
if (len > 0)
return(xmlOutputBufferWrite(out, len, str));
return(len);
}
int
xmlOutputBufferFlush(xmlOutputBufferPtr out) {
int nbchars = 0, ret = 0;
if ((out->conv != NULL) && (out->encoder != NULL)) {
nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
if (nbchars < 0) {
xmlGenericError(xmlGenericErrorContext,
"xmlOutputBufferFlush: encoder error\n");
return(-1);
}
}
if ((out->conv != NULL) && (out->encoder != NULL) &&
(out->writecallback != NULL)) {
ret = out->writecallback(out->context,
(const char *)out->conv->content, out->conv->use);
if (ret >= 0)
xmlBufferShrink(out->conv, ret);
} else if (out->writecallback != NULL) {
ret = out->writecallback(out->context,
(const char *)out->buffer->content, out->buffer->use);
if (ret >= 0)
xmlBufferShrink(out->buffer, ret);
}
if (ret < 0) {
xmlGenericError(xmlGenericErrorContext,
"I/O: error %d flushing %d bytes\n", ret, nbchars);
return(ret);
}
out->written += ret;
#ifdef DEBUG_INPUT
xmlGenericError(xmlGenericErrorContext,
"I/O: flushed %d chars\n", ret);
#endif
return(ret);
}
char *
xmlParserGetDirectory(const char *filename) {
char *ret = NULL;
char dir[1024];
char *cur;
char sep = '/';
#ifdef _WIN32_WCE
return NULL;
#endif
if (xmlInputCallbackInitialized == 0)
xmlRegisterDefaultInputCallbacks();
if (filename == NULL) return(NULL);
#if defined(WIN32) && !defined(__CYGWIN__)
sep = '\\';
#endif
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) != NULL) {
dir[1023] = 0;
ret = xmlMemStrdup(dir);
}
}
return(ret);
}
#ifdef LIBXML_CATALOG_ENABLED
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))
#if defined (_WIN32) && !defined(__CYGWIN__)
path = &URL[17];
#else
path = &URL[16];
#endif
else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
#if defined (_WIN32) && !defined(__CYGWIN__)
path = &URL[8];
#else
path = &URL[7];
#endif
} else
path = URL;
ret = stat(path, &info);
if (ret == 0)
return(1);
#endif
return(0);
}
#endif
static
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
pref = xmlCatalogGetDefaults();
if ((pref != XML_CATA_ALLOW_NONE) && (!xmlSysIDExists(URL))) {
if ((ctxt->catalogs != NULL) &&
((pref == XML_CATA_ALLOW_ALL) ||
(pref == XML_CATA_ALLOW_DOCUMENT))) {
resource = xmlCatalogLocalResolve(ctxt->catalogs,
(const xmlChar *)ID,
(const xmlChar *)URL);
}
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 != NULL) {
xmlFree(resource);
resource = tmp;
}
}
}
#endif
if (resource == NULL)
resource = (xmlChar *) URL;
if (resource == NULL) {
if (ID == NULL)
ID = "NULL";
if ((ctxt->validate) && (ctxt->sax != NULL) &&
(ctxt->sax->error != NULL))
ctxt->sax->error(ctxt,
"failed to load external entity \"%s\"\n", ID);
else if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
ctxt->sax->warning(ctxt,
"failed to load external entity \"%s\"\n", ID);
return(NULL);
}
ret = xmlNewInputFromFile(ctxt, (const char *)resource);
if (ret == NULL) {
if ((ctxt->validate) && (ctxt->sax != NULL) &&
(ctxt->sax->error != NULL))
ctxt->sax->error(ctxt,
"failed to load external entity \"%s\"\n", resource);
else if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
ctxt->sax->warning(ctxt,
"failed to load external entity \"%s\"\n", resource);
}
if ((resource != NULL) && (resource != (xmlChar *) URL))
xmlFree(resource);
return(ret);
}
static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
xmlDefaultExternalEntityLoader;
void
xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
xmlCurrentExternalEntityLoader = f;
}
xmlExternalEntityLoader
xmlGetExternalEntityLoader(void) {
return(xmlCurrentExternalEntityLoader);
}
xmlParserInputPtr
xmlLoadExternalEntity(const char *URL, const char *ID,
xmlParserCtxtPtr ctxt) {
return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
}
#ifdef LIBXML_CATALOG_ENABLED
static int
xmlNoNetExists(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))
#if defined (_WIN32) && !defined(__CYGWIN__)
path = &URL[17];
#else
path = &URL[16];
#endif
else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
#if defined (_WIN32) && !defined(__CYGWIN__)
path = &URL[8];
#else
path = &URL[7];
#endif
} else
path = URL;
ret = stat(path, &info);
if (ret == 0)
return (1);
#endif
return (0);
}
#endif
xmlParserInputPtr
xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
xmlParserCtxtPtr ctxt) {
xmlParserInputPtr input = NULL;
xmlChar *resource = NULL;
#ifdef LIBXML_CATALOG_ENABLED
xmlCatalogAllow pref;
pref = xmlCatalogGetDefaults();
if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
if ((ctxt->catalogs != NULL) &&
((pref == XML_CATA_ALLOW_ALL) ||
(pref == XML_CATA_ALLOW_DOCUMENT))) {
resource = xmlCatalogLocalResolve(ctxt->catalogs,
(const xmlChar *)ID,
(const xmlChar *)URL);
}
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))) {
xmlGenericError(xmlGenericErrorContext,
"Attempt to load network entity %s \n", resource);
if (resource != (xmlChar *) URL)
xmlFree(resource);
return(NULL);
}
}
input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
if (resource != (xmlChar *) URL)
xmlFree(resource);
return(input);
}