mirror of
				https://gitlab.gnome.org/GNOME/libxml2.git
				synced 2025-10-24 13:33:01 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			3047 lines
		
	
	
		
			76 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			3047 lines
		
	
	
		
			76 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * 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);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Tables generated with tools/genEscape.py
 | |
|  */
 | |
| 
 | |
| static const char xmlEscapeContent[] = {
 | |
|       8, '&', '#', 'x', 'F', 'F', 'F', 'D', ';',   4, '&', '#',
 | |
|     '9', ';',   5, '&', '#', '1', '0', ';',   5, '&', '#', '1',
 | |
|     '3', ';',   6, '&', 'q', 'u', 'o', 't', ';',   5, '&', 'a',
 | |
|     'm', 'p', ';',   4, '&', 'l', 't', ';',   4, '&', 'g', 't',
 | |
|     ';',
 | |
| };
 | |
| 
 | |
| static const signed char xmlEscapeTab[128] = {
 | |
|      0,  0,  0,  0,  0,  0,  0,  0,  0, -1, -1,  0,  0, 20,  0,  0,
 | |
|      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
 | |
|     -1, -1, -1, -1, -1, -1, 33, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 | |
|     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 39, -1, 44, -1,
 | |
|     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 | |
|     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 | |
|     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 | |
|     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 | |
| };
 | |
| 
 | |
| static const signed char xmlEscapeTabQuot[128] = {
 | |
|      0,  0,  0,  0,  0,  0,  0,  0,  0, -1, -1,  0,  0, 20,  0,  0,
 | |
|      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
 | |
|     -1, -1, 26, -1, -1, -1, 33, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 | |
|     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 39, -1, 44, -1,
 | |
|     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 | |
|     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 | |
|     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 | |
|     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 | |
| };
 | |
| 
 | |
| static const signed char xmlEscapeTabAttr[128] = {
 | |
|      0,  0,  0,  0,  0,  0,  0,  0,  0,  9, 14,  0,  0, 20,  0,  0,
 | |
|      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
 | |
|     -1, -1, 26, -1, -1, -1, 33, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 | |
|     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 39, -1, 44, -1,
 | |
|     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 | |
|     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 | |
|     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 | |
|     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 | |
| };
 | |
| 
 | |
| #ifdef LIBXML_HTML_ENABLED
 | |
| 
 | |
| static const signed char htmlEscapeTab[128] = {
 | |
|      0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 | |
|     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 | |
|     -1, -1, -1, -1, -1, -1, 33, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 | |
|     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 39, -1, 44, -1,
 | |
|     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 | |
|     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 | |
|     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 | |
|     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 | |
| };
 | |
| 
 | |
| static const signed char htmlEscapeTabAttr[128] = {
 | |
|      0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 | |
|     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 | |
|     -1, -1, 26, -1, -1, -1, 33, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 | |
|     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 | |
|     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 | |
|     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 | |
|     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 | |
|     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 | |
| };
 | |
| 
 | |
| #endif /* LIBXML_HTML_ENABLED */
 | |
| 
 | |
| /*
 | |
|  * @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);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * @param buf  input buffer to be filled
 | |
|  * @param filename  filename or URI
 | |
|  * @param flags  XML_INPUT flags
 | |
|  * @returns an xmlParserErrors code.
 | |
|  */
 | |
| static xmlParserErrors
 | |
| xmlInputDefaultOpen(xmlParserInputBufferPtr buf, const char *filename,
 | |
|                     xmlParserInputFlags flags) {
 | |
|     xmlParserErrors ret;
 | |
|     int fd;
 | |
| 
 | |
|     if (!xmlFileMatch(filename))
 | |
|         return(XML_IO_ENOENT);
 | |
| 
 | |
|     ret = xmlFdOpen(filename, 0, &fd);
 | |
|     if (ret != XML_ERR_OK)
 | |
|         return(ret);
 | |
| 
 | |
|     ret = xmlInputFromFd(buf, fd, flags);
 | |
| 
 | |
|     close(fd);
 | |
| 
 | |
|     return(ret);
 | |
| }
 | |
| 
 | |
| #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) {
 | |
|             ret = xmlInputDefaultOpen(buf, URI, flags);
 | |
| 
 | |
|             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);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * 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 */
 | |
| 
 |