| /* |
| * xmlIO.c : implementation of the I/O interfaces used by the parser |
| * |
| * See Copyright for the status of this software. |
| * |
| * Author: Daniel Veillard |
| */ |
| |
| #define IN_LIBXML |
| #include "libxml.h" |
| |
| #include <string.h> |
| #include <stdlib.h> |
| #include <errno.h> |
| |
| #include <fcntl.h> |
| #include <sys/stat.h> |
| |
| #if defined(_WIN32) |
| #define WIN32_LEAN_AND_MEAN |
| #include <windows.h> |
| #include <io.h> |
| #include <direct.h> |
| #else |
| #include <unistd.h> |
| #endif |
| |
| #ifdef LIBXML_ZLIB_ENABLED |
| #include <zlib.h> |
| #endif |
| #ifdef LIBXML_LZMA_ENABLED |
| #include <lzma.h> |
| #endif |
| |
| #include <libxml/xmlIO.h> |
| #include <libxml/xmlmemory.h> |
| #include <libxml/uri.h> |
| #include <libxml/parserInternals.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" |
| |
| #ifndef SIZE_MAX |
| #define SIZE_MAX ((size_t) -1) |
| #endif |
| |
| /* #define VERBOSE_FAILURE */ |
| |
| #define MINLEN 4000 |
| |
| #ifndef STDOUT_FILENO |
| #define STDOUT_FILENO 1 |
| #endif |
| |
| #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 */ |
| |
| /************************************************************************ |
| * * |
| * Special escaping routines * |
| * * |
| ************************************************************************/ |
| |
| /* |
| * @param buf a char buffer |
| * @param val a codepoint |
| * |
| * Serializes a hex char ref like ` `. |
| * |
| * Writes at most 9 bytes. Does not include a terminating zero byte. |
| * |
| * @returns the number of bytes written. |
| */ |
| static int |
| xmlSerializeHexCharRef(char *buf, int val) { |
| char *out = buf; |
| int shift = 0, bits; |
| |
| *out++ = '&'; |
| *out++ = '#'; |
| *out++ = 'x'; |
| |
| bits = val; |
| if (bits & 0xFF0000) { |
| shift = 16; |
| bits &= 0xFF0000; |
| } else if (bits & 0x00FF00) { |
| shift = 8; |
| bits &= 0x00FF00; |
| } |
| if (bits & 0xF0F0F0) { |
| shift += 4; |
| } |
| |
| do { |
| int d = (val >> shift) & 0x0F; |
| |
| if (d < 10) |
| *out++ = '0' + d; |
| else |
| *out++ = 'A' + (d - 10); |
| |
| shift -= 4; |
| } while (shift >= 0); |
| |
| *out++ = ';'; |
| |
| return(out - buf); |
| } |
| |
| #include "codegen/escape.inc" |
| |
| /* |
| * @param text input text |
| * @param flags XML_ESCAPE flags |
| * |
| * Escapes certain characters with char refs. |
| * |
| * - XML_ESCAPE_ATTR: for attribute content. |
| * - XML_ESCAPE_NON_ASCII: escape non-ASCII chars. |
| * - XML_ESCAPE_HTML: for HTML content. |
| * - XML_ESCAPE_QUOT: escape double quotes. |
| * |
| * @returns an escaped string or NULL if a memory allocation failed. |
| */ |
| xmlChar * |
| xmlEscapeText(const xmlChar *string, int flags) { |
| const xmlChar *cur; |
| xmlChar *buffer; |
| xmlChar *out; |
| const signed char *tab; |
| size_t size = 50; |
| |
| #ifdef LIBXML_HTML_ENABLED |
| if (flags & XML_ESCAPE_HTML) { |
| if (flags & XML_ESCAPE_ATTR) |
| tab = htmlEscapeTabAttr; |
| else |
| tab = htmlEscapeTab; |
| } |
| else |
| #endif |
| { |
| if (flags & XML_ESCAPE_QUOT) |
| tab = xmlEscapeTabQuot; |
| else if (flags & XML_ESCAPE_ATTR) |
| tab = xmlEscapeTabAttr; |
| else |
| tab = xmlEscapeTab; |
| } |
| |
| buffer = xmlMalloc(size + 1); |
| if (buffer == NULL) |
| return(NULL); |
| out = buffer; |
| |
| cur = string; |
| |
| while (*cur != 0) { |
| char tempBuf[12]; |
| const xmlChar *base; |
| const char *repl; |
| size_t used; |
| size_t replSize; |
| size_t unescapedSize; |
| size_t totalSize; |
| int c; |
| int offset; |
| |
| base = cur; |
| offset = -1; |
| |
| while (1) { |
| c = *cur; |
| |
| if (c < 0x80) { |
| offset = tab[c]; |
| if (offset >= 0) |
| break; |
| } else if (flags & XML_ESCAPE_NON_ASCII) { |
| break; |
| } |
| |
| cur += 1; |
| } |
| |
| unescapedSize = cur - base; |
| |
| if (offset >= 0) { |
| if (c == 0) { |
| replSize = 0; |
| repl = ""; |
| } else { |
| replSize = xmlEscapeContent[offset], |
| repl = &xmlEscapeContent[offset+1]; |
| cur += 1; |
| } |
| } else { |
| int val = 0, len = 4; |
| |
| val = xmlGetUTF8Char(cur, &len); |
| if (val < 0) { |
| val = 0xFFFD; |
| cur += 1; |
| } else { |
| if ((val == 0xFFFE) || (val == 0xFFFF)) |
| val = 0xFFFD; |
| cur += len; |
| } |
| |
| replSize = xmlSerializeHexCharRef(tempBuf, val); |
| repl = tempBuf; |
| } |
| |
| used = out - buffer; |
| totalSize = unescapedSize + replSize; |
| |
| if (totalSize > size - used) { |
| xmlChar *tmp; |
| int newSize; |
| |
| if ((size > (SIZE_MAX - 1) / 2) || |
| (totalSize > (SIZE_MAX - 1) / 2 - size)) { |
| xmlFree(buffer); |
| return(NULL); |
| } |
| newSize = size + totalSize; |
| if (*cur != 0) |
| newSize *= 2; |
| tmp = xmlRealloc(buffer, newSize + 1); |
| if (tmp == NULL) { |
| xmlFree(buffer); |
| return(NULL); |
| } |
| buffer = tmp; |
| size = newSize; |
| out = buffer + used; |
| } |
| |
| memcpy(out, base, unescapedSize); |
| out += unescapedSize; |
| memcpy(out, repl, replSize); |
| out += replSize; |
| |
| if (c == 0) |
| break; |
| |
| base = cur; |
| } |
| |
| *out = 0; |
| return(buffer); |
| } |
| |
| #ifdef LIBXML_OUTPUT_ENABLED |
| void |
| xmlSerializeText(xmlOutputBuffer *buf, const xmlChar *string, size_t maxSize, |
| unsigned flags) { |
| const xmlChar *cur; |
| const signed char *tab; |
| |
| if (string == NULL) |
| return; |
| |
| #ifdef LIBXML_HTML_ENABLED |
| if (flags & XML_ESCAPE_HTML) { |
| if (flags & XML_ESCAPE_ATTR) |
| tab = htmlEscapeTabAttr; |
| else |
| tab = htmlEscapeTab; |
| } |
| else |
| #endif |
| { |
| if (flags & XML_ESCAPE_QUOT) |
| tab = xmlEscapeTabQuot; |
| else if (flags & XML_ESCAPE_ATTR) |
| tab = xmlEscapeTabAttr; |
| else |
| tab = xmlEscapeTab; |
| } |
| |
| cur = string; |
| |
| while (1) { |
| const xmlChar *base; |
| int c; |
| int offset; |
| |
| base = cur; |
| offset = -1; |
| |
| while (1) { |
| if ((size_t) (cur - string) >= maxSize) |
| break; |
| |
| c = (unsigned char) *cur; |
| |
| if (c < 0x80) { |
| offset = tab[c]; |
| if (offset >= 0) |
| break; |
| } else if (flags & XML_ESCAPE_NON_ASCII) { |
| break; |
| } |
| |
| cur += 1; |
| } |
| |
| if (cur > base) |
| xmlOutputBufferWrite(buf, cur - base, (char *) base); |
| |
| if ((size_t) (cur - string) >= maxSize) |
| break; |
| |
| if (offset >= 0) { |
| if (c == 0) |
| break; |
| |
| xmlOutputBufferWrite(buf, xmlEscapeContent[offset], |
| &xmlEscapeContent[offset+1]); |
| cur += 1; |
| } else { |
| char tempBuf[12]; |
| int tempSize; |
| int val = 0, len = 4; |
| |
| val = xmlGetUTF8Char(cur, &len); |
| if (val < 0) { |
| val = 0xFFFD; |
| cur += 1; |
| } else { |
| if ((val == 0xFFFE) || (val == 0xFFFF)) |
| val = 0xFFFD; |
| cur += len; |
| } |
| |
| tempSize = xmlSerializeHexCharRef(tempBuf, val); |
| xmlOutputBufferWrite(buf, tempSize, tempBuf); |
| } |
| } |
| } |
| #endif /* LIBXML_OUTPUT_ENABLED */ |
| |
| /************************************************************************ |
| * * |
| * Error handling * |
| * * |
| ************************************************************************/ |
| |
| /** |
| * Convert errno to xmlParserErrors. |
| * |
| * @param err the error number |
| * @returns an xmlParserErrors code. |
| */ |
| static int |
| xmlIOErr(int err) |
| { |
| xmlParserErrors code; |
| |
| switch (err) { |
| #ifdef EACCES |
| case EACCES: code = XML_IO_EACCES; break; |
| #endif |
| #ifdef EAGAIN |
| case EAGAIN: code = XML_IO_EAGAIN; break; |
| #endif |
| #ifdef EBADF |
| case EBADF: code = XML_IO_EBADF; break; |
| #endif |
| #ifdef EBADMSG |
| case EBADMSG: code = XML_IO_EBADMSG; break; |
| #endif |
| #ifdef EBUSY |
| case EBUSY: code = XML_IO_EBUSY; break; |
| #endif |
| #ifdef ECANCELED |
| case ECANCELED: code = XML_IO_ECANCELED; break; |
| #endif |
| #ifdef ECHILD |
| case ECHILD: code = XML_IO_ECHILD; break; |
| #endif |
| #ifdef EDEADLK |
| case EDEADLK: code = XML_IO_EDEADLK; break; |
| #endif |
| #ifdef EDOM |
| case EDOM: code = XML_IO_EDOM; break; |
| #endif |
| #ifdef EEXIST |
| case EEXIST: code = XML_IO_EEXIST; break; |
| #endif |
| #ifdef EFAULT |
| case EFAULT: code = XML_IO_EFAULT; break; |
| #endif |
| #ifdef EFBIG |
| case EFBIG: code = XML_IO_EFBIG; break; |
| #endif |
| #ifdef EINPROGRESS |
| case EINPROGRESS: code = XML_IO_EINPROGRESS; break; |
| #endif |
| #ifdef EINTR |
| case EINTR: code = XML_IO_EINTR; break; |
| #endif |
| #ifdef EINVAL |
| case EINVAL: code = XML_IO_EINVAL; break; |
| #endif |
| #ifdef EIO |
| case EIO: code = XML_IO_EIO; break; |
| #endif |
| #ifdef EISDIR |
| case EISDIR: code = XML_IO_EISDIR; break; |
| #endif |
| #ifdef EMFILE |
| case EMFILE: code = XML_IO_EMFILE; break; |
| #endif |
| #ifdef EMLINK |
| case EMLINK: code = XML_IO_EMLINK; break; |
| #endif |
| #ifdef EMSGSIZE |
| case EMSGSIZE: code = XML_IO_EMSGSIZE; break; |
| #endif |
| #ifdef ENAMETOOLONG |
| case ENAMETOOLONG: code = XML_IO_ENAMETOOLONG; break; |
| #endif |
| #ifdef ENFILE |
| case ENFILE: code = XML_IO_ENFILE; break; |
| #endif |
| #ifdef ENODEV |
| case ENODEV: code = XML_IO_ENODEV; break; |
| #endif |
| #ifdef ENOENT |
| case ENOENT: code = XML_IO_ENOENT; break; |
| #endif |
| #ifdef ENOEXEC |
| case ENOEXEC: code = XML_IO_ENOEXEC; break; |
| #endif |
| #ifdef ENOLCK |
| case ENOLCK: code = XML_IO_ENOLCK; break; |
| #endif |
| #ifdef ENOMEM |
| case ENOMEM: code = XML_IO_ENOMEM; break; |
| #endif |
| #ifdef ENOSPC |
| case ENOSPC: code = XML_IO_ENOSPC; break; |
| #endif |
| #ifdef ENOSYS |
| case ENOSYS: code = XML_IO_ENOSYS; break; |
| #endif |
| #ifdef ENOTDIR |
| case ENOTDIR: code = XML_IO_ENOTDIR; break; |
| #endif |
| #ifdef ENOTEMPTY |
| case ENOTEMPTY: code = XML_IO_ENOTEMPTY; break; |
| #endif |
| #ifdef ENOTSUP |
| case ENOTSUP: code = XML_IO_ENOTSUP; break; |
| #endif |
| #ifdef ENOTTY |
| case ENOTTY: code = XML_IO_ENOTTY; break; |
| #endif |
| #ifdef ENXIO |
| case ENXIO: code = XML_IO_ENXIO; break; |
| #endif |
| #ifdef EPERM |
| case EPERM: code = XML_IO_EPERM; break; |
| #endif |
| #ifdef EPIPE |
| case EPIPE: code = XML_IO_EPIPE; break; |
| #endif |
| #ifdef ERANGE |
| case ERANGE: code = XML_IO_ERANGE; break; |
| #endif |
| #ifdef EROFS |
| case EROFS: code = XML_IO_EROFS; break; |
| #endif |
| #ifdef ESPIPE |
| case ESPIPE: code = XML_IO_ESPIPE; break; |
| #endif |
| #ifdef ESRCH |
| case ESRCH: code = XML_IO_ESRCH; break; |
| #endif |
| #ifdef ETIMEDOUT |
| case ETIMEDOUT: code = XML_IO_ETIMEDOUT; break; |
| #endif |
| #ifdef EXDEV |
| case EXDEV: code = XML_IO_EXDEV; break; |
| #endif |
| #ifdef ENOTSOCK |
| case ENOTSOCK: code = XML_IO_ENOTSOCK; break; |
| #endif |
| #ifdef EISCONN |
| case EISCONN: code = XML_IO_EISCONN; break; |
| #endif |
| #ifdef ECONNREFUSED |
| case ECONNREFUSED: code = XML_IO_ECONNREFUSED; break; |
| #endif |
| #ifdef ENETUNREACH |
| case ENETUNREACH: code = XML_IO_ENETUNREACH; break; |
| #endif |
| #ifdef EADDRINUSE |
| case EADDRINUSE: code = XML_IO_EADDRINUSE; break; |
| #endif |
| #ifdef EALREADY |
| case EALREADY: code = XML_IO_EALREADY; break; |
| #endif |
| #ifdef EAFNOSUPPORT |
| case EAFNOSUPPORT: code = XML_IO_EAFNOSUPPORT; break; |
| #endif |
| default: code = XML_IO_UNKNOWN; break; |
| } |
| |
| return(code); |
| } |
| |
| /************************************************************************ |
| * * |
| * Standard I/O for file accesses * |
| * * |
| ************************************************************************/ |
| |
| #if defined(_WIN32) |
| |
| /** |
| * Convert a string from utf-8 to wchar (WINDOWS ONLY!) |
| * |
| * @param u8String uft-8 string |
| */ |
| 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; |
| } |
| |
| #endif |
| |
| /** |
| * @deprecated This never really worked. |
| * |
| * @param path the input file path |
| * @returns a copy of path. |
| */ |
| xmlChar * |
| xmlNormalizeWindowsPath(const xmlChar *path) |
| { |
| return xmlStrdup(path); |
| } |
| |
| /** |
| * if stat is not available on the target machine, |
| * |
| * @deprecated Internal function, don't use. |
| * |
| * @param path the path to check |
| * @returns 0 if stat fails, 2 if stat succeeds and the file is |
| * a directory, 1 otherwise. |
| */ |
| int |
| xmlCheckFilename(const char *path) |
| { |
| #if defined(_WIN32) |
| struct _stat stat_buffer; |
| #else |
| struct stat stat_buffer; |
| #endif |
| int res; |
| |
| if (path == NULL) |
| return(0); |
| |
| #if defined(_WIN32) |
| { |
| wchar_t *wpath; |
| |
| /* |
| * 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; |
| |
| wpath = __xmlIOWin32UTF8ToWChar(path); |
| if (wpath == NULL) |
| return(0); |
| res = _wstat(wpath, &stat_buffer); |
| xmlFree(wpath); |
| } |
| #else |
| res = stat(path, &stat_buffer); |
| #endif |
| |
| if (res < 0) |
| return 0; |
| |
| #ifdef S_ISDIR |
| if (S_ISDIR(stat_buffer.st_mode)) |
| return 2; |
| #endif |
| |
| 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); |
| } |
| |
| typedef struct { |
| int fd; |
| } xmlFdIOCtxt; |
| |
| /** |
| * @param filename the URI for matching |
| * @param write whether the fd is opened for writing |
| * @param out pointer to resulting context |
| * @returns an xmlParserErrors code |
| */ |
| static xmlParserErrors |
| xmlFdOpen(const char *filename, int write, int *out) { |
| char *fromUri = NULL; |
| int flags; |
| int fd; |
| xmlParserErrors ret; |
| |
| *out = -1; |
| 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); |
| } |
| if (write) |
| flags = _O_WRONLY | _O_CREAT | _O_TRUNC; |
| else |
| flags = _O_RDONLY; |
| fd = _wopen(wpath, flags | _O_BINARY, 0666); |
| xmlFree(wpath); |
| } |
| #else |
| if (write) |
| flags = O_WRONLY | O_CREAT | O_TRUNC; |
| else |
| flags = O_RDONLY; |
| fd = open(filename, flags, 0666); |
| #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 { |
| ret = xmlIOErr(errno); |
| } |
| } else { |
| *out = fd; |
| ret = XML_ERR_OK; |
| } |
| |
| xmlFree(fromUri); |
| return(ret); |
| } |
| |
| /** |
| * Read `len` bytes to `buffer` from the I/O channel. |
| * |
| * @param context the I/O context |
| * @param buffer where to drop data |
| * @param len number of bytes to read |
| * @returns the number of bytes read |
| */ |
| static int |
| xmlFdRead(void *context, char *buffer, int len) { |
| xmlFdIOCtxt *fdctxt = context; |
| int fd = fdctxt->fd; |
| int ret = 0; |
| int bytes; |
| |
| while (len > 0) { |
| bytes = read(fd, buffer, len); |
| if (bytes < 0) { |
| /* |
| * If we already got some bytes, return them without |
| * raising an error. |
| */ |
| if (ret > 0) |
| break; |
| return(-xmlIOErr(errno)); |
| } |
| if (bytes == 0) |
| break; |
| ret += bytes; |
| buffer += bytes; |
| len -= bytes; |
| } |
| |
| return(ret); |
| } |
| |
| #ifdef LIBXML_OUTPUT_ENABLED |
| /** |
| * Write `len` bytes from `buffer` to the I/O channel. |
| * |
| * @param context the I/O context |
| * @param buffer where to get data |
| * @param len number of bytes to write |
| * @returns the number of bytes written |
| */ |
| static int |
| xmlFdWrite(void *context, const char *buffer, int len) { |
| xmlFdIOCtxt *fdctxt = context; |
| int fd = fdctxt->fd; |
| int ret = 0; |
| int bytes; |
| |
| while (len > 0) { |
| bytes = write(fd, buffer, len); |
| if (bytes < 0) |
| return(-xmlIOErr(errno)); |
| ret += bytes; |
| buffer += bytes; |
| len -= bytes; |
| } |
| |
| return(ret); |
| } |
| #endif /* LIBXML_OUTPUT_ENABLED */ |
| |
| static int |
| xmlFdFree(void *context) { |
| xmlFree(context); |
| return(XML_ERR_OK); |
| } |
| |
| /** |
| * Close an I/O channel |
| * |
| * @param context the I/O context |
| * @returns 0 in case of success and error code otherwise |
| */ |
| static int |
| xmlFdClose (void * context) { |
| xmlFdIOCtxt *fdctxt = context; |
| int fd = fdctxt->fd; |
| int ret; |
| |
| ret = close(fd); |
| |
| xmlFree(fdctxt); |
| |
| if (ret < 0) |
| return(xmlIOErr(errno)); |
| |
| return(XML_ERR_OK); |
| } |
| |
| /** |
| * @deprecated Internal function, don't use. |
| * |
| * @param filename the URI for matching |
| * @returns 1 if matches, 0 otherwise |
| */ |
| int |
| xmlFileMatch (const char *filename ATTRIBUTE_UNUSED) { |
| return(1); |
| } |
| |
| /** |
| * input from FILE * |
| * |
| * @param filename the URI for matching |
| * @param write whether the file is opened for writing |
| * @param out pointer to resulting context |
| * @returns an xmlParserErrors code |
| */ |
| static xmlParserErrors |
| xmlFileOpenSafe(const char *filename, int write, void **out) { |
| char *fromUri = NULL; |
| FILE *fd; |
| xmlParserErrors ret = XML_ERR_OK; |
| |
| *out = NULL; |
| 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 = _wfopen(wpath, write ? L"wb" : L"rb"); |
| xmlFree(wpath); |
| } |
| #else |
| fd = fopen(filename, write ? "wb" : "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(errno); |
| } |
| } |
| |
| *out = fd; |
| xmlFree(fromUri); |
| return(ret); |
| } |
| |
| /** |
| * @deprecated Internal function, don't use. |
| * |
| * @param filename the URI for matching |
| * @returns an IO context or NULL in case or failure |
| */ |
| void * |
| xmlFileOpen(const char *filename) { |
| void *context; |
| |
| xmlFileOpenSafe(filename, 0, &context); |
| return(context); |
| } |
| |
| /** |
| * @deprecated Internal function, don't use. |
| * |
| * @param context the I/O context |
| * @param buffer where to drop data |
| * @param len number of bytes to write |
| * @returns the number of bytes read or < 0 in case of failure |
| */ |
| int |
| xmlFileRead(void * context, char * buffer, int len) { |
| FILE *file = context; |
| size_t bytes; |
| |
| if ((context == NULL) || (buffer == NULL)) |
| return(-1); |
| |
| /* |
| * The C standard doesn't mandate that fread sets errno, only |
| * POSIX does. The Windows documentation isn't really clear. |
| * Set errno to zero which will be reported as unknown error |
| * if fread fails without setting errno. |
| */ |
| errno = 0; |
| bytes = fread(buffer, 1, len, file); |
| if ((bytes < (size_t) len) && (ferror(file))) |
| return(-xmlIOErr(errno)); |
| |
| return(bytes); |
| } |
| |
| #ifdef LIBXML_OUTPUT_ENABLED |
| /** |
| * Write `len` bytes from `buffer` to the I/O channel. |
| * |
| * @param context the I/O context |
| * @param buffer where to drop data |
| * @param len number of bytes to write |
| * @returns the number of bytes written |
| */ |
| static int |
| xmlFileWrite(void *context, const char *buffer, int len) { |
| FILE *file = context; |
| size_t bytes; |
| |
| if ((context == NULL) || (buffer == NULL)) |
| return(-1); |
| |
| errno = 0; |
| bytes = fwrite(buffer, 1, len, file); |
| if (bytes < (size_t) len) |
| return(-xmlIOErr(errno)); |
| |
| return(len); |
| } |
| #endif /* LIBXML_OUTPUT_ENABLED */ |
| |
| /** |
| * Flush an I/O channel |
| * |
| * @param context the I/O context |
| */ |
| static int |
| xmlFileFlush (void * context) { |
| FILE *file = context; |
| |
| if (file == NULL) |
| return(-1); |
| |
| if (fflush(file) != 0) |
| return(xmlIOErr(errno)); |
| |
| return(XML_ERR_OK); |
| } |
| |
| /** |
| * @deprecated Internal function, don't use. |
| * |
| * @param context the I/O context |
| * @returns 0 or -1 an error code case of error |
| */ |
| int |
| xmlFileClose (void * context) { |
| FILE *file = context; |
| |
| if (context == NULL) |
| return(-1); |
| |
| if (file == stdin) |
| return(0); |
| if ((file == stdout) || (file == stderr)) |
| return(xmlFileFlush(file)); |
| |
| if (fclose(file) != 0) |
| return(xmlIOErr(errno)); |
| |
| return(0); |
| } |
| |
| #ifdef LIBXML_OUTPUT_ENABLED |
| /** |
| * Write `len` bytes from `buffer` to the xml buffer |
| * |
| * @param context the xmlBuffer |
| * @param buffer the data to write |
| * @param len number of bytes to write |
| * @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 * |
| * * |
| ************************************************************************/ |
| |
| /** |
| * Read `len` bytes to `buffer` from the compressed I/O channel. |
| * |
| * @param context the I/O context |
| * @param buffer where to drop data |
| * @param len number of bytes to write |
| * @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) |
| return(-XML_IO_UNKNOWN); |
| return(ret); |
| } |
| |
| #ifdef LIBXML_OUTPUT_ENABLED |
| /** |
| * Write `len` bytes from `buffer` to the compressed I/O channel. |
| * |
| * @param context the I/O context |
| * @param buffer where to drop data |
| * @param len number of bytes to write |
| * @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) |
| return(-XML_IO_UNKNOWN); |
| return(ret); |
| } |
| #endif /* LIBXML_OUTPUT_ENABLED */ |
| |
| /** |
| * Close a compressed I/O channel |
| * |
| * @param context the I/O context |
| */ |
| static int |
| xmlGzfileClose (void * context) { |
| if (gzclose((gzFile) context) != Z_OK) |
| return(XML_IO_UNKNOWN); |
| return(0); |
| } |
| #endif /* LIBXML_ZLIB_ENABLED */ |
| |
| /************************************************************************ |
| * * |
| * I/O for compressed file accesses * |
| * * |
| ************************************************************************/ |
| |
| #ifdef LIBXML_LZMA_ENABLED |
| |
| #include "private/xzlib.h" |
| |
| /** |
| * Read `len` bytes to `buffer` from the compressed I/O channel. |
| * |
| * @param context the I/O context |
| * @param buffer where to drop data |
| * @param len number of bytes to write |
| * @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) |
| return(-XML_IO_UNKNOWN); |
| return(ret); |
| } |
| |
| /** |
| * Close a compressed I/O channel |
| * |
| * @param context the I/O context |
| */ |
| static int |
| xmlXzfileClose (void * context) { |
| if (__libxml2_xzclose((xzFile) context) != LZMA_OK) |
| return(XML_IO_UNKNOWN); |
| return(0); |
| } |
| #endif /* LIBXML_LZMA_ENABLED */ |
| |
| /************************************************************************ |
| * * |
| * Input/output buffers * |
| * * |
| ************************************************************************/ |
| |
| static int |
| xmlIODefaultMatch(const char *filename ATTRIBUTE_UNUSED) { |
| return(1); |
| } |
| |
| /** |
| * Update the buffer to read from `fd`. Supports the XML_INPUT_UNZIP |
| * flag. |
| * |
| * @param buf parser input buffer |
| * @param fd file descriptor |
| * @param flags flags |
| * @returns an xmlParserErrors code. |
| */ |
| xmlParserErrors |
| xmlInputFromFd(xmlParserInputBuffer *buf, int fd, |
| xmlParserInputFlags flags) { |
| xmlFdIOCtxt *fdctxt; |
| int copy; |
| |
| (void) flags; |
| |
| #ifdef LIBXML_LZMA_ENABLED |
| if (flags & XML_INPUT_UNZIP) { |
| xzFile xzStream; |
| off_t pos; |
| |
| pos = lseek(fd, 0, SEEK_CUR); |
| |
| copy = dup(fd); |
| if (copy == -1) |
| return(xmlIOErr(errno)); |
| |
| xzStream = __libxml2_xzdopen("?", copy, "rb"); |
| |
| if (xzStream == NULL) { |
| close(copy); |
| } else { |
| int compressed = (__libxml2_xzcompressed(xzStream) > 0); |
| |
| if ((compressed) || |
| /* Try to rewind if not gzip compressed */ |
| (pos < 0) || |
| (lseek(fd, pos, SEEK_SET) < 0)) { |
| /* |
| * If a file isn't seekable, we pipe uncompressed |
| * input through xzlib. |
| */ |
| buf->context = xzStream; |
| buf->readcallback = xmlXzfileRead; |
| buf->closecallback = xmlXzfileClose; |
| buf->compressed = compressed; |
| |
| return(XML_ERR_OK); |
| } |
| |
| xmlXzfileClose(xzStream); |
| } |
| } |
| #endif /* LIBXML_LZMA_ENABLED */ |
| |
| #ifdef LIBXML_ZLIB_ENABLED |
| if (flags & XML_INPUT_UNZIP) { |
| gzFile gzStream; |
| off_t pos; |
| |
| pos = lseek(fd, 0, SEEK_CUR); |
| |
| copy = dup(fd); |
| if (copy == -1) |
| return(xmlIOErr(errno)); |
| |
| gzStream = gzdopen(copy, "rb"); |
| |
| if (gzStream == NULL) { |
| close(copy); |
| } else { |
| int compressed = (gzdirect(gzStream) == 0); |
| |
| if ((compressed) || |
| /* Try to rewind if not gzip compressed */ |
| (pos < 0) || |
| (lseek(fd, pos, SEEK_SET) < 0)) { |
| /* |
| * If a file isn't seekable, we pipe uncompressed |
| * input through zlib. |
| */ |
| buf->context = gzStream; |
| buf->readcallback = xmlGzfileRead; |
| buf->closecallback = xmlGzfileClose; |
| buf->compressed = compressed; |
| |
| return(XML_ERR_OK); |
| } |
| |
| xmlGzfileClose(gzStream); |
| } |
| } |
| #endif /* LIBXML_ZLIB_ENABLED */ |
| |
| copy = dup(fd); |
| if (copy == -1) |
| return(xmlIOErr(errno)); |
| |
| fdctxt = xmlMalloc(sizeof(*fdctxt)); |
| if (fdctxt == NULL) { |
| close(copy); |
| return(XML_ERR_NO_MEMORY); |
| } |
| fdctxt->fd = copy; |
| |
| buf->context = fdctxt; |
| buf->readcallback = xmlFdRead; |
| buf->closecallback = xmlFdClose; |
| |
| return(XML_ERR_OK); |
| } |
| |
| #ifdef LIBXML_OUTPUT_ENABLED |
| /** |
| * @param buf input buffer to be filled |
| * @param filename filename or URI |
| * @param compression compression level or 0 |
| * @returns an xmlParserErrors code. |
| */ |
| static xmlParserErrors |
| xmlOutputDefaultOpen(xmlOutputBufferPtr buf, const char *filename, |
| int compression) { |
| xmlFdIOCtxt *fdctxt; |
| int fd; |
| |
| (void) compression; |
| |
| if (!strcmp(filename, "-")) { |
| fd = dup(STDOUT_FILENO); |
| |
| if (fd < 0) |
| return(xmlIOErr(errno)); |
| } else { |
| int ret; |
| |
| ret = xmlFdOpen(filename, /* write */ 1, &fd); |
| if (ret != XML_ERR_OK) |
| return(ret); |
| } |
| |
| #ifdef LIBXML_ZLIB_ENABLED |
| if ((compression > 0) && (compression <= 9)) { |
| gzFile gzStream; |
| char mode[15]; |
| |
| snprintf(mode, sizeof(mode), "wb%d", compression); |
| gzStream = gzdopen(fd, mode); |
| |
| if (gzStream == NULL) { |
| close(fd); |
| return(XML_IO_UNKNOWN); |
| } |
| |
| buf->context = gzStream; |
| buf->writecallback = xmlGzfileWrite; |
| buf->closecallback = xmlGzfileClose; |
| |
| return(XML_ERR_OK); |
| } |
| #endif /* LIBXML_ZLIB_ENABLED */ |
| |
| fdctxt = xmlMalloc(sizeof(*fdctxt)); |
| if (fdctxt == NULL) { |
| close(fd); |
| return(XML_ERR_NO_MEMORY); |
| } |
| fdctxt->fd = fd; |
| |
| buf->context = fdctxt; |
| buf->writecallback = xmlFdWrite; |
| buf->closecallback = xmlFdClose; |
| return(XML_ERR_OK); |
| } |
| #endif |
| |
| /** |
| * Create a buffered parser input for progressive parsing. |
| * |
| * @deprecated Use xmlNewInputFrom*. |
| * |
| * 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. |
| * |
| * @param enc the charset encoding if known (deprecated) |
| * @returns the new parser input or NULL |
| */ |
| xmlParserInputBuffer * |
| xmlAllocParserInputBuffer(xmlCharEncoding enc) { |
| xmlParserInputBufferPtr ret; |
| |
| ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer)); |
| if (ret == NULL) { |
| return(NULL); |
| } |
| memset(ret, 0, sizeof(xmlParserInputBuffer)); |
| ret->buffer = xmlBufCreate(XML_IO_BUFFER_SIZE); |
| if (ret->buffer == NULL) { |
| xmlFree(ret); |
| return(NULL); |
| } |
| if (enc != XML_CHAR_ENCODING_NONE) { |
| if (xmlLookupCharEncodingHandler(enc, &ret->encoder) != XML_ERR_OK) { |
| /* We can't handle errors properly here. */ |
| xmlFreeParserInputBuffer(ret); |
| return(NULL); |
| } |
| } |
| if (ret->encoder != NULL) |
| ret->raw = xmlBufCreate(XML_IO_BUFFER_SIZE); |
| 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 |
| /** |
| * Create a buffered parser output |
| * |
| * Consumes `encoder` but not in error case. |
| * |
| * @param encoder the encoding converter or NULL |
| * @returns the new parser output or NULL |
| */ |
| xmlOutputBuffer * |
| xmlAllocOutputBuffer(xmlCharEncodingHandler *encoder) { |
| xmlOutputBufferPtr ret; |
| |
| ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer)); |
| if (ret == NULL) { |
| return(NULL); |
| } |
| memset(ret, 0, sizeof(xmlOutputBuffer)); |
| ret->buffer = xmlBufCreate(MINLEN); |
| if (ret->buffer == NULL) { |
| xmlFree(ret); |
| return(NULL); |
| } |
| |
| ret->encoder = encoder; |
| if (encoder != NULL) { |
| ret->conv = xmlBufCreate(MINLEN); |
| 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 */ |
| |
| /** |
| * Free up the memory used by a buffered parser input |
| * |
| * @param in a buffered parser input |
| */ |
| void |
| xmlFreeParserInputBuffer(xmlParserInputBuffer *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 |
| /** |
| * flushes and close the output I/O channel |
| * and free up all the associated resources |
| * |
| * @param out a buffered output |
| * @returns the number of byte written or a negative xmlParserErrors |
| * code in case of error. |
| */ |
| int |
| xmlOutputBufferClose(xmlOutputBuffer *out) |
| { |
| int ret; |
| |
| if (out == NULL) |
| return (-1); |
| |
| if (out->writecallback != NULL) |
| xmlOutputBufferFlush(out); |
| |
| if (out->closecallback != NULL) { |
| int code = out->closecallback(out->context); |
| |
| if ((code != XML_ERR_OK) && |
| (!xmlIsCatastrophicError(XML_ERR_FATAL, out->error))) { |
| if (code < 0) |
| out->error = XML_IO_UNKNOWN; |
| else |
| out->error = code; |
| } |
| } |
| |
| if (out->error != XML_ERR_OK) |
| ret = -out->error; |
| else |
| ret = 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; |
| } |
| |
| xmlFree(out); |
| |
| return(ret); |
| } |
| #endif /* LIBXML_OUTPUT_ENABLED */ |
| |
| /** |
| * @param URI the filename or URI |
| * @param enc encoding enum (deprecated) |
| * @param flags XML_INPUT flags |
| * @param out pointer to resulting input buffer |
| * @returns an xmlParserErrors code. |
| */ |
| xmlParserErrors |
| xmlParserInputBufferCreateUrl(const char *URI, xmlCharEncoding enc, |
| xmlParserInputFlags flags, |
| xmlParserInputBuffer **out) { |
| xmlParserInputBufferPtr buf; |
| xmlParserErrors ret; |
| int i; |
| |
| xmlInitParser(); |
| |
| *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) { |
| int fd; |
| |
| ret = xmlFdOpen(URI, 0, &fd); |
| |
| if (ret == XML_ERR_OK) { |
| ret = xmlInputFromFd(buf, fd, flags); |
| close(fd); |
| break; |
| } else if (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); |
| } |
| |
| /** |
| * 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 |
| * |
| * Internal implementation, never uses the callback installed with |
| * #xmlParserInputBufferCreateFilenameDefault. |
| * |
| * @deprecated Use #xmlNewInputFromUrl. |
| * |
| * @param URI a C string containing the URI or filename |
| * @param enc the charset encoding if known |
| * @returns the new parser input or NULL |
| */ |
| xmlParserInputBuffer * |
| __xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) { |
| xmlParserInputBufferPtr ret; |
| |
| xmlParserInputBufferCreateUrl(URI, enc, 0, &ret); |
| return(ret); |
| } |
| |
| /** |
| * 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 |
| * |
| * Allows the actual function to be overridden with |
| * #xmlParserInputBufferCreateFilenameDefault. |
| * |
| * @deprecated Use #xmlNewInputFromUrl. |
| * |
| * @param URI a C string containing the URI or filename |
| * @param enc the charset encoding if known |
| * @returns the new parser input or NULL |
| */ |
| xmlParserInputBuffer * |
| xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) { |
| xmlParserInputBufferPtr ret; |
| xmlParserErrors code; |
| |
| if (xmlParserInputBufferCreateFilenameValue != NULL) |
| return(xmlParserInputBufferCreateFilenameValue(URI, enc)); |
| |
| code = xmlParserInputBufferCreateUrl(URI, enc, 0, &ret); |
| |
| /* |
| * xmlParserInputBufferCreateFilename has no way to return |
| * the kind of error although it really is crucial. |
| * All we can do is to set the global error. |
| */ |
| if ((code != XML_ERR_OK) && (code != XML_IO_ENOENT)) { |
| if (xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_IO, code, |
| XML_ERR_ERROR, URI, 0, NULL, NULL, NULL, 0, 0, |
| "Failed to open file\n") < 0) |
| xmlRaiseMemoryError(NULL, NULL, NULL, XML_FROM_IO, NULL); |
| } |
| |
| return(ret); |
| } |
| |
| #ifdef LIBXML_OUTPUT_ENABLED |
| /** |
| * 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. |
| * |
| * Consumes `encoder` but not in error case. |
| * |
| * Internal implementation, never uses the callback installed with |
| * #xmlOutputBufferCreateFilenameDefault. |
| * |
| * @param URI a C string containing the URI or filename |
| * @param encoder the encoding converter or NULL |
| * @param compression the compression ration (0 none, 9 max). |
| * @returns the new output or NULL |
| */ |
| xmlOutputBuffer * |
| __xmlOutputBufferCreateFilename(const char *URI, |
| xmlCharEncodingHandler *encoder, |
| int compression) { |
| xmlOutputBufferPtr ret = NULL; |
| xmlURIPtr puri; |
| int i = 0; |
| char *unescaped = NULL; |
| |
| xmlInitParser(); |
| |
| if (URI == NULL) |
| goto error; |
| |
| puri = xmlParseURI(URI); |
| if (puri != NULL) { |
| /* |
| * try to limit the damages of the URI unescaping code. |
| */ |
| if (puri->scheme == NULL) { |
| unescaped = xmlURIUnescapeString(URI, 0, NULL); |
| if (unescaped == NULL) { |
| xmlFreeURI(puri); |
| goto error; |
| } |
| URI = unescaped; |
| } |
| xmlFreeURI(puri); |
| } |
| |
| /* |
| * Allocate the Output buffer front-end. |
| */ |
| ret = xmlAllocOutputBuffer(encoder); |
| if (ret == NULL) |
| goto error; |
| |
| /* |
| * 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]; |
| xmlParserErrors code; |
| |
| if (cb->matchcallback == xmlIODefaultMatch) { |
| code = xmlOutputDefaultOpen(ret, URI, compression); |
| /* 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) { |
| /* Don't free encoder */ |
| ret->encoder = NULL; |
| xmlOutputBufferClose(ret); |
| ret = NULL; |
| } |
| |
| error: |
| xmlFree(unescaped); |
| return(ret); |
| } |
| |
| /** |
| * 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. |
| * |
| * Consumes `encoder` but not in error case. |
| * |
| * Allows the actual function to be overridden with |
| * #xmlOutputBufferCreateFilenameDefault. |
| * |
| * @param URI a C string containing the URI or filename |
| * @param encoder the encoding converter or NULL |
| * @param compression the compression ration (0 none, 9 max). |
| * @returns the new output or NULL |
| */ |
| xmlOutputBuffer * |
| xmlOutputBufferCreateFilename(const char *URI, |
| xmlCharEncodingHandler *encoder, |
| int compression ATTRIBUTE_UNUSED) { |
| if ((xmlOutputBufferCreateFilenameValue)) { |
| return xmlOutputBufferCreateFilenameValue(URI, encoder, compression); |
| } |
| return __xmlOutputBufferCreateFilename(URI, encoder, compression); |
| } |
| #endif /* LIBXML_OUTPUT_ENABLED */ |
| |
| /** |
| * Create a buffered parser input for the progressive parsing of a FILE * |
| * buffered C I/O |
| * |
| * @deprecated Don't use. |
| * |
| * 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. |
| * |
| * @param file a FILE* |
| * @param enc the charset encoding if known (deprecated) |
| * @returns the new parser input or NULL |
| */ |
| xmlParserInputBuffer * |
| 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 = NULL; |
| } |
| |
| return(ret); |
| } |
| |
| #ifdef LIBXML_OUTPUT_ENABLED |
| /** |
| * Create a buffered output for the progressive saving to a `FILE *` |
| * buffered C I/O. |
| * |
| * Consumes `encoder` but not in error case. |
| * |
| * @param file a `FILE *` |
| * @param encoder the encoding converter or NULL |
| * @returns the new parser output or NULL |
| */ |
| xmlOutputBuffer * |
| xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandler *encoder) { |
| xmlOutputBufferPtr ret; |
| |
| if (file == NULL) { |
| return(NULL); |
| } |
| |
| ret = xmlAllocOutputBuffer(encoder); |
| if (ret != NULL) { |
| ret->context = file; |
| ret->writecallback = xmlFileWrite; |
| ret->closecallback = xmlFileFlush; |
| } |
| |
| return(ret); |
| } |
| |
| /** |
| * Create a buffered output for the progressive saving to a xmlBuffer |
| * |
| * Consumes `encoder` but not in error case. |
| * |
| * @param buffer a xmlBuffer |
| * @param encoder the encoding converter or NULL |
| * @returns the new parser output or NULL |
| */ |
| xmlOutputBuffer * |
| xmlOutputBufferCreateBuffer(xmlBuffer *buffer, |
| xmlCharEncodingHandler *encoder) { |
| xmlOutputBufferPtr ret; |
| |
| if (buffer == NULL) { |
| return(NULL); |
| } |
| |
| ret = xmlOutputBufferCreateIO(xmlBufferWrite, NULL, (void *) buffer, |
| encoder); |
| |
| return(ret); |
| } |
| |
| /** |
| * Gives a pointer to the data currently held in the output buffer |
| * |
| * @param out an xmlOutputBuffer |
| * @returns a pointer to the data or NULL in case of error |
| */ |
| const xmlChar * |
| xmlOutputBufferGetContent(xmlOutputBuffer *out) { |
| if ((out == NULL) || (out->buffer == NULL) || (out->error != 0)) |
| return(NULL); |
| |
| return(xmlBufContent(out->buffer)); |
| } |
| |
| /** |
| * Gives the length of the data currently held in the output buffer |
| * |
| * @param out an xmlOutputBuffer |
| * @returns 0 in case or error or no data is held, the size otherwise |
| */ |
| size_t |
| xmlOutputBufferGetSize(xmlOutputBuffer *out) { |
| if ((out == NULL) || (out->buffer == NULL) || (out->error != 0)) |
| return(0); |
| |
| return(xmlBufUse(out->buffer)); |
| } |
| |
| |
| #endif /* LIBXML_OUTPUT_ENABLED */ |
| |
| /** |
| * Create a buffered parser input for the progressive parsing for the input |
| * from a file descriptor |
| * |
| * @deprecated Use #xmlNewInputFromFd. |
| * |
| * 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. |
| * |
| * @param fd a file descriptor number |
| * @param enc the charset encoding if known (deprecated) |
| * @returns the new parser input or NULL |
| */ |
| xmlParserInputBuffer * |
| xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) { |
| xmlParserInputBufferPtr ret; |
| |
| if (fd < 0) return(NULL); |
| |
| ret = xmlAllocParserInputBuffer(enc); |
| if (ret != NULL) { |
| xmlFdIOCtxt *fdctxt; |
| |
| fdctxt = xmlMalloc(sizeof(*fdctxt)); |
| if (fdctxt == NULL) { |
| return(NULL); |
| } |
| fdctxt->fd = fd; |
| |
| ret->context = fdctxt; |
| ret->readcallback = xmlFdRead; |
| ret->closecallback = xmlFdFree; |
| } |
| |
| return(ret); |
| } |
| |
| typedef struct { |
| 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; |
| |
| xmlFree(ctxt); |
| return(0); |
| } |
| |
| /** |
| * Create an input buffer for memory. |
| * |
| * @param mem memory buffer |
| * @param size size of buffer |
| * @param flags flags |
| * @param enc the charset encoding if known (deprecated) |
| * @returns the new input buffer or NULL. |
| */ |
| xmlParserInputBuffer * |
| xmlNewInputBufferMemory(const void *mem, size_t size, |
| xmlParserInputFlags flags, xmlCharEncoding enc) { |
| xmlParserInputBufferPtr ret; |
| |
| if ((flags & XML_INPUT_BUF_STATIC) && |
| ((flags & XML_INPUT_BUF_ZERO_TERMINATED) == 0)) { |
| xmlMemIOCtxt *ctxt; |
| |
| /* |
| * Static buffer without zero terminator. |
| * Stream memory to avoid a copy. |
| */ |
| ret = xmlAllocParserInputBuffer(enc); |
| if (ret == NULL) |
| return(NULL); |
| |
| ctxt = xmlMalloc(sizeof(*ctxt)); |
| if (ctxt == NULL) { |
| xmlFreeParserInputBuffer(ret); |
| return(NULL); |
| } |
| |
| ctxt->cur = mem; |
| ctxt->size = size; |
| |
| ret->context = ctxt; |
| ret->readcallback = xmlMemRead; |
| ret->closecallback = xmlMemClose; |
| } else { |
| ret = xmlMalloc(sizeof(*ret)); |
| if (ret == NULL) |
| return(NULL); |
| memset(ret, 0, sizeof(xmlParserInputBuffer)); |
| ret->compressed = -1; |
| |
| ret->buffer = xmlBufCreateMem((const xmlChar *) mem, size, |
| (flags & XML_INPUT_BUF_STATIC ? 1 : 0)); |
| if (ret->buffer == NULL) { |
| xmlFree(ret); |
| return(NULL); |
| } |
| } |
| |
| return(ret); |
| } |
| |
| /** |
| * Create a parser input buffer for parsing from a memory area. |
| * |
| * @deprecated Use #xmlNewInputFromMemory. |
| * |
| * 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. |
| * |
| * @param mem the memory input |
| * @param size the length of the memory block |
| * @param enc the charset encoding if known (deprecated) |
| * @returns the new parser input or NULL in case of error. |
| */ |
| xmlParserInputBuffer * |
| xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) { |
| if ((mem == NULL) || (size < 0)) |
| return(NULL); |
| |
| return(xmlNewInputBufferMemory(mem, size, 0, enc)); |
| } |
| |
| /** |
| * Create a parser input buffer for parsing from a memory area. |
| * |
| * @deprecated Use #xmlNewInputFromMemory. |
| * |
| * 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. |
| * |
| * @param mem the memory input |
| * @param size the length of the memory block |
| * @param enc the charset encoding if known |
| * @returns the new parser input or NULL in case of error. |
| */ |
| xmlParserInputBuffer * |
| xmlParserInputBufferCreateStatic(const char *mem, int size, |
| xmlCharEncoding enc) { |
| if ((mem == NULL) || (size < 0)) |
| return(NULL); |
| |
| return(xmlNewInputBufferMemory(mem, size, XML_INPUT_BUF_STATIC, enc)); |
| } |
| |
| /** |
| * Create an input buffer for a null-terminated C string. |
| * |
| * @deprecated Use #xmlNewInputFromString. |
| * |
| * @param str C string |
| * @param flags flags |
| * @returns the new input buffer or NULL. |
| */ |
| xmlParserInputBuffer * |
| xmlNewInputBufferString(const char *str, xmlParserInputFlags flags) { |
| xmlParserInputBufferPtr ret; |
| |
| ret = xmlMalloc(sizeof(*ret)); |
| if (ret == NULL) |
| return(NULL); |
| memset(ret, 0, sizeof(xmlParserInputBuffer)); |
| ret->compressed = -1; |
| |
| ret->buffer = xmlBufCreateMem((const xmlChar *) str, strlen(str), |
| (flags & XML_INPUT_BUF_STATIC ? 1 : 0)); |
| if (ret->buffer == NULL) { |
| xmlFree(ret); |
| return(NULL); |
| } |
| |
| return(ret); |
| } |
| |
| #ifdef LIBXML_OUTPUT_ENABLED |
| /** |
| * Create a buffered output for the progressive saving |
| * to a file descriptor |
| * |
| * Consumes `encoder` but not in error case. |
| * |
| * @param fd a file descriptor number |
| * @param encoder the encoding converter or NULL |
| * @returns the new parser output or NULL |
| */ |
| xmlOutputBuffer * |
| xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandler *encoder) { |
| xmlOutputBufferPtr ret; |
| |
| if (fd < 0) { |
| return(NULL); |
| } |
| |
| ret = xmlAllocOutputBuffer(encoder); |
| if (ret != NULL) { |
| xmlFdIOCtxt *fdctxt; |
| |
| fdctxt = xmlMalloc(sizeof(*fdctxt)); |
| if (fdctxt == NULL) { |
| return(NULL); |
| } |
| fdctxt->fd = fd; |
| |
| ret->context = fdctxt; |
| ret->writecallback = xmlFdWrite; |
| ret->closecallback = xmlFdFree; |
| } |
| |
| return(ret); |
| } |
| #endif /* LIBXML_OUTPUT_ENABLED */ |
| |
| /** |
| * Create a buffered parser input for the progressive parsing for the input |
| * from an I/O handler |
| * |
| * @deprecated Use #xmlNewInputFromIO. |
| * |
| * 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. |
| * |
| * @param ioread an I/O read function |
| * @param ioclose an I/O close function |
| * @param ioctx an I/O handler |
| * @param enc the charset encoding if known (deprecated) |
| * @returns the new parser input or NULL |
| */ |
| xmlParserInputBuffer * |
| 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 |
| /** |
| * Create a buffered output for the progressive saving |
| * to an I/O handler |
| * |
| * Consumes `encoder` but not in error case. |
| * |
| * @param iowrite an I/O write function |
| * @param ioclose an I/O close function |
| * @param ioctx an I/O handler |
| * @param encoder the charset encoding if known |
| * @returns the new parser output or NULL |
| */ |
| xmlOutputBuffer * |
| xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite, |
| xmlOutputCloseCallback ioclose, void *ioctx, |
| xmlCharEncodingHandler *encoder) { |
| xmlOutputBufferPtr ret; |
| |
| if (iowrite == NULL) { |
| return(NULL); |
| } |
| |
| ret = xmlAllocOutputBuffer(encoder); |
| if (ret != NULL) { |
| ret->context = (void *) ioctx; |
| ret->writecallback = iowrite; |
| ret->closecallback = ioclose; |
| } |
| |
| return(ret); |
| } |
| #endif /* LIBXML_OUTPUT_ENABLED */ |
| |
| /** |
| * Registers a callback for URI input file handling |
| * |
| * @deprecated Use #xmlCtxtSetResourceLoader or similar functions. |
| * |
| * @param func function pointer to the new ParserInputBufferCreateFilenameFunc |
| * @returns the old value of the registration function |
| */ |
| xmlParserInputBufferCreateFilenameFunc |
| xmlParserInputBufferCreateFilenameDefault( |
| xmlParserInputBufferCreateFilenameFunc func) |
| { |
| xmlParserInputBufferCreateFilenameFunc old; |
| |
| old = xmlParserInputBufferCreateFilenameValue; |
| if (old == NULL) |
| old = __xmlParserInputBufferCreateFilename; |
| |
| if (func == __xmlParserInputBufferCreateFilename) |
| func = NULL; |
| xmlParserInputBufferCreateFilenameValue = func; |
| return(old); |
| } |
| |
| /** |
| * Registers a callback for URI output file handling |
| * |
| * @param func function pointer to the new OutputBufferCreateFilenameFunc |
| * @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); |
| } |
| |
| /** |
| * 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. |
| * |
| * @deprecated Internal function, don't use. |
| * |
| * @param in a buffered parser input |
| * @param len the size in bytes of the array. |
| * @param buf an char array |
| * @returns the number of chars read and stored in the buffer, or -1 |
| * in case of error. |
| */ |
| int |
| xmlParserInputBufferPush(xmlParserInputBuffer *in, |
| int len, const char *buf) { |
| size_t 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(50); |
| 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 = SIZE_MAX; |
| if (xmlCharEncInput(in, &nbchars, /* flush */ 0) != |
| XML_ENC_ERR_SUCCESS) |
| return(-1); |
| if (nbchars > INT_MAX) |
| nbchars = INT_MAX; |
| } else { |
| nbchars = len; |
| ret = xmlBufAdd(in->buffer, (xmlChar *) buf, nbchars); |
| if (ret != 0) { |
| in->error = XML_ERR_NO_MEMORY; |
| return(-1); |
| } |
| } |
| return(nbchars); |
| } |
| |
| /* |
| * 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); |
| } |
| |
| /** |
| * 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 |
| * |
| * @deprecated Internal function, don't use. |
| * |
| * @param in a buffered parser input |
| * @param len indicative value of the amount of chars to read |
| * @returns the number of chars read and stored in the buffer, or -1 |
| * in case of error. |
| */ |
| int |
| xmlParserInputBufferGrow(xmlParserInputBuffer *in, int len) { |
| int res = 0; |
| |
| if ((in == NULL) || (in->error)) |
| return(-1); |
| |
| if (len < MINLEN) |
| len = MINLEN; |
| |
| /* |
| * Call the read method for this I/O type. |
| */ |
| if (in->readcallback != NULL) { |
| xmlBufPtr buf; |
| |
| if (in->encoder == NULL) { |
| buf = in->buffer; |
| } else { |
| /* |
| * Some users only set 'encoder' and expect us to create |
| * the raw buffer lazily. |
| */ |
| if (in->raw == NULL) { |
| in->raw = xmlBufCreate(XML_IO_BUFFER_SIZE); |
| if (in->raw == NULL) { |
| in->error = XML_ERR_NO_MEMORY; |
| return(-1); |
| } |
| } |
| buf = in->raw; |
| } |
| |
| if (xmlBufGrow(buf, len) < 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); |
| } |
| } |
| |
| /* |
| * Handle encoding. |
| */ |
| if (in->encoder != NULL) { |
| size_t sizeOut; |
| |
| /* |
| * Don't convert whole buffer when reading from memory. |
| */ |
| if (in->readcallback == NULL) |
| sizeOut = len; |
| else |
| sizeOut = SIZE_MAX; |
| |
| if (xmlCharEncInput(in, &sizeOut, /* flush */ 0) != |
| XML_ENC_ERR_SUCCESS) |
| return(-1); |
| res = sizeOut; |
| } |
| return(res); |
| } |
| |
| /** |
| * Same as #xmlParserInputBufferGrow. |
| * |
| * @deprecated Internal function, don't use. |
| * |
| * @param in a buffered parser input |
| * @param len indicative value of the amount of chars to read |
| * @returns the number of chars read and stored in the buffer, or -1 |
| * in case of error. |
| */ |
| int |
| xmlParserInputBufferRead(xmlParserInputBuffer *in, int len) { |
| return(xmlParserInputBufferGrow(in, len)); |
| } |
| |
| #ifdef LIBXML_OUTPUT_ENABLED |
| /** |
| * 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. |
| * |
| * @param out a buffered parser output |
| * @param len the size in bytes of the array. |
| * @param data an char array |
| * @returns the number of chars immediately written, or -1 |
| * in case of error. |
| */ |
| int |
| xmlOutputBufferWrite(xmlOutputBuffer *out, int len, const char *data) { |
| xmlBufPtr buf = NULL; |
| size_t written = 0; |
| int ret; |
| |
| if ((out == NULL) || (out->error)) |
| return(-1); |
| if (len < 0) |
| return(0); |
| |
| ret = xmlBufAdd(out->buffer, (const xmlChar *) data, len); |
| if (ret != 0) { |
| out->error = XML_ERR_NO_MEMORY; |
| return(-1); |
| } |
| |
| /* |
| * first handle encoding stuff. |
| */ |
| if (out->encoder != NULL) { |
| /* |
| * Store the data in the incoming raw buffer |
| */ |
| if (out->conv == NULL) { |
| out->conv = xmlBufCreate(MINLEN); |
| if (out->conv == NULL) { |
| out->error = XML_ERR_NO_MEMORY; |
| return(-1); |
| } |
| } |
| |
| /* |
| * convert as much as possible to the parser reading buffer. |
| */ |
| if (xmlBufUse(out->buffer) < 256) { |
| ret = 0; |
| } else { |
| ret = xmlCharEncOutput(out, 0); |
| if (ret < 0) |
| return(-1); |
| } |
| |
| if (out->writecallback) |
| buf = out->conv; |
| else |
| written = ret; |
| } else { |
| if (out->writecallback) |
| buf = out->buffer; |
| else |
| written = len; |
| } |
| |
| if ((buf != NULL) && (out->writecallback)) { |
| /* |
| * second write the stuff to the I/O channel |
| */ |
| while (1) { |
| size_t nbchars = xmlBufUse(buf); |
| |
| if (nbchars < MINLEN) |
| break; |
| |
| ret = out->writecallback(out->context, |
| (const char *)xmlBufContent(buf), nbchars); |
| if (ret < 0) { |
| out->error = (ret == -1) ? XML_IO_WRITE : -ret; |
| return(-1); |
| } |
| if ((ret == 0) || ((size_t) ret > nbchars)) { |
| out->error = XML_ERR_INTERNAL_ERROR; |
| return(-1); |
| } |
| |
| xmlBufShrink(buf, ret); |
| written += ret; |
| if (out->written > INT_MAX - ret) |
| out->written = INT_MAX; |
| else |
| out->written += ret; |
| } |
| } |
| |
| return(written <= INT_MAX ? written : INT_MAX); |
| } |
| |
| /** |
| * 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. |
| * |
| * @param out a buffered parser output |
| * @param str a zero terminated UTF-8 string |
| * @param escaping an optional escaping function (or NULL) |
| * @returns the number of chars immediately written, or -1 |
| * in case of error. |
| */ |
| int |
| xmlOutputBufferWriteEscape(xmlOutputBuffer *out, const xmlChar *str, |
| xmlCharEncodingOutputFunc escaping) { |
| int ret; |
| int written = 0; |
| size_t len; |
| |
| if ((out == NULL) || (out->error) || (str == NULL)) |
| return(-1); |
| |
| len = strlen((const char *) str); |
| if (len >= INT_MAX) { |
| out->error = XML_ERR_RESOURCE_LIMIT; |
| return(-1); |
| } |
| |
| if (escaping == NULL) { |
| char *escaped = (char *) xmlEscapeText(str, 0); |
| |
| if (escaped == NULL) { |
| out->error = XML_ERR_NO_MEMORY; |
| return(-1); |
| } |
| |
| len = strlen(escaped); |
| if (len >= INT_MAX) { |
| out->error = XML_ERR_RESOURCE_LIMIT; |
| return(-1); |
| } |
| |
| ret = xmlOutputBufferWrite(out, len, escaped); |
| |
| xmlFree(escaped); |
| return(ret); |
| } |
| |
| while (len > 0) { |
| xmlChar buf[1024]; |
| int c_out; |
| int c_in; |
| |
| c_out = 1024; |
| c_in = len; |
| |
| ret = escaping(buf, &c_out, str, &c_in); |
| if (ret < 0) { |
| out->error = XML_ERR_NO_MEMORY; |
| return(-1); |
| } |
| str += c_in; |
| len -= c_in; |
| |
| ret = xmlOutputBufferWrite(out, c_out, (char *) buf); |
| if (ret < 0) |
| return(ret); |
| written += ret; |
| } |
| |
| return(written); |
| } |
| |
| /** |
| * 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. |
| * |
| * @param out a buffered parser output |
| * @param str a zero terminated C string |
| * @returns the number of chars immediately written, or -1 |
| * in case of error. |
| */ |
| int |
| xmlOutputBufferWriteString(xmlOutputBuffer *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); |
| } |
| |
| /** |
| * Write a string surrounded by quotes to an output buffer. |
| * |
| * Uses double quotes if the string contains no double quotes. |
| * Otherwise, uses single quotes if the string contains no |
| * single quotes. Otherwise, uses double quotes and escapes |
| * double quotes. |
| * |
| * This should only be used to escape system IDs. Currently, |
| * we also use it for public IDs and original entity values. |
| * |
| * @param buf output buffer |
| * @param string the string to add |
| */ |
| void |
| xmlOutputBufferWriteQuotedString(xmlOutputBuffer *buf, |
| const xmlChar *string) { |
| const xmlChar *cur, *base; |
| |
| if ((buf == NULL) || (buf->error)) |
| return; |
| |
| if (xmlStrchr(string, '\"')) { |
| if (xmlStrchr(string, '\'')) { |
| xmlOutputBufferWrite(buf, 1, "\""); |
| base = cur = string; |
| while(*cur != 0){ |
| if(*cur == '"'){ |
| if (base != cur) |
| xmlOutputBufferWrite(buf, cur - base, |
| (const char *) base); |
| xmlOutputBufferWrite(buf, 6, """); |
| cur++; |
| base = cur; |
| } |
| else { |
| cur++; |
| } |
| } |
| if (base != cur) |
| xmlOutputBufferWrite(buf, cur - base, (const char *) base); |
| xmlOutputBufferWrite(buf, 1, "\""); |
| } |
| else{ |
| xmlOutputBufferWrite(buf, 1, "'"); |
| xmlOutputBufferWriteString(buf, (const char *) string); |
| xmlOutputBufferWrite(buf, 1, "'"); |
| } |
| } else { |
| xmlOutputBufferWrite(buf, 1, "\""); |
| xmlOutputBufferWriteString(buf, (const char *) string); |
| xmlOutputBufferWrite(buf, 1, "\""); |
| } |
| } |
| |
| /** |
| * flushes the output I/O channel |
| * |
| * @param out a buffered output |
| * @returns the number of byte written or -1 in case of error. |
| */ |
| int |
| xmlOutputBufferFlush(xmlOutputBuffer *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) { |
| out->error = (ret == -1) ? XML_IO_WRITE : -ret; |
| return(ret); |
| } |
| if (out->written > INT_MAX - ret) |
| out->written = INT_MAX; |
| else |
| out->written += ret; |
| |
| return(ret); |
| } |
| #endif /* LIBXML_OUTPUT_ENABLED */ |
| |
| /** |
| * lookup the directory for that file |
| * |
| * @param filename the path to a 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 { |
| ret = xmlMemStrdup("."); |
| } |
| return(ret); |
| #undef IS_XMLPGD_SEP |
| } |
| |
| /** |
| * Like #xmlCheckFilename but handles file URIs. |
| * |
| * @deprecated Internal function, don't use. |
| * |
| * @param filename the path to check |
| * @returns 0, 1, or 2. |
| */ |
| 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); |
| } |
| |
| /************************************************************************ |
| * * |
| * Input/output callbacks * |
| * * |
| ************************************************************************/ |
| |
| /** |
| * Initialize callback tables. |
| */ |
| void |
| xmlInitIOCallbacks(void) |
| { |
| xmlInputCallbackNr = 1; |
| xmlInputCallbackTable[0].matchcallback = xmlIODefaultMatch; |
| |
| #ifdef LIBXML_OUTPUT_ENABLED |
| xmlOutputCallbackNr = 1; |
| xmlOutputCallbackTable[0].matchcallback = xmlIODefaultMatch; |
| #endif |
| } |
| |
| /** |
| * Register a new set of I/O callback for handling parser input. |
| * |
| * @deprecated Use #xmlCtxtSetResourceLoader or similar functions. |
| * |
| * @param matchFunc the xmlInputMatchCallback |
| * @param openFunc the xmlInputOpenCallback |
| * @param readFunc the xmlInputReadCallback |
| * @param closeFunc the xmlInputCloseCallback |
| * @returns the registered handler number or -1 in case of error |
| */ |
| int |
| xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc, |
| xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc, |
| xmlInputCloseCallback closeFunc) { |
| xmlInitParser(); |
| |
| 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++); |
| } |
| |
| /** |
| * Registers the default compiled-in I/O handlers. |
| */ |
| void |
| xmlRegisterDefaultInputCallbacks(void) { |
| xmlRegisterInputCallbacks(xmlIODefaultMatch, NULL, NULL, NULL); |
| } |
| |
| /** |
| * 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) |
| { |
| xmlInitParser(); |
| |
| if (xmlInputCallbackNr <= 0) |
| return(-1); |
| |
| xmlInputCallbackNr--; |
| |
| return(xmlInputCallbackNr); |
| } |
| |
| /** |
| * clears the entire input callback table. this includes the |
| * compiled-in I/O. |
| */ |
| void |
| xmlCleanupInputCallbacks(void) |
| { |
| xmlInitParser(); |
| |
| xmlInputCallbackNr = 0; |
| } |
| |
| #ifdef LIBXML_OUTPUT_ENABLED |
| /** |
| * Register a new set of I/O callback for handling output. |
| * |
| * @param matchFunc the xmlOutputMatchCallback |
| * @param openFunc the xmlOutputOpenCallback |
| * @param writeFunc the xmlOutputWriteCallback |
| * @param closeFunc the xmlOutputCloseCallback |
| * @returns the registered handler number or -1 in case of error |
| */ |
| int |
| xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc, |
| xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc, |
| xmlOutputCloseCallback closeFunc) { |
| xmlInitParser(); |
| |
| 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++); |
| } |
| |
| /** |
| * Registers the default compiled-in I/O handlers. |
| */ |
| void |
| xmlRegisterDefaultOutputCallbacks (void) { |
| xmlRegisterOutputCallbacks(xmlIODefaultMatch, NULL, NULL, NULL); |
| } |
| |
| /** |
| * 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) |
| { |
| xmlInitParser(); |
| |
| if (xmlOutputCallbackNr <= 0) |
| return(-1); |
| |
| xmlOutputCallbackNr--; |
| |
| return(xmlOutputCallbackNr); |
| } |
| |
| /** |
| * clears the entire output callback table. this includes the |
| * compiled-in I/O callbacks. |
| */ |
| void |
| xmlCleanupOutputCallbacks(void) |
| { |
| xmlInitParser(); |
| |
| xmlOutputCallbackNr = 0; |
| } |
| #endif /* LIBXML_OUTPUT_ENABLED */ |
| |