mirror of
https://gitlab.gnome.org/GNOME/libxml2.git
synced 2024-10-26 12:25:09 +03:00
8ab1b122c4
Many strings are passed to the library that could be either URIs or filesystem paths. We now assume that strings are a URI if they contain the substring "://". This means that they have a scheme and an authority. Otherwise, URI resolution wouldn't make much sense. Fix xmlBuildURI to work with filesystem paths. If the base URI doesn't contain "://" it is treated as filename. The resolved URI is unescaped, appended and the result is normalized. Rewrite xmlNormalizePath to handle Windows quirks. All special handling for Windows paths is removed in xmlCanonicPath. If the path looks like an URI, only escape characters allowed in Legacy Extended IRIs. Make xmlPathToURI only call xmlCanonicPath. Theh additional round-trip through URI parser and serializer seems useless. Add a helper function xmlConvertUriToPath in xmlIO.c which checks for file URIs and unescapes them. Always process strings with xmlCanonicPath in xmlLoadExternalEntity. This should be harmless now. Should help with #334, #387, #611.
3568 lines
86 KiB
C
3568 lines
86 KiB
C
/*
|
|
* xmlIO.c : implementation of the I/O interfaces used by the parser
|
|
*
|
|
* See Copyright for the status of this software.
|
|
*
|
|
* daniel@veillard.com
|
|
*/
|
|
|
|
#define IN_LIBXML
|
|
#include "libxml.h"
|
|
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <errno.h>
|
|
|
|
#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 LIBXML_ZLIB_ENABLED
|
|
#include <zlib.h>
|
|
#endif
|
|
#ifdef LIBXML_LZMA_ENABLED
|
|
#include <lzma.h>
|
|
#endif
|
|
|
|
#if defined(_WIN32)
|
|
#define WIN32_LEAN_AND_MEAN
|
|
#include <windows.h>
|
|
#include <io.h>
|
|
#include <direct.h>
|
|
#endif
|
|
|
|
#include <libxml/xmlIO.h>
|
|
#include <libxml/xmlmemory.h>
|
|
#include <libxml/parser.h>
|
|
#include <libxml/parserInternals.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 "private/buf.h"
|
|
#include "private/enc.h"
|
|
#include "private/error.h"
|
|
#include "private/io.h"
|
|
#include "private/parser.h"
|
|
|
|
/* #define VERBOSE_FAILURE */
|
|
|
|
#define MINLEN 4000
|
|
|
|
#ifndef S_ISDIR
|
|
# ifdef _S_ISDIR
|
|
# define S_ISDIR(x) _S_ISDIR(x)
|
|
# elif defined(S_IFDIR)
|
|
# ifdef S_IFMT
|
|
# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
|
|
# elif defined(_S_IFMT)
|
|
# define S_ISDIR(m) (((m) & _S_IFMT) == S_IFDIR)
|
|
# endif
|
|
# endif
|
|
#endif
|
|
|
|
/*
|
|
* Input I/O callback sets
|
|
*/
|
|
typedef struct _xmlInputCallback {
|
|
xmlInputMatchCallback matchcallback;
|
|
xmlInputOpenCallback opencallback;
|
|
xmlInputReadCallback readcallback;
|
|
xmlInputCloseCallback closecallback;
|
|
} xmlInputCallback;
|
|
|
|
/* This dummy function only marks default IO in the callback table */
|
|
static int
|
|
xmlIODefaultMatch(const char *filename);
|
|
|
|
#define MAX_INPUT_CALLBACK 10
|
|
|
|
static xmlInputCallback xmlInputCallbackTable[MAX_INPUT_CALLBACK];
|
|
static int xmlInputCallbackNr;
|
|
|
|
#ifdef LIBXML_OUTPUT_ENABLED
|
|
/*
|
|
* Output I/O callback sets
|
|
*/
|
|
typedef struct _xmlOutputCallback {
|
|
xmlOutputMatchCallback matchcallback;
|
|
xmlOutputOpenCallback opencallback;
|
|
xmlOutputWriteCallback writecallback;
|
|
xmlOutputCloseCallback closecallback;
|
|
} xmlOutputCallback;
|
|
|
|
#define MAX_OUTPUT_CALLBACK 10
|
|
|
|
static xmlOutputCallback xmlOutputCallbackTable[MAX_OUTPUT_CALLBACK];
|
|
static int xmlOutputCallbackNr;
|
|
#endif /* LIBXML_OUTPUT_ENABLED */
|
|
|
|
/************************************************************************
|
|
* *
|
|
* Error handling *
|
|
* *
|
|
************************************************************************/
|
|
|
|
/**
|
|
* xmlIOErrMemory:
|
|
* @extra: extra information
|
|
*
|
|
* Handle an out of memory condition
|
|
*/
|
|
static void
|
|
xmlIOErrMemory(void)
|
|
{
|
|
xmlRaiseMemoryError(NULL, NULL, NULL, XML_FROM_IO, NULL);
|
|
}
|
|
|
|
/**
|
|
* __xmlIOErr:
|
|
* @code: the error number
|
|
* @
|
|
* @extra: extra information
|
|
*
|
|
* Handle an I/O error
|
|
*/
|
|
int
|
|
__xmlIOErr(int domain, int code, const char *extra)
|
|
{
|
|
int res;
|
|
|
|
if (code == 0) {
|
|
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;
|
|
}
|
|
|
|
res = __xmlRaiseError(NULL, NULL, NULL, NULL, NULL,
|
|
domain, code, XML_ERR_ERROR, NULL, 0,
|
|
extra, NULL, NULL, 0, 0,
|
|
"%s", xmlErrString(code));
|
|
if (res < 0) {
|
|
xmlIOErrMemory();
|
|
return(XML_ERR_NO_MEMORY);
|
|
}
|
|
|
|
return(code);
|
|
}
|
|
|
|
/**
|
|
* xmlIOErr:
|
|
* @code: the error number
|
|
* @extra: extra information
|
|
*
|
|
* Handle an I/O error
|
|
*/
|
|
static int
|
|
xmlIOErr(int code, const char *extra)
|
|
{
|
|
return(__xmlIOErr(XML_FROM_IO, code, extra));
|
|
}
|
|
|
|
/**
|
|
* xmlCtxtErrIO:
|
|
* @ctxt: parser context
|
|
* @code: xmlParserErrors code
|
|
* @uri: filename or URI (optional)
|
|
*
|
|
* If filename is empty, use the one from context input if available.
|
|
*
|
|
* Report an IO error to the parser context.
|
|
*/
|
|
void
|
|
xmlCtxtErrIO(xmlParserCtxtPtr ctxt, int code, const char *uri)
|
|
{
|
|
const char *errstr, *msg, *str1, *str2;
|
|
xmlErrorLevel level;
|
|
|
|
if (ctxt == NULL)
|
|
return;
|
|
|
|
if ((code == XML_IO_ENOENT) ||
|
|
(code == XML_IO_NETWORK_ATTEMPT) ||
|
|
(code == XML_IO_UNKNOWN)) {
|
|
if (ctxt->validate == 0)
|
|
level = XML_ERR_WARNING;
|
|
else
|
|
level = XML_ERR_ERROR;
|
|
} else {
|
|
level = XML_ERR_FATAL;
|
|
}
|
|
|
|
errstr = xmlErrString(code);
|
|
|
|
if (uri == NULL) {
|
|
msg = "%s\n";
|
|
str1 = errstr;
|
|
str2 = NULL;
|
|
} else {
|
|
msg = "failed to load \"%s\": %s\n";
|
|
str1 = uri;
|
|
str2 = errstr;
|
|
}
|
|
|
|
xmlCtxtErr(ctxt, NULL, XML_FROM_IO, code, level,
|
|
(const xmlChar *) uri, NULL, NULL, 0,
|
|
msg, str1, str2);
|
|
}
|
|
|
|
/************************************************************************
|
|
* *
|
|
* Standard I/O for file accesses *
|
|
* *
|
|
************************************************************************/
|
|
|
|
#if defined(_WIN32)
|
|
|
|
/**
|
|
* __xmlIOWin32UTF8ToWChar:
|
|
* @u8String: uft-8 string
|
|
*
|
|
* Convert a string from utf-8 to wchar (WINDOWS ONLY!)
|
|
*/
|
|
static wchar_t *
|
|
__xmlIOWin32UTF8ToWChar(const char *u8String)
|
|
{
|
|
wchar_t *wString = NULL;
|
|
int i;
|
|
|
|
if (u8String) {
|
|
int wLen =
|
|
MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, u8String,
|
|
-1, NULL, 0);
|
|
if (wLen) {
|
|
wString = xmlMalloc(wLen * sizeof(wchar_t));
|
|
if (wString) {
|
|
if (MultiByteToWideChar
|
|
(CP_UTF8, 0, u8String, -1, wString, wLen) == 0) {
|
|
xmlFree(wString);
|
|
wString = NULL;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Convert to backward slash
|
|
*/
|
|
for (i = 0; wString[i] != 0; i++) {
|
|
if (wString[i] == '/')
|
|
wString[i] = '\\';
|
|
}
|
|
}
|
|
}
|
|
|
|
return wString;
|
|
}
|
|
|
|
/**
|
|
* xmlWrapOpenUtf8:
|
|
* @path: the path in utf-8 encoding
|
|
* @mode: type of access (0 - read, 1 - write)
|
|
*
|
|
* function opens the file specified by @path
|
|
*
|
|
*/
|
|
static FILE*
|
|
xmlWrapOpenUtf8(const char *path,int mode)
|
|
{
|
|
FILE *fd = NULL;
|
|
wchar_t *wPath;
|
|
|
|
wPath = __xmlIOWin32UTF8ToWChar(path);
|
|
if(wPath)
|
|
{
|
|
fd = _wfopen(wPath, mode ? L"wb" : L"rb");
|
|
xmlFree(wPath);
|
|
}
|
|
/* maybe path in native encoding */
|
|
if(fd == NULL)
|
|
fd = fopen(path, mode ? "wb" : "rb");
|
|
|
|
return fd;
|
|
}
|
|
|
|
#ifdef LIBXML_ZLIB_ENABLED
|
|
static gzFile
|
|
xmlWrapGzOpenUtf8(const char *path, const char *mode)
|
|
{
|
|
gzFile fd;
|
|
wchar_t *wPath;
|
|
|
|
fd = gzopen (path, mode);
|
|
if (fd)
|
|
return fd;
|
|
|
|
wPath = __xmlIOWin32UTF8ToWChar(path);
|
|
if(wPath)
|
|
{
|
|
int d, m = (strstr(mode, "r") ? O_RDONLY : O_RDWR);
|
|
#ifdef _O_BINARY
|
|
m |= (strstr(mode, "b") ? _O_BINARY : 0);
|
|
#endif
|
|
d = _wopen(wPath, m);
|
|
if (d >= 0)
|
|
fd = gzdopen(d, mode);
|
|
xmlFree(wPath);
|
|
}
|
|
|
|
return fd;
|
|
}
|
|
#endif
|
|
|
|
/**
|
|
* xmlWrapStatUtf8:
|
|
* @path: the path in utf-8 encoding
|
|
* @info: structure that stores results
|
|
*
|
|
* function obtains information about the file or directory
|
|
*
|
|
*/
|
|
static int
|
|
xmlWrapStatUtf8(const char *path, struct _stat *info) {
|
|
int retval = -1;
|
|
wchar_t *wPath;
|
|
|
|
wPath = __xmlIOWin32UTF8ToWChar(path);
|
|
if (wPath) {
|
|
retval = _wstat(wPath, info);
|
|
xmlFree(wPath);
|
|
}
|
|
/* maybe path in native encoding */
|
|
if(retval < 0)
|
|
retval = _stat(path, info);
|
|
return retval;
|
|
}
|
|
|
|
#endif
|
|
|
|
/**
|
|
* xmlNormalizeWindowsPath:
|
|
* @path: the input file path
|
|
*
|
|
* DEPRECATED: See xmlURIFromPath in uri.c for a better solution.
|
|
*
|
|
* Returns a canonicalized version of the path
|
|
*/
|
|
xmlChar *
|
|
xmlNormalizeWindowsPath(const xmlChar *path)
|
|
{
|
|
return xmlCanonicPath(path);
|
|
}
|
|
|
|
/**
|
|
* xmlCheckFilename:
|
|
* @path: the path to check
|
|
*
|
|
* DEPRECATED: Internal function, don't use.
|
|
*
|
|
* if stat is not available on the target machine,
|
|
* returns 1. if stat fails, returns 0 (if calling
|
|
* stat on the filename fails, it can't be right).
|
|
* if stat succeeds and the file is a directory,
|
|
* returns 2. otherwise returns 1.
|
|
*/
|
|
|
|
int
|
|
xmlCheckFilename (const char *path)
|
|
{
|
|
#ifdef HAVE_STAT
|
|
#if defined(_WIN32)
|
|
struct _stat stat_buffer;
|
|
#else
|
|
struct stat stat_buffer;
|
|
#endif
|
|
#endif
|
|
if (path == NULL)
|
|
return(0);
|
|
|
|
#ifdef HAVE_STAT
|
|
#if defined(_WIN32)
|
|
/*
|
|
* On Windows stat and wstat do not work with long pathname,
|
|
* which start with '\\?\'
|
|
*/
|
|
if ((path[0] == '\\') && (path[1] == '\\') && (path[2] == '?') &&
|
|
(path[3] == '\\') )
|
|
return 1;
|
|
|
|
if (xmlWrapStatUtf8(path, &stat_buffer) == -1)
|
|
return 0;
|
|
#else
|
|
if (stat(path, &stat_buffer) == -1)
|
|
return 0;
|
|
#endif
|
|
#ifdef S_ISDIR
|
|
if (S_ISDIR(stat_buffer.st_mode))
|
|
return 2;
|
|
#endif
|
|
#endif /* HAVE_STAT */
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
xmlConvertUriToPath(const char *uri, char **out) {
|
|
const char *escaped;
|
|
char *unescaped;
|
|
|
|
*out = NULL;
|
|
|
|
if (!xmlStrncasecmp(BAD_CAST uri, BAD_CAST "file://localhost/", 17)) {
|
|
escaped = &uri[16];
|
|
} else if (!xmlStrncasecmp(BAD_CAST uri, BAD_CAST "file:///", 8)) {
|
|
escaped = &uri[7];
|
|
} else if (!xmlStrncasecmp(BAD_CAST uri, BAD_CAST "file:/", 6)) {
|
|
/* lots of generators seems to lazy to read RFC 1738 */
|
|
escaped = &uri[5];
|
|
} else {
|
|
return(1);
|
|
}
|
|
|
|
#ifdef _WIN32
|
|
/* Ignore slash like in file:///C:/file.txt */
|
|
escaped += 1;
|
|
#endif
|
|
|
|
unescaped = xmlURIUnescapeString(escaped, 0, NULL);
|
|
if (unescaped == NULL)
|
|
return(-1);
|
|
|
|
*out = unescaped;
|
|
return(0);
|
|
}
|
|
|
|
/**
|
|
* xmlFdOpen:
|
|
* @filename: the URI for matching
|
|
* @out: pointer to resulting context
|
|
*
|
|
* Returns an xmlParserErrors code
|
|
*/
|
|
static int
|
|
xmlFdOpen(const char *filename, void **out) {
|
|
char *fromUri = NULL;
|
|
int fd;
|
|
int ret;
|
|
|
|
*out = (void *) 0;
|
|
if (filename == NULL)
|
|
return(XML_ERR_ARGUMENT);
|
|
|
|
if (xmlConvertUriToPath(filename, &fromUri) < 0)
|
|
return(XML_ERR_NO_MEMORY);
|
|
|
|
if (fromUri != NULL)
|
|
filename = fromUri;
|
|
|
|
#if defined(_WIN32)
|
|
{
|
|
wchar_t *wpath;
|
|
|
|
wpath = __xmlIOWin32UTF8ToWChar(filename);
|
|
if (wpath == NULL) {
|
|
xmlFree(fromUri);
|
|
return(XML_ERR_NO_MEMORY);
|
|
}
|
|
fd = _wopen(wpath, _O_RDONLY | _O_BINARY);
|
|
xmlFree(wpath);
|
|
}
|
|
#else
|
|
fd = open(filename, O_RDONLY);
|
|
#endif /* WIN32 */
|
|
|
|
if (fd < 0) {
|
|
/*
|
|
* Windows and possibly other platforms return EINVAL
|
|
* for invalid filenames.
|
|
*/
|
|
if ((errno == ENOENT) || (errno == EINVAL)) {
|
|
ret = XML_IO_ENOENT;
|
|
} else {
|
|
/*
|
|
* This error won't be forwarded to the parser context
|
|
* which will report it a second time.
|
|
*/
|
|
ret = xmlIOErr(0, filename);
|
|
}
|
|
} else {
|
|
*out = (void *) (ptrdiff_t) fd;
|
|
ret = XML_ERR_OK;
|
|
}
|
|
|
|
xmlFree(fromUri);
|
|
return(ret);
|
|
}
|
|
|
|
/**
|
|
* xmlFdRead:
|
|
* @context: the I/O context
|
|
* @buffer: where to drop data
|
|
* @len: number of bytes to read
|
|
*
|
|
* Read @len bytes to @buffer from the I/O channel.
|
|
*
|
|
* Returns the number of bytes written
|
|
*/
|
|
static int
|
|
xmlFdRead (void * context, char * buffer, int len) {
|
|
int ret;
|
|
|
|
ret = read((int) (ptrdiff_t) context, &buffer[0], len);
|
|
if (ret < 0)
|
|
return(-xmlIOErr(0, "fread()"));
|
|
return(ret);
|
|
}
|
|
|
|
#ifdef LIBXML_OUTPUT_ENABLED
|
|
/**
|
|
* xmlFdWrite:
|
|
* @context: the I/O context
|
|
* @buffer: where to get data
|
|
* @len: number of bytes to write
|
|
*
|
|
* Write @len bytes from @buffer to the I/O channel.
|
|
*
|
|
* Returns the number of bytes written
|
|
*/
|
|
static int
|
|
xmlFdWrite (void * context, const char * buffer, int len) {
|
|
int ret = 0;
|
|
|
|
if (len > 0) {
|
|
ret = write((int) (ptrdiff_t) context, &buffer[0], len);
|
|
if (ret < 0) xmlIOErr(0, "write()");
|
|
}
|
|
return(ret);
|
|
}
|
|
#endif /* LIBXML_OUTPUT_ENABLED */
|
|
|
|
/**
|
|
* xmlFdClose:
|
|
* @context: the I/O context
|
|
*
|
|
* Close an I/O channel
|
|
*
|
|
* Returns 0 in case of success and error code otherwise
|
|
*/
|
|
static int
|
|
xmlFdClose (void * context) {
|
|
int ret;
|
|
ret = close((int) (ptrdiff_t) context);
|
|
if (ret < 0) xmlIOErr(0, "close()");
|
|
return(ret);
|
|
}
|
|
|
|
/**
|
|
* xmlFileMatch:
|
|
* @filename: the URI for matching
|
|
*
|
|
* DEPRECATED: Internal function, don't use.
|
|
*
|
|
* Returns 1 if matches, 0 otherwise
|
|
*/
|
|
int
|
|
xmlFileMatch (const char *filename ATTRIBUTE_UNUSED) {
|
|
return(1);
|
|
}
|
|
|
|
/**
|
|
* xmlFileOpenReal:
|
|
* @filename: the URI for matching
|
|
* @out: pointer to resulting context
|
|
*
|
|
* input from FILE *, supports compressed input
|
|
*
|
|
* Returns an I/O context or NULL in case of error
|
|
*/
|
|
static int
|
|
xmlFileOpenReal(const char *filename, void **out) {
|
|
const char *path = filename;
|
|
FILE *fd;
|
|
int ret = XML_ERR_OK;
|
|
|
|
*out = NULL;
|
|
if (filename == NULL)
|
|
return(XML_ERR_ARGUMENT);
|
|
|
|
if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) {
|
|
#if defined (_WIN32)
|
|
path = &filename[17];
|
|
#else
|
|
path = &filename[16];
|
|
#endif
|
|
} else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
|
|
#if defined (_WIN32)
|
|
path = &filename[8];
|
|
#else
|
|
path = &filename[7];
|
|
#endif
|
|
} else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:/", 6)) {
|
|
/* lots of generators seems to lazy to read RFC 1738 */
|
|
#if defined (_WIN32)
|
|
path = &filename[6];
|
|
#else
|
|
path = &filename[5];
|
|
#endif
|
|
}
|
|
|
|
#if defined(_WIN32)
|
|
fd = xmlWrapOpenUtf8(path, 0);
|
|
#else
|
|
fd = fopen(path, "rb");
|
|
#endif /* WIN32 */
|
|
|
|
if (fd == NULL) {
|
|
/*
|
|
* Windows and possibly other platforms return EINVAL
|
|
* for invalid filenames.
|
|
*/
|
|
if ((errno == ENOENT) || (errno == EINVAL)) {
|
|
ret = XML_IO_ENOENT;
|
|
} else {
|
|
/*
|
|
* This error won't be forwarded to the parser context
|
|
* which will report it a second time.
|
|
*/
|
|
ret = xmlIOErr(0, path);
|
|
}
|
|
}
|
|
|
|
*out = fd;
|
|
return(ret);
|
|
}
|
|
|
|
/**
|
|
* xmlFileOpenSafe:
|
|
* @filename: the URI for matching
|
|
* @out: pointer to resulting context
|
|
*
|
|
* Wrapper around xmlFileOpen_real that try it with an unescaped
|
|
* version of @filename, if this fails fallback to @filename
|
|
*
|
|
* Returns an xmlParserErrors code.
|
|
*/
|
|
static int
|
|
xmlFileOpenSafe(const char *filename, void **out) {
|
|
char *unescaped;
|
|
int retval;
|
|
|
|
retval = xmlFileOpenReal(filename, out);
|
|
if (retval == XML_ERR_OK)
|
|
return(retval);
|
|
|
|
if (retval == XML_IO_ENOENT) {
|
|
unescaped = xmlURIUnescapeString(filename, 0, NULL);
|
|
if (unescaped == NULL)
|
|
return(XML_ERR_NO_MEMORY);
|
|
retval = xmlFileOpenReal(unescaped, out);
|
|
xmlFree(unescaped);
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
/**
|
|
* xmlFileOpen:
|
|
* @filename: the URI for matching
|
|
*
|
|
* DEPRECATED: Internal function, don't use.
|
|
*
|
|
* Returns an IO context or NULL in case or failure
|
|
*/
|
|
void *
|
|
xmlFileOpen(const char *filename) {
|
|
void *context;
|
|
|
|
xmlFileOpenSafe(filename, &context);
|
|
return(context);
|
|
}
|
|
|
|
#ifdef LIBXML_OUTPUT_ENABLED
|
|
/**
|
|
* xmlFileOpenW:
|
|
* @filename: the URI for matching
|
|
*
|
|
* output to from FILE *,
|
|
* if @filename is "-" then the standard output is used
|
|
*
|
|
* Returns an I/O context or NULL in case of error
|
|
*/
|
|
static void *
|
|
xmlFileOpenW (const char *filename) {
|
|
char *fromUri = NULL;
|
|
FILE *fd;
|
|
|
|
if (!strcmp(filename, "-")) {
|
|
fd = stdout;
|
|
return((void *) fd);
|
|
}
|
|
|
|
if (xmlConvertUriToPath(filename, &fromUri) < 0)
|
|
return(NULL);
|
|
|
|
if (fromUri != NULL)
|
|
filename = fromUri;
|
|
|
|
#if defined(_WIN32)
|
|
fd = xmlWrapOpenUtf8(filename, 1);
|
|
#elif(__MVS__)
|
|
fd = fopen(filename, "w");
|
|
#else
|
|
fd = fopen(filename, "wb");
|
|
#endif /* WIN32 */
|
|
|
|
if (fd == NULL)
|
|
xmlIOErr(0, filename);
|
|
|
|
xmlFree(fromUri);
|
|
return((void *) fd);
|
|
}
|
|
#endif /* LIBXML_OUTPUT_ENABLED */
|
|
|
|
/**
|
|
* xmlFileRead:
|
|
* @context: the I/O context
|
|
* @buffer: where to drop data
|
|
* @len: number of bytes to write
|
|
*
|
|
* DEPRECATED: Internal function, don't use.
|
|
*
|
|
* Returns the number of bytes written or < 0 in case of failure
|
|
*/
|
|
int
|
|
xmlFileRead (void * context, char * buffer, int len) {
|
|
int ret;
|
|
if ((context == NULL) || (buffer == NULL))
|
|
return(-1);
|
|
ret = fread(&buffer[0], 1, len, (FILE *) context);
|
|
if (ret < 0)
|
|
return(-xmlIOErr(0, "fread()"));
|
|
return(ret);
|
|
}
|
|
|
|
#ifdef LIBXML_OUTPUT_ENABLED
|
|
/**
|
|
* xmlFileWrite:
|
|
* @context: the I/O context
|
|
* @buffer: where to drop data
|
|
* @len: number of bytes to write
|
|
*
|
|
* Write @len bytes from @buffer to the I/O channel.
|
|
*
|
|
* Returns the number of bytes written
|
|
*/
|
|
static int
|
|
xmlFileWrite (void * context, const char * buffer, int len) {
|
|
int items;
|
|
|
|
if ((context == NULL) || (buffer == NULL))
|
|
return(-1);
|
|
items = fwrite(&buffer[0], len, 1, (FILE *) context);
|
|
if ((items == 0) && (ferror((FILE *) context))) {
|
|
xmlIOErr(0, "fwrite()");
|
|
return(-1);
|
|
}
|
|
return(items * len);
|
|
}
|
|
#endif /* LIBXML_OUTPUT_ENABLED */
|
|
|
|
/**
|
|
* xmlFileClose:
|
|
* @context: the I/O context
|
|
*
|
|
* DEPRECATED: Internal function, don't use.
|
|
*
|
|
* Returns 0 or -1 in case of error
|
|
*/
|
|
int
|
|
xmlFileClose (void * context) {
|
|
FILE *fil;
|
|
int ret;
|
|
|
|
if (context == NULL)
|
|
return(-1);
|
|
fil = (FILE *) context;
|
|
if ((fil == stdout) || (fil == stderr)) {
|
|
ret = fflush(fil);
|
|
if (ret < 0)
|
|
xmlIOErr(0, "fflush()");
|
|
return(0);
|
|
}
|
|
if (fil == stdin)
|
|
return(0);
|
|
ret = ( fclose((FILE *) context) == EOF ) ? -1 : 0;
|
|
if (ret < 0)
|
|
xmlIOErr(0, "fclose()");
|
|
return(ret);
|
|
}
|
|
|
|
/**
|
|
* xmlFileFlush:
|
|
* @context: the I/O context
|
|
*
|
|
* Flush an I/O channel
|
|
*/
|
|
static int
|
|
xmlFileFlush (void * context) {
|
|
int ret;
|
|
|
|
if (context == NULL)
|
|
return(-1);
|
|
ret = ( fflush((FILE *) context) == EOF ) ? -1 : 0;
|
|
if (ret < 0)
|
|
xmlIOErr(0, "fflush()");
|
|
return(ret);
|
|
}
|
|
|
|
#ifdef LIBXML_OUTPUT_ENABLED
|
|
/**
|
|
* xmlBufferWrite:
|
|
* @context: the xmlBuffer
|
|
* @buffer: the data to write
|
|
* @len: number of bytes to write
|
|
*
|
|
* Write @len bytes from @buffer to the xml buffer
|
|
*
|
|
* Returns the number of bytes written or a negative xmlParserErrors
|
|
* value.
|
|
*/
|
|
static int
|
|
xmlBufferWrite (void * context, const char * buffer, int len) {
|
|
int ret;
|
|
|
|
ret = xmlBufferAdd((xmlBufferPtr) context, (const xmlChar *) buffer, len);
|
|
if (ret != 0)
|
|
return(-XML_ERR_NO_MEMORY);
|
|
return(len);
|
|
}
|
|
#endif
|
|
|
|
#ifdef LIBXML_ZLIB_ENABLED
|
|
/************************************************************************
|
|
* *
|
|
* I/O for compressed file accesses *
|
|
* *
|
|
************************************************************************/
|
|
/**
|
|
* xmlGzfileMatch:
|
|
* @filename: the URI for matching
|
|
*
|
|
* input from compressed file test
|
|
*
|
|
* Returns 1 if matches, 0 otherwise
|
|
*/
|
|
static int
|
|
xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
|
|
return(1);
|
|
}
|
|
|
|
/**
|
|
* xmlGzfileOpen_real:
|
|
* @filename: the URI for matching
|
|
*
|
|
* input from compressed file open
|
|
* if @filename is " " then the standard input is used
|
|
*
|
|
* Returns an I/O context or NULL in case of error
|
|
*/
|
|
static void *
|
|
xmlGzfileOpen_real (const char *filename) {
|
|
char *fromUri = NULL;
|
|
gzFile fd;
|
|
|
|
if (xmlConvertUriToPath(filename, &fromUri) < 0)
|
|
return(NULL);
|
|
|
|
if (fromUri != NULL)
|
|
filename = fromUri;
|
|
|
|
if (!xmlCheckFilename(filename))
|
|
return(NULL);
|
|
|
|
#if defined(_WIN32)
|
|
fd = xmlWrapGzOpenUtf8(filename, "rb");
|
|
#else
|
|
fd = gzopen(filename, "rb");
|
|
#endif
|
|
|
|
xmlFree(fromUri);
|
|
return((void *) fd);
|
|
}
|
|
|
|
/**
|
|
* xmlGzfileOpen:
|
|
* @filename: the URI for matching
|
|
*
|
|
* Wrapper around xmlGzfileOpen_real if the open fails, it will
|
|
* try to unescape @filename
|
|
*/
|
|
static void *
|
|
xmlGzfileOpen (const char *filename) {
|
|
char *unescaped;
|
|
void *retval;
|
|
|
|
retval = xmlGzfileOpen_real(filename);
|
|
if (retval == NULL) {
|
|
unescaped = xmlURIUnescapeString(filename, 0, NULL);
|
|
if (unescaped != NULL) {
|
|
retval = xmlGzfileOpen_real(unescaped);
|
|
}
|
|
xmlFree(unescaped);
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
#ifdef LIBXML_OUTPUT_ENABLED
|
|
/**
|
|
* xmlGzfileOpenW:
|
|
* @filename: the URI for matching
|
|
* @compression: the compression factor (0 - 9 included)
|
|
*
|
|
* input from compressed file open
|
|
* if @filename is " " then the standard input is used
|
|
*
|
|
* Returns an I/O context or NULL in case of error
|
|
*/
|
|
static void *
|
|
xmlGzfileOpenW (const char *filename, int compression) {
|
|
char *fromUri = NULL;
|
|
char mode[15];
|
|
gzFile fd;
|
|
|
|
snprintf(mode, sizeof(mode), "wb%d", compression);
|
|
if (!strcmp(filename, "-")) {
|
|
int duped_fd = dup(fileno(stdout));
|
|
fd = gzdopen(duped_fd, "rb");
|
|
if (fd == Z_NULL && duped_fd >= 0) {
|
|
close(duped_fd); /* gzdOpen() does not close on failure */
|
|
}
|
|
|
|
return((void *) fd);
|
|
}
|
|
|
|
if (xmlConvertUriToPath(filename, &fromUri) < 0)
|
|
return(NULL);
|
|
|
|
if (fromUri != NULL)
|
|
filename = fromUri;
|
|
|
|
#if defined(_WIN32)
|
|
fd = xmlWrapGzOpenUtf8(filename, mode);
|
|
#else
|
|
fd = gzopen(filename, mode);
|
|
#endif
|
|
|
|
xmlFree(fromUri);
|
|
return((void *) fd);
|
|
}
|
|
#endif /* LIBXML_OUTPUT_ENABLED */
|
|
|
|
/**
|
|
* xmlGzfileRead:
|
|
* @context: the I/O context
|
|
* @buffer: where to drop data
|
|
* @len: number of bytes to write
|
|
*
|
|
* Read @len bytes to @buffer from the compressed I/O channel.
|
|
*
|
|
* Returns the number of bytes read.
|
|
*/
|
|
static int
|
|
xmlGzfileRead (void * context, char * buffer, int len) {
|
|
int ret;
|
|
|
|
ret = gzread((gzFile) context, &buffer[0], len);
|
|
if (ret < 0) xmlIOErr(0, "gzread()");
|
|
return(ret);
|
|
}
|
|
|
|
#ifdef LIBXML_OUTPUT_ENABLED
|
|
/**
|
|
* xmlGzfileWrite:
|
|
* @context: the I/O context
|
|
* @buffer: where to drop data
|
|
* @len: number of bytes to write
|
|
*
|
|
* Write @len bytes from @buffer to the compressed I/O channel.
|
|
*
|
|
* Returns the number of bytes written
|
|
*/
|
|
static int
|
|
xmlGzfileWrite (void * context, const char * buffer, int len) {
|
|
int ret;
|
|
|
|
ret = gzwrite((gzFile) context, (char *) &buffer[0], len);
|
|
if (ret < 0) xmlIOErr(0, "gzwrite()");
|
|
return(ret);
|
|
}
|
|
#endif /* LIBXML_OUTPUT_ENABLED */
|
|
|
|
/**
|
|
* xmlGzfileClose:
|
|
* @context: the I/O context
|
|
*
|
|
* Close a compressed I/O channel
|
|
*/
|
|
static int
|
|
xmlGzfileClose (void * context) {
|
|
int ret;
|
|
|
|
ret = (gzclose((gzFile) context) == Z_OK ) ? 0 : -1;
|
|
if (ret < 0) xmlIOErr(0, "gzclose()");
|
|
return(ret);
|
|
}
|
|
#endif /* LIBXML_ZLIB_ENABLED */
|
|
|
|
#ifdef LIBXML_LZMA_ENABLED
|
|
/************************************************************************
|
|
* *
|
|
* I/O for compressed file accesses *
|
|
* *
|
|
************************************************************************/
|
|
#include "private/xzlib.h"
|
|
/**
|
|
* xmlXzfileMatch:
|
|
* @filename: the URI for matching
|
|
*
|
|
* input from compressed file test
|
|
*
|
|
* Returns 1 if matches, 0 otherwise
|
|
*/
|
|
static int
|
|
xmlXzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
|
|
return(1);
|
|
}
|
|
|
|
/**
|
|
* xmlXzFileOpen_real:
|
|
* @filename: the URI for matching
|
|
*
|
|
* input from compressed file open
|
|
* if @filename is " " then the standard input is used
|
|
*
|
|
* Returns an I/O context or NULL in case of error
|
|
*/
|
|
static void *
|
|
xmlXzfileOpen_real (const char *filename) {
|
|
char *fromUri = NULL;
|
|
xzFile fd;
|
|
|
|
if (xmlConvertUriToPath(filename, &fromUri) < 0)
|
|
return(NULL);
|
|
|
|
if (fromUri != NULL)
|
|
filename = fromUri;
|
|
|
|
if (!xmlCheckFilename(filename)) {
|
|
xmlFree(fromUri);
|
|
return(NULL);
|
|
}
|
|
|
|
fd = __libxml2_xzopen(filename, "rb");
|
|
|
|
xmlFree(fromUri);
|
|
return((void *) fd);
|
|
}
|
|
|
|
/**
|
|
* xmlXzfileOpen:
|
|
* @filename: the URI for matching
|
|
*
|
|
* Wrapper around xmlXzfileOpen_real that try it with an unescaped
|
|
* version of @filename, if this fails fallback to @filename
|
|
*
|
|
* Returns a handler or NULL in case or failure
|
|
*/
|
|
static void *
|
|
xmlXzfileOpen (const char *filename) {
|
|
char *unescaped;
|
|
void *retval;
|
|
|
|
retval = xmlXzfileOpen_real(filename);
|
|
if (retval == NULL) {
|
|
unescaped = xmlURIUnescapeString(filename, 0, NULL);
|
|
if (unescaped != NULL) {
|
|
retval = xmlXzfileOpen_real(unescaped);
|
|
}
|
|
xmlFree(unescaped);
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
/**
|
|
* xmlXzfileRead:
|
|
* @context: the I/O context
|
|
* @buffer: where to drop data
|
|
* @len: number of bytes to write
|
|
*
|
|
* Read @len bytes to @buffer from the compressed I/O channel.
|
|
*
|
|
* Returns the number of bytes written
|
|
*/
|
|
static int
|
|
xmlXzfileRead (void * context, char * buffer, int len) {
|
|
int ret;
|
|
|
|
ret = __libxml2_xzread((xzFile) context, &buffer[0], len);
|
|
if (ret < 0) xmlIOErr(0, "xzread()");
|
|
return(ret);
|
|
}
|
|
|
|
/**
|
|
* xmlXzfileClose:
|
|
* @context: the I/O context
|
|
*
|
|
* Close a compressed I/O channel
|
|
*/
|
|
static int
|
|
xmlXzfileClose (void * context) {
|
|
int ret;
|
|
|
|
ret = (__libxml2_xzclose((xzFile) context) == LZMA_OK ) ? 0 : -1;
|
|
if (ret < 0) xmlIOErr(0, "xzclose()");
|
|
return(ret);
|
|
}
|
|
#endif /* LIBXML_LZMA_ENABLED */
|
|
|
|
/************************************************************************
|
|
* *
|
|
* I/O for HTTP file accesses *
|
|
* *
|
|
************************************************************************/
|
|
|
|
#ifdef LIBXML_HTTP_ENABLED
|
|
/**
|
|
* xmlIOHTTPMatch:
|
|
* @filename: the URI for matching
|
|
*
|
|
* DEPRECATED: Internal function, don't use.
|
|
*
|
|
* check if the URI matches an HTTP one
|
|
*
|
|
* Returns 1 if matches, 0 otherwise
|
|
*/
|
|
int
|
|
xmlIOHTTPMatch (const char *filename) {
|
|
if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "http://", 7))
|
|
return(1);
|
|
return(0);
|
|
}
|
|
|
|
/**
|
|
* xmlIOHTTPOpen:
|
|
* @filename: the URI for matching
|
|
*
|
|
* DEPRECATED: Internal function, don't use.
|
|
*
|
|
* open an HTTP I/O channel
|
|
*
|
|
* Returns an I/O context or NULL in case of error
|
|
*/
|
|
void *
|
|
xmlIOHTTPOpen (const char *filename) {
|
|
return(xmlNanoHTTPOpen(filename, NULL));
|
|
}
|
|
|
|
#ifdef LIBXML_OUTPUT_ENABLED
|
|
/**
|
|
* xmlIOHTTPOpenW:
|
|
* @post_uri: The destination URI for the document
|
|
* @compression: The compression desired for the document.
|
|
*
|
|
* DEPRECATED: Support for HTTP POST has been removed.
|
|
*
|
|
* Returns NULL.
|
|
*/
|
|
void *
|
|
xmlIOHTTPOpenW(const char *post_uri ATTRIBUTE_UNUSED,
|
|
int compression ATTRIBUTE_UNUSED)
|
|
{
|
|
return(NULL);
|
|
}
|
|
#endif /* LIBXML_OUTPUT_ENABLED */
|
|
|
|
/**
|
|
* xmlIOHTTPRead:
|
|
* @context: the I/O context
|
|
* @buffer: where to drop data
|
|
* @len: number of bytes to write
|
|
*
|
|
* DEPRECATED: Internal function, don't use.
|
|
*
|
|
* Read @len bytes to @buffer from the I/O channel.
|
|
*
|
|
* Returns the number of bytes written
|
|
*/
|
|
int
|
|
xmlIOHTTPRead(void * context, char * buffer, int len) {
|
|
if ((buffer == NULL) || (len < 0)) return(-1);
|
|
return(xmlNanoHTTPRead(context, &buffer[0], len));
|
|
}
|
|
|
|
/**
|
|
* xmlIOHTTPClose:
|
|
* @context: the I/O context
|
|
*
|
|
* DEPRECATED: Internal function, don't use.
|
|
*
|
|
* Close an HTTP I/O channel
|
|
*
|
|
* Returns 0
|
|
*/
|
|
int
|
|
xmlIOHTTPClose (void * context) {
|
|
xmlNanoHTTPClose(context);
|
|
return 0;
|
|
}
|
|
#endif /* LIBXML_HTTP_ENABLED */
|
|
|
|
#ifdef LIBXML_FTP_ENABLED
|
|
/************************************************************************
|
|
* *
|
|
* I/O for FTP file accesses *
|
|
* *
|
|
************************************************************************/
|
|
/**
|
|
* xmlIOFTPMatch:
|
|
* @filename: the URI for matching
|
|
*
|
|
* DEPRECATED: Internal function, don't use.
|
|
*
|
|
* check if the URI matches an FTP one
|
|
*
|
|
* Returns 1 if matches, 0 otherwise
|
|
*/
|
|
int
|
|
xmlIOFTPMatch (const char *filename) {
|
|
if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "ftp://", 6))
|
|
return(1);
|
|
return(0);
|
|
}
|
|
|
|
/**
|
|
* xmlIOFTPOpen:
|
|
* @filename: the URI for matching
|
|
*
|
|
* DEPRECATED: Internal function, don't use.
|
|
*
|
|
* 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
|
|
*
|
|
* DEPRECATED: Internal function, don't use.
|
|
*
|
|
* Read @len bytes to @buffer from the I/O channel.
|
|
*
|
|
* Returns the number of bytes written
|
|
*/
|
|
int
|
|
xmlIOFTPRead(void * context, char * buffer, int len) {
|
|
if ((buffer == NULL) || (len < 0)) return(-1);
|
|
return(xmlNanoFTPRead(context, &buffer[0], len));
|
|
}
|
|
|
|
/**
|
|
* xmlIOFTPClose:
|
|
* @context: the I/O context
|
|
*
|
|
* DEPRECATED: Internal function, don't use.
|
|
*
|
|
* Close an FTP I/O channel
|
|
*
|
|
* Returns 0
|
|
*/
|
|
int
|
|
xmlIOFTPClose (void * context) {
|
|
return ( xmlNanoFTPClose(context) );
|
|
}
|
|
#endif /* LIBXML_FTP_ENABLED */
|
|
|
|
/************************************************************************
|
|
* *
|
|
* Input/output buffers *
|
|
* *
|
|
************************************************************************/
|
|
|
|
static int
|
|
xmlIODefaultMatch(const char *filename ATTRIBUTE_UNUSED) {
|
|
return(1);
|
|
}
|
|
|
|
/**
|
|
* xmlInputDefaultOpen:
|
|
* @buf: input buffer to be filled
|
|
* @filename: filename or URI
|
|
*
|
|
* Returns an xmlParserErrors code.
|
|
*/
|
|
static int
|
|
xmlInputDefaultOpen(xmlParserInputBufferPtr buf, const char *filename) {
|
|
int ret;
|
|
|
|
#ifdef LIBXML_FTP_ENABLED
|
|
if (xmlIOFTPMatch(filename)) {
|
|
buf->context = xmlIOFTPOpen(filename);
|
|
|
|
if (buf->context != NULL) {
|
|
buf->readcallback = xmlIOFTPRead;
|
|
buf->closecallback = xmlIOFTPClose;
|
|
return(XML_ERR_OK);
|
|
}
|
|
}
|
|
#endif /* LIBXML_FTP_ENABLED */
|
|
|
|
#ifdef LIBXML_HTTP_ENABLED
|
|
if (xmlIOHTTPMatch(filename)) {
|
|
buf->context = xmlIOHTTPOpen(filename);
|
|
|
|
if (buf->context != NULL) {
|
|
buf->readcallback = xmlIOHTTPRead;
|
|
buf->closecallback = xmlIOHTTPClose;
|
|
return(XML_ERR_OK);
|
|
}
|
|
}
|
|
#endif /* LIBXML_HTTP_ENABLED */
|
|
|
|
#ifdef LIBXML_LZMA_ENABLED
|
|
if (xmlXzfileMatch(filename)) {
|
|
void *context = xmlXzfileOpen(filename);
|
|
|
|
if (context != NULL) {
|
|
if (__libxml2_xzcompressed(context) > 0) {
|
|
buf->context = context;
|
|
buf->readcallback = xmlXzfileRead;
|
|
buf->closecallback = xmlXzfileClose;
|
|
buf->compressed = __libxml2_xzcompressed(buf->context);
|
|
|
|
return(XML_ERR_OK);
|
|
}
|
|
|
|
xmlXzfileClose(context);
|
|
}
|
|
}
|
|
#endif /* LIBXML_LZMA_ENABLED */
|
|
|
|
#ifdef LIBXML_ZLIB_ENABLED
|
|
if (xmlGzfileMatch(filename)) {
|
|
void *context = xmlGzfileOpen(filename);
|
|
|
|
if (context != NULL) {
|
|
char buff4[4];
|
|
|
|
if ((gzread(context, buff4, 4) > 0) &&
|
|
(gzdirect(context) == 0)) {
|
|
gzrewind(context);
|
|
|
|
buf->context = context;
|
|
buf->readcallback = xmlGzfileRead;
|
|
buf->closecallback = xmlGzfileClose;
|
|
buf->compressed = 1;
|
|
|
|
return(XML_ERR_OK);
|
|
}
|
|
|
|
xmlGzfileClose(context);
|
|
}
|
|
}
|
|
#endif /* LIBXML_ZLIB_ENABLED */
|
|
|
|
if (xmlFileMatch(filename)) {
|
|
ret = xmlFdOpen(filename, &buf->context);
|
|
|
|
/* Note that context can be NULL for stdin */
|
|
if (ret == XML_ERR_OK) {
|
|
buf->readcallback = xmlFdRead;
|
|
buf->closecallback = xmlFdClose;
|
|
return(XML_ERR_OK);
|
|
}
|
|
if (ret != XML_IO_ENOENT)
|
|
return(ret);
|
|
}
|
|
|
|
return(XML_IO_ENOENT);
|
|
}
|
|
|
|
#ifdef LIBXML_OUTPUT_ENABLED
|
|
/**
|
|
* xmlOutputDefaultOpen:
|
|
* @buf: input buffer to be filled
|
|
* @filename: filename or URI
|
|
* @compression: compression level or 0
|
|
* @is_file_uri: whether filename is a file URI
|
|
*
|
|
* Returns an xmlParserErrors code.
|
|
*/
|
|
static int
|
|
xmlOutputDefaultOpen(xmlOutputBufferPtr buf, const char *filename,
|
|
int compression, int is_file_uri) {
|
|
(void) compression;
|
|
(void) is_file_uri;
|
|
|
|
#ifdef LIBXML_ZLIB_ENABLED
|
|
if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
|
|
buf->context = xmlGzfileOpenW(filename, compression);
|
|
if (buf->context != NULL) {
|
|
buf->writecallback = xmlGzfileWrite;
|
|
buf->closecallback = xmlGzfileClose;
|
|
return(XML_ERR_OK);
|
|
}
|
|
}
|
|
#endif /* LIBXML_ZLIB_ENABLED */
|
|
|
|
if (xmlFileMatch(filename)) {
|
|
buf->context = xmlFileOpenW(filename);
|
|
|
|
if (buf->context != NULL) {
|
|
buf->writecallback = xmlFileWrite;
|
|
buf->closecallback = xmlFileClose;
|
|
return(XML_ERR_OK);
|
|
}
|
|
}
|
|
|
|
return(XML_IO_ENOENT);
|
|
}
|
|
#endif
|
|
|
|
/**
|
|
* xmlAllocParserInputBuffer:
|
|
* @enc: the charset encoding if known (deprecated)
|
|
*
|
|
* Create a buffered parser input for progressive parsing.
|
|
*
|
|
* The encoding argument is deprecated and should be set to
|
|
* XML_CHAR_ENCODING_NONE. The encoding can be changed with
|
|
* xmlSwitchEncoding or xmlSwitchEncodingName later on.
|
|
*
|
|
* Returns the new parser input or NULL
|
|
*/
|
|
xmlParserInputBufferPtr
|
|
xmlAllocParserInputBuffer(xmlCharEncoding enc) {
|
|
xmlParserInputBufferPtr ret;
|
|
|
|
ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
|
|
if (ret == NULL) {
|
|
return(NULL);
|
|
}
|
|
memset(ret, 0, sizeof(xmlParserInputBuffer));
|
|
ret->buffer = xmlBufCreateSize(2 * xmlDefaultBufferSize);
|
|
if (ret->buffer == NULL) {
|
|
xmlFree(ret);
|
|
return(NULL);
|
|
}
|
|
xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_DOUBLEIT);
|
|
if (enc != XML_CHAR_ENCODING_NONE) {
|
|
if (xmlLookupCharEncodingHandler(enc, &ret->encoder) != 0) {
|
|
/* We can't handle errors properly here. */
|
|
xmlFreeParserInputBuffer(ret);
|
|
return(NULL);
|
|
}
|
|
}
|
|
if (ret->encoder != NULL)
|
|
ret->raw = xmlBufCreateSize(2 * xmlDefaultBufferSize);
|
|
else
|
|
ret->raw = NULL;
|
|
ret->readcallback = NULL;
|
|
ret->closecallback = NULL;
|
|
ret->context = NULL;
|
|
ret->compressed = -1;
|
|
ret->rawconsumed = 0;
|
|
|
|
return(ret);
|
|
}
|
|
|
|
#ifdef LIBXML_OUTPUT_ENABLED
|
|
/**
|
|
* xmlAllocOutputBuffer:
|
|
* @encoder: the encoding converter or NULL
|
|
*
|
|
* Create a buffered parser output
|
|
*
|
|
* Returns the new parser output or NULL
|
|
*/
|
|
xmlOutputBufferPtr
|
|
xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
|
|
xmlOutputBufferPtr ret;
|
|
|
|
ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
|
|
if (ret == NULL) {
|
|
return(NULL);
|
|
}
|
|
memset(ret, 0, sizeof(xmlOutputBuffer));
|
|
ret->buffer = xmlBufCreate();
|
|
if (ret->buffer == NULL) {
|
|
xmlFree(ret);
|
|
return(NULL);
|
|
}
|
|
xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_DOUBLEIT);
|
|
|
|
ret->encoder = encoder;
|
|
if (encoder != NULL) {
|
|
ret->conv = xmlBufCreateSize(4000);
|
|
if (ret->conv == NULL) {
|
|
xmlBufFree(ret->buffer);
|
|
xmlFree(ret);
|
|
return(NULL);
|
|
}
|
|
|
|
/*
|
|
* This call is designed to initiate the encoder state
|
|
*/
|
|
xmlCharEncOutput(ret, 1);
|
|
} else
|
|
ret->conv = NULL;
|
|
ret->writecallback = NULL;
|
|
ret->closecallback = NULL;
|
|
ret->context = NULL;
|
|
ret->written = 0;
|
|
|
|
return(ret);
|
|
}
|
|
|
|
/**
|
|
* xmlAllocOutputBufferInternal:
|
|
* @encoder: the encoding converter or NULL
|
|
*
|
|
* Create a buffered parser output
|
|
*
|
|
* Returns the new parser output or NULL
|
|
*/
|
|
xmlOutputBufferPtr
|
|
xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder) {
|
|
xmlOutputBufferPtr ret;
|
|
|
|
ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
|
|
if (ret == NULL) {
|
|
return(NULL);
|
|
}
|
|
memset(ret, 0, sizeof(xmlOutputBuffer));
|
|
ret->buffer = xmlBufCreate();
|
|
if (ret->buffer == NULL) {
|
|
xmlFree(ret);
|
|
return(NULL);
|
|
}
|
|
|
|
|
|
/*
|
|
* For conversion buffers we use the special IO handling
|
|
*/
|
|
xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_IO);
|
|
|
|
ret->encoder = encoder;
|
|
if (encoder != NULL) {
|
|
ret->conv = xmlBufCreateSize(4000);
|
|
if (ret->conv == NULL) {
|
|
xmlBufFree(ret->buffer);
|
|
xmlFree(ret);
|
|
return(NULL);
|
|
}
|
|
|
|
/*
|
|
* This call is designed to initiate the encoder state
|
|
*/
|
|
xmlCharEncOutput(ret, 1);
|
|
} else
|
|
ret->conv = NULL;
|
|
ret->writecallback = NULL;
|
|
ret->closecallback = NULL;
|
|
ret->context = NULL;
|
|
ret->written = 0;
|
|
|
|
return(ret);
|
|
}
|
|
|
|
#endif /* LIBXML_OUTPUT_ENABLED */
|
|
|
|
/**
|
|
* xmlFreeParserInputBuffer:
|
|
* @in: a buffered parser input
|
|
*
|
|
* Free up the memory used by a buffered parser input
|
|
*/
|
|
void
|
|
xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
|
|
if (in == NULL) return;
|
|
|
|
if (in->raw) {
|
|
xmlBufFree(in->raw);
|
|
in->raw = NULL;
|
|
}
|
|
if (in->encoder != NULL) {
|
|
xmlCharEncCloseFunc(in->encoder);
|
|
}
|
|
if (in->closecallback != NULL) {
|
|
in->closecallback(in->context);
|
|
}
|
|
if (in->buffer != NULL) {
|
|
xmlBufFree(in->buffer);
|
|
in->buffer = NULL;
|
|
}
|
|
|
|
xmlFree(in);
|
|
}
|
|
|
|
#ifdef LIBXML_OUTPUT_ENABLED
|
|
/**
|
|
* xmlOutputBufferClose:
|
|
* @out: a buffered output
|
|
*
|
|
* flushes and close the output I/O channel
|
|
* and free up all the associated resources
|
|
*
|
|
* Returns the number of byte written or -1 in case of error.
|
|
*/
|
|
int
|
|
xmlOutputBufferClose(xmlOutputBufferPtr out)
|
|
{
|
|
int written;
|
|
int err_rc = 0;
|
|
|
|
if (out == NULL)
|
|
return (-1);
|
|
if (out->writecallback != NULL)
|
|
xmlOutputBufferFlush(out);
|
|
if (out->closecallback != NULL) {
|
|
err_rc = out->closecallback(out->context);
|
|
}
|
|
written = out->written;
|
|
if (out->conv) {
|
|
xmlBufFree(out->conv);
|
|
out->conv = NULL;
|
|
}
|
|
if (out->encoder != NULL) {
|
|
xmlCharEncCloseFunc(out->encoder);
|
|
}
|
|
if (out->buffer != NULL) {
|
|
xmlBufFree(out->buffer);
|
|
out->buffer = NULL;
|
|
}
|
|
|
|
if (out->error)
|
|
err_rc = -1;
|
|
xmlFree(out);
|
|
return ((err_rc == 0) ? written : err_rc);
|
|
}
|
|
#endif /* LIBXML_OUTPUT_ENABLED */
|
|
|
|
/**
|
|
* xmlParserInputBufferCreateFilenameInt:
|
|
* @URI: the filename or URI
|
|
* @enc: encoding enum (deprecated)
|
|
* @out: pointer to resulting input buffer
|
|
*
|
|
* Returns an xmlParserErrors code.
|
|
*/
|
|
static int
|
|
xmlParserInputBufferCreateFilenameInt(const char *URI, xmlCharEncoding enc,
|
|
xmlParserInputBufferPtr *out) {
|
|
xmlParserInputBufferPtr buf;
|
|
int ret;
|
|
int i;
|
|
|
|
*out = NULL;
|
|
if (URI == NULL)
|
|
return(XML_ERR_ARGUMENT);
|
|
|
|
/*
|
|
* Allocate the Input buffer front-end.
|
|
*/
|
|
buf = xmlAllocParserInputBuffer(enc);
|
|
if (buf == NULL)
|
|
return(XML_ERR_NO_MEMORY);
|
|
|
|
/*
|
|
* Try to find one of the input accept method accepting that scheme
|
|
* Go in reverse to give precedence to user defined handlers.
|
|
*/
|
|
ret = XML_IO_ENOENT;
|
|
for (i = xmlInputCallbackNr - 1; i >= 0; i--) {
|
|
xmlInputCallback *cb = &xmlInputCallbackTable[i];
|
|
|
|
if (cb->matchcallback == xmlIODefaultMatch) {
|
|
ret = xmlInputDefaultOpen(buf, URI);
|
|
|
|
if ((ret == XML_ERR_OK) || (ret != XML_IO_ENOENT))
|
|
break;
|
|
} else if ((cb->matchcallback != NULL) &&
|
|
(cb->matchcallback(URI) != 0)) {
|
|
buf->context = cb->opencallback(URI);
|
|
if (buf->context != NULL) {
|
|
buf->readcallback = cb->readcallback;
|
|
buf->closecallback = cb->closecallback;
|
|
ret = XML_ERR_OK;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (ret != XML_ERR_OK) {
|
|
xmlFreeParserInputBuffer(buf);
|
|
*out = NULL;
|
|
return(ret);
|
|
}
|
|
|
|
*out = buf;
|
|
return(ret);
|
|
}
|
|
|
|
xmlParserInputBufferPtr
|
|
__xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
|
|
xmlParserInputBufferPtr ret;
|
|
|
|
xmlParserInputBufferCreateFilenameInt(URI, enc, &ret);
|
|
return(ret);
|
|
}
|
|
|
|
/**
|
|
* xmlParserInputBufferCreateFilename:
|
|
* @URI: a C string containing the URI or filename
|
|
* @enc: the charset encoding if known
|
|
*
|
|
* Create a buffered parser input for the progressive parsing of a file
|
|
* Automatic support for ZLIB/Compress compressed document is provided
|
|
* by default if found at compile-time.
|
|
* Do an encoding check if enc == XML_CHAR_ENCODING_NONE
|
|
*
|
|
* Returns the new parser input or NULL
|
|
*/
|
|
xmlParserInputBufferPtr
|
|
xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
|
|
if (xmlParserInputBufferCreateFilenameValue != NULL)
|
|
return(xmlParserInputBufferCreateFilenameValue(URI, enc));
|
|
|
|
return(__xmlParserInputBufferCreateFilename(URI, enc));
|
|
}
|
|
|
|
/**
|
|
* xmlParserInputBufferCreateFilenameSafe:
|
|
* @URI: the filename or URI
|
|
* @enc: encoding enum (deprecated)
|
|
* @out: pointer to resulting input buffer
|
|
*
|
|
* Returns an xmlParserErrors code.
|
|
*/
|
|
int
|
|
xmlParserInputBufferCreateFilenameSafe(const char *URI, xmlCharEncoding enc,
|
|
xmlParserInputBufferPtr *out) {
|
|
if (xmlParserInputBufferCreateFilenameValue != NULL) {
|
|
*out = xmlParserInputBufferCreateFilenameValue(URI, enc);
|
|
|
|
if (*out == NULL)
|
|
return(XML_IO_ENOENT);
|
|
return(XML_ERR_OK);
|
|
}
|
|
|
|
return(xmlParserInputBufferCreateFilenameInt(URI, enc, out));
|
|
}
|
|
|
|
#ifdef LIBXML_OUTPUT_ENABLED
|
|
xmlOutputBufferPtr
|
|
__xmlOutputBufferCreateFilename(const char *URI,
|
|
xmlCharEncodingHandlerPtr encoder,
|
|
int compression) {
|
|
xmlOutputBufferPtr ret;
|
|
xmlURIPtr puri;
|
|
int i = 0;
|
|
char *unescaped = NULL;
|
|
int is_file_uri = 1;
|
|
|
|
if (URI == NULL)
|
|
return(NULL);
|
|
|
|
puri = xmlParseURI(URI);
|
|
if (puri != NULL) {
|
|
if ((puri->scheme != NULL) &&
|
|
(!xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
|
|
is_file_uri = 0;
|
|
|
|
/*
|
|
* try to limit the damages of the URI unescaping code.
|
|
*/
|
|
if (puri->scheme == NULL) {
|
|
unescaped = xmlURIUnescapeString(URI, 0, NULL);
|
|
if (unescaped == NULL) {
|
|
xmlFreeURI(puri);
|
|
return(NULL);
|
|
}
|
|
URI = unescaped;
|
|
}
|
|
xmlFreeURI(puri);
|
|
}
|
|
|
|
/*
|
|
* Allocate the Output buffer front-end.
|
|
*/
|
|
ret = xmlAllocOutputBufferInternal(encoder);
|
|
if (ret == NULL) {
|
|
xmlFree(unescaped);
|
|
return(NULL);
|
|
}
|
|
|
|
/*
|
|
* Try to find one of the output accept method accepting that scheme
|
|
* Go in reverse to give precedence to user defined handlers.
|
|
*/
|
|
for (i = xmlOutputCallbackNr - 1; i >= 0; i--) {
|
|
xmlOutputCallback *cb = &xmlOutputCallbackTable[i];
|
|
int code;
|
|
|
|
if (cb->matchcallback == xmlIODefaultMatch) {
|
|
code = xmlOutputDefaultOpen(ret, URI, compression, is_file_uri);
|
|
/* TODO: Handle other errors */
|
|
if (code == XML_ERR_OK)
|
|
break;
|
|
} else if ((cb->matchcallback != NULL) &&
|
|
(cb->matchcallback(URI) != 0)) {
|
|
ret->context = cb->opencallback(URI);
|
|
if (ret->context != NULL) {
|
|
ret->writecallback = cb->writecallback;
|
|
ret->closecallback = cb->closecallback;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ret->context == NULL) {
|
|
xmlOutputBufferClose(ret);
|
|
ret = NULL;
|
|
}
|
|
|
|
xmlFree(unescaped);
|
|
return(ret);
|
|
}
|
|
|
|
/**
|
|
* xmlOutputBufferCreateFilename:
|
|
* @URI: a C string containing the URI or filename
|
|
* @encoder: the encoding converter or NULL
|
|
* @compression: the compression ration (0 none, 9 max).
|
|
*
|
|
* Create a buffered output for the progressive saving of a file
|
|
* If filename is "-' then we use stdout as the output.
|
|
* Automatic support for ZLIB/Compress compressed document is provided
|
|
* by default if found at compile-time.
|
|
* TODO: currently if compression is set, the library only support
|
|
* writing to a local file.
|
|
*
|
|
* Returns the new output or NULL
|
|
*/
|
|
xmlOutputBufferPtr
|
|
xmlOutputBufferCreateFilename(const char *URI,
|
|
xmlCharEncodingHandlerPtr encoder,
|
|
int compression ATTRIBUTE_UNUSED) {
|
|
if ((xmlOutputBufferCreateFilenameValue)) {
|
|
return xmlOutputBufferCreateFilenameValue(URI, encoder, compression);
|
|
}
|
|
return __xmlOutputBufferCreateFilename(URI, encoder, compression);
|
|
}
|
|
#endif /* LIBXML_OUTPUT_ENABLED */
|
|
|
|
/**
|
|
* xmlParserInputBufferCreateFile:
|
|
* @file: a FILE*
|
|
* @enc: the charset encoding if known (deprecated)
|
|
*
|
|
* Create a buffered parser input for the progressive parsing of a FILE *
|
|
* buffered C I/O
|
|
*
|
|
* The encoding argument is deprecated and should be set to
|
|
* XML_CHAR_ENCODING_NONE. The encoding can be changed with
|
|
* xmlSwitchEncoding or xmlSwitchEncodingName later on.
|
|
*
|
|
* Returns the new parser input or NULL
|
|
*/
|
|
xmlParserInputBufferPtr
|
|
xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
|
|
xmlParserInputBufferPtr ret;
|
|
|
|
if (file == NULL) return(NULL);
|
|
|
|
ret = xmlAllocParserInputBuffer(enc);
|
|
if (ret != NULL) {
|
|
ret->context = file;
|
|
ret->readcallback = xmlFileRead;
|
|
ret->closecallback = xmlFileFlush;
|
|
}
|
|
|
|
return(ret);
|
|
}
|
|
|
|
#ifdef LIBXML_OUTPUT_ENABLED
|
|
/**
|
|
* xmlOutputBufferCreateFile:
|
|
* @file: a FILE*
|
|
* @encoder: the encoding converter or NULL
|
|
*
|
|
* Create a buffered output for the progressive saving to a FILE *
|
|
* buffered C I/O
|
|
*
|
|
* Returns the new parser output or NULL
|
|
*/
|
|
xmlOutputBufferPtr
|
|
xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
|
|
xmlOutputBufferPtr ret;
|
|
|
|
if (file == NULL) return(NULL);
|
|
|
|
ret = xmlAllocOutputBufferInternal(encoder);
|
|
if (ret != NULL) {
|
|
ret->context = file;
|
|
ret->writecallback = xmlFileWrite;
|
|
ret->closecallback = xmlFileFlush;
|
|
}
|
|
|
|
return(ret);
|
|
}
|
|
|
|
/**
|
|
* xmlOutputBufferCreateBuffer:
|
|
* @buffer: a xmlBufferPtr
|
|
* @encoder: the encoding converter or NULL
|
|
*
|
|
* Create a buffered output for the progressive saving to a xmlBuffer
|
|
*
|
|
* Returns the new parser output or NULL
|
|
*/
|
|
xmlOutputBufferPtr
|
|
xmlOutputBufferCreateBuffer(xmlBufferPtr buffer,
|
|
xmlCharEncodingHandlerPtr encoder) {
|
|
xmlOutputBufferPtr ret;
|
|
|
|
if (buffer == NULL) return(NULL);
|
|
|
|
ret = xmlOutputBufferCreateIO(xmlBufferWrite, NULL, (void *) buffer,
|
|
encoder);
|
|
|
|
return(ret);
|
|
}
|
|
|
|
/**
|
|
* xmlOutputBufferGetContent:
|
|
* @out: an xmlOutputBufferPtr
|
|
*
|
|
* Gives a pointer to the data currently held in the output buffer
|
|
*
|
|
* Returns a pointer to the data or NULL in case of error
|
|
*/
|
|
const xmlChar *
|
|
xmlOutputBufferGetContent(xmlOutputBufferPtr out) {
|
|
if ((out == NULL) || (out->buffer == NULL) || (out->error != 0))
|
|
return(NULL);
|
|
|
|
return(xmlBufContent(out->buffer));
|
|
}
|
|
|
|
/**
|
|
* xmlOutputBufferGetSize:
|
|
* @out: an xmlOutputBufferPtr
|
|
*
|
|
* Gives the length of the data currently held in the output buffer
|
|
*
|
|
* Returns 0 in case or error or no data is held, the size otherwise
|
|
*/
|
|
size_t
|
|
xmlOutputBufferGetSize(xmlOutputBufferPtr out) {
|
|
if ((out == NULL) || (out->buffer == NULL) || (out->error != 0))
|
|
return(0);
|
|
|
|
return(xmlBufUse(out->buffer));
|
|
}
|
|
|
|
|
|
#endif /* LIBXML_OUTPUT_ENABLED */
|
|
|
|
/**
|
|
* xmlParserInputBufferCreateFd:
|
|
* @fd: a file descriptor number
|
|
* @enc: the charset encoding if known (deprecated)
|
|
*
|
|
* Create a buffered parser input for the progressive parsing for the input
|
|
* from a file descriptor
|
|
*
|
|
* The encoding argument is deprecated and should be set to
|
|
* XML_CHAR_ENCODING_NONE. The encoding can be changed with
|
|
* xmlSwitchEncoding or xmlSwitchEncodingName later on.
|
|
*
|
|
* Returns the new parser input or NULL
|
|
*/
|
|
xmlParserInputBufferPtr
|
|
xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
|
|
xmlParserInputBufferPtr ret;
|
|
|
|
if (fd < 0) return(NULL);
|
|
|
|
ret = xmlAllocParserInputBuffer(enc);
|
|
if (ret != NULL) {
|
|
ret->context = (void *) (ptrdiff_t) fd;
|
|
ret->readcallback = xmlFdRead;
|
|
ret->closecallback = xmlFdClose;
|
|
}
|
|
|
|
return(ret);
|
|
}
|
|
|
|
typedef struct {
|
|
char *mem;
|
|
const char *cur;
|
|
size_t size;
|
|
} xmlMemIOCtxt;
|
|
|
|
static int
|
|
xmlMemRead(void *vctxt, char *buf, int size) {
|
|
xmlMemIOCtxt *ctxt = vctxt;
|
|
|
|
if ((size_t) size > ctxt->size)
|
|
size = ctxt->size;
|
|
|
|
memcpy(buf, ctxt->cur, size);
|
|
ctxt->cur += size;
|
|
ctxt->size -= size;
|
|
|
|
return size;
|
|
}
|
|
|
|
static int
|
|
xmlMemClose(void *vctxt) {
|
|
xmlMemIOCtxt *ctxt = vctxt;
|
|
|
|
if (ctxt->mem != 0)
|
|
xmlFree(ctxt->mem);
|
|
xmlFree(ctxt);
|
|
return(0);
|
|
}
|
|
|
|
/**
|
|
* xmlParserInputBufferCreateMem:
|
|
* @mem: the memory input
|
|
* @size: the length of the memory block
|
|
* @enc: the charset encoding if known (deprecated)
|
|
*
|
|
* Create a parser input buffer for parsing from a memory area.
|
|
*
|
|
* This function makes a copy of the whole input buffer. If you are sure
|
|
* that the contents of the buffer will remain valid until the document
|
|
* was parsed, you can avoid the copy by using
|
|
* xmlParserInputBufferCreateStatic.
|
|
*
|
|
* The encoding argument is deprecated and should be set to
|
|
* XML_CHAR_ENCODING_NONE. The encoding can be changed with
|
|
* xmlSwitchEncoding or xmlSwitchEncodingName later on.
|
|
*
|
|
* Returns the new parser input or NULL in case of error.
|
|
*/
|
|
xmlParserInputBufferPtr
|
|
xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
|
|
xmlParserInputBufferPtr buf;
|
|
xmlMemIOCtxt *ctxt;
|
|
char *copy;
|
|
|
|
if ((size < 0) || (mem == NULL))
|
|
return(NULL);
|
|
|
|
copy = (char *) xmlStrndup((const xmlChar *) mem, size);
|
|
if (copy == NULL)
|
|
return(NULL);
|
|
|
|
buf = xmlParserInputBufferCreateStatic(copy, size, enc);
|
|
if (buf == NULL) {
|
|
xmlFree(copy);
|
|
return(NULL);
|
|
}
|
|
|
|
ctxt = buf->context;
|
|
ctxt->mem = copy;
|
|
|
|
return(buf);
|
|
}
|
|
|
|
/**
|
|
* xmlParserInputBufferCreateStatic:
|
|
* @mem: the memory input
|
|
* @size: the length of the memory block
|
|
* @enc: the charset encoding if known
|
|
*
|
|
* Create a parser input buffer for parsing from a memory area.
|
|
*
|
|
* This functions assumes that the contents of the input buffer remain
|
|
* valid until the document was parsed. Use xmlParserInputBufferCreateMem
|
|
* otherwise.
|
|
*
|
|
* The encoding argument is deprecated and should be set to
|
|
* XML_CHAR_ENCODING_NONE. The encoding can be changed with
|
|
* xmlSwitchEncoding or xmlSwitchEncodingName later on.
|
|
*
|
|
* Returns the new parser input or NULL in case of error.
|
|
*/
|
|
xmlParserInputBufferPtr
|
|
xmlParserInputBufferCreateStatic(const char *mem, int size,
|
|
xmlCharEncoding enc) {
|
|
xmlParserInputBufferPtr ret;
|
|
xmlMemIOCtxt *ctxt;
|
|
|
|
if ((size < 0) || (mem == NULL))
|
|
return(NULL);
|
|
|
|
ret = xmlAllocParserInputBuffer(enc);
|
|
if (ret == NULL)
|
|
return(NULL);
|
|
|
|
ctxt = xmlMalloc(sizeof(*ctxt));
|
|
if (ctxt == NULL) {
|
|
xmlFreeParserInputBuffer(ret);
|
|
return(NULL);
|
|
}
|
|
ctxt->mem = NULL;
|
|
ctxt->cur = mem;
|
|
ctxt->size = size;
|
|
|
|
ret->context = ctxt;
|
|
ret->readcallback = xmlMemRead;
|
|
ret->closecallback = xmlMemClose;
|
|
|
|
return(ret);
|
|
}
|
|
|
|
typedef struct {
|
|
const xmlChar *str;
|
|
} xmlStringIOCtxt;
|
|
|
|
static int
|
|
xmlStringRead(void *vctxt, char *buf, int size) {
|
|
xmlStringIOCtxt *ctxt = vctxt;
|
|
const xmlChar *zero;
|
|
size_t len;
|
|
|
|
zero = memchr(ctxt->str, 0, size);
|
|
len = zero ? zero - ctxt->str : size;
|
|
|
|
memcpy(buf, ctxt->str, len);
|
|
ctxt->str += len;
|
|
|
|
return(len);
|
|
}
|
|
|
|
static int
|
|
xmlStringClose(void *vctxt) {
|
|
xmlFree(vctxt);
|
|
return(0);
|
|
}
|
|
|
|
/**
|
|
* xmlParserInputBufferCreateString:
|
|
* @str: a null-terminated string
|
|
*
|
|
* Create a buffered parser input for the progressive parsing for the input
|
|
* from a null-terminated C string.
|
|
*
|
|
* Returns the new parser input or NULL
|
|
*/
|
|
xmlParserInputBufferPtr
|
|
xmlParserInputBufferCreateString(const xmlChar *str) {
|
|
xmlParserInputBufferPtr ret;
|
|
xmlStringIOCtxt *ctxt;
|
|
|
|
if (str == NULL) return(NULL);
|
|
|
|
ret = xmlAllocParserInputBuffer(XML_CHAR_ENCODING_NONE);
|
|
if (ret == NULL)
|
|
return(NULL);
|
|
|
|
ctxt = xmlMalloc(sizeof(*ctxt));
|
|
if (ctxt == NULL) {
|
|
xmlFreeParserInputBuffer(ret);
|
|
return(NULL);
|
|
}
|
|
ctxt->str = str;
|
|
|
|
ret->context = ctxt;
|
|
ret->readcallback = xmlStringRead;
|
|
ret->closecallback = xmlStringClose;
|
|
|
|
return(ret);
|
|
}
|
|
|
|
#ifdef LIBXML_OUTPUT_ENABLED
|
|
/**
|
|
* xmlOutputBufferCreateFd:
|
|
* @fd: a file descriptor number
|
|
* @encoder: the encoding converter or NULL
|
|
*
|
|
* Create a buffered output for the progressive saving
|
|
* to a file descriptor
|
|
*
|
|
* Returns the new parser output or NULL
|
|
*/
|
|
xmlOutputBufferPtr
|
|
xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
|
|
xmlOutputBufferPtr ret;
|
|
|
|
if (fd < 0) return(NULL);
|
|
|
|
ret = xmlAllocOutputBufferInternal(encoder);
|
|
if (ret != NULL) {
|
|
ret->context = (void *) (ptrdiff_t) fd;
|
|
ret->writecallback = xmlFdWrite;
|
|
ret->closecallback = NULL;
|
|
}
|
|
|
|
return(ret);
|
|
}
|
|
#endif /* LIBXML_OUTPUT_ENABLED */
|
|
|
|
/**
|
|
* xmlParserInputBufferCreateIO:
|
|
* @ioread: an I/O read function
|
|
* @ioclose: an I/O close function
|
|
* @ioctx: an I/O handler
|
|
* @enc: the charset encoding if known (deprecated)
|
|
*
|
|
* Create a buffered parser input for the progressive parsing for the input
|
|
* from an I/O handler
|
|
*
|
|
* The encoding argument is deprecated and should be set to
|
|
* XML_CHAR_ENCODING_NONE. The encoding can be changed with
|
|
* xmlSwitchEncoding or xmlSwitchEncodingName later on.
|
|
*
|
|
* Returns the new parser input or NULL
|
|
*/
|
|
xmlParserInputBufferPtr
|
|
xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
|
|
xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
|
|
xmlParserInputBufferPtr ret;
|
|
|
|
if (ioread == NULL) return(NULL);
|
|
|
|
ret = xmlAllocParserInputBuffer(enc);
|
|
if (ret != NULL) {
|
|
ret->context = (void *) ioctx;
|
|
ret->readcallback = ioread;
|
|
ret->closecallback = ioclose;
|
|
}
|
|
|
|
return(ret);
|
|
}
|
|
|
|
#ifdef LIBXML_OUTPUT_ENABLED
|
|
/**
|
|
* xmlOutputBufferCreateIO:
|
|
* @iowrite: an I/O write function
|
|
* @ioclose: an I/O close function
|
|
* @ioctx: an I/O handler
|
|
* @encoder: the charset encoding if known
|
|
*
|
|
* Create a buffered output for the progressive saving
|
|
* to an I/O handler
|
|
*
|
|
* Returns the new parser output or NULL
|
|
*/
|
|
xmlOutputBufferPtr
|
|
xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
|
|
xmlOutputCloseCallback ioclose, void *ioctx,
|
|
xmlCharEncodingHandlerPtr encoder) {
|
|
xmlOutputBufferPtr ret;
|
|
|
|
if (iowrite == NULL) return(NULL);
|
|
|
|
ret = xmlAllocOutputBufferInternal(encoder);
|
|
if (ret != NULL) {
|
|
ret->context = (void *) ioctx;
|
|
ret->writecallback = iowrite;
|
|
ret->closecallback = ioclose;
|
|
}
|
|
|
|
return(ret);
|
|
}
|
|
#endif /* LIBXML_OUTPUT_ENABLED */
|
|
|
|
/**
|
|
* xmlParserInputBufferCreateFilenameDefault:
|
|
* @func: function pointer to the new ParserInputBufferCreateFilenameFunc
|
|
*
|
|
* Registers a callback for URI input file handling
|
|
*
|
|
* Returns the old value of the registration function
|
|
*/
|
|
xmlParserInputBufferCreateFilenameFunc
|
|
xmlParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func)
|
|
{
|
|
xmlParserInputBufferCreateFilenameFunc old = xmlParserInputBufferCreateFilenameValue;
|
|
if (old == NULL) {
|
|
old = __xmlParserInputBufferCreateFilename;
|
|
}
|
|
|
|
xmlParserInputBufferCreateFilenameValue = func;
|
|
return(old);
|
|
}
|
|
|
|
/**
|
|
* xmlOutputBufferCreateFilenameDefault:
|
|
* @func: function pointer to the new OutputBufferCreateFilenameFunc
|
|
*
|
|
* Registers a callback for URI output file handling
|
|
*
|
|
* Returns the old value of the registration function
|
|
*/
|
|
xmlOutputBufferCreateFilenameFunc
|
|
xmlOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func)
|
|
{
|
|
xmlOutputBufferCreateFilenameFunc old = xmlOutputBufferCreateFilenameValue;
|
|
#ifdef LIBXML_OUTPUT_ENABLED
|
|
if (old == NULL) {
|
|
old = __xmlOutputBufferCreateFilename;
|
|
}
|
|
#endif
|
|
xmlOutputBufferCreateFilenameValue = func;
|
|
return(old);
|
|
}
|
|
|
|
/**
|
|
* xmlParserInputBufferPush:
|
|
* @in: a buffered parser input
|
|
* @len: the size in bytes of the array.
|
|
* @buf: an char array
|
|
*
|
|
* Push the content of the arry in the input buffer
|
|
* This routine handle the I18N transcoding to internal UTF-8
|
|
* This is used when operating the parser in progressive (push) mode.
|
|
*
|
|
* Returns the number of chars read and stored in the buffer, or -1
|
|
* in case of error.
|
|
*/
|
|
int
|
|
xmlParserInputBufferPush(xmlParserInputBufferPtr in,
|
|
int len, const char *buf) {
|
|
int nbchars = 0;
|
|
int ret;
|
|
|
|
if (len < 0) return(0);
|
|
if ((in == NULL) || (in->error)) return(-1);
|
|
if (in->encoder != NULL) {
|
|
/*
|
|
* Store the data in the incoming raw buffer
|
|
*/
|
|
if (in->raw == NULL) {
|
|
in->raw = xmlBufCreate();
|
|
if (in->raw == NULL) {
|
|
in->error = XML_ERR_NO_MEMORY;
|
|
return(-1);
|
|
}
|
|
}
|
|
ret = xmlBufAdd(in->raw, (const xmlChar *) buf, len);
|
|
if (ret != 0) {
|
|
in->error = XML_ERR_NO_MEMORY;
|
|
return(-1);
|
|
}
|
|
|
|
/*
|
|
* convert as much as possible to the parser reading buffer.
|
|
*/
|
|
nbchars = xmlCharEncInput(in);
|
|
if (nbchars < 0)
|
|
return(-1);
|
|
} else {
|
|
nbchars = len;
|
|
ret = xmlBufAdd(in->buffer, (xmlChar *) buf, nbchars);
|
|
if (ret != 0) {
|
|
in->error = XML_ERR_NO_MEMORY;
|
|
return(-1);
|
|
}
|
|
}
|
|
return(nbchars);
|
|
}
|
|
|
|
/**
|
|
* endOfInput:
|
|
*
|
|
* When reading from an Input channel indicated end of file or error
|
|
* don't reread from it again.
|
|
*/
|
|
static int
|
|
endOfInput (void * context ATTRIBUTE_UNUSED,
|
|
char * buffer ATTRIBUTE_UNUSED,
|
|
int len ATTRIBUTE_UNUSED) {
|
|
return(0);
|
|
}
|
|
|
|
/**
|
|
* xmlParserInputBufferGrow:
|
|
* @in: a buffered parser input
|
|
* @len: indicative value of the amount of chars to read
|
|
*
|
|
* Grow up the content of the input buffer, the old data are preserved
|
|
* This routine handle the I18N transcoding to internal UTF-8
|
|
* This routine is used when operating the parser in normal (pull) mode
|
|
*
|
|
* TODO: one should be able to remove one extra copy by copying directly
|
|
* onto in->buffer or in->raw
|
|
*
|
|
* Returns the number of chars read and stored in the buffer, or -1
|
|
* in case of error.
|
|
*/
|
|
int
|
|
xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
|
|
xmlBufPtr buf;
|
|
int res = 0;
|
|
|
|
if ((in == NULL) || (in->error)) return(-1);
|
|
if ((len <= MINLEN) && (len != 4))
|
|
len = MINLEN;
|
|
|
|
if (in->encoder == NULL) {
|
|
if (in->readcallback == NULL)
|
|
return(0);
|
|
buf = in->buffer;
|
|
} else {
|
|
if (in->raw == NULL) {
|
|
in->raw = xmlBufCreate();
|
|
}
|
|
buf = in->raw;
|
|
}
|
|
|
|
/*
|
|
* Call the read method for this I/O type.
|
|
*/
|
|
if (in->readcallback != NULL) {
|
|
if (xmlBufGrow(buf, len + 1) < 0) {
|
|
in->error = XML_ERR_NO_MEMORY;
|
|
return(-1);
|
|
}
|
|
|
|
res = in->readcallback(in->context, (char *)xmlBufEnd(buf), len);
|
|
if (res <= 0)
|
|
in->readcallback = endOfInput;
|
|
if (res < 0) {
|
|
if (res == -1)
|
|
in->error = XML_IO_UNKNOWN;
|
|
else
|
|
in->error = -res;
|
|
return(-1);
|
|
}
|
|
|
|
if (xmlBufAddLen(buf, res) < 0) {
|
|
in->error = XML_ERR_NO_MEMORY;
|
|
return(-1);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* try to establish compressed status of input if not done already
|
|
*/
|
|
if (in->compressed == -1) {
|
|
#ifdef LIBXML_LZMA_ENABLED
|
|
if (in->readcallback == xmlXzfileRead)
|
|
in->compressed = __libxml2_xzcompressed(in->context);
|
|
#endif
|
|
}
|
|
|
|
if (in->encoder != NULL) {
|
|
res = xmlCharEncInput(in);
|
|
if (res < 0)
|
|
return(-1);
|
|
}
|
|
return(res);
|
|
}
|
|
|
|
/**
|
|
* 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) {
|
|
return(xmlParserInputBufferGrow(in, len));
|
|
}
|
|
|
|
#ifdef LIBXML_OUTPUT_ENABLED
|
|
/**
|
|
* xmlOutputBufferWrite:
|
|
* @out: a buffered parser output
|
|
* @len: the size in bytes of the array.
|
|
* @buf: an char array
|
|
*
|
|
* Write the content of the array in the output I/O buffer
|
|
* This routine handle the I18N transcoding from internal UTF-8
|
|
* The buffer is lossless, i.e. will store in case of partial
|
|
* or delayed writes.
|
|
*
|
|
* Returns the number of chars immediately written, or -1
|
|
* in case of error.
|
|
*/
|
|
int
|
|
xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
|
|
int nbchars = 0; /* number of chars to output to I/O */
|
|
int ret; /* return from function call */
|
|
int written = 0; /* number of char written to I/O so far */
|
|
int chunk; /* number of byte current processed from buf */
|
|
|
|
if ((out == NULL) || (out->error)) return(-1);
|
|
if (len < 0) return(0);
|
|
if (out->error) return(-1);
|
|
|
|
do {
|
|
chunk = len;
|
|
if (chunk > 4 * MINLEN)
|
|
chunk = 4 * MINLEN;
|
|
|
|
/*
|
|
* first handle encoding stuff.
|
|
*/
|
|
if (out->encoder != NULL) {
|
|
/*
|
|
* Store the data in the incoming raw buffer
|
|
*/
|
|
if (out->conv == NULL) {
|
|
out->conv = xmlBufCreate();
|
|
if (out->conv == NULL) {
|
|
out->error = XML_ERR_NO_MEMORY;
|
|
return(-1);
|
|
}
|
|
}
|
|
ret = xmlBufAdd(out->buffer, (const xmlChar *) buf, chunk);
|
|
if (ret != 0)
|
|
return(-1);
|
|
|
|
if ((xmlBufUse(out->buffer) < MINLEN) && (chunk == len))
|
|
goto done;
|
|
|
|
/*
|
|
* convert as much as possible to the parser reading buffer.
|
|
*/
|
|
ret = xmlCharEncOutput(out, 0);
|
|
if (ret < 0)
|
|
return(-1);
|
|
if (out->writecallback)
|
|
nbchars = xmlBufUse(out->conv);
|
|
else
|
|
nbchars = ret >= 0 ? ret : 0;
|
|
} else {
|
|
ret = xmlBufAdd(out->buffer, (const xmlChar *) buf, chunk);
|
|
if (ret != 0)
|
|
return(-1);
|
|
if (out->writecallback)
|
|
nbchars = xmlBufUse(out->buffer);
|
|
else
|
|
nbchars = chunk;
|
|
}
|
|
buf += chunk;
|
|
len -= chunk;
|
|
|
|
if (out->writecallback) {
|
|
if ((nbchars < MINLEN) && (len <= 0))
|
|
goto done;
|
|
|
|
/*
|
|
* second write the stuff to the I/O channel
|
|
*/
|
|
if (out->encoder != NULL) {
|
|
ret = out->writecallback(out->context,
|
|
(const char *)xmlBufContent(out->conv), nbchars);
|
|
if (ret >= 0)
|
|
xmlBufShrink(out->conv, ret);
|
|
} else {
|
|
ret = out->writecallback(out->context,
|
|
(const char *)xmlBufContent(out->buffer), nbchars);
|
|
if (ret >= 0)
|
|
xmlBufShrink(out->buffer, ret);
|
|
}
|
|
if (ret < 0) {
|
|
int errNo = (ret == -1) ? XML_IO_WRITE : -ret;
|
|
|
|
xmlIOErr(errNo, NULL);
|
|
out->error = errNo;
|
|
return(ret);
|
|
}
|
|
if (out->written > INT_MAX - ret)
|
|
out->written = INT_MAX;
|
|
else
|
|
out->written += ret;
|
|
}
|
|
written += nbchars;
|
|
} while (len > 0);
|
|
|
|
done:
|
|
return(written);
|
|
}
|
|
|
|
/**
|
|
* xmlEscapeContent:
|
|
* @out: a pointer to an array of bytes to store the result
|
|
* @outlen: the length of @out
|
|
* @in: a pointer to an array of unescaped UTF-8 bytes
|
|
* @inlen: the length of @in
|
|
*
|
|
* Take a block of UTF-8 chars in and escape them.
|
|
* Returns 0 if success, or -1 otherwise
|
|
* The value of @inlen after return is the number of octets consumed
|
|
* if the return value is positive, else unpredictable.
|
|
* The value of @outlen after return is the number of octets consumed.
|
|
*/
|
|
static int
|
|
xmlEscapeContent(unsigned char* out, int *outlen,
|
|
const xmlChar* in, int *inlen) {
|
|
unsigned char* outstart = out;
|
|
const unsigned char* base = in;
|
|
unsigned char* outend = out + *outlen;
|
|
const unsigned char* inend;
|
|
|
|
inend = in + (*inlen);
|
|
|
|
while ((in < inend) && (out < outend)) {
|
|
if (*in == '<') {
|
|
if (outend - out < 4) break;
|
|
*out++ = '&';
|
|
*out++ = 'l';
|
|
*out++ = 't';
|
|
*out++ = ';';
|
|
} else if (*in == '>') {
|
|
if (outend - out < 4) break;
|
|
*out++ = '&';
|
|
*out++ = 'g';
|
|
*out++ = 't';
|
|
*out++ = ';';
|
|
} else if (*in == '&') {
|
|
if (outend - out < 5) break;
|
|
*out++ = '&';
|
|
*out++ = 'a';
|
|
*out++ = 'm';
|
|
*out++ = 'p';
|
|
*out++ = ';';
|
|
} else if (*in == '\r') {
|
|
if (outend - out < 5) break;
|
|
*out++ = '&';
|
|
*out++ = '#';
|
|
*out++ = '1';
|
|
*out++ = '3';
|
|
*out++ = ';';
|
|
} else {
|
|
*out++ = *in;
|
|
}
|
|
++in;
|
|
}
|
|
*outlen = out - outstart;
|
|
*inlen = in - base;
|
|
return(0);
|
|
}
|
|
|
|
/**
|
|
* xmlOutputBufferWriteEscape:
|
|
* @out: a buffered parser output
|
|
* @str: a zero terminated UTF-8 string
|
|
* @escaping: an optional escaping function (or NULL)
|
|
*
|
|
* Write the content of the string in the output I/O buffer
|
|
* This routine escapes the characters and then handle the I18N
|
|
* transcoding from internal UTF-8
|
|
* The buffer is lossless, i.e. will store in case of partial
|
|
* or delayed writes.
|
|
*
|
|
* Returns the number of chars immediately written, or -1
|
|
* in case of error.
|
|
*/
|
|
int
|
|
xmlOutputBufferWriteEscape(xmlOutputBufferPtr out, const xmlChar *str,
|
|
xmlCharEncodingOutputFunc escaping) {
|
|
int nbchars = 0; /* number of chars to output to I/O */
|
|
int ret; /* return from function call */
|
|
int written = 0; /* number of char written to I/O so far */
|
|
int oldwritten=0;/* loop guard */
|
|
int chunk; /* number of byte currently processed from str */
|
|
int len; /* number of bytes in str */
|
|
int cons; /* byte from str consumed */
|
|
|
|
if ((out == NULL) || (out->error) || (str == NULL) ||
|
|
(out->buffer == NULL))
|
|
return(-1);
|
|
len = strlen((const char *)str);
|
|
if (len < 0) return(0);
|
|
if (out->error) return(-1);
|
|
if (escaping == NULL) escaping = xmlEscapeContent;
|
|
|
|
do {
|
|
oldwritten = written;
|
|
|
|
/*
|
|
* how many bytes to consume and how many bytes to store.
|
|
*/
|
|
cons = len;
|
|
chunk = xmlBufAvail(out->buffer);
|
|
|
|
/*
|
|
* make sure we have enough room to save first, if this is
|
|
* not the case force a flush, but make sure we stay in the loop
|
|
*/
|
|
if (chunk < 40) {
|
|
if (xmlBufGrow(out->buffer, 100) < 0)
|
|
return(-1);
|
|
oldwritten = -1;
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* first handle encoding stuff.
|
|
*/
|
|
if (out->encoder != NULL) {
|
|
/*
|
|
* Store the data in the incoming raw buffer
|
|
*/
|
|
if (out->conv == NULL) {
|
|
out->conv = xmlBufCreate();
|
|
}
|
|
ret = escaping(xmlBufEnd(out->buffer) ,
|
|
&chunk, str, &cons);
|
|
if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
|
|
return(-1);
|
|
xmlBufAddLen(out->buffer, chunk);
|
|
|
|
if ((xmlBufUse(out->buffer) < MINLEN) && (cons == len))
|
|
goto done;
|
|
|
|
/*
|
|
* convert as much as possible to the output buffer.
|
|
*/
|
|
ret = xmlCharEncOutput(out, 0);
|
|
if (ret < 0)
|
|
return(-1);
|
|
if (out->writecallback)
|
|
nbchars = xmlBufUse(out->conv);
|
|
else
|
|
nbchars = ret >= 0 ? ret : 0;
|
|
} else {
|
|
ret = escaping(xmlBufEnd(out->buffer), &chunk, str, &cons);
|
|
if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
|
|
return(-1);
|
|
xmlBufAddLen(out->buffer, chunk);
|
|
if (out->writecallback)
|
|
nbchars = xmlBufUse(out->buffer);
|
|
else
|
|
nbchars = chunk;
|
|
}
|
|
str += cons;
|
|
len -= cons;
|
|
|
|
if (out->writecallback) {
|
|
if ((nbchars < MINLEN) && (len <= 0))
|
|
goto done;
|
|
|
|
/*
|
|
* second write the stuff to the I/O channel
|
|
*/
|
|
if (out->encoder != NULL) {
|
|
ret = out->writecallback(out->context,
|
|
(const char *)xmlBufContent(out->conv), nbchars);
|
|
if (ret >= 0)
|
|
xmlBufShrink(out->conv, ret);
|
|
} else {
|
|
ret = out->writecallback(out->context,
|
|
(const char *)xmlBufContent(out->buffer), nbchars);
|
|
if (ret >= 0)
|
|
xmlBufShrink(out->buffer, ret);
|
|
}
|
|
if (ret < 0) {
|
|
int errNo = (ret == -1) ? XML_IO_WRITE : -ret;
|
|
xmlIOErr(errNo, NULL);
|
|
out->error = errNo;
|
|
return(ret);
|
|
}
|
|
if (out->written > INT_MAX - ret)
|
|
out->written = INT_MAX;
|
|
else
|
|
out->written += ret;
|
|
} else if (xmlBufAvail(out->buffer) < MINLEN) {
|
|
xmlBufGrow(out->buffer, MINLEN);
|
|
}
|
|
written += nbchars;
|
|
} while ((len > 0) && (oldwritten != written));
|
|
|
|
done:
|
|
return(written);
|
|
}
|
|
|
|
/**
|
|
* xmlOutputBufferWriteString:
|
|
* @out: a buffered parser output
|
|
* @str: a zero terminated C string
|
|
*
|
|
* Write the content of the string in the output I/O buffer
|
|
* This routine handle the I18N transcoding from internal UTF-8
|
|
* The buffer is lossless, i.e. will store in case of partial
|
|
* or delayed writes.
|
|
*
|
|
* Returns the number of chars immediately written, or -1
|
|
* in case of error.
|
|
*/
|
|
int
|
|
xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
|
|
int len;
|
|
|
|
if ((out == NULL) || (out->error)) return(-1);
|
|
if (str == NULL)
|
|
return(-1);
|
|
len = strlen(str);
|
|
|
|
if (len > 0)
|
|
return(xmlOutputBufferWrite(out, len, str));
|
|
return(len);
|
|
}
|
|
|
|
/**
|
|
* xmlOutputBufferFlush:
|
|
* @out: a buffered output
|
|
*
|
|
* flushes the output I/O channel
|
|
*
|
|
* Returns the number of byte written or -1 in case of error.
|
|
*/
|
|
int
|
|
xmlOutputBufferFlush(xmlOutputBufferPtr out) {
|
|
int nbchars = 0, ret = 0;
|
|
|
|
if ((out == NULL) || (out->error)) return(-1);
|
|
/*
|
|
* first handle encoding stuff.
|
|
*/
|
|
if ((out->conv != NULL) && (out->encoder != NULL)) {
|
|
/*
|
|
* convert as much as possible to the parser output buffer.
|
|
*/
|
|
do {
|
|
nbchars = xmlCharEncOutput(out, 0);
|
|
if (nbchars < 0)
|
|
return(-1);
|
|
} while (nbchars);
|
|
}
|
|
|
|
/*
|
|
* second flush the stuff to the I/O channel
|
|
*/
|
|
if ((out->conv != NULL) && (out->encoder != NULL) &&
|
|
(out->writecallback != NULL)) {
|
|
ret = out->writecallback(out->context,
|
|
(const char *)xmlBufContent(out->conv),
|
|
xmlBufUse(out->conv));
|
|
if (ret >= 0)
|
|
xmlBufShrink(out->conv, ret);
|
|
} else if (out->writecallback != NULL) {
|
|
ret = out->writecallback(out->context,
|
|
(const char *)xmlBufContent(out->buffer),
|
|
xmlBufUse(out->buffer));
|
|
if (ret >= 0)
|
|
xmlBufShrink(out->buffer, ret);
|
|
}
|
|
if (ret < 0) {
|
|
int errNo = (ret == -1) ? XML_IO_WRITE : -ret;
|
|
|
|
xmlIOErr(errNo, NULL);
|
|
out->error = errNo;
|
|
return(ret);
|
|
}
|
|
if (out->written > INT_MAX - ret)
|
|
out->written = INT_MAX;
|
|
else
|
|
out->written += ret;
|
|
|
|
return(ret);
|
|
}
|
|
#endif /* LIBXML_OUTPUT_ENABLED */
|
|
|
|
/**
|
|
* xmlParserGetDirectory:
|
|
* @filename: the path to a file
|
|
*
|
|
* lookup the directory for that file
|
|
*
|
|
* Returns a new allocated string containing the directory, or NULL.
|
|
*/
|
|
char *
|
|
xmlParserGetDirectory(const char *filename) {
|
|
char *ret = NULL;
|
|
char dir[1024];
|
|
char *cur;
|
|
|
|
if (filename == NULL) return(NULL);
|
|
|
|
#if defined(_WIN32)
|
|
# define IS_XMLPGD_SEP(ch) ((ch=='/')||(ch=='\\'))
|
|
#else
|
|
# define IS_XMLPGD_SEP(ch) (ch=='/')
|
|
#endif
|
|
|
|
strncpy(dir, filename, 1023);
|
|
dir[1023] = 0;
|
|
cur = &dir[strlen(dir)];
|
|
while (cur > dir) {
|
|
if (IS_XMLPGD_SEP(*cur)) break;
|
|
cur --;
|
|
}
|
|
if (IS_XMLPGD_SEP(*cur)) {
|
|
if (cur == dir) dir[1] = 0;
|
|
else *cur = 0;
|
|
ret = xmlMemStrdup(dir);
|
|
} else {
|
|
if (getcwd(dir, 1024) != NULL) {
|
|
dir[1023] = 0;
|
|
ret = xmlMemStrdup(dir);
|
|
}
|
|
}
|
|
return(ret);
|
|
#undef IS_XMLPGD_SEP
|
|
}
|
|
|
|
/****************************************************************
|
|
* *
|
|
* External entities loading *
|
|
* *
|
|
****************************************************************/
|
|
|
|
/**
|
|
* xmlCheckHTTPInput:
|
|
* @ctxt: an XML parser context
|
|
* @ret: an XML parser input
|
|
*
|
|
* DEPRECATED: Internal function, don't use.
|
|
*
|
|
* Check an input in case it was created from an HTTP stream, in that
|
|
* case it will handle encoding and update of the base URL in case of
|
|
* redirection. It also checks for HTTP errors in which case the input
|
|
* is cleanly freed up and an appropriate error is raised in context
|
|
*
|
|
* Returns the input or NULL in case of HTTP error.
|
|
*/
|
|
xmlParserInputPtr
|
|
xmlCheckHTTPInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr ret) {
|
|
/* Avoid unused variable warning if features are disabled. */
|
|
(void) ctxt;
|
|
|
|
#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)
|
|
xmlCtxtErrIO(ctxt, XML_IO_LOAD_ERROR, ret->filename);
|
|
else
|
|
xmlCtxtErrIO(ctxt, XML_IO_LOAD_ERROR, "<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)
|
|
xmlSwitchEncodingName(ctxt, encoding);
|
|
#if 0
|
|
} else if (xmlStrstr(BAD_CAST mime, BAD_CAST "html")) {
|
|
#endif
|
|
}
|
|
redir = xmlNanoHTTPRedir(ret->buf->context);
|
|
if (redir != NULL) {
|
|
if (ret->filename != NULL)
|
|
xmlFree((xmlChar *) ret->filename);
|
|
if (ret->directory != NULL) {
|
|
xmlFree((xmlChar *) ret->directory);
|
|
ret->directory = NULL;
|
|
}
|
|
ret->filename =
|
|
(char *) xmlStrdup((const xmlChar *) redir);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
return(ret);
|
|
}
|
|
|
|
static int xmlNoNetExists(const char *filename) {
|
|
char *fromUri;
|
|
int ret;
|
|
|
|
if (filename == NULL)
|
|
return(0);
|
|
|
|
if (xmlConvertUriToPath(filename, &fromUri) < 0)
|
|
return(0);
|
|
|
|
if (fromUri != NULL)
|
|
filename = fromUri;
|
|
|
|
ret = xmlCheckFilename(filename);
|
|
|
|
xmlFree(fromUri);
|
|
return(ret);
|
|
}
|
|
|
|
#ifdef LIBXML_CATALOG_ENABLED
|
|
|
|
/**
|
|
* xmlResolveResourceFromCatalog:
|
|
* @URL: the URL for the entity to load
|
|
* @ID: the System ID for the entity to load
|
|
* @ctxt: the context in which the entity is called or NULL
|
|
*
|
|
* Resolves the URL and ID against the appropriate catalog.
|
|
* This function is used by xmlDefaultExternalEntityLoader and
|
|
* xmlNoNetExternalEntityLoader.
|
|
*
|
|
* Returns a new allocated URL, or NULL.
|
|
*/
|
|
static xmlChar *
|
|
xmlResolveResourceFromCatalog(const char *URL, const char *ID,
|
|
xmlParserCtxtPtr ctxt) {
|
|
xmlChar *resource = NULL;
|
|
xmlCatalogAllow pref;
|
|
|
|
/*
|
|
* If the resource doesn't exists as a file,
|
|
* try to load it from the resource pointed in the catalogs
|
|
*/
|
|
pref = xmlCatalogGetDefaults();
|
|
|
|
if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
|
|
/*
|
|
* Do a local lookup
|
|
*/
|
|
if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
|
|
((pref == XML_CATA_ALLOW_ALL) ||
|
|
(pref == XML_CATA_ALLOW_DOCUMENT))) {
|
|
resource = xmlCatalogLocalResolve(ctxt->catalogs,
|
|
(const xmlChar *)ID,
|
|
(const xmlChar *)URL);
|
|
}
|
|
/*
|
|
* Try a global lookup
|
|
*/
|
|
if ((resource == NULL) &&
|
|
((pref == XML_CATA_ALLOW_ALL) ||
|
|
(pref == XML_CATA_ALLOW_GLOBAL))) {
|
|
resource = xmlCatalogResolve((const xmlChar *)ID,
|
|
(const xmlChar *)URL);
|
|
}
|
|
if ((resource == NULL) && (URL != NULL))
|
|
resource = xmlStrdup((const xmlChar *) URL);
|
|
|
|
/*
|
|
* TODO: do an URI lookup on the reference
|
|
*/
|
|
if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
|
|
xmlChar *tmp = NULL;
|
|
|
|
if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
|
|
((pref == XML_CATA_ALLOW_ALL) ||
|
|
(pref == XML_CATA_ALLOW_DOCUMENT))) {
|
|
tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
|
|
}
|
|
if ((tmp == NULL) &&
|
|
((pref == XML_CATA_ALLOW_ALL) ||
|
|
(pref == XML_CATA_ALLOW_GLOBAL))) {
|
|
tmp = xmlCatalogResolveURI(resource);
|
|
}
|
|
|
|
if (tmp != NULL) {
|
|
xmlFree(resource);
|
|
resource = tmp;
|
|
}
|
|
}
|
|
}
|
|
|
|
return resource;
|
|
}
|
|
|
|
#endif
|
|
|
|
/**
|
|
* xmlDefaultExternalEntityLoader:
|
|
* @URL: the URL for the entity to load
|
|
* @ID: the System ID for the entity to load
|
|
* @ctxt: the context in which the entity is called or NULL
|
|
*
|
|
* By default we don't load external entities, yet.
|
|
*
|
|
* Returns a new allocated xmlParserInputPtr, or NULL.
|
|
*/
|
|
static xmlParserInputPtr
|
|
xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
|
|
xmlParserCtxtPtr ctxt)
|
|
{
|
|
xmlParserInputPtr ret = NULL;
|
|
xmlChar *resource = NULL;
|
|
|
|
if (URL == NULL)
|
|
return(NULL);
|
|
|
|
if ((ctxt != NULL) && (ctxt->options & XML_PARSE_NONET)) {
|
|
int options = ctxt->options;
|
|
|
|
ctxt->options -= XML_PARSE_NONET;
|
|
ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
|
|
ctxt->options = options;
|
|
return(ret);
|
|
}
|
|
#ifdef LIBXML_CATALOG_ENABLED
|
|
resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
|
|
#endif
|
|
|
|
if (resource == NULL)
|
|
resource = (xmlChar *) URL;
|
|
|
|
ret = xmlNewInputFromFile(ctxt, (const char *) resource);
|
|
if ((resource != NULL) && (resource != (xmlChar *) URL))
|
|
xmlFree(resource);
|
|
return (ret);
|
|
}
|
|
|
|
static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
|
|
xmlDefaultExternalEntityLoader;
|
|
|
|
/**
|
|
* xmlSetExternalEntityLoader:
|
|
* @f: the new entity resolver function
|
|
*
|
|
* Changes the defaultexternal entity resolver function for the application
|
|
*/
|
|
void
|
|
xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
|
|
xmlCurrentExternalEntityLoader = f;
|
|
}
|
|
|
|
/**
|
|
* xmlGetExternalEntityLoader:
|
|
*
|
|
* Get the default external entity resolver function for the application
|
|
*
|
|
* Returns the xmlExternalEntityLoader function pointer
|
|
*/
|
|
xmlExternalEntityLoader
|
|
xmlGetExternalEntityLoader(void) {
|
|
return(xmlCurrentExternalEntityLoader);
|
|
}
|
|
|
|
/**
|
|
* xmlLoadExternalEntity:
|
|
* @URL: the URL for the entity to load
|
|
* @ID: the Public ID for the entity to load
|
|
* @ctxt: the context in which the entity is called or NULL
|
|
*
|
|
* Load an external entity, note that the use of this function for
|
|
* unparsed entities may generate problems
|
|
*
|
|
* Returns the xmlParserInputPtr or NULL
|
|
*/
|
|
xmlParserInputPtr
|
|
xmlLoadExternalEntity(const char *URL, const char *ID,
|
|
xmlParserCtxtPtr ctxt) {
|
|
char *canonicFilename;
|
|
xmlParserInputPtr ret;
|
|
|
|
if (URL == NULL)
|
|
return(NULL);
|
|
|
|
canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL);
|
|
if (canonicFilename == NULL) {
|
|
xmlCtxtErrMemory(ctxt);
|
|
return(NULL);
|
|
}
|
|
|
|
ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt);
|
|
xmlFree(canonicFilename);
|
|
return(ret);
|
|
}
|
|
|
|
/************************************************************************
|
|
* *
|
|
* Disabling Network access *
|
|
* *
|
|
************************************************************************/
|
|
|
|
/**
|
|
* xmlNoNetExternalEntityLoader:
|
|
* @URL: the URL for the entity to load
|
|
* @ID: the System ID for the entity to load
|
|
* @ctxt: the context in which the entity is called or NULL
|
|
*
|
|
* A specific entity loader disabling network accesses, though still
|
|
* allowing local catalog accesses for resolution.
|
|
*
|
|
* Returns a new allocated xmlParserInputPtr, or NULL.
|
|
*/
|
|
xmlParserInputPtr
|
|
xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
|
|
xmlParserCtxtPtr ctxt) {
|
|
xmlParserInputPtr input = NULL;
|
|
xmlChar *resource = NULL;
|
|
|
|
#ifdef LIBXML_CATALOG_ENABLED
|
|
resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
|
|
#endif
|
|
|
|
if (resource == NULL)
|
|
resource = (xmlChar *) URL;
|
|
|
|
if (resource != NULL) {
|
|
if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
|
|
(!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
|
|
xmlCtxtErrIO(ctxt, 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);
|
|
}
|
|
|
|
/************************************************************************
|
|
* *
|
|
* Input/output callbacks *
|
|
* *
|
|
************************************************************************/
|
|
|
|
/**
|
|
* xmlInitIOCallbacks:
|
|
*
|
|
* Initialize callback tables.
|
|
*/
|
|
void
|
|
xmlInitIOCallbacks(void)
|
|
{
|
|
xmlInputCallbackNr = 1;
|
|
xmlInputCallbackTable[0].matchcallback = xmlIODefaultMatch;
|
|
|
|
#ifdef LIBXML_OUTPUT_ENABLED
|
|
xmlOutputCallbackNr = 1;
|
|
xmlOutputCallbackTable[0].matchcallback = xmlIODefaultMatch;
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* xmlRegisterInputCallbacks:
|
|
* @matchFunc: the xmlInputMatchCallback
|
|
* @openFunc: the xmlInputOpenCallback
|
|
* @readFunc: the xmlInputReadCallback
|
|
* @closeFunc: the xmlInputCloseCallback
|
|
*
|
|
* Register a new set of I/O callback for handling parser input.
|
|
*
|
|
* Returns the registered handler number or -1 in case of error
|
|
*/
|
|
int
|
|
xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
|
|
xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
|
|
xmlInputCloseCallback closeFunc) {
|
|
if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
|
|
return(-1);
|
|
}
|
|
xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
|
|
xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
|
|
xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
|
|
xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
|
|
return(xmlInputCallbackNr++);
|
|
}
|
|
|
|
/**
|
|
* xmlRegisterDefaultInputCallbacks:
|
|
*
|
|
* Registers the default compiled-in I/O handlers.
|
|
*/
|
|
void
|
|
xmlRegisterDefaultInputCallbacks(void) {
|
|
xmlRegisterInputCallbacks(xmlIODefaultMatch, NULL, NULL, NULL);
|
|
}
|
|
|
|
/**
|
|
* xmlPopInputCallbacks:
|
|
*
|
|
* Clear the top input callback from the input stack. this includes the
|
|
* compiled-in I/O.
|
|
*
|
|
* Returns the number of input callback registered or -1 in case of error.
|
|
*/
|
|
int
|
|
xmlPopInputCallbacks(void)
|
|
{
|
|
if (xmlInputCallbackNr <= 0)
|
|
return(-1);
|
|
|
|
xmlInputCallbackNr--;
|
|
|
|
return(xmlInputCallbackNr);
|
|
}
|
|
|
|
/**
|
|
* xmlCleanupInputCallbacks:
|
|
*
|
|
* clears the entire input callback table. this includes the
|
|
* compiled-in I/O.
|
|
*/
|
|
void
|
|
xmlCleanupInputCallbacks(void)
|
|
{
|
|
xmlInputCallbackNr = 0;
|
|
}
|
|
|
|
#ifdef LIBXML_OUTPUT_ENABLED
|
|
/**
|
|
* xmlRegisterOutputCallbacks:
|
|
* @matchFunc: the xmlOutputMatchCallback
|
|
* @openFunc: the xmlOutputOpenCallback
|
|
* @writeFunc: the xmlOutputWriteCallback
|
|
* @closeFunc: the xmlOutputCloseCallback
|
|
*
|
|
* Register a new set of I/O callback for handling output.
|
|
*
|
|
* Returns the registered handler number or -1 in case of error
|
|
*/
|
|
int
|
|
xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
|
|
xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
|
|
xmlOutputCloseCallback closeFunc) {
|
|
if (xmlOutputCallbackNr >= MAX_OUTPUT_CALLBACK) {
|
|
return(-1);
|
|
}
|
|
xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
|
|
xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
|
|
xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
|
|
xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
|
|
return(xmlOutputCallbackNr++);
|
|
}
|
|
|
|
/**
|
|
* xmlRegisterDefaultOutputCallbacks:
|
|
*
|
|
* Registers the default compiled-in I/O handlers.
|
|
*/
|
|
void
|
|
xmlRegisterDefaultOutputCallbacks (void) {
|
|
xmlRegisterOutputCallbacks(xmlIODefaultMatch, NULL, NULL, NULL);
|
|
}
|
|
|
|
/**
|
|
* xmlPopOutputCallbacks:
|
|
*
|
|
* Remove the top output callbacks from the output stack. This includes the
|
|
* compiled-in I/O.
|
|
*
|
|
* Returns the number of output callback registered or -1 in case of error.
|
|
*/
|
|
int
|
|
xmlPopOutputCallbacks(void)
|
|
{
|
|
if (xmlOutputCallbackNr <= 0)
|
|
return(-1);
|
|
|
|
xmlOutputCallbackNr--;
|
|
|
|
return(xmlOutputCallbackNr);
|
|
}
|
|
|
|
/**
|
|
* xmlCleanupOutputCallbacks:
|
|
*
|
|
* clears the entire output callback table. this includes the
|
|
* compiled-in I/O callbacks.
|
|
*/
|
|
void
|
|
xmlCleanupOutputCallbacks(void)
|
|
{
|
|
xmlOutputCallbackNr = 0;
|
|
}
|
|
|
|
#ifdef LIBXML_HTTP_ENABLED
|
|
/**
|
|
* xmlRegisterHTTPPostCallbacks:
|
|
*
|
|
* DEPRECATED: Support for HTTP POST has been removed.
|
|
*/
|
|
void
|
|
xmlRegisterHTTPPostCallbacks(void) {
|
|
xmlRegisterDefaultOutputCallbacks();
|
|
}
|
|
#endif
|
|
#endif /* LIBXML_OUTPUT_ENABLED */
|
|
|