mirror of
https://gitlab.gnome.org/GNOME/libxml2.git
synced 2025-01-29 21:46:59 +03:00
d6d7f7bf96
a reconfigurable routine. The changes are: * xmlerror.h : added the export of an error context type (void *) an error handler type xmlGenericErrorFunc there is an interface xmlSetGenericErrorFunc(void *ctx, xmlGenericErrorFunc handler); to reset the error handling routine and its argument (by default it's equivalent to respectively fprintf and stderr. * all the c files: all wild accesses to stderr or stdout within the library have been replaced to calls to the handler. Daniel
1630 lines
39 KiB
C
1630 lines
39 KiB
C
/*
|
|
* xmlIO.c : implementation of the I/O interfaces used by the parser
|
|
*
|
|
* See Copyright for the status of this software.
|
|
*
|
|
* Daniel.Veillard@w3.org
|
|
*/
|
|
|
|
#ifdef WIN32
|
|
#include "win32config.h"
|
|
#else
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#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
|
|
|
|
#include <libxml/xmlmemory.h>
|
|
#include <libxml/parser.h>
|
|
#include <libxml/parserInternals.h>
|
|
#include <libxml/xmlIO.h>
|
|
#include <libxml/nanohttp.h>
|
|
#include <libxml/nanoftp.h>
|
|
#include <libxml/xmlerror.h>
|
|
|
|
/* #define VERBOSE_FAILURE */
|
|
/* #define DEBUG_EXTERNAL_ENTITIES */
|
|
/* #define DEBUG_INPUT */
|
|
|
|
#ifdef DEBUG_INPUT
|
|
#define MINLEN 40
|
|
#else
|
|
#define MINLEN 4000
|
|
#endif
|
|
|
|
/*
|
|
* Input I/O callback sets
|
|
*/
|
|
typedef struct _xmlInputCallback {
|
|
xmlInputMatchCallback matchcallback;
|
|
xmlInputOpenCallback opencallback;
|
|
xmlInputReadCallback readcallback;
|
|
xmlInputCloseCallback closecallback;
|
|
} xmlInputCallback;
|
|
|
|
#define MAX_INPUT_CALLBACK 15
|
|
|
|
xmlInputCallback xmlInputCallbackTable[MAX_INPUT_CALLBACK];
|
|
int xmlInputCallbackNr = 0;
|
|
int xmlInputCallbackInitialized = 0;
|
|
|
|
/*
|
|
* Output I/O callback sets
|
|
*/
|
|
typedef struct _xmlOutputCallback {
|
|
xmlOutputMatchCallback matchcallback;
|
|
xmlOutputOpenCallback opencallback;
|
|
xmlOutputWriteCallback writecallback;
|
|
xmlOutputCloseCallback closecallback;
|
|
} xmlOutputCallback;
|
|
|
|
#define MAX_OUTPUT_CALLBACK 15
|
|
|
|
xmlOutputCallback xmlOutputCallbackTable[MAX_OUTPUT_CALLBACK];
|
|
int xmlOutputCallbackNr = 0;
|
|
int xmlOutputCallbackInitialized = 0;
|
|
|
|
/************************************************************************
|
|
* *
|
|
* Standard I/O for file accesses *
|
|
* *
|
|
************************************************************************/
|
|
|
|
int
|
|
xmlNop(void) {
|
|
return(0);
|
|
}
|
|
|
|
/**
|
|
* xmlFdMatch:
|
|
* @filename: the URI for matching
|
|
*
|
|
* input from file descriptor
|
|
*
|
|
* Returns 1 if matches, 0 otherwise
|
|
*/
|
|
int
|
|
xmlFdMatch (const char *filename) {
|
|
return(1);
|
|
}
|
|
|
|
/**
|
|
* xmlFdOpen:
|
|
* @filename: the URI for matching
|
|
*
|
|
* input from file descriptor, supports compressed input
|
|
* if @filename is " " then the standard input is used
|
|
*
|
|
* Returns an I/O context or NULL in case of error
|
|
*/
|
|
void *
|
|
xmlFdOpen (const char *filename) {
|
|
const char *path = NULL;
|
|
int fd;
|
|
|
|
if (!strcmp(filename, "-")) {
|
|
fd = 0;
|
|
return((void *) fd);
|
|
}
|
|
|
|
if (!strncmp(filename, "file://localhost", 16))
|
|
path = &filename[16];
|
|
else if (!strncmp(filename, "file:///", 8))
|
|
path = &filename[8];
|
|
else if (filename[0] == '/')
|
|
path = filename;
|
|
if (path == NULL)
|
|
return(NULL);
|
|
|
|
#ifdef WIN32
|
|
fd = _open (filename, O_RDONLY | _O_BINARY);
|
|
#else
|
|
fd = open (filename, O_RDONLY);
|
|
#endif
|
|
|
|
return((void *) fd);
|
|
}
|
|
|
|
/**
|
|
* xmlFdOpenW:
|
|
* @filename: the URI for matching
|
|
*
|
|
* input from file descriptor,
|
|
* if @filename is "-" then the standard output is used
|
|
*
|
|
* Returns an I/O context or NULL in case of error
|
|
*/
|
|
void *
|
|
xmlFdOpenW (const char *filename) {
|
|
const char *path = NULL;
|
|
int fd;
|
|
|
|
if (!strcmp(filename, "-")) {
|
|
fd = 1;
|
|
return((void *) fd);
|
|
}
|
|
|
|
if (!strncmp(filename, "file://localhost", 16))
|
|
path = &filename[16];
|
|
else if (!strncmp(filename, "file:///", 8))
|
|
path = &filename[8];
|
|
else if (filename[0] == '/')
|
|
path = filename;
|
|
if (path == NULL)
|
|
return(NULL);
|
|
|
|
fd = open (filename, O_WRONLY);
|
|
|
|
return((void *) fd);
|
|
}
|
|
|
|
/**
|
|
* xmlFdRead:
|
|
* @context: the I/O context
|
|
* @buffer: where to drop data
|
|
* @len: number of bytes to read
|
|
*
|
|
* Read @len bytes to @buffer from the I/O channel.
|
|
*
|
|
* Returns the number of bytes written
|
|
*/
|
|
int
|
|
xmlFdRead (void * context, char * buffer, int len) {
|
|
return(read((int) context, &buffer[0], len));
|
|
}
|
|
|
|
/**
|
|
* xmlFdWrite:
|
|
* @context: the I/O context
|
|
* @buffer: where to get data
|
|
* @len: number of bytes to write
|
|
*
|
|
* Write @len bytes from @buffer to the I/O channel.
|
|
*
|
|
* Returns the number of bytes written
|
|
*/
|
|
int
|
|
xmlFdWrite (void * context, const char * buffer, int len) {
|
|
return(write((int) context, &buffer[0], len));
|
|
}
|
|
|
|
/**
|
|
* xmlFdClose:
|
|
* @context: the I/O context
|
|
*
|
|
* Close an I/O channel
|
|
*/
|
|
void
|
|
xmlFdClose (void * context) {
|
|
close((int) context);
|
|
}
|
|
|
|
/**
|
|
* xmlFileMatch:
|
|
* @filename: the URI for matching
|
|
*
|
|
* input from FILE *
|
|
*
|
|
* Returns 1 if matches, 0 otherwise
|
|
*/
|
|
int
|
|
xmlFileMatch (const char *filename) {
|
|
return(1);
|
|
}
|
|
|
|
/**
|
|
* xmlFileOpen:
|
|
* @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
|
|
*/
|
|
void *
|
|
xmlFileOpen (const char *filename) {
|
|
const char *path = NULL;
|
|
FILE *fd;
|
|
|
|
if (!strcmp(filename, "-")) {
|
|
fd = stdin;
|
|
return((void *) fd);
|
|
}
|
|
|
|
if (!strncmp(filename, "file://localhost", 16))
|
|
path = &filename[16];
|
|
else if (!strncmp(filename, "file:///", 8))
|
|
path = &filename[8];
|
|
else
|
|
path = filename;
|
|
if (path == NULL)
|
|
return(NULL);
|
|
|
|
#ifdef WIN32
|
|
fd = fopen(path, "rb");
|
|
#else
|
|
fd = fopen(path, "r");
|
|
#endif /* WIN32 */
|
|
return((void *) fd);
|
|
}
|
|
|
|
/**
|
|
* xmlFileOpenW:
|
|
* @filename: the URI for matching
|
|
*
|
|
* output to from FILE *,
|
|
* if @filename is "-" then the standard output is used
|
|
*
|
|
* Returns an I/O context or NULL in case of error
|
|
*/
|
|
void *
|
|
xmlFileOpenW (const char *filename) {
|
|
const char *path = NULL;
|
|
FILE *fd;
|
|
|
|
if (!strcmp(filename, "-")) {
|
|
fd = stdout;
|
|
return((void *) fd);
|
|
}
|
|
|
|
if (!strncmp(filename, "file://localhost", 16))
|
|
path = &filename[16];
|
|
else if (!strncmp(filename, "file:///", 8))
|
|
path = &filename[8];
|
|
else
|
|
path = filename;
|
|
if (path == NULL)
|
|
return(NULL);
|
|
|
|
fd = fopen(path, "w");
|
|
return((void *) fd);
|
|
}
|
|
|
|
/**
|
|
* xmlFileRead:
|
|
* @context: the I/O context
|
|
* @buffer: where to drop data
|
|
* @len: number of bytes to write
|
|
*
|
|
* Read @len bytes to @buffer from the I/O channel.
|
|
*
|
|
* Returns the number of bytes written
|
|
*/
|
|
int
|
|
xmlFileRead (void * context, char * buffer, int len) {
|
|
return(fread(&buffer[0], 1, len, (FILE *) context));
|
|
}
|
|
|
|
/**
|
|
* xmlFileWrite:
|
|
* @context: the I/O context
|
|
* @buffer: where to drop data
|
|
* @len: number of bytes to write
|
|
*
|
|
* Write @len bytes from @buffer to the I/O channel.
|
|
*
|
|
* Returns the number of bytes written
|
|
*/
|
|
int
|
|
xmlFileWrite (void * context, const char * buffer, int len) {
|
|
return(fwrite(&buffer[0], 1, len, (FILE *) context));
|
|
}
|
|
|
|
/**
|
|
* xmlFileClose:
|
|
* @context: the I/O context
|
|
*
|
|
* Close an I/O channel
|
|
*/
|
|
void
|
|
xmlFileClose (void * context) {
|
|
fclose((FILE *) context);
|
|
}
|
|
|
|
/**
|
|
* xmlFileFlush:
|
|
* @context: the I/O context
|
|
*
|
|
* Flush an I/O channel
|
|
*/
|
|
void
|
|
xmlFileFlush (void * context) {
|
|
fflush((FILE *) context);
|
|
}
|
|
|
|
#ifdef HAVE_ZLIB_H
|
|
/************************************************************************
|
|
* *
|
|
* I/O for compressed file accesses *
|
|
* *
|
|
************************************************************************/
|
|
/**
|
|
* xmlGzfileMatch:
|
|
* @filename: the URI for matching
|
|
*
|
|
* input from compressed file test
|
|
*
|
|
* Returns 1 if matches, 0 otherwise
|
|
*/
|
|
int
|
|
xmlGzfileMatch (const char *filename) {
|
|
return(1);
|
|
}
|
|
|
|
/**
|
|
* xmlGzfileOpen:
|
|
* @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
|
|
*/
|
|
void *
|
|
xmlGzfileOpen (const char *filename) {
|
|
const char *path = NULL;
|
|
gzFile fd;
|
|
|
|
if (!strcmp(filename, "-")) {
|
|
fd = gzdopen(fileno(stdin), "rb");
|
|
return((void *) fd);
|
|
}
|
|
|
|
if (!strncmp(filename, "file://localhost", 16))
|
|
path = &filename[16];
|
|
else if (!strncmp(filename, "file:///", 8))
|
|
path = &filename[8];
|
|
else
|
|
path = filename;
|
|
|
|
fd = gzopen(filename, "rb");
|
|
return((void *) fd);
|
|
}
|
|
|
|
/**
|
|
* xmlGzfileOpenW:
|
|
* @filename: the URI for matching
|
|
* @compression: the compression factor (0 - 9 included)
|
|
*
|
|
* input from compressed file open
|
|
* if @filename is " " then the standard input is used
|
|
*
|
|
* Returns an I/O context or NULL in case of error
|
|
*/
|
|
void *
|
|
xmlGzfileOpenW (const char *filename, int compression) {
|
|
const char *path = NULL;
|
|
char mode[15];
|
|
gzFile fd;
|
|
|
|
sprintf(mode, "wb%d", compression);
|
|
if (!strcmp(filename, "-")) {
|
|
fd = gzdopen(1, mode);
|
|
return((void *) fd);
|
|
}
|
|
|
|
if (!strncmp(filename, "file://localhost", 16))
|
|
path = &filename[16];
|
|
else if (!strncmp(filename, "file:///", 8))
|
|
path = &filename[8];
|
|
else
|
|
path = filename;
|
|
|
|
fd = gzopen(filename, mode);
|
|
return((void *) fd);
|
|
}
|
|
|
|
/**
|
|
* xmlGzfileRead:
|
|
* @context: the I/O context
|
|
* @buffer: where to drop data
|
|
* @len: number of bytes to write
|
|
*
|
|
* Read @len bytes to @buffer from the compressed I/O channel.
|
|
*
|
|
* Returns the number of bytes written
|
|
*/
|
|
int
|
|
xmlGzfileRead (void * context, char * buffer, int len) {
|
|
return(gzread((gzFile) context, &buffer[0], len));
|
|
}
|
|
|
|
/**
|
|
* xmlGzfileWrite:
|
|
* @context: the I/O context
|
|
* @buffer: where to drop data
|
|
* @len: number of bytes to write
|
|
*
|
|
* Write @len bytes from @buffer to the compressed I/O channel.
|
|
*
|
|
* Returns the number of bytes written
|
|
*/
|
|
int
|
|
xmlGzfileWrite (void * context, const char * buffer, int len) {
|
|
return(gzwrite((gzFile) context, (char *) &buffer[0], len));
|
|
}
|
|
|
|
/**
|
|
* xmlGzfileClose:
|
|
* @context: the I/O context
|
|
*
|
|
* Close a compressed I/O channel
|
|
*/
|
|
void
|
|
xmlGzfileClose (void * context) {
|
|
gzclose((gzFile) context);
|
|
}
|
|
#endif /* HAVE_ZLIB_H */
|
|
|
|
#ifdef LIBXML_HTTP_ENABLED
|
|
/************************************************************************
|
|
* *
|
|
* I/O for HTTP file accesses *
|
|
* *
|
|
************************************************************************/
|
|
/**
|
|
* xmlIOHTTPMatch:
|
|
* @filename: the URI for matching
|
|
*
|
|
* check if the URI matches an HTTP one
|
|
*
|
|
* Returns 1 if matches, 0 otherwise
|
|
*/
|
|
int
|
|
xmlIOHTTPMatch (const char *filename) {
|
|
if (!strncmp(filename, "http://", 7))
|
|
return(1);
|
|
return(0);
|
|
}
|
|
|
|
/**
|
|
* xmlIOHTTPOpen:
|
|
* @filename: the URI for matching
|
|
*
|
|
* open an HTTP I/O channel
|
|
*
|
|
* Returns an I/O context or NULL in case of error
|
|
*/
|
|
void *
|
|
xmlIOHTTPOpen (const char *filename) {
|
|
return(xmlNanoHTTPOpen(filename, NULL));
|
|
}
|
|
|
|
/**
|
|
* xmlIOHTTPRead:
|
|
* @context: the I/O context
|
|
* @buffer: where to drop data
|
|
* @len: number of bytes to write
|
|
*
|
|
* Read @len bytes to @buffer from the I/O channel.
|
|
*
|
|
* Returns the number of bytes written
|
|
*/
|
|
int
|
|
xmlIOHTTPRead(void * context, char * buffer, int len) {
|
|
return(xmlNanoHTTPRead(context, &buffer[0], len));
|
|
}
|
|
|
|
/**
|
|
* xmlIOHTTPClose:
|
|
* @context: the I/O context
|
|
*
|
|
* Close an HTTP I/O channel
|
|
*/
|
|
void
|
|
xmlIOHTTPClose (void * context) {
|
|
xmlNanoHTTPClose(context);
|
|
}
|
|
#endif /* LIBXML_HTTP_ENABLED */
|
|
|
|
#ifdef LIBXML_FTP_ENABLED
|
|
/************************************************************************
|
|
* *
|
|
* I/O for FTP file accesses *
|
|
* *
|
|
************************************************************************/
|
|
/**
|
|
* xmlIOFTPMatch:
|
|
* @filename: the URI for matching
|
|
*
|
|
* check if the URI matches an FTP one
|
|
*
|
|
* Returns 1 if matches, 0 otherwise
|
|
*/
|
|
int
|
|
xmlIOFTPMatch (const char *filename) {
|
|
if (!strncmp(filename, "ftp://", 6))
|
|
return(1);
|
|
return(0);
|
|
}
|
|
|
|
/**
|
|
* xmlIOFTPOpen:
|
|
* @filename: the URI for matching
|
|
*
|
|
* open an FTP I/O channel
|
|
*
|
|
* Returns an I/O context or NULL in case of error
|
|
*/
|
|
void *
|
|
xmlIOFTPOpen (const char *filename) {
|
|
return(xmlNanoFTPOpen(filename));
|
|
}
|
|
|
|
/**
|
|
* xmlIOFTPRead:
|
|
* @context: the I/O context
|
|
* @buffer: where to drop data
|
|
* @len: number of bytes to write
|
|
*
|
|
* Read @len bytes to @buffer from the I/O channel.
|
|
*
|
|
* Returns the number of bytes written
|
|
*/
|
|
int
|
|
xmlIOFTPRead(void * context, char * buffer, int len) {
|
|
return(xmlNanoFTPRead(context, &buffer[0], len));
|
|
}
|
|
|
|
/**
|
|
* xmlIOFTPClose:
|
|
* @context: the I/O context
|
|
*
|
|
* Close an FTP I/O channel
|
|
*/
|
|
void
|
|
xmlIOFTPClose (void * context) {
|
|
xmlNanoFTPClose(context);
|
|
}
|
|
#endif /* LIBXML_FTP_ENABLED */
|
|
|
|
|
|
/**
|
|
* xmlRegisterInputCallbacks:
|
|
* @match: the xmlInputMatchCallback
|
|
* @open: the xmlInputOpenCallback
|
|
* @read: the xmlInputReadCallback
|
|
* @close: the xmlInputCloseCallback
|
|
*
|
|
* Register a new set of I/O callback for handling parser input.
|
|
*
|
|
* Returns the registered handler number or -1 in case of error
|
|
*/
|
|
int
|
|
xmlRegisterInputCallbacks(xmlInputMatchCallback match,
|
|
xmlInputOpenCallback open, xmlInputReadCallback read,
|
|
xmlInputCloseCallback close) {
|
|
if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
|
|
return(-1);
|
|
}
|
|
xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = match;
|
|
xmlInputCallbackTable[xmlInputCallbackNr].opencallback = open;
|
|
xmlInputCallbackTable[xmlInputCallbackNr].readcallback = read;
|
|
xmlInputCallbackTable[xmlInputCallbackNr].closecallback = close;
|
|
return(xmlInputCallbackNr++);
|
|
}
|
|
|
|
/**
|
|
* xmlRegisterOutputCallbacks:
|
|
* @match: the xmlOutputMatchCallback
|
|
* @open: the xmlOutputOpenCallback
|
|
* @write: the xmlOutputWriteCallback
|
|
* @close: the xmlOutputCloseCallback
|
|
*
|
|
* Register a new set of I/O callback for handling output.
|
|
*
|
|
* Returns the registered handler number or -1 in case of error
|
|
*/
|
|
int
|
|
xmlRegisterOutputCallbacks(xmlOutputMatchCallback match,
|
|
xmlOutputOpenCallback open, xmlOutputWriteCallback write,
|
|
xmlOutputCloseCallback close) {
|
|
if (xmlOutputCallbackNr >= MAX_INPUT_CALLBACK) {
|
|
return(-1);
|
|
}
|
|
xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = match;
|
|
xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = open;
|
|
xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = write;
|
|
xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = close;
|
|
return(xmlOutputCallbackNr++);
|
|
}
|
|
|
|
/**
|
|
* xmlRegisterDefaultInputCallbacks:
|
|
*
|
|
* Registers the default compiled-in I/O handlers.
|
|
*/
|
|
void
|
|
xmlRegisterDefaultInputCallbacks(void) {
|
|
if (xmlInputCallbackInitialized)
|
|
return;
|
|
|
|
xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
|
|
xmlFileRead, xmlFileClose);
|
|
#ifdef HAVE_ZLIB_H
|
|
xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
|
|
xmlGzfileRead, xmlGzfileClose);
|
|
#endif /* HAVE_ZLIB_H */
|
|
|
|
#ifdef LIBXML_HTTP_ENABLED
|
|
xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
|
|
xmlIOHTTPRead, xmlIOHTTPClose);
|
|
#endif /* LIBXML_HTTP_ENABLED */
|
|
|
|
#ifdef LIBXML_FTP_ENABLED
|
|
xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
|
|
xmlIOFTPRead, xmlIOFTPClose);
|
|
#endif /* LIBXML_FTP_ENABLED */
|
|
xmlInputCallbackInitialized = 1;
|
|
}
|
|
|
|
/**
|
|
* xmlRegisterDefaultOutputCallbacks:
|
|
*
|
|
* Registers the default compiled-in I/O handlers.
|
|
*/
|
|
void
|
|
xmlRegisterDefaultOutputCallbacks(void) {
|
|
if (xmlOutputCallbackInitialized)
|
|
return;
|
|
|
|
xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
|
|
xmlFileWrite, xmlFileClose);
|
|
/*********************************
|
|
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
|
|
No HTTP PUT support yet, patches welcome
|
|
|
|
#ifdef LIBXML_HTTP_ENABLED
|
|
xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
|
|
xmlIOHTTPWrite, xmlIOHTTPClose);
|
|
#endif
|
|
|
|
Nor FTP PUT ....
|
|
#ifdef LIBXML_FTP_ENABLED
|
|
xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
|
|
xmlIOFTPWrite, xmlIOFTPClose);
|
|
#endif
|
|
**********************************/
|
|
xmlOutputCallbackInitialized = 1;
|
|
}
|
|
|
|
/**
|
|
* xmlAllocParserInputBuffer:
|
|
* @enc: the charset encoding if known
|
|
*
|
|
* Create a buffered parser input for progressive parsing
|
|
*
|
|
* Returns the new parser input or NULL
|
|
*/
|
|
xmlParserInputBufferPtr
|
|
xmlAllocParserInputBuffer(xmlCharEncoding enc) {
|
|
xmlParserInputBufferPtr ret;
|
|
|
|
ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
|
|
if (ret == NULL) {
|
|
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);
|
|
}
|
|
|
|
/**
|
|
* xmlAllocOutputBuffer:
|
|
* @encoder: the encoding converter or NULL
|
|
*
|
|
* Create a buffered parser output
|
|
*
|
|
* Returns the new parser output or NULL
|
|
*/
|
|
xmlOutputBufferPtr
|
|
xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
|
|
xmlOutputBufferPtr ret;
|
|
|
|
ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
|
|
if (ret == NULL) {
|
|
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);
|
|
/*
|
|
* This call is designed to initiate the encoder state
|
|
*/
|
|
xmlCharEncOutFunc(encoder, ret->conv, NULL);
|
|
} else
|
|
ret->conv = NULL;
|
|
ret->writecallback = NULL;
|
|
ret->closecallback = NULL;
|
|
ret->context = NULL;
|
|
ret->written = 0;
|
|
|
|
return(ret);
|
|
}
|
|
|
|
/**
|
|
* xmlFreeParserInputBuffer:
|
|
* @in: a buffered parser input
|
|
*
|
|
* Free up the memory used by a buffered parser input
|
|
*/
|
|
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;
|
|
}
|
|
|
|
memset(in, 0xbe, (size_t) sizeof(xmlParserInputBuffer));
|
|
xmlFree(in);
|
|
}
|
|
|
|
/**
|
|
* xmlOutputBufferClose:
|
|
* @out: a buffered output
|
|
*
|
|
* flushes and close the output I/O channel
|
|
* and free up all the associated resources
|
|
*
|
|
* Returns the number of byte written or -1 in case of error.
|
|
*/
|
|
int
|
|
xmlOutputBufferClose(xmlOutputBufferPtr out) {
|
|
int written;
|
|
|
|
if (out == NULL)
|
|
return(-1);
|
|
xmlOutputBufferFlush(out);
|
|
if (out->closecallback != NULL) {
|
|
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;
|
|
}
|
|
|
|
memset(out, 0xbe, (size_t) sizeof(xmlOutputBuffer));
|
|
xmlFree(out);
|
|
return(written);
|
|
}
|
|
|
|
/**
|
|
* xmlParserInputBufferCreateFilename:
|
|
* @URI: a C string containing the URI or filename
|
|
* @enc: the charset encoding if known
|
|
*
|
|
* Create a buffered parser input for the progressive parsing of a file
|
|
* If filename is "-' then we use stdin as the input.
|
|
* Automatic support for ZLIB/Compress compressed document is provided
|
|
* by default if found at compile-time.
|
|
* Do an encoding check if enc == XML_CHAR_ENCODING_NONE
|
|
*
|
|
* Returns the new parser input or NULL
|
|
*/
|
|
xmlParserInputBufferPtr
|
|
xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
|
|
xmlParserInputBufferPtr ret;
|
|
int i;
|
|
void *context = NULL;
|
|
|
|
if (xmlInputCallbackInitialized == 0)
|
|
xmlRegisterDefaultInputCallbacks();
|
|
|
|
if (URI == NULL) return(NULL);
|
|
|
|
/*
|
|
* Try to find one of the input accept method accepting taht scheme
|
|
* Go in reverse to give precedence to user defined handlers.
|
|
*/
|
|
for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
|
|
if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
|
|
(xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
|
|
context = xmlInputCallbackTable[i].opencallback(URI);
|
|
if (context != NULL)
|
|
break;
|
|
}
|
|
}
|
|
if (context == NULL) {
|
|
return(NULL);
|
|
}
|
|
|
|
/*
|
|
* Allocate the Input buffer front-end.
|
|
*/
|
|
ret = xmlAllocParserInputBuffer(enc);
|
|
if (ret != NULL) {
|
|
ret->context = context;
|
|
ret->readcallback = xmlInputCallbackTable[i].readcallback;
|
|
ret->closecallback = xmlInputCallbackTable[i].closecallback;
|
|
}
|
|
return(ret);
|
|
}
|
|
|
|
/**
|
|
* xmlOutputBufferCreateFilename:
|
|
* @URI: a C string containing the URI or filename
|
|
* @encoder: the encoding converter or NULL
|
|
* @compression: the compression ration (0 none, 9 max).
|
|
*
|
|
* Create a buffered output for the progressive saving of a file
|
|
* If filename is "-' then we use stdout as the output.
|
|
* Automatic support for ZLIB/Compress compressed document is provided
|
|
* by default if found at compile-time.
|
|
* TODO: currently if compression is set, the library only support
|
|
* writing to a local file.
|
|
*
|
|
* Returns the new output or NULL
|
|
*/
|
|
xmlOutputBufferPtr
|
|
xmlOutputBufferCreateFilename(const char *URI,
|
|
xmlCharEncodingHandlerPtr encoder,
|
|
int compression) {
|
|
xmlOutputBufferPtr ret;
|
|
int i;
|
|
void *context = NULL;
|
|
|
|
if (xmlOutputCallbackInitialized == 0)
|
|
xmlRegisterDefaultOutputCallbacks();
|
|
|
|
if (URI == NULL) return(NULL);
|
|
|
|
#ifdef HAVE_ZLIB_H
|
|
if ((compression > 0) && (compression <= 9)) {
|
|
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
|
|
|
|
/*
|
|
* Try to find one of the output accept method accepting taht scheme
|
|
* Go in reverse to give precedence to user defined handlers.
|
|
*/
|
|
for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
|
|
if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
|
|
(xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
|
|
context = xmlOutputCallbackTable[i].opencallback(URI);
|
|
if (context != NULL)
|
|
break;
|
|
}
|
|
}
|
|
if (context == NULL) {
|
|
return(NULL);
|
|
}
|
|
|
|
/*
|
|
* Allocate the Output buffer front-end.
|
|
*/
|
|
ret = xmlAllocOutputBuffer(encoder);
|
|
if (ret != NULL) {
|
|
ret->context = context;
|
|
ret->writecallback = xmlOutputCallbackTable[i].writecallback;
|
|
ret->closecallback = xmlOutputCallbackTable[i].closecallback;
|
|
}
|
|
return(ret);
|
|
}
|
|
|
|
/**
|
|
* xmlParserInputBufferCreateFile:
|
|
* @file: a FILE*
|
|
* @enc: the charset encoding if known
|
|
*
|
|
* Create a buffered parser input for the progressive parsing of a FILE *
|
|
* buffered C I/O
|
|
*
|
|
* Returns the new parser input or NULL
|
|
*/
|
|
xmlParserInputBufferPtr
|
|
xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
|
|
xmlParserInputBufferPtr ret;
|
|
|
|
if (xmlInputCallbackInitialized == 0)
|
|
xmlRegisterDefaultInputCallbacks();
|
|
|
|
if (file == NULL) return(NULL);
|
|
|
|
ret = xmlAllocParserInputBuffer(enc);
|
|
if (ret != NULL) {
|
|
ret->context = file;
|
|
ret->readcallback = xmlFileRead;
|
|
ret->closecallback = xmlFileFlush;
|
|
}
|
|
|
|
return(ret);
|
|
}
|
|
|
|
/**
|
|
* xmlOutputBufferCreateFile:
|
|
* @file: a FILE*
|
|
* @encoder: the encoding converter or NULL
|
|
*
|
|
* Create a buffered output for the progressive saving to a FILE *
|
|
* buffered C I/O
|
|
*
|
|
* Returns the new parser output or NULL
|
|
*/
|
|
xmlOutputBufferPtr
|
|
xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
|
|
xmlOutputBufferPtr ret;
|
|
|
|
if (xmlOutputCallbackInitialized == 0)
|
|
xmlRegisterDefaultOutputCallbacks();
|
|
|
|
if (file == NULL) return(NULL);
|
|
|
|
ret = xmlAllocOutputBuffer(encoder);
|
|
if (ret != NULL) {
|
|
ret->context = file;
|
|
ret->writecallback = xmlFileWrite;
|
|
ret->closecallback = xmlFileFlush;
|
|
}
|
|
|
|
return(ret);
|
|
}
|
|
|
|
/**
|
|
* xmlParserInputBufferCreateFd:
|
|
* @fd: a file descriptor number
|
|
* @enc: the charset encoding if known
|
|
*
|
|
* Create a buffered parser input for the progressive parsing for the input
|
|
* from a file descriptor
|
|
*
|
|
* Returns the new parser input or NULL
|
|
*/
|
|
xmlParserInputBufferPtr
|
|
xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
|
|
xmlParserInputBufferPtr ret;
|
|
|
|
if (fd < 0) return(NULL);
|
|
|
|
ret = xmlAllocParserInputBuffer(enc);
|
|
if (ret != NULL) {
|
|
ret->context = (void *) fd;
|
|
ret->readcallback = xmlFdRead;
|
|
ret->closecallback = xmlFdClose;
|
|
}
|
|
|
|
return(ret);
|
|
}
|
|
|
|
/**
|
|
* xmlParserInputBufferCreateMem:
|
|
* @mem: the memory input
|
|
* @size: the length of the memory block
|
|
* @enc: the charset encoding if known
|
|
*
|
|
* Create a buffered parser input for the progressive parsing for the input
|
|
* from a file descriptor
|
|
*
|
|
* Returns the new parser input or NULL
|
|
*/
|
|
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);
|
|
}
|
|
|
|
/**
|
|
* xmlOutputBufferCreateFd:
|
|
* @fd: a file descriptor number
|
|
* @encoder: the encoding converter or NULL
|
|
*
|
|
* Create a buffered output for the progressive saving
|
|
* to a file descriptor
|
|
*
|
|
* Returns the new parser output or NULL
|
|
*/
|
|
xmlOutputBufferPtr
|
|
xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
|
|
xmlOutputBufferPtr ret;
|
|
|
|
if (fd < 0) return(NULL);
|
|
|
|
ret = xmlAllocOutputBuffer(encoder);
|
|
if (ret != NULL) {
|
|
ret->context = (void *) fd;
|
|
ret->writecallback = xmlFdWrite;
|
|
ret->closecallback = xmlFdClose;
|
|
}
|
|
|
|
return(ret);
|
|
}
|
|
|
|
/**
|
|
* xmlParserInputBufferCreateIO:
|
|
* @ioread: an I/O read function
|
|
* @ioclose: an I/O close function
|
|
* @ioctx: an I/O handler
|
|
* @enc: the charset encoding if known
|
|
*
|
|
* Create a buffered parser input for the progressive parsing for the input
|
|
* from an I/O handler
|
|
*
|
|
* Returns the new parser input or NULL
|
|
*/
|
|
xmlParserInputBufferPtr
|
|
xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
|
|
xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
|
|
xmlParserInputBufferPtr ret;
|
|
|
|
if (ioread == NULL) return(NULL);
|
|
|
|
ret = xmlAllocParserInputBuffer(enc);
|
|
if (ret != NULL) {
|
|
ret->context = (void *) ioctx;
|
|
ret->readcallback = ioread;
|
|
ret->closecallback = ioclose;
|
|
}
|
|
|
|
return(ret);
|
|
}
|
|
|
|
/**
|
|
* xmlOutputBufferCreateIO:
|
|
* @iowrite: an I/O write function
|
|
* @ioclose: an I/O close function
|
|
* @ioctx: an I/O handler
|
|
* @enc: the charset encoding if known
|
|
*
|
|
* Create a buffered output for the progressive saving
|
|
* to an I/O handler
|
|
*
|
|
* Returns the new parser output or NULL
|
|
*/
|
|
xmlOutputBufferPtr
|
|
xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
|
|
xmlOutputCloseCallback ioclose, void *ioctx,
|
|
xmlCharEncodingHandlerPtr encoder) {
|
|
xmlOutputBufferPtr ret;
|
|
|
|
if (iowrite == NULL) return(NULL);
|
|
|
|
ret = xmlAllocOutputBuffer(encoder);
|
|
if (ret != NULL) {
|
|
ret->context = (void *) ioctx;
|
|
ret->writecallback = iowrite;
|
|
ret->closecallback = ioclose;
|
|
}
|
|
|
|
return(ret);
|
|
}
|
|
|
|
/**
|
|
* xmlParserInputBufferPush:
|
|
* @in: a buffered parser input
|
|
* @len: the size in bytes of the array.
|
|
* @buf: an char array
|
|
*
|
|
* Push the content of the arry in the input buffer
|
|
* This routine handle the I18N transcoding to internal UTF-8
|
|
* This is used when operating the parser in progressive (push) mode.
|
|
*
|
|
* Returns the number of chars read and stored in the buffer, or -1
|
|
* in case of error.
|
|
*/
|
|
int
|
|
xmlParserInputBufferPush(xmlParserInputBufferPtr in,
|
|
int len, const char *buf) {
|
|
int nbchars = 0;
|
|
|
|
if (len < 0) return(0);
|
|
if (in->encoder != NULL) {
|
|
/*
|
|
* Store the data in the incoming raw buffer
|
|
*/
|
|
if (in->raw == NULL) {
|
|
in->raw = xmlBufferCreate();
|
|
}
|
|
xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
|
|
|
|
/*
|
|
* convert as much as possible to the parser reading buffer.
|
|
*/
|
|
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);
|
|
}
|
|
|
|
/**
|
|
* xmlParserInputBufferGrow:
|
|
* @in: a buffered parser input
|
|
* @len: indicative value of the amount of chars to read
|
|
*
|
|
* Grow up the content of the input buffer, the old data are preserved
|
|
* This routine handle the I18N transcoding to internal UTF-8
|
|
* This routine is used when operating the parser in normal (pull) mode
|
|
*
|
|
* TODO: one should be able to remove one extra copy by copying directy
|
|
* onto in->buffer or in->raw
|
|
*
|
|
* Returns the number of chars read and stored in the buffer, or -1
|
|
* in case of error.
|
|
*/
|
|
int
|
|
xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
|
|
char *buffer = NULL;
|
|
int res = 0;
|
|
int nbchars = 0;
|
|
int buffree;
|
|
|
|
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;
|
|
|
|
buffer = (char *) xmlMalloc((len + 1) * sizeof(char));
|
|
if (buffer == NULL) {
|
|
xmlGenericError(xmlGenericErrorContext,
|
|
"xmlParserInputBufferGrow : out of memory !\n");
|
|
return(-1);
|
|
}
|
|
|
|
/*
|
|
* Call the read method for this I/O type.
|
|
*/
|
|
if (in->readcallback != NULL) {
|
|
res = in->readcallback(in->context, &buffer[0], len);
|
|
} else {
|
|
xmlGenericError(xmlGenericErrorContext,
|
|
"xmlParserInputBufferGrow : no input !\n");
|
|
xmlFree(buffer);
|
|
return(-1);
|
|
}
|
|
if (res < 0) {
|
|
perror ("read error");
|
|
xmlFree(buffer);
|
|
return(-1);
|
|
}
|
|
len = res;
|
|
if (in->encoder != NULL) {
|
|
/*
|
|
* Store the data in the incoming raw buffer
|
|
*/
|
|
if (in->raw == NULL) {
|
|
in->raw = xmlBufferCreate();
|
|
}
|
|
xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
|
|
|
|
/*
|
|
* convert as much as possible to the parser reading buffer.
|
|
*/
|
|
nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
|
|
if (nbchars < 0) {
|
|
xmlGenericError(xmlGenericErrorContext,
|
|
"xmlParserInputBufferGrow: encoder error\n");
|
|
return(-1);
|
|
}
|
|
} else {
|
|
nbchars = len;
|
|
buffer[nbchars] = 0;
|
|
xmlBufferAdd(in->buffer, (xmlChar *) buffer, nbchars);
|
|
}
|
|
#ifdef DEBUG_INPUT
|
|
xmlGenericError(xmlGenericErrorContext,
|
|
"I/O: read %d chars, buffer %d/%d\n",
|
|
nbchars, in->buffer->use, in->buffer->size);
|
|
#endif
|
|
xmlFree(buffer);
|
|
return(nbchars);
|
|
}
|
|
|
|
/**
|
|
* xmlParserInputBufferRead:
|
|
* @in: a buffered parser input
|
|
* @len: indicative value of the amount of chars to read
|
|
*
|
|
* Refresh the content of the input buffer, the old data are considered
|
|
* consumed
|
|
* This routine handle the I18N transcoding to internal UTF-8
|
|
*
|
|
* Returns the number of chars read and stored in the buffer, or -1
|
|
* in case of error.
|
|
*/
|
|
int
|
|
xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
|
|
/* xmlBufferEmpty(in->buffer); */
|
|
if (in->readcallback != NULL)
|
|
return(xmlParserInputBufferGrow(in, len));
|
|
else
|
|
return(-1);
|
|
}
|
|
|
|
/**
|
|
* xmlOutputBufferWrite:
|
|
* @out: a buffered parser output
|
|
* @len: the size in bytes of the array.
|
|
* @buf: an char array
|
|
*
|
|
* Write the content of the array in the output I/O buffer
|
|
* This routine handle the I18N transcoding from internal UTF-8
|
|
* The buffer is lossless, i.e. will store in case of partial
|
|
* or delayed writes.
|
|
*
|
|
* Returns the number of chars immediately written, or -1
|
|
* in case of error.
|
|
*/
|
|
int
|
|
xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
|
|
int nbchars = 0, ret;
|
|
|
|
if (len < 0) return(0);
|
|
|
|
/*
|
|
* first handle encoding stuff.
|
|
*/
|
|
if (out->encoder != NULL) {
|
|
/*
|
|
* Store the data in the incoming raw buffer
|
|
*/
|
|
if (out->conv == NULL) {
|
|
out->conv = xmlBufferCreate();
|
|
}
|
|
xmlBufferAdd(out->buffer, (const xmlChar *) buf, len);
|
|
|
|
if (out->buffer->use < MINLEN)
|
|
return(0);
|
|
|
|
/*
|
|
* convert as much as possible to the parser reading buffer.
|
|
*/
|
|
nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
|
|
if (nbchars < 0) {
|
|
xmlGenericError(xmlGenericErrorContext,
|
|
"xmlOutputBufferWrite: encoder error\n");
|
|
return(-1);
|
|
}
|
|
nbchars = out->conv->use;
|
|
} else {
|
|
xmlBufferAdd(out->buffer, (const xmlChar *) buf, len);
|
|
nbchars = out->buffer->use;
|
|
}
|
|
if (nbchars < MINLEN)
|
|
return(0);
|
|
|
|
/*
|
|
* 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, nbchars);
|
|
} else {
|
|
ret = out->writecallback(out->context,
|
|
(const char *)out->buffer->content, nbchars);
|
|
if (ret >= 0)
|
|
xmlBufferShrink(out->buffer, nbchars);
|
|
}
|
|
if (ret < 0) {
|
|
xmlGenericError(xmlGenericErrorContext,
|
|
"I/O: error %d writing %d bytes\n", ret, nbchars);
|
|
return(ret);
|
|
}
|
|
out->written += ret;
|
|
|
|
#ifdef DEBUG_INPUT
|
|
xmlGenericError(xmlGenericErrorContext,
|
|
"I/O: wrote %d chars\n", ret);
|
|
#endif
|
|
return(nbchars);
|
|
}
|
|
|
|
/**
|
|
* xmlOutputBufferWriteString:
|
|
* @out: a buffered parser output
|
|
* @str: a zero terminated C string
|
|
*
|
|
* Write the content of the string in the output I/O buffer
|
|
* This routine handle the I18N transcoding from internal UTF-8
|
|
* The buffer is lossless, i.e. will store in case of partial
|
|
* or delayed writes.
|
|
*
|
|
* Returns the number of chars immediately written, or -1
|
|
* in case of error.
|
|
*/
|
|
int
|
|
xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
|
|
int len;
|
|
|
|
if (str == NULL)
|
|
return(-1);
|
|
len = strlen(str);
|
|
|
|
if (len > 0)
|
|
return(xmlOutputBufferWrite(out, len, str));
|
|
return(len);
|
|
}
|
|
|
|
/**
|
|
* xmlOutputBufferFlush:
|
|
* @out: a buffered output
|
|
*
|
|
* flushes the output I/O channel
|
|
*
|
|
* Returns the number of byte written or -1 in case of error.
|
|
*/
|
|
int
|
|
xmlOutputBufferFlush(xmlOutputBufferPtr out) {
|
|
int nbchars = 0, ret;
|
|
|
|
/*
|
|
* first handle encoding stuff.
|
|
*/
|
|
if ((out->conv != NULL) && (out->encoder != NULL)) {
|
|
/*
|
|
* convert as much as possible to the parser reading buffer.
|
|
*/
|
|
nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
|
|
if (nbchars < 0) {
|
|
xmlGenericError(xmlGenericErrorContext,
|
|
"xmlOutputBufferWrite: encoder error\n");
|
|
return(-1);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* second flush the stuff to the I/O channel
|
|
*/
|
|
if ((out->conv != NULL) && (out->encoder != NULL)) {
|
|
ret = out->writecallback(out->context,
|
|
(const char *)out->conv->content, out->conv->use);
|
|
if (ret >= 0)
|
|
xmlBufferShrink(out->conv, ret);
|
|
} else {
|
|
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);
|
|
}
|
|
|
|
/*
|
|
* xmlParserGetDirectory:
|
|
* @filename: the path to a file
|
|
*
|
|
* lookup the directory for that file
|
|
*
|
|
* Returns a new allocated string containing the directory, or NULL.
|
|
*/
|
|
char *
|
|
xmlParserGetDirectory(const char *filename) {
|
|
char *ret = NULL;
|
|
char dir[1024];
|
|
char *cur;
|
|
char sep = '/';
|
|
|
|
if (xmlInputCallbackInitialized == 0)
|
|
xmlRegisterDefaultInputCallbacks();
|
|
|
|
if (filename == NULL) return(NULL);
|
|
#ifdef WIN32
|
|
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);
|
|
}
|
|
|
|
/****************************************************************
|
|
* *
|
|
* External entities loading *
|
|
* *
|
|
****************************************************************/
|
|
|
|
/*
|
|
* xmlDefaultExternalEntityLoader:
|
|
* @URL: the URL for the entity to load
|
|
* @ID: the System ID for the entity to load
|
|
* @ctxt: the context in which the entity is called or NULL
|
|
*
|
|
* By default we don't load external entitites, yet.
|
|
*
|
|
* Returns a new allocated xmlParserInputPtr, or NULL.
|
|
*/
|
|
static
|
|
xmlParserInputPtr
|
|
xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
|
|
xmlParserCtxtPtr ctxt) {
|
|
xmlParserInputPtr ret = NULL;
|
|
|
|
#ifdef DEBUG_EXTERNAL_ENTITIES
|
|
xmlGenericError(xmlGenericErrorContext,
|
|
"xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
|
|
#endif
|
|
if (URL == NULL) {
|
|
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, URL);
|
|
if (ret == NULL) {
|
|
if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
|
|
ctxt->sax->warning(ctxt,
|
|
"failed to load external entity \"%s\"\n", URL);
|
|
}
|
|
return(ret);
|
|
}
|
|
|
|
static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
|
|
xmlDefaultExternalEntityLoader;
|
|
|
|
/*
|
|
* xmlSetExternalEntityLoader:
|
|
* @f: the new entity resolver function
|
|
*
|
|
* Changes the defaultexternal entity resolver function for the application
|
|
*/
|
|
void
|
|
xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
|
|
xmlCurrentExternalEntityLoader = f;
|
|
}
|
|
|
|
/*
|
|
* xmlGetExternalEntityLoader:
|
|
*
|
|
* Get the default external entity resolver function for the application
|
|
*
|
|
* Returns the xmlExternalEntityLoader function pointer
|
|
*/
|
|
xmlExternalEntityLoader
|
|
xmlGetExternalEntityLoader(void) {
|
|
return(xmlCurrentExternalEntityLoader);
|
|
}
|
|
|
|
/*
|
|
* xmlLoadExternalEntity:
|
|
* @URL: the URL for the entity to load
|
|
* @ID: the System ID for the entity to load
|
|
* @ctxt: the context in which the entity is called or NULL
|
|
*
|
|
* Load an external entity, note that the use of this function for
|
|
* unparsed entities may generate problems
|
|
* TODO: a more generic External entitiy API must be designed
|
|
*
|
|
* Returns the xmlParserInputPtr or NULL
|
|
*/
|
|
xmlParserInputPtr
|
|
xmlLoadExternalEntity(const char *URL, const char *ID,
|
|
xmlParserCtxtPtr ctxt) {
|
|
return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
|
|
}
|
|
|