2 * xmlIO.c : implementation of the I/O interfaces used by the parser
4 * See Copyright for the status of this software.
8 * 14 Nov 2000 ht - for VMS, truncated name of long functions to under 32 char
18 #ifdef HAVE_SYS_STAT_H
27 #ifdef LIBXML_ZLIB_ENABLED
30 #ifdef LIBXML_LZMA_ENABLED
35 #define WIN32_LEAN_AND_MEAN
43 # define S_ISDIR(x) _S_ISDIR(x)
44 # elif defined(S_IFDIR)
46 # define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
47 # elif defined(_S_IFMT)
48 # define S_ISDIR(m) (((m) & _S_IFMT) == S_IFDIR)
53 #include <libxml/xmlmemory.h>
54 #include <libxml/parser.h>
55 #include <libxml/parserInternals.h>
56 #include <libxml/xmlIO.h>
57 #include <libxml/uri.h>
58 #include <libxml/nanohttp.h>
59 #include <libxml/nanoftp.h>
60 #include <libxml/xmlerror.h>
61 #ifdef LIBXML_CATALOG_ENABLED
62 #include <libxml/catalog.h>
64 #include <libxml/globals.h>
66 #include "private/buf.h"
67 #include "private/enc.h"
68 #include "private/error.h"
69 #include "private/io.h"
70 #include "private/parser.h"
72 /* #define VERBOSE_FAILURE */
73 /* #define DEBUG_EXTERNAL_ENTITIES */
74 /* #define DEBUG_INPUT */
83 * Input I/O callback sets
85 typedef struct _xmlInputCallback
{
86 xmlInputMatchCallback matchcallback
;
87 xmlInputOpenCallback opencallback
;
88 xmlInputReadCallback readcallback
;
89 xmlInputCloseCallback closecallback
;
92 #define MAX_INPUT_CALLBACK 15
94 static xmlInputCallback xmlInputCallbackTable
[MAX_INPUT_CALLBACK
];
95 static int xmlInputCallbackNr
= 0;
96 static int xmlInputCallbackInitialized
= 0;
98 #ifdef LIBXML_OUTPUT_ENABLED
100 * Output I/O callback sets
102 typedef struct _xmlOutputCallback
{
103 xmlOutputMatchCallback matchcallback
;
104 xmlOutputOpenCallback opencallback
;
105 xmlOutputWriteCallback writecallback
;
106 xmlOutputCloseCallback closecallback
;
109 #define MAX_OUTPUT_CALLBACK 15
111 static xmlOutputCallback xmlOutputCallbackTable
[MAX_OUTPUT_CALLBACK
];
112 static int xmlOutputCallbackNr
= 0;
113 static int xmlOutputCallbackInitialized
= 0;
114 #endif /* LIBXML_OUTPUT_ENABLED */
116 /************************************************************************
118 * Tree memory error handler *
120 ************************************************************************/
122 static const char* const IOerr
[] = {
123 "Unknown IO error", /* UNKNOWN */
124 "Permission denied", /* EACCES */
125 "Resource temporarily unavailable",/* EAGAIN */
126 "Bad file descriptor", /* EBADF */
127 "Bad message", /* EBADMSG */
128 "Resource busy", /* EBUSY */
129 "Operation canceled", /* ECANCELED */
130 "No child processes", /* ECHILD */
131 "Resource deadlock avoided",/* EDEADLK */
132 "Domain error", /* EDOM */
133 "File exists", /* EEXIST */
134 "Bad address", /* EFAULT */
135 "File too large", /* EFBIG */
136 "Operation in progress", /* EINPROGRESS */
137 "Interrupted function call",/* EINTR */
138 "Invalid argument", /* EINVAL */
139 "Input/output error", /* EIO */
140 "Is a directory", /* EISDIR */
141 "Too many open files", /* EMFILE */
142 "Too many links", /* EMLINK */
143 "Inappropriate message buffer length",/* EMSGSIZE */
144 "Filename too long", /* ENAMETOOLONG */
145 "Too many open files in system",/* ENFILE */
146 "No such device", /* ENODEV */
147 "No such file or directory",/* ENOENT */
148 "Exec format error", /* ENOEXEC */
149 "No locks available", /* ENOLCK */
150 "Not enough space", /* ENOMEM */
151 "No space left on device", /* ENOSPC */
152 "Function not implemented", /* ENOSYS */
153 "Not a directory", /* ENOTDIR */
154 "Directory not empty", /* ENOTEMPTY */
155 "Not supported", /* ENOTSUP */
156 "Inappropriate I/O control operation",/* ENOTTY */
157 "No such device or address",/* ENXIO */
158 "Operation not permitted", /* EPERM */
159 "Broken pipe", /* EPIPE */
160 "Result too large", /* ERANGE */
161 "Read-only file system", /* EROFS */
162 "Invalid seek", /* ESPIPE */
163 "No such process", /* ESRCH */
164 "Operation timed out", /* ETIMEDOUT */
165 "Improper link", /* EXDEV */
166 "Attempt to load network entity %s", /* XML_IO_NETWORK_ATTEMPT */
167 "encoder error", /* XML_IO_ENCODER */
173 "not a socket", /* ENOTSOCK */
174 "already connected", /* EISCONN */
175 "connection refused", /* ECONNREFUSED */
176 "unreachable network", /* ENETUNREACH */
177 "address in use", /* EADDRINUSE */
178 "already in use", /* EALREADY */
179 "unknown address family", /* EAFNOSUPPORT */
184 * __xmlIOWin32UTF8ToWChar:
185 * @u8String: uft-8 string
187 * Convert a string from utf-8 to wchar (WINDOWS ONLY!)
190 __xmlIOWin32UTF8ToWChar(const char *u8String
)
192 wchar_t *wString
= NULL
;
196 MultiByteToWideChar(CP_UTF8
, MB_ERR_INVALID_CHARS
, u8String
,
199 wString
= xmlMalloc(wLen
* sizeof(wchar_t));
201 if (MultiByteToWideChar
202 (CP_UTF8
, 0, u8String
, -1, wString
, wLen
) == 0) {
216 * @extra: extra information
218 * Handle an out of memory condition
221 xmlIOErrMemory(const char *extra
)
223 __xmlSimpleError(XML_FROM_IO
, XML_ERR_NO_MEMORY
, NULL
, NULL
, extra
);
228 * @code: the error number
230 * @extra: extra information
232 * Handle an I/O error
235 __xmlIOErr(int domain
, int code
, const char *extra
)
240 if (errno
== 0) code
= 0;
242 else if (errno
== EACCES
) code
= XML_IO_EACCES
;
245 else if (errno
== EAGAIN
) code
= XML_IO_EAGAIN
;
248 else if (errno
== EBADF
) code
= XML_IO_EBADF
;
251 else if (errno
== EBADMSG
) code
= XML_IO_EBADMSG
;
254 else if (errno
== EBUSY
) code
= XML_IO_EBUSY
;
257 else if (errno
== ECANCELED
) code
= XML_IO_ECANCELED
;
260 else if (errno
== ECHILD
) code
= XML_IO_ECHILD
;
263 else if (errno
== EDEADLK
) code
= XML_IO_EDEADLK
;
266 else if (errno
== EDOM
) code
= XML_IO_EDOM
;
269 else if (errno
== EEXIST
) code
= XML_IO_EEXIST
;
272 else if (errno
== EFAULT
) code
= XML_IO_EFAULT
;
275 else if (errno
== EFBIG
) code
= XML_IO_EFBIG
;
278 else if (errno
== EINPROGRESS
) code
= XML_IO_EINPROGRESS
;
281 else if (errno
== EINTR
) code
= XML_IO_EINTR
;
284 else if (errno
== EINVAL
) code
= XML_IO_EINVAL
;
287 else if (errno
== EIO
) code
= XML_IO_EIO
;
290 else if (errno
== EISDIR
) code
= XML_IO_EISDIR
;
293 else if (errno
== EMFILE
) code
= XML_IO_EMFILE
;
296 else if (errno
== EMLINK
) code
= XML_IO_EMLINK
;
299 else if (errno
== EMSGSIZE
) code
= XML_IO_EMSGSIZE
;
302 else if (errno
== ENAMETOOLONG
) code
= XML_IO_ENAMETOOLONG
;
305 else if (errno
== ENFILE
) code
= XML_IO_ENFILE
;
308 else if (errno
== ENODEV
) code
= XML_IO_ENODEV
;
311 else if (errno
== ENOENT
) code
= XML_IO_ENOENT
;
314 else if (errno
== ENOEXEC
) code
= XML_IO_ENOEXEC
;
317 else if (errno
== ENOLCK
) code
= XML_IO_ENOLCK
;
320 else if (errno
== ENOMEM
) code
= XML_IO_ENOMEM
;
323 else if (errno
== ENOSPC
) code
= XML_IO_ENOSPC
;
326 else if (errno
== ENOSYS
) code
= XML_IO_ENOSYS
;
329 else if (errno
== ENOTDIR
) code
= XML_IO_ENOTDIR
;
332 else if (errno
== ENOTEMPTY
) code
= XML_IO_ENOTEMPTY
;
335 else if (errno
== ENOTSUP
) code
= XML_IO_ENOTSUP
;
338 else if (errno
== ENOTTY
) code
= XML_IO_ENOTTY
;
341 else if (errno
== ENXIO
) code
= XML_IO_ENXIO
;
344 else if (errno
== EPERM
) code
= XML_IO_EPERM
;
347 else if (errno
== EPIPE
) code
= XML_IO_EPIPE
;
350 else if (errno
== ERANGE
) code
= XML_IO_ERANGE
;
353 else if (errno
== EROFS
) code
= XML_IO_EROFS
;
356 else if (errno
== ESPIPE
) code
= XML_IO_ESPIPE
;
359 else if (errno
== ESRCH
) code
= XML_IO_ESRCH
;
362 else if (errno
== ETIMEDOUT
) code
= XML_IO_ETIMEDOUT
;
365 else if (errno
== EXDEV
) code
= XML_IO_EXDEV
;
368 else if (errno
== ENOTSOCK
) code
= XML_IO_ENOTSOCK
;
371 else if (errno
== EISCONN
) code
= XML_IO_EISCONN
;
374 else if (errno
== ECONNREFUSED
) code
= XML_IO_ECONNREFUSED
;
377 else if (errno
== ETIMEDOUT
) code
= XML_IO_ETIMEDOUT
;
380 else if (errno
== ENETUNREACH
) code
= XML_IO_ENETUNREACH
;
383 else if (errno
== EADDRINUSE
) code
= XML_IO_EADDRINUSE
;
386 else if (errno
== EINPROGRESS
) code
= XML_IO_EINPROGRESS
;
389 else if (errno
== EALREADY
) code
= XML_IO_EALREADY
;
392 else if (errno
== EAFNOSUPPORT
) code
= XML_IO_EAFNOSUPPORT
;
394 else code
= XML_IO_UNKNOWN
;
397 if (code
>= XML_IO_UNKNOWN
) idx
= code
- XML_IO_UNKNOWN
;
398 if (idx
>= (sizeof(IOerr
) / sizeof(IOerr
[0]))) idx
= 0;
400 __xmlSimpleError(domain
, code
, NULL
, IOerr
[idx
], extra
);
405 * @code: the error number
406 * @extra: extra information
408 * Handle an I/O error
411 xmlIOErr(int code
, const char *extra
)
413 __xmlIOErr(XML_FROM_IO
, code
, extra
);
418 * @ctx: the parser context
419 * @extra: extra information
421 * Handle a resource access error
424 __xmlLoaderErr(void *ctx
, const char *msg
, const char *filename
)
426 xmlParserCtxtPtr ctxt
= (xmlParserCtxtPtr
) ctx
;
427 xmlStructuredErrorFunc schannel
= NULL
;
428 xmlGenericErrorFunc channel
= NULL
;
430 xmlErrorLevel level
= XML_ERR_ERROR
;
432 if ((ctxt
!= NULL
) && (ctxt
->disableSAX
!= 0) &&
433 (ctxt
->instate
== XML_PARSER_EOF
))
435 if ((ctxt
!= NULL
) && (ctxt
->sax
!= NULL
)) {
436 if (ctxt
->validate
) {
437 channel
= ctxt
->sax
->error
;
438 level
= XML_ERR_ERROR
;
440 channel
= ctxt
->sax
->warning
;
441 level
= XML_ERR_WARNING
;
443 if (ctxt
->sax
->initialized
== XML_SAX2_MAGIC
)
444 schannel
= ctxt
->sax
->serror
;
445 data
= ctxt
->userData
;
447 __xmlRaiseError(schannel
, channel
, data
, ctxt
, NULL
, XML_FROM_IO
,
448 XML_IO_LOAD_ERROR
, level
, NULL
, 0,
449 filename
, NULL
, NULL
, 0, 0,
454 /************************************************************************
456 * Tree memory error handler *
458 ************************************************************************/
460 * xmlNormalizeWindowsPath:
461 * @path: the input file path
463 * This function is obsolete. Please see xmlURIFromPath in uri.c for
466 * Returns a canonicalized version of the path
469 xmlNormalizeWindowsPath(const xmlChar
*path
)
471 return xmlCanonicPath(path
);
475 * xmlCleanupInputCallbacks:
477 * clears the entire input callback table. this includes the
481 xmlCleanupInputCallbacks(void)
485 if (!xmlInputCallbackInitialized
)
488 for (i
= xmlInputCallbackNr
- 1; i
>= 0; i
--) {
489 xmlInputCallbackTable
[i
].matchcallback
= NULL
;
490 xmlInputCallbackTable
[i
].opencallback
= NULL
;
491 xmlInputCallbackTable
[i
].readcallback
= NULL
;
492 xmlInputCallbackTable
[i
].closecallback
= NULL
;
495 xmlInputCallbackNr
= 0;
496 xmlInputCallbackInitialized
= 0;
500 * xmlPopInputCallbacks:
502 * Clear the top input callback from the input stack. this includes the
505 * Returns the number of input callback registered or -1 in case of error.
508 xmlPopInputCallbacks(void)
510 if (!xmlInputCallbackInitialized
)
513 if (xmlInputCallbackNr
<= 0)
516 xmlInputCallbackNr
--;
517 xmlInputCallbackTable
[xmlInputCallbackNr
].matchcallback
= NULL
;
518 xmlInputCallbackTable
[xmlInputCallbackNr
].opencallback
= NULL
;
519 xmlInputCallbackTable
[xmlInputCallbackNr
].readcallback
= NULL
;
520 xmlInputCallbackTable
[xmlInputCallbackNr
].closecallback
= NULL
;
522 return(xmlInputCallbackNr
);
525 #ifdef LIBXML_OUTPUT_ENABLED
527 * xmlCleanupOutputCallbacks:
529 * clears the entire output callback table. this includes the
530 * compiled-in I/O callbacks.
533 xmlCleanupOutputCallbacks(void)
537 if (!xmlOutputCallbackInitialized
)
540 for (i
= xmlOutputCallbackNr
- 1; i
>= 0; i
--) {
541 xmlOutputCallbackTable
[i
].matchcallback
= NULL
;
542 xmlOutputCallbackTable
[i
].opencallback
= NULL
;
543 xmlOutputCallbackTable
[i
].writecallback
= NULL
;
544 xmlOutputCallbackTable
[i
].closecallback
= NULL
;
547 xmlOutputCallbackNr
= 0;
548 xmlOutputCallbackInitialized
= 0;
552 * xmlPopOutputCallbacks:
554 * Remove the top output callbacks from the output stack. This includes the
557 * Returns the number of output callback registered or -1 in case of error.
560 xmlPopOutputCallbacks(void)
562 if (!xmlOutputCallbackInitialized
)
565 if (xmlOutputCallbackNr
<= 0)
568 xmlOutputCallbackNr
--;
569 xmlOutputCallbackTable
[xmlOutputCallbackNr
].matchcallback
= NULL
;
570 xmlOutputCallbackTable
[xmlOutputCallbackNr
].opencallback
= NULL
;
571 xmlOutputCallbackTable
[xmlOutputCallbackNr
].writecallback
= NULL
;
572 xmlOutputCallbackTable
[xmlOutputCallbackNr
].closecallback
= NULL
;
574 return(xmlOutputCallbackNr
);
577 #endif /* LIBXML_OUTPUT_ENABLED */
579 /************************************************************************
581 * Standard I/O for file accesses *
583 ************************************************************************/
589 * @path: the path in utf-8 encoding
590 * @mode: type of access (0 - read, 1 - write)
592 * function opens the file specified by @path
596 xmlWrapOpenUtf8(const char *path
,int mode
)
601 wPath
= __xmlIOWin32UTF8ToWChar(path
);
604 fd
= _wfopen(wPath
, mode
? L
"wb" : L
"rb");
607 /* maybe path in native encoding */
609 fd
= fopen(path
, mode
? "wb" : "rb");
614 #ifdef LIBXML_ZLIB_ENABLED
616 xmlWrapGzOpenUtf8(const char *path
, const char *mode
)
621 fd
= gzopen (path
, mode
);
625 wPath
= __xmlIOWin32UTF8ToWChar(path
);
628 int d
, m
= (strstr(mode
, "r") ? O_RDONLY
: O_RDWR
);
630 m
|= (strstr(mode
, "b") ? _O_BINARY
: 0);
632 d
= _wopen(wPath
, m
);
634 fd
= gzdopen(d
, mode
);
644 * @path: the path in utf-8 encoding
645 * @info: structure that stores results
647 * function obtains information about the file or directory
651 xmlWrapStatUtf8(const char *path
, struct _stat
*info
) {
655 wPath
= __xmlIOWin32UTF8ToWChar(path
);
657 retval
= _wstat(wPath
, info
);
660 /* maybe path in native encoding */
662 retval
= _stat(path
, info
);
670 * @path: the path to check
672 * function checks to see if @path is a valid source
673 * (file, socket...) for XML.
675 * if stat is not available on the target machine,
676 * returns 1. if stat fails, returns 0 (if calling
677 * stat on the filename fails, it can't be right).
678 * if stat succeeds and the file is a directory,
679 * returns 2. otherwise returns 1.
683 xmlCheckFilename (const char *path
)
687 struct _stat stat_buffer
;
689 struct stat stat_buffer
;
698 * On Windows stat and wstat do not work with long pathname,
699 * which start with '\\?\'
701 if ((path
[0] == '\\') && (path
[1] == '\\') && (path
[2] == '?') &&
705 if (xmlWrapStatUtf8(path
, &stat_buffer
) == -1)
708 if (stat(path
, &stat_buffer
) == -1)
712 if (S_ISDIR(stat_buffer
.st_mode
))
715 #endif /* HAVE_STAT */
721 * @context: the I/O context
722 * @buffer: where to drop data
723 * @len: number of bytes to read
725 * Read @len bytes to @buffer from the I/O channel.
727 * Returns the number of bytes written
730 xmlFdRead (void * context
, char * buffer
, int len
) {
733 ret
= read((int) (ptrdiff_t) context
, &buffer
[0], len
);
734 if (ret
< 0) xmlIOErr(0, "read()");
738 #ifdef LIBXML_OUTPUT_ENABLED
741 * @context: the I/O context
742 * @buffer: where to get data
743 * @len: number of bytes to write
745 * Write @len bytes from @buffer to the I/O channel.
747 * Returns the number of bytes written
750 xmlFdWrite (void * context
, const char * buffer
, int len
) {
754 ret
= write((int) (ptrdiff_t) context
, &buffer
[0], len
);
755 if (ret
< 0) xmlIOErr(0, "write()");
759 #endif /* LIBXML_OUTPUT_ENABLED */
763 * @context: the I/O context
765 * Close an I/O channel
767 * Returns 0 in case of success and error code otherwise
770 xmlFdClose (void * context
) {
772 ret
= close((int) (ptrdiff_t) context
);
773 if (ret
< 0) xmlIOErr(0, "close()");
779 * @filename: the URI for matching
783 * Returns 1 if matches, 0 otherwise
786 xmlFileMatch (const char *filename ATTRIBUTE_UNUSED
) {
792 * @filename: the URI for matching
794 * input from FILE *, supports compressed input
795 * if @filename is " " then the standard input is used
797 * Returns an I/O context or NULL in case of error
800 xmlFileOpen_real (const char *filename
) {
801 const char *path
= filename
;
804 if (filename
== NULL
)
807 if (!strcmp(filename
, "-")) {
812 if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file://localhost/", 17)) {
814 path
= &filename
[17];
816 path
= &filename
[16];
818 } else if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file:///", 8)) {
824 } else if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file:/", 6)) {
825 /* lots of generators seems to lazy to read RFC 1738 */
833 /* Do not check DDNAME on zOS ! */
834 #if !defined(__MVS__)
835 if (!xmlCheckFilename(path
))
840 fd
= xmlWrapOpenUtf8(path
, 0);
842 fd
= fopen(path
, "rb");
844 if (fd
== NULL
) xmlIOErr(0, path
);
850 * @filename: the URI for matching
852 * Wrapper around xmlFileOpen_real that try it with an unescaped
853 * version of @filename, if this fails fallback to @filename
855 * Returns a handler or NULL in case or failure
858 xmlFileOpen (const char *filename
) {
862 retval
= xmlFileOpen_real(filename
);
863 if (retval
== NULL
) {
864 unescaped
= xmlURIUnescapeString(filename
, 0, NULL
);
865 if (unescaped
!= NULL
) {
866 retval
= xmlFileOpen_real(unescaped
);
874 #ifdef LIBXML_OUTPUT_ENABLED
877 * @filename: the URI for matching
879 * output to from FILE *,
880 * if @filename is "-" then the standard output is used
882 * Returns an I/O context or NULL in case of error
885 xmlFileOpenW (const char *filename
) {
886 const char *path
= NULL
;
889 if (!strcmp(filename
, "-")) {
894 if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file://localhost/", 17))
896 path
= &filename
[17];
898 path
= &filename
[16];
900 else if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file:///", 8)) {
913 fd
= xmlWrapOpenUtf8(path
, 1);
915 fd
= fopen(path
, "w");
917 fd
= fopen(path
, "wb");
920 if (fd
== NULL
) xmlIOErr(0, path
);
923 #endif /* LIBXML_OUTPUT_ENABLED */
927 * @context: the I/O context
928 * @buffer: where to drop data
929 * @len: number of bytes to write
931 * Read @len bytes to @buffer from the I/O channel.
933 * Returns the number of bytes written or < 0 in case of failure
936 xmlFileRead (void * context
, char * buffer
, int len
) {
938 if ((context
== NULL
) || (buffer
== NULL
))
940 ret
= fread(&buffer
[0], 1, len
, (FILE *) context
);
941 if (ret
< 0) xmlIOErr(0, "fread()");
945 #ifdef LIBXML_OUTPUT_ENABLED
948 * @context: the I/O context
949 * @buffer: where to drop data
950 * @len: number of bytes to write
952 * Write @len bytes from @buffer to the I/O channel.
954 * Returns the number of bytes written
957 xmlFileWrite (void * context
, const char * buffer
, int len
) {
960 if ((context
== NULL
) || (buffer
== NULL
))
962 items
= fwrite(&buffer
[0], len
, 1, (FILE *) context
);
963 if ((items
== 0) && (ferror((FILE *) context
))) {
964 xmlIOErr(0, "fwrite()");
969 #endif /* LIBXML_OUTPUT_ENABLED */
973 * @context: the I/O context
975 * Close an I/O channel
977 * Returns 0 or -1 in case of error
980 xmlFileClose (void * context
) {
986 fil
= (FILE *) context
;
987 if ((fil
== stdout
) || (fil
== stderr
)) {
990 xmlIOErr(0, "fflush()");
995 ret
= ( fclose((FILE *) context
) == EOF
) ? -1 : 0;
997 xmlIOErr(0, "fclose()");
1003 * @context: the I/O context
1005 * Flush an I/O channel
1008 xmlFileFlush (void * context
) {
1011 if (context
== NULL
)
1013 ret
= ( fflush((FILE *) context
) == EOF
) ? -1 : 0;
1015 xmlIOErr(0, "fflush()");
1019 #ifdef LIBXML_OUTPUT_ENABLED
1022 * @context: the xmlBuffer
1023 * @buffer: the data to write
1024 * @len: number of bytes to write
1026 * Write @len bytes from @buffer to the xml buffer
1028 * Returns the number of bytes written
1031 xmlBufferWrite (void * context
, const char * buffer
, int len
) {
1034 ret
= xmlBufferAdd((xmlBufferPtr
) context
, (const xmlChar
*) buffer
, len
);
1041 #ifdef LIBXML_ZLIB_ENABLED
1042 /************************************************************************
1044 * I/O for compressed file accesses *
1046 ************************************************************************/
1049 * @filename: the URI for matching
1051 * input from compressed file test
1053 * Returns 1 if matches, 0 otherwise
1056 xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED
) {
1061 * xmlGzfileOpen_real:
1062 * @filename: the URI for matching
1064 * input from compressed file open
1065 * if @filename is " " then the standard input is used
1067 * Returns an I/O context or NULL in case of error
1070 xmlGzfileOpen_real (const char *filename
) {
1071 const char *path
= NULL
;
1074 if (!strcmp(filename
, "-")) {
1075 int duped_fd
= dup(fileno(stdin
));
1076 fd
= gzdopen(duped_fd
, "rb");
1077 if (fd
== Z_NULL
&& duped_fd
>= 0) {
1078 close(duped_fd
); /* gzdOpen() does not close on failure */
1081 return((void *) fd
);
1084 if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file://localhost/", 17))
1085 #if defined (_WIN32)
1086 path
= &filename
[17];
1088 path
= &filename
[16];
1090 else if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file:///", 8)) {
1091 #if defined (_WIN32)
1092 path
= &filename
[8];
1094 path
= &filename
[7];
1101 if (!xmlCheckFilename(path
))
1105 fd
= xmlWrapGzOpenUtf8(path
, "rb");
1107 fd
= gzopen(path
, "rb");
1109 return((void *) fd
);
1114 * @filename: the URI for matching
1116 * Wrapper around xmlGzfileOpen_real if the open fails, it will
1117 * try to unescape @filename
1120 xmlGzfileOpen (const char *filename
) {
1124 retval
= xmlGzfileOpen_real(filename
);
1125 if (retval
== NULL
) {
1126 unescaped
= xmlURIUnescapeString(filename
, 0, NULL
);
1127 if (unescaped
!= NULL
) {
1128 retval
= xmlGzfileOpen_real(unescaped
);
1135 #ifdef LIBXML_OUTPUT_ENABLED
1138 * @filename: the URI for matching
1139 * @compression: the compression factor (0 - 9 included)
1141 * input from compressed file open
1142 * if @filename is " " then the standard input is used
1144 * Returns an I/O context or NULL in case of error
1147 xmlGzfileOpenW (const char *filename
, int compression
) {
1148 const char *path
= NULL
;
1152 snprintf(mode
, sizeof(mode
), "wb%d", compression
);
1153 if (!strcmp(filename
, "-")) {
1154 int duped_fd
= dup(fileno(stdout
));
1155 fd
= gzdopen(duped_fd
, "rb");
1156 if (fd
== Z_NULL
&& duped_fd
>= 0) {
1157 close(duped_fd
); /* gzdOpen() does not close on failure */
1160 return((void *) fd
);
1163 if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file://localhost/", 17))
1164 #if defined (_WIN32)
1165 path
= &filename
[17];
1167 path
= &filename
[16];
1169 else if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file:///", 8)) {
1170 #if defined (_WIN32)
1171 path
= &filename
[8];
1173 path
= &filename
[7];
1182 fd
= xmlWrapGzOpenUtf8(path
, mode
);
1184 fd
= gzopen(path
, mode
);
1186 return((void *) fd
);
1188 #endif /* LIBXML_OUTPUT_ENABLED */
1192 * @context: the I/O context
1193 * @buffer: where to drop data
1194 * @len: number of bytes to write
1196 * Read @len bytes to @buffer from the compressed I/O channel.
1198 * Returns the number of bytes read.
1201 xmlGzfileRead (void * context
, char * buffer
, int len
) {
1204 ret
= gzread((gzFile
) context
, &buffer
[0], len
);
1205 if (ret
< 0) xmlIOErr(0, "gzread()");
1209 #ifdef LIBXML_OUTPUT_ENABLED
1212 * @context: the I/O context
1213 * @buffer: where to drop data
1214 * @len: number of bytes to write
1216 * Write @len bytes from @buffer to the compressed I/O channel.
1218 * Returns the number of bytes written
1221 xmlGzfileWrite (void * context
, const char * buffer
, int len
) {
1224 ret
= gzwrite((gzFile
) context
, (char *) &buffer
[0], len
);
1225 if (ret
< 0) xmlIOErr(0, "gzwrite()");
1228 #endif /* LIBXML_OUTPUT_ENABLED */
1232 * @context: the I/O context
1234 * Close a compressed I/O channel
1237 xmlGzfileClose (void * context
) {
1240 ret
= (gzclose((gzFile
) context
) == Z_OK
) ? 0 : -1;
1241 if (ret
< 0) xmlIOErr(0, "gzclose()");
1244 #endif /* LIBXML_ZLIB_ENABLED */
1246 #ifdef LIBXML_LZMA_ENABLED
1247 /************************************************************************
1249 * I/O for compressed file accesses *
1251 ************************************************************************/
1252 #include "private/xzlib.h"
1255 * @filename: the URI for matching
1257 * input from compressed file test
1259 * Returns 1 if matches, 0 otherwise
1262 xmlXzfileMatch (const char *filename ATTRIBUTE_UNUSED
) {
1267 * xmlXzFileOpen_real:
1268 * @filename: the URI for matching
1270 * input from compressed file open
1271 * if @filename is " " then the standard input is used
1273 * Returns an I/O context or NULL in case of error
1276 xmlXzfileOpen_real (const char *filename
) {
1277 const char *path
= NULL
;
1280 if (!strcmp(filename
, "-")) {
1281 fd
= __libxml2_xzdopen(dup(fileno(stdin
)), "rb");
1282 return((void *) fd
);
1285 if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file://localhost/", 17)) {
1286 path
= &filename
[16];
1287 } else if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file:///", 8)) {
1288 path
= &filename
[7];
1289 } else if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file:/", 6)) {
1290 /* lots of generators seems to lazy to read RFC 1738 */
1291 path
= &filename
[5];
1297 if (!xmlCheckFilename(path
))
1300 fd
= __libxml2_xzopen(path
, "rb");
1301 return((void *) fd
);
1306 * @filename: the URI for matching
1308 * Wrapper around xmlXzfileOpen_real that try it with an unescaped
1309 * version of @filename, if this fails fallback to @filename
1311 * Returns a handler or NULL in case or failure
1314 xmlXzfileOpen (const char *filename
) {
1318 retval
= xmlXzfileOpen_real(filename
);
1319 if (retval
== NULL
) {
1320 unescaped
= xmlURIUnescapeString(filename
, 0, NULL
);
1321 if (unescaped
!= NULL
) {
1322 retval
= xmlXzfileOpen_real(unescaped
);
1332 * @context: the I/O context
1333 * @buffer: where to drop data
1334 * @len: number of bytes to write
1336 * Read @len bytes to @buffer from the compressed I/O channel.
1338 * Returns the number of bytes written
1341 xmlXzfileRead (void * context
, char * buffer
, int len
) {
1344 ret
= __libxml2_xzread((xzFile
) context
, &buffer
[0], len
);
1345 if (ret
< 0) xmlIOErr(0, "xzread()");
1351 * @context: the I/O context
1353 * Close a compressed I/O channel
1356 xmlXzfileClose (void * context
) {
1359 ret
= (__libxml2_xzclose((xzFile
) context
) == LZMA_OK
) ? 0 : -1;
1360 if (ret
< 0) xmlIOErr(0, "xzclose()");
1363 #endif /* LIBXML_LZMA_ENABLED */
1365 #ifdef LIBXML_HTTP_ENABLED
1366 /************************************************************************
1368 * I/O for HTTP file accesses *
1370 ************************************************************************/
1372 #ifdef LIBXML_OUTPUT_ENABLED
1373 typedef struct xmlIOHTTPWriteCtxt_
1381 } xmlIOHTTPWriteCtxt
, *xmlIOHTTPWriteCtxtPtr
;
1383 #ifdef LIBXML_ZLIB_ENABLED
1385 #define DFLT_WBITS ( -15 )
1386 #define DFLT_MEM_LVL ( 8 )
1387 #define GZ_MAGIC1 ( 0x1f )
1388 #define GZ_MAGIC2 ( 0x8b )
1389 #define LXML_ZLIB_OS_CODE ( 0x03 )
1390 #define INIT_HTTP_BUFF_SIZE ( 32768 )
1391 #define DFLT_ZLIB_RATIO ( 5 )
1394 ** Data structure and functions to work with sending compressed data
1398 typedef struct xmlZMemBuff_
1403 unsigned char * zbuff
;
1406 } xmlZMemBuff
, *xmlZMemBuffPtr
;
1409 * append_reverse_ulong
1410 * @buff: Compressed memory buffer
1411 * @data: Unsigned long to append
1413 * Append a unsigned long in reverse byte order to the end of the
1417 append_reverse_ulong( xmlZMemBuff
* buff
, unsigned long data
) {
1425 ** This is plagiarized from putLong in gzio.c (zlib source) where
1426 ** the number "4" is hardcoded. If zlib is ever patched to
1427 ** support 64 bit file sizes, this code would need to be patched
1431 for ( idx
= 0; idx
< 4; idx
++ ) {
1432 *buff
->zctrl
.next_out
= ( data
& 0xff );
1434 buff
->zctrl
.next_out
++;
1443 * @buff: The memory buffer context to clear
1445 * Release all the resources associated with the compressed memory buffer.
1448 xmlFreeZMemBuff( xmlZMemBuffPtr buff
) {
1457 xmlFree( buff
->zbuff
);
1459 z_err
= deflateEnd( &buff
->zctrl
);
1460 if ( z_err
!= Z_OK
)
1461 xmlGenericError( xmlGenericErrorContext
,
1462 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
1465 deflateEnd( &buff
->zctrl
);
1474 *@compression: Compression value to use
1476 * Create a memory buffer to hold the compressed XML document. The
1477 * compressed document in memory will end up being identical to what
1478 * would be created if gzopen/gzwrite/gzclose were being used to
1479 * write the document to disk. The code for the header/trailer data to
1480 * the compression is plagiarized from the zlib source files.
1483 xmlCreateZMemBuff( int compression
) {
1487 xmlZMemBuffPtr buff
= NULL
;
1489 if ( ( compression
< 1 ) || ( compression
> 9 ) )
1492 /* Create the control and data areas */
1494 buff
= xmlMalloc( sizeof( xmlZMemBuff
) );
1495 if ( buff
== NULL
) {
1496 xmlIOErrMemory("creating buffer context");
1500 (void)memset( buff
, 0, sizeof( xmlZMemBuff
) );
1501 buff
->size
= INIT_HTTP_BUFF_SIZE
;
1502 buff
->zbuff
= xmlMalloc( buff
->size
);
1503 if ( buff
->zbuff
== NULL
) {
1504 xmlFreeZMemBuff( buff
);
1505 xmlIOErrMemory("creating buffer");
1509 z_err
= deflateInit2( &buff
->zctrl
, compression
, Z_DEFLATED
,
1510 DFLT_WBITS
, DFLT_MEM_LVL
, Z_DEFAULT_STRATEGY
);
1511 if ( z_err
!= Z_OK
) {
1513 xmlFreeZMemBuff( buff
);
1515 xmlStrPrintf(msg
, 500,
1516 "xmlCreateZMemBuff: %s %d\n",
1517 "Error initializing compression context. ZLIB error:",
1519 xmlIOErr(XML_IO_WRITE
, (const char *) msg
);
1523 /* Set the header data. The CRC will be needed for the trailer */
1524 buff
->crc
= crc32( 0L, NULL
, 0 );
1525 hdr_lgth
= snprintf( (char *)buff
->zbuff
, buff
->size
,
1526 "%c%c%c%c%c%c%c%c%c%c",
1527 GZ_MAGIC1
, GZ_MAGIC2
, Z_DEFLATED
,
1528 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE
);
1529 buff
->zctrl
.next_out
= buff
->zbuff
+ hdr_lgth
;
1530 buff
->zctrl
.avail_out
= buff
->size
- hdr_lgth
;
1537 * @buff: Buffer used to compress and consolidate data.
1538 * @ext_amt: Number of bytes to extend the buffer.
1540 * Extend the internal buffer used to store the compressed data by the
1543 * Returns 0 on success or -1 on failure to extend the buffer. On failure
1544 * the original buffer still exists at the original size.
1547 xmlZMemBuffExtend( xmlZMemBuffPtr buff
, size_t ext_amt
) {
1553 unsigned char * tmp_ptr
= NULL
;
1558 else if ( ext_amt
== 0 )
1561 cur_used
= buff
->zctrl
.next_out
- buff
->zbuff
;
1562 new_size
= buff
->size
+ ext_amt
;
1565 if ( cur_used
> new_size
)
1566 xmlGenericError( xmlGenericErrorContext
,
1567 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
1568 "Buffer overwrite detected during compressed memory",
1569 "buffer extension. Overflowed by",
1570 (cur_used
- new_size
) );
1573 tmp_ptr
= xmlRealloc( buff
->zbuff
, new_size
);
1574 if ( tmp_ptr
!= NULL
) {
1576 buff
->size
= new_size
;
1577 buff
->zbuff
= tmp_ptr
;
1578 buff
->zctrl
.next_out
= tmp_ptr
+ cur_used
;
1579 buff
->zctrl
.avail_out
= new_size
- cur_used
;
1583 xmlStrPrintf(msg
, 500,
1584 "xmlZMemBuffExtend: %s %lu bytes.\n",
1585 "Allocation failure extending output buffer to",
1586 (unsigned long) new_size
);
1587 xmlIOErr(XML_IO_WRITE
, (const char *) msg
);
1595 * @buff: Buffer used to compress and consolidate data
1596 * @src: Uncompressed source content to append to buffer
1597 * @len: Length of source data to append to buffer
1599 * Compress and append data to the internal buffer. The data buffer
1600 * will be expanded if needed to store the additional data.
1602 * Returns the number of bytes appended to the buffer or -1 on error.
1605 xmlZMemBuffAppend( xmlZMemBuffPtr buff
, const char * src
, int len
) {
1610 if ( ( buff
== NULL
) || ( src
== NULL
) )
1613 buff
->zctrl
.avail_in
= len
;
1614 buff
->zctrl
.next_in
= (unsigned char *)src
;
1615 while ( buff
->zctrl
.avail_in
> 0 ) {
1617 ** Extend the buffer prior to deflate call if a reasonable amount
1618 ** of output buffer space is not available.
1620 min_accept
= buff
->zctrl
.avail_in
/ DFLT_ZLIB_RATIO
;
1621 if ( buff
->zctrl
.avail_out
<= min_accept
) {
1622 if ( xmlZMemBuffExtend( buff
, buff
->size
) == -1 )
1626 z_err
= deflate( &buff
->zctrl
, Z_NO_FLUSH
);
1627 if ( z_err
!= Z_OK
) {
1629 xmlStrPrintf(msg
, 500,
1630 "xmlZMemBuffAppend: %s %d %s - %d",
1631 "Compression error while appending",
1632 len
, "bytes to buffer. ZLIB error", z_err
);
1633 xmlIOErr(XML_IO_WRITE
, (const char *) msg
);
1638 buff
->crc
= crc32( buff
->crc
, (unsigned char *)src
, len
);
1644 * xmlZMemBuffGetContent
1645 * @buff: Compressed memory content buffer
1646 * @data_ref: Pointer reference to point to compressed content
1648 * Flushes the compression buffers, appends gzip file trailers and
1649 * returns the compressed content and length of the compressed data.
1650 * NOTE: The gzip trailer code here is plagiarized from zlib source.
1652 * Returns the length of the compressed data or -1 on error.
1655 xmlZMemBuffGetContent( xmlZMemBuffPtr buff
, char ** data_ref
) {
1660 if ( ( buff
== NULL
) || ( data_ref
== NULL
) )
1663 /* Need to loop until compression output buffers are flushed */
1667 z_err
= deflate( &buff
->zctrl
, Z_FINISH
);
1668 if ( z_err
== Z_OK
) {
1669 /* In this case Z_OK means more buffer space needed */
1671 if ( xmlZMemBuffExtend( buff
, buff
->size
) == -1 )
1675 while ( z_err
== Z_OK
);
1677 /* If the compression state is not Z_STREAM_END, some error occurred */
1679 if ( z_err
== Z_STREAM_END
) {
1681 /* Need to append the gzip data trailer */
1683 if ( buff
->zctrl
.avail_out
< ( 2 * sizeof( unsigned long ) ) ) {
1684 if ( xmlZMemBuffExtend(buff
, (2 * sizeof(unsigned long))) == -1 )
1689 ** For whatever reason, the CRC and length data are pushed out
1690 ** in reverse byte order. So a memcpy can't be used here.
1693 append_reverse_ulong( buff
, buff
->crc
);
1694 append_reverse_ulong( buff
, buff
->zctrl
.total_in
);
1696 zlgth
= buff
->zctrl
.next_out
- buff
->zbuff
;
1697 *data_ref
= (char *)buff
->zbuff
;
1702 xmlStrPrintf(msg
, 500,
1703 "xmlZMemBuffGetContent: %s - %d\n",
1704 "Error flushing zlib buffers. Error code", z_err
);
1705 xmlIOErr(XML_IO_WRITE
, (const char *) msg
);
1710 #endif /* LIBXML_OUTPUT_ENABLED */
1711 #endif /* LIBXML_ZLIB_ENABLED */
1713 #ifdef LIBXML_OUTPUT_ENABLED
1715 * xmlFreeHTTPWriteCtxt
1716 * @ctxt: Context to cleanup
1718 * Free allocated memory and reclaim system resources.
1723 xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt
)
1725 if ( ctxt
->uri
!= NULL
)
1726 xmlFree( ctxt
->uri
);
1728 if ( ctxt
->doc_buff
!= NULL
) {
1730 #ifdef LIBXML_ZLIB_ENABLED
1731 if ( ctxt
->compression
> 0 ) {
1732 xmlFreeZMemBuff( ctxt
->doc_buff
);
1737 xmlOutputBufferClose( ctxt
->doc_buff
);
1744 #endif /* LIBXML_OUTPUT_ENABLED */
1749 * @filename: the URI for matching
1751 * check if the URI matches an HTTP one
1753 * Returns 1 if matches, 0 otherwise
1756 xmlIOHTTPMatch (const char *filename
) {
1757 if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"http://", 7))
1764 * @filename: the URI for matching
1766 * open an HTTP I/O channel
1768 * Returns an I/O context or NULL in case of error
1771 xmlIOHTTPOpen (const char *filename
) {
1772 return(xmlNanoHTTPOpen(filename
, NULL
));
1775 #ifdef LIBXML_OUTPUT_ENABLED
1778 * @post_uri: The destination URI for the document
1779 * @compression: The compression desired for the document.
1781 * Open a temporary buffer to collect the document for a subsequent HTTP POST
1782 * request. Non-static as is called from the output buffer creation routine.
1784 * Returns an I/O context or NULL in case of error.
1788 xmlIOHTTPOpenW(const char *post_uri
, int compression ATTRIBUTE_UNUSED
)
1791 xmlIOHTTPWriteCtxtPtr ctxt
= NULL
;
1793 if (post_uri
== NULL
)
1796 ctxt
= xmlMalloc(sizeof(xmlIOHTTPWriteCtxt
));
1798 xmlIOErrMemory("creating HTTP output context");
1802 (void) memset(ctxt
, 0, sizeof(xmlIOHTTPWriteCtxt
));
1804 ctxt
->uri
= (char *) xmlStrdup((const xmlChar
*)post_uri
);
1805 if (ctxt
->uri
== NULL
) {
1806 xmlIOErrMemory("copying URI");
1807 xmlFreeHTTPWriteCtxt(ctxt
);
1812 * ** Since the document length is required for an HTTP post,
1813 * ** need to put the document into a buffer. A memory buffer
1814 * ** is being used to avoid pushing the data to disk and back.
1817 #ifdef LIBXML_ZLIB_ENABLED
1818 if ((compression
> 0) && (compression
<= 9)) {
1820 ctxt
->compression
= compression
;
1821 ctxt
->doc_buff
= xmlCreateZMemBuff(compression
);
1825 /* Any character conversions should have been done before this */
1827 ctxt
->doc_buff
= xmlAllocOutputBufferInternal(NULL
);
1830 if (ctxt
->doc_buff
== NULL
) {
1831 xmlFreeHTTPWriteCtxt(ctxt
);
1837 #endif /* LIBXML_OUTPUT_ENABLED */
1839 #ifdef LIBXML_OUTPUT_ENABLED
1841 * xmlIOHTTPDfltOpenW
1842 * @post_uri: The destination URI for this document.
1844 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
1845 * HTTP post command. This function should generally not be used as
1846 * the open callback is short circuited in xmlOutputBufferCreateFile.
1848 * Returns a pointer to the new IO context.
1851 xmlIOHTTPDfltOpenW( const char * post_uri
) {
1852 return ( xmlIOHTTPOpenW( post_uri
, 0 ) );
1854 #endif /* LIBXML_OUTPUT_ENABLED */
1858 * @context: the I/O context
1859 * @buffer: where to drop data
1860 * @len: number of bytes to write
1862 * Read @len bytes to @buffer from the I/O channel.
1864 * Returns the number of bytes written
1867 xmlIOHTTPRead(void * context
, char * buffer
, int len
) {
1868 if ((buffer
== NULL
) || (len
< 0)) return(-1);
1869 return(xmlNanoHTTPRead(context
, &buffer
[0], len
));
1872 #ifdef LIBXML_OUTPUT_ENABLED
1875 * @context: previously opened writing context
1876 * @buffer: data to output to temporary buffer
1877 * @len: bytes to output
1879 * Collect data from memory buffer into a temporary file for later
1882 * Returns number of bytes written.
1886 xmlIOHTTPWrite( void * context
, const char * buffer
, int len
) {
1888 xmlIOHTTPWriteCtxtPtr ctxt
= context
;
1890 if ( ( ctxt
== NULL
) || ( ctxt
->doc_buff
== NULL
) || ( buffer
== NULL
) )
1895 /* Use gzwrite or fwrite as previously setup in the open call */
1897 #ifdef LIBXML_ZLIB_ENABLED
1898 if ( ctxt
->compression
> 0 )
1899 len
= xmlZMemBuffAppend( ctxt
->doc_buff
, buffer
, len
);
1903 len
= xmlOutputBufferWrite( ctxt
->doc_buff
, len
, buffer
);
1907 xmlStrPrintf(msg
, 500,
1908 "xmlIOHTTPWrite: %s\n%s '%s'.\n",
1909 "Error appending to internal buffer.",
1910 "Error sending document to URI",
1912 xmlIOErr(XML_IO_WRITE
, (const char *) msg
);
1918 #endif /* LIBXML_OUTPUT_ENABLED */
1923 * @context: the I/O context
1925 * Close an HTTP I/O channel
1930 xmlIOHTTPClose (void * context
) {
1931 xmlNanoHTTPClose(context
);
1935 #ifdef LIBXML_OUTPUT_ENABLED
1937 * xmlIOHTTCloseWrite
1938 * @context: The I/O context
1939 * @http_mthd: The HTTP method to be used when sending the data
1941 * Close the transmit HTTP I/O channel and actually send the data.
1944 xmlIOHTTPCloseWrite( void * context
, const char * http_mthd
) {
1948 int content_lgth
= 0;
1949 xmlIOHTTPWriteCtxtPtr ctxt
= context
;
1951 char * http_content
= NULL
;
1952 char * content_encoding
= NULL
;
1953 char * content_type
= (char *) "text/xml";
1954 void * http_ctxt
= NULL
;
1956 if ( ( ctxt
== NULL
) || ( http_mthd
== NULL
) )
1959 /* Retrieve the content from the appropriate buffer */
1961 #ifdef LIBXML_ZLIB_ENABLED
1963 if ( ctxt
->compression
> 0 ) {
1964 content_lgth
= xmlZMemBuffGetContent( ctxt
->doc_buff
, &http_content
);
1965 content_encoding
= (char *) "Content-Encoding: gzip";
1970 /* Pull the data out of the memory output buffer */
1972 xmlOutputBufferPtr dctxt
= ctxt
->doc_buff
;
1973 http_content
= (char *) xmlBufContent(dctxt
->buffer
);
1974 content_lgth
= xmlBufUse(dctxt
->buffer
);
1977 if ( http_content
== NULL
) {
1979 xmlStrPrintf(msg
, 500,
1980 "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
1981 "Error retrieving content.\nUnable to",
1982 http_mthd
, "data to URI", ctxt
->uri
);
1983 xmlIOErr(XML_IO_WRITE
, (const char *) msg
);
1988 http_ctxt
= xmlNanoHTTPMethod( ctxt
->uri
, http_mthd
, http_content
,
1989 &content_type
, content_encoding
,
1992 if ( http_ctxt
!= NULL
) {
1994 /* If testing/debugging - dump reply with request content */
1996 FILE * tst_file
= NULL
;
1997 char buffer
[ 4096 ];
1998 char * dump_name
= NULL
;
2001 xmlGenericError( xmlGenericErrorContext
,
2002 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
2003 http_mthd
, ctxt
->uri
,
2004 xmlNanoHTTPReturnCode( http_ctxt
) );
2007 ** Since either content or reply may be gzipped,
2008 ** dump them to separate files instead of the
2009 ** standard error context.
2012 dump_name
= tempnam( NULL
, "lxml" );
2013 if ( dump_name
!= NULL
) {
2014 (void)snprintf( buffer
, sizeof(buffer
), "%s.content", dump_name
);
2016 tst_file
= fopen( buffer
, "wb" );
2017 if ( tst_file
!= NULL
) {
2018 xmlGenericError( xmlGenericErrorContext
,
2019 "Transmitted content saved in file: %s\n", buffer
);
2021 fwrite( http_content
, 1, content_lgth
, tst_file
);
2025 (void)snprintf( buffer
, sizeof(buffer
), "%s.reply", dump_name
);
2026 tst_file
= fopen( buffer
, "wb" );
2027 if ( tst_file
!= NULL
) {
2028 xmlGenericError( xmlGenericErrorContext
,
2029 "Reply content saved in file: %s\n", buffer
);
2032 while ( (avail
= xmlNanoHTTPRead( http_ctxt
,
2033 buffer
, sizeof( buffer
) )) > 0 ) {
2035 fwrite( buffer
, 1, avail
, tst_file
);
2043 #endif /* DEBUG_HTTP */
2045 http_rtn
= xmlNanoHTTPReturnCode( http_ctxt
);
2046 if ( ( http_rtn
>= 200 ) && ( http_rtn
< 300 ) )
2050 xmlStrPrintf(msg
, 500,
2051 "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
2052 http_mthd
, content_lgth
,
2053 "bytes to URI", ctxt
->uri
,
2054 "failed. HTTP return code:", http_rtn
);
2055 xmlIOErr(XML_IO_WRITE
, (const char *) msg
);
2058 xmlNanoHTTPClose( http_ctxt
);
2059 xmlFree( content_type
);
2063 /* Final cleanups */
2065 xmlFreeHTTPWriteCtxt( ctxt
);
2067 return ( close_rc
);
2073 * @context: The I/O context
2075 * Close the transmit HTTP I/O channel and actually send data using a PUT
2079 xmlIOHTTPClosePut( void * ctxt
) {
2080 return ( xmlIOHTTPCloseWrite( ctxt
, "PUT" ) );
2085 * xmlIOHTTPClosePost
2087 * @context: The I/O context
2089 * Close the transmit HTTP I/O channel and actually send data using a POST
2093 xmlIOHTTPClosePost( void * ctxt
) {
2094 return ( xmlIOHTTPCloseWrite( ctxt
, "POST" ) );
2096 #endif /* LIBXML_OUTPUT_ENABLED */
2098 #endif /* LIBXML_HTTP_ENABLED */
2100 #ifdef LIBXML_FTP_ENABLED
2101 /************************************************************************
2103 * I/O for FTP file accesses *
2105 ************************************************************************/
2108 * @filename: the URI for matching
2110 * check if the URI matches an FTP one
2112 * Returns 1 if matches, 0 otherwise
2115 xmlIOFTPMatch (const char *filename
) {
2116 if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"ftp://", 6))
2123 * @filename: the URI for matching
2125 * open an FTP I/O channel
2127 * Returns an I/O context or NULL in case of error
2130 xmlIOFTPOpen (const char *filename
) {
2131 return(xmlNanoFTPOpen(filename
));
2136 * @context: the I/O context
2137 * @buffer: where to drop data
2138 * @len: number of bytes to write
2140 * Read @len bytes to @buffer from the I/O channel.
2142 * Returns the number of bytes written
2145 xmlIOFTPRead(void * context
, char * buffer
, int len
) {
2146 if ((buffer
== NULL
) || (len
< 0)) return(-1);
2147 return(xmlNanoFTPRead(context
, &buffer
[0], len
));
2152 * @context: the I/O context
2154 * Close an FTP I/O channel
2159 xmlIOFTPClose (void * context
) {
2160 return ( xmlNanoFTPClose(context
) );
2162 #endif /* LIBXML_FTP_ENABLED */
2166 * xmlRegisterInputCallbacks:
2167 * @matchFunc: the xmlInputMatchCallback
2168 * @openFunc: the xmlInputOpenCallback
2169 * @readFunc: the xmlInputReadCallback
2170 * @closeFunc: the xmlInputCloseCallback
2172 * Register a new set of I/O callback for handling parser input.
2174 * Returns the registered handler number or -1 in case of error
2177 xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc
,
2178 xmlInputOpenCallback openFunc
, xmlInputReadCallback readFunc
,
2179 xmlInputCloseCallback closeFunc
) {
2180 if (xmlInputCallbackNr
>= MAX_INPUT_CALLBACK
) {
2183 xmlInputCallbackTable
[xmlInputCallbackNr
].matchcallback
= matchFunc
;
2184 xmlInputCallbackTable
[xmlInputCallbackNr
].opencallback
= openFunc
;
2185 xmlInputCallbackTable
[xmlInputCallbackNr
].readcallback
= readFunc
;
2186 xmlInputCallbackTable
[xmlInputCallbackNr
].closecallback
= closeFunc
;
2187 xmlInputCallbackInitialized
= 1;
2188 return(xmlInputCallbackNr
++);
2191 #ifdef LIBXML_OUTPUT_ENABLED
2193 * xmlRegisterOutputCallbacks:
2194 * @matchFunc: the xmlOutputMatchCallback
2195 * @openFunc: the xmlOutputOpenCallback
2196 * @writeFunc: the xmlOutputWriteCallback
2197 * @closeFunc: the xmlOutputCloseCallback
2199 * Register a new set of I/O callback for handling output.
2201 * Returns the registered handler number or -1 in case of error
2204 xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc
,
2205 xmlOutputOpenCallback openFunc
, xmlOutputWriteCallback writeFunc
,
2206 xmlOutputCloseCallback closeFunc
) {
2207 if (xmlOutputCallbackNr
>= MAX_OUTPUT_CALLBACK
) {
2210 xmlOutputCallbackTable
[xmlOutputCallbackNr
].matchcallback
= matchFunc
;
2211 xmlOutputCallbackTable
[xmlOutputCallbackNr
].opencallback
= openFunc
;
2212 xmlOutputCallbackTable
[xmlOutputCallbackNr
].writecallback
= writeFunc
;
2213 xmlOutputCallbackTable
[xmlOutputCallbackNr
].closecallback
= closeFunc
;
2214 xmlOutputCallbackInitialized
= 1;
2215 return(xmlOutputCallbackNr
++);
2217 #endif /* LIBXML_OUTPUT_ENABLED */
2220 * xmlRegisterDefaultInputCallbacks:
2222 * Registers the default compiled-in I/O handlers.
2225 xmlRegisterDefaultInputCallbacks(void) {
2226 if (xmlInputCallbackInitialized
)
2229 xmlRegisterInputCallbacks(xmlFileMatch
, xmlFileOpen
,
2230 xmlFileRead
, xmlFileClose
);
2231 #ifdef LIBXML_ZLIB_ENABLED
2232 xmlRegisterInputCallbacks(xmlGzfileMatch
, xmlGzfileOpen
,
2233 xmlGzfileRead
, xmlGzfileClose
);
2234 #endif /* LIBXML_ZLIB_ENABLED */
2235 #ifdef LIBXML_LZMA_ENABLED
2236 xmlRegisterInputCallbacks(xmlXzfileMatch
, xmlXzfileOpen
,
2237 xmlXzfileRead
, xmlXzfileClose
);
2238 #endif /* LIBXML_LZMA_ENABLED */
2240 #ifdef LIBXML_HTTP_ENABLED
2241 xmlRegisterInputCallbacks(xmlIOHTTPMatch
, xmlIOHTTPOpen
,
2242 xmlIOHTTPRead
, xmlIOHTTPClose
);
2243 #endif /* LIBXML_HTTP_ENABLED */
2245 #ifdef LIBXML_FTP_ENABLED
2246 xmlRegisterInputCallbacks(xmlIOFTPMatch
, xmlIOFTPOpen
,
2247 xmlIOFTPRead
, xmlIOFTPClose
);
2248 #endif /* LIBXML_FTP_ENABLED */
2249 xmlInputCallbackInitialized
= 1;
2252 #ifdef LIBXML_OUTPUT_ENABLED
2254 * xmlRegisterDefaultOutputCallbacks:
2256 * Registers the default compiled-in I/O handlers.
2259 xmlRegisterDefaultOutputCallbacks (void) {
2260 if (xmlOutputCallbackInitialized
)
2263 xmlRegisterOutputCallbacks(xmlFileMatch
, xmlFileOpenW
,
2264 xmlFileWrite
, xmlFileClose
);
2266 #ifdef LIBXML_HTTP_ENABLED
2267 xmlRegisterOutputCallbacks(xmlIOHTTPMatch
, xmlIOHTTPDfltOpenW
,
2268 xmlIOHTTPWrite
, xmlIOHTTPClosePut
);
2271 /*********************************
2272 No way a-priori to distinguish between gzipped files from
2273 uncompressed ones except opening if existing then closing
2274 and saving with same compression ratio ... a pain.
2276 #ifdef LIBXML_ZLIB_ENABLED
2277 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
2278 xmlGzfileWrite, xmlGzfileClose);
2282 #ifdef LIBXML_FTP_ENABLED
2283 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
2284 xmlIOFTPWrite, xmlIOFTPClose);
2286 **********************************/
2287 xmlOutputCallbackInitialized
= 1;
2290 #ifdef LIBXML_HTTP_ENABLED
2292 * xmlRegisterHTTPPostCallbacks:
2294 * By default, libxml submits HTTP output requests using the "PUT" method.
2295 * Calling this method changes the HTTP output method to use the "POST"
2300 xmlRegisterHTTPPostCallbacks( void ) {
2302 /* Register defaults if not done previously */
2304 if ( xmlOutputCallbackInitialized
== 0 )
2305 xmlRegisterDefaultOutputCallbacks( );
2307 xmlRegisterOutputCallbacks(xmlIOHTTPMatch
, xmlIOHTTPDfltOpenW
,
2308 xmlIOHTTPWrite
, xmlIOHTTPClosePost
);
2312 #endif /* LIBXML_OUTPUT_ENABLED */
2315 * xmlAllocParserInputBuffer:
2316 * @enc: the charset encoding if known
2318 * Create a buffered parser input for progressive parsing
2320 * Returns the new parser input or NULL
2322 xmlParserInputBufferPtr
2323 xmlAllocParserInputBuffer(xmlCharEncoding enc
) {
2324 xmlParserInputBufferPtr ret
;
2326 ret
= (xmlParserInputBufferPtr
) xmlMalloc(sizeof(xmlParserInputBuffer
));
2328 xmlIOErrMemory("creating input buffer");
2331 memset(ret
, 0, sizeof(xmlParserInputBuffer
));
2332 ret
->buffer
= xmlBufCreateSize(2 * xmlDefaultBufferSize
);
2333 if (ret
->buffer
== NULL
) {
2337 xmlBufSetAllocationScheme(ret
->buffer
, XML_BUFFER_ALLOC_DOUBLEIT
);
2338 ret
->encoder
= xmlGetCharEncodingHandler(enc
);
2339 if (ret
->encoder
!= NULL
)
2340 ret
->raw
= xmlBufCreateSize(2 * xmlDefaultBufferSize
);
2343 ret
->readcallback
= NULL
;
2344 ret
->closecallback
= NULL
;
2345 ret
->context
= NULL
;
2346 ret
->compressed
= -1;
2347 ret
->rawconsumed
= 0;
2352 #ifdef LIBXML_OUTPUT_ENABLED
2354 * xmlAllocOutputBuffer:
2355 * @encoder: the encoding converter or NULL
2357 * Create a buffered parser output
2359 * Returns the new parser output or NULL
2362 xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder
) {
2363 xmlOutputBufferPtr ret
;
2365 ret
= (xmlOutputBufferPtr
) xmlMalloc(sizeof(xmlOutputBuffer
));
2367 xmlIOErrMemory("creating output buffer");
2370 memset(ret
, 0, sizeof(xmlOutputBuffer
));
2371 ret
->buffer
= xmlBufCreate();
2372 if (ret
->buffer
== NULL
) {
2376 xmlBufSetAllocationScheme(ret
->buffer
, XML_BUFFER_ALLOC_DOUBLEIT
);
2378 ret
->encoder
= encoder
;
2379 if (encoder
!= NULL
) {
2380 ret
->conv
= xmlBufCreateSize(4000);
2381 if (ret
->conv
== NULL
) {
2382 xmlBufFree(ret
->buffer
);
2388 * This call is designed to initiate the encoder state
2390 xmlCharEncOutput(ret
, 1);
2393 ret
->writecallback
= NULL
;
2394 ret
->closecallback
= NULL
;
2395 ret
->context
= NULL
;
2402 * xmlAllocOutputBufferInternal:
2403 * @encoder: the encoding converter or NULL
2405 * Create a buffered parser output
2407 * Returns the new parser output or NULL
2410 xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder
) {
2411 xmlOutputBufferPtr ret
;
2413 ret
= (xmlOutputBufferPtr
) xmlMalloc(sizeof(xmlOutputBuffer
));
2415 xmlIOErrMemory("creating output buffer");
2418 memset(ret
, 0, sizeof(xmlOutputBuffer
));
2419 ret
->buffer
= xmlBufCreate();
2420 if (ret
->buffer
== NULL
) {
2427 * For conversion buffers we use the special IO handling
2429 xmlBufSetAllocationScheme(ret
->buffer
, XML_BUFFER_ALLOC_IO
);
2431 ret
->encoder
= encoder
;
2432 if (encoder
!= NULL
) {
2433 ret
->conv
= xmlBufCreateSize(4000);
2434 if (ret
->conv
== NULL
) {
2435 xmlBufFree(ret
->buffer
);
2441 * This call is designed to initiate the encoder state
2443 xmlCharEncOutput(ret
, 1);
2446 ret
->writecallback
= NULL
;
2447 ret
->closecallback
= NULL
;
2448 ret
->context
= NULL
;
2454 #endif /* LIBXML_OUTPUT_ENABLED */
2457 * xmlFreeParserInputBuffer:
2458 * @in: a buffered parser input
2460 * Free up the memory used by a buffered parser input
2463 xmlFreeParserInputBuffer(xmlParserInputBufferPtr in
) {
2464 if (in
== NULL
) return;
2467 xmlBufFree(in
->raw
);
2470 if (in
->encoder
!= NULL
) {
2471 xmlCharEncCloseFunc(in
->encoder
);
2473 if (in
->closecallback
!= NULL
) {
2474 in
->closecallback(in
->context
);
2476 if (in
->buffer
!= NULL
) {
2477 xmlBufFree(in
->buffer
);
2484 #ifdef LIBXML_OUTPUT_ENABLED
2486 * xmlOutputBufferClose:
2487 * @out: a buffered output
2489 * flushes and close the output I/O channel
2490 * and free up all the associated resources
2492 * Returns the number of byte written or -1 in case of error.
2495 xmlOutputBufferClose(xmlOutputBufferPtr out
)
2502 if (out
->writecallback
!= NULL
)
2503 xmlOutputBufferFlush(out
);
2504 if (out
->closecallback
!= NULL
) {
2505 err_rc
= out
->closecallback(out
->context
);
2507 written
= out
->written
;
2509 xmlBufFree(out
->conv
);
2512 if (out
->encoder
!= NULL
) {
2513 xmlCharEncCloseFunc(out
->encoder
);
2515 if (out
->buffer
!= NULL
) {
2516 xmlBufFree(out
->buffer
);
2523 return ((err_rc
== 0) ? written
: err_rc
);
2525 #endif /* LIBXML_OUTPUT_ENABLED */
2527 xmlParserInputBufferPtr
2528 __xmlParserInputBufferCreateFilename(const char *URI
, xmlCharEncoding enc
) {
2529 xmlParserInputBufferPtr ret
;
2531 void *context
= NULL
;
2533 if (xmlInputCallbackInitialized
== 0)
2534 xmlRegisterDefaultInputCallbacks();
2536 if (URI
== NULL
) return(NULL
);
2539 * Try to find one of the input accept method accepting that scheme
2540 * Go in reverse to give precedence to user defined handlers.
2542 if (context
== NULL
) {
2543 for (i
= xmlInputCallbackNr
- 1;i
>= 0;i
--) {
2544 if ((xmlInputCallbackTable
[i
].matchcallback
!= NULL
) &&
2545 (xmlInputCallbackTable
[i
].matchcallback(URI
) != 0)) {
2546 context
= xmlInputCallbackTable
[i
].opencallback(URI
);
2547 if (context
!= NULL
) {
2553 if (context
== NULL
) {
2558 * Allocate the Input buffer front-end.
2560 ret
= xmlAllocParserInputBuffer(enc
);
2562 ret
->context
= context
;
2563 ret
->readcallback
= xmlInputCallbackTable
[i
].readcallback
;
2564 ret
->closecallback
= xmlInputCallbackTable
[i
].closecallback
;
2565 #ifdef LIBXML_ZLIB_ENABLED
2566 if ((xmlInputCallbackTable
[i
].opencallback
== xmlGzfileOpen
) &&
2567 (strcmp(URI
, "-") != 0)) {
2568 #if defined(ZLIB_VERNUM) && ZLIB_VERNUM >= 0x1230
2569 ret
->compressed
= !gzdirect(context
);
2571 if (((z_stream
*)context
)->avail_in
> 4) {
2572 char *cptr
, buff4
[4];
2573 cptr
= (char *) ((z_stream
*)context
)->next_in
;
2574 if (gzread(context
, buff4
, 4) == 4) {
2575 if (strncmp(buff4
, cptr
, 4) == 0)
2576 ret
->compressed
= 0;
2578 ret
->compressed
= 1;
2585 #ifdef LIBXML_LZMA_ENABLED
2586 if ((xmlInputCallbackTable
[i
].opencallback
== xmlXzfileOpen
) &&
2587 (strcmp(URI
, "-") != 0)) {
2588 ret
->compressed
= __libxml2_xzcompressed(context
);
2593 xmlInputCallbackTable
[i
].closecallback (context
);
2599 * xmlParserInputBufferCreateFilename:
2600 * @URI: a C string containing the URI or filename
2601 * @enc: the charset encoding if known
2603 * Create a buffered parser input for the progressive parsing of a file
2604 * If filename is "-' then we use stdin as the input.
2605 * Automatic support for ZLIB/Compress compressed document is provided
2606 * by default if found at compile-time.
2607 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
2609 * Returns the new parser input or NULL
2611 xmlParserInputBufferPtr
2612 xmlParserInputBufferCreateFilename(const char *URI
, xmlCharEncoding enc
) {
2613 if ((xmlParserInputBufferCreateFilenameValue
)) {
2614 return xmlParserInputBufferCreateFilenameValue(URI
, enc
);
2616 return __xmlParserInputBufferCreateFilename(URI
, enc
);
2619 #ifdef LIBXML_OUTPUT_ENABLED
2621 __xmlOutputBufferCreateFilename(const char *URI
,
2622 xmlCharEncodingHandlerPtr encoder
,
2623 int compression ATTRIBUTE_UNUSED
) {
2624 xmlOutputBufferPtr ret
;
2627 void *context
= NULL
;
2628 char *unescaped
= NULL
;
2629 #ifdef LIBXML_ZLIB_ENABLED
2630 int is_file_uri
= 1;
2633 if (xmlOutputCallbackInitialized
== 0)
2634 xmlRegisterDefaultOutputCallbacks();
2636 if (URI
== NULL
) return(NULL
);
2638 puri
= xmlParseURI(URI
);
2640 #ifdef LIBXML_ZLIB_ENABLED
2641 if ((puri
->scheme
!= NULL
) &&
2642 (!xmlStrEqual(BAD_CAST puri
->scheme
, BAD_CAST
"file")))
2646 * try to limit the damages of the URI unescaping code.
2648 if ((puri
->scheme
== NULL
) ||
2649 (xmlStrEqual(BAD_CAST puri
->scheme
, BAD_CAST
"file")))
2650 unescaped
= xmlURIUnescapeString(URI
, 0, NULL
);
2655 * Try to find one of the output accept method accepting that scheme
2656 * Go in reverse to give precedence to user defined handlers.
2657 * try with an unescaped version of the URI
2659 if (unescaped
!= NULL
) {
2660 #ifdef LIBXML_ZLIB_ENABLED
2661 if ((compression
> 0) && (compression
<= 9) && (is_file_uri
== 1)) {
2662 context
= xmlGzfileOpenW(unescaped
, compression
);
2663 if (context
!= NULL
) {
2664 ret
= xmlAllocOutputBufferInternal(encoder
);
2666 ret
->context
= context
;
2667 ret
->writecallback
= xmlGzfileWrite
;
2668 ret
->closecallback
= xmlGzfileClose
;
2675 for (i
= xmlOutputCallbackNr
- 1;i
>= 0;i
--) {
2676 if ((xmlOutputCallbackTable
[i
].matchcallback
!= NULL
) &&
2677 (xmlOutputCallbackTable
[i
].matchcallback(unescaped
) != 0)) {
2678 #if defined(LIBXML_HTTP_ENABLED) && defined(LIBXML_ZLIB_ENABLED)
2679 /* Need to pass compression parameter into HTTP open calls */
2680 if (xmlOutputCallbackTable
[i
].matchcallback
== xmlIOHTTPMatch
)
2681 context
= xmlIOHTTPOpenW(unescaped
, compression
);
2684 context
= xmlOutputCallbackTable
[i
].opencallback(unescaped
);
2685 if (context
!= NULL
)
2693 * If this failed try with a non-escaped URI this may be a strange
2696 if (context
== NULL
) {
2697 #ifdef LIBXML_ZLIB_ENABLED
2698 if ((compression
> 0) && (compression
<= 9) && (is_file_uri
== 1)) {
2699 context
= xmlGzfileOpenW(URI
, compression
);
2700 if (context
!= NULL
) {
2701 ret
= xmlAllocOutputBufferInternal(encoder
);
2703 ret
->context
= context
;
2704 ret
->writecallback
= xmlGzfileWrite
;
2705 ret
->closecallback
= xmlGzfileClose
;
2708 xmlGzfileClose(context
);
2713 for (i
= xmlOutputCallbackNr
- 1;i
>= 0;i
--) {
2714 if ((xmlOutputCallbackTable
[i
].matchcallback
!= NULL
) &&
2715 (xmlOutputCallbackTable
[i
].matchcallback(URI
) != 0)) {
2716 #if defined(LIBXML_HTTP_ENABLED) && defined(LIBXML_ZLIB_ENABLED)
2717 /* Need to pass compression parameter into HTTP open calls */
2718 if (xmlOutputCallbackTable
[i
].matchcallback
== xmlIOHTTPMatch
)
2719 context
= xmlIOHTTPOpenW(URI
, compression
);
2722 context
= xmlOutputCallbackTable
[i
].opencallback(URI
);
2723 if (context
!= NULL
)
2729 if (context
== NULL
) {
2734 * Allocate the Output buffer front-end.
2736 ret
= xmlAllocOutputBufferInternal(encoder
);
2738 ret
->context
= context
;
2739 ret
->writecallback
= xmlOutputCallbackTable
[i
].writecallback
;
2740 ret
->closecallback
= xmlOutputCallbackTable
[i
].closecallback
;
2746 * xmlOutputBufferCreateFilename:
2747 * @URI: a C string containing the URI or filename
2748 * @encoder: the encoding converter or NULL
2749 * @compression: the compression ration (0 none, 9 max).
2751 * Create a buffered output for the progressive saving of a file
2752 * If filename is "-' then we use stdout as the output.
2753 * Automatic support for ZLIB/Compress compressed document is provided
2754 * by default if found at compile-time.
2755 * TODO: currently if compression is set, the library only support
2756 * writing to a local file.
2758 * Returns the new output or NULL
2761 xmlOutputBufferCreateFilename(const char *URI
,
2762 xmlCharEncodingHandlerPtr encoder
,
2763 int compression ATTRIBUTE_UNUSED
) {
2764 if ((xmlOutputBufferCreateFilenameValue
)) {
2765 return xmlOutputBufferCreateFilenameValue(URI
, encoder
, compression
);
2767 return __xmlOutputBufferCreateFilename(URI
, encoder
, compression
);
2769 #endif /* LIBXML_OUTPUT_ENABLED */
2772 * xmlParserInputBufferCreateFile:
2774 * @enc: the charset encoding if known
2776 * Create a buffered parser input for the progressive parsing of a FILE *
2779 * Returns the new parser input or NULL
2781 xmlParserInputBufferPtr
2782 xmlParserInputBufferCreateFile(FILE *file
, xmlCharEncoding enc
) {
2783 xmlParserInputBufferPtr ret
;
2785 if (xmlInputCallbackInitialized
== 0)
2786 xmlRegisterDefaultInputCallbacks();
2788 if (file
== NULL
) return(NULL
);
2790 ret
= xmlAllocParserInputBuffer(enc
);
2792 ret
->context
= file
;
2793 ret
->readcallback
= xmlFileRead
;
2794 ret
->closecallback
= xmlFileFlush
;
2800 #ifdef LIBXML_OUTPUT_ENABLED
2802 * xmlOutputBufferCreateFile:
2804 * @encoder: the encoding converter or NULL
2806 * Create a buffered output for the progressive saving to a FILE *
2809 * Returns the new parser output or NULL
2812 xmlOutputBufferCreateFile(FILE *file
, xmlCharEncodingHandlerPtr encoder
) {
2813 xmlOutputBufferPtr ret
;
2815 if (xmlOutputCallbackInitialized
== 0)
2816 xmlRegisterDefaultOutputCallbacks();
2818 if (file
== NULL
) return(NULL
);
2820 ret
= xmlAllocOutputBufferInternal(encoder
);
2822 ret
->context
= file
;
2823 ret
->writecallback
= xmlFileWrite
;
2824 ret
->closecallback
= xmlFileFlush
;
2831 * xmlOutputBufferCreateBuffer:
2832 * @buffer: a xmlBufferPtr
2833 * @encoder: the encoding converter or NULL
2835 * Create a buffered output for the progressive saving to a xmlBuffer
2837 * Returns the new parser output or NULL
2840 xmlOutputBufferCreateBuffer(xmlBufferPtr buffer
,
2841 xmlCharEncodingHandlerPtr encoder
) {
2842 xmlOutputBufferPtr ret
;
2844 if (buffer
== NULL
) return(NULL
);
2846 ret
= xmlOutputBufferCreateIO(xmlBufferWrite
, NULL
, (void *) buffer
,
2853 * xmlOutputBufferGetContent:
2854 * @out: an xmlOutputBufferPtr
2856 * Gives a pointer to the data currently held in the output buffer
2858 * Returns a pointer to the data or NULL in case of error
2861 xmlOutputBufferGetContent(xmlOutputBufferPtr out
) {
2862 if ((out
== NULL
) || (out
->buffer
== NULL
))
2865 return(xmlBufContent(out
->buffer
));
2869 * xmlOutputBufferGetSize:
2870 * @out: an xmlOutputBufferPtr
2872 * Gives the length of the data currently held in the output buffer
2874 * Returns 0 in case or error or no data is held, the size otherwise
2877 xmlOutputBufferGetSize(xmlOutputBufferPtr out
) {
2878 if ((out
== NULL
) || (out
->buffer
== NULL
))
2881 return(xmlBufUse(out
->buffer
));
2885 #endif /* LIBXML_OUTPUT_ENABLED */
2888 * xmlParserInputBufferCreateFd:
2889 * @fd: a file descriptor number
2890 * @enc: the charset encoding if known
2892 * Create a buffered parser input for the progressive parsing for the input
2893 * from a file descriptor
2895 * Returns the new parser input or NULL
2897 xmlParserInputBufferPtr
2898 xmlParserInputBufferCreateFd(int fd
, xmlCharEncoding enc
) {
2899 xmlParserInputBufferPtr ret
;
2901 if (fd
< 0) return(NULL
);
2903 ret
= xmlAllocParserInputBuffer(enc
);
2905 ret
->context
= (void *) (ptrdiff_t) fd
;
2906 ret
->readcallback
= xmlFdRead
;
2907 ret
->closecallback
= xmlFdClose
;
2914 * xmlParserInputBufferCreateMem:
2915 * @mem: the memory input
2916 * @size: the length of the memory block
2917 * @enc: the charset encoding if known
2919 * Create a buffered parser input for the progressive parsing for the input
2920 * from a memory area.
2922 * Returns the new parser input or NULL
2924 xmlParserInputBufferPtr
2925 xmlParserInputBufferCreateMem(const char *mem
, int size
, xmlCharEncoding enc
) {
2926 xmlParserInputBufferPtr ret
;
2929 if (size
< 0) return(NULL
);
2930 if (mem
== NULL
) return(NULL
);
2932 ret
= xmlAllocParserInputBuffer(enc
);
2934 ret
->context
= (void *) mem
;
2935 ret
->readcallback
= NULL
;
2936 ret
->closecallback
= NULL
;
2937 errcode
= xmlBufAdd(ret
->buffer
, (const xmlChar
*) mem
, size
);
2939 xmlFreeParserInputBuffer(ret
);
2948 * xmlParserInputBufferCreateStatic:
2949 * @mem: the memory input
2950 * @size: the length of the memory block
2951 * @enc: the charset encoding if known
2953 * DEPRECATED: Use xmlParserInputBufferCreateMem.
2955 * Returns the new parser input or NULL
2957 xmlParserInputBufferPtr
2958 xmlParserInputBufferCreateStatic(const char *mem
, int size
,
2959 xmlCharEncoding enc
) {
2960 return(xmlParserInputBufferCreateMem(mem
, size
, enc
));
2963 #ifdef LIBXML_OUTPUT_ENABLED
2965 * xmlOutputBufferCreateFd:
2966 * @fd: a file descriptor number
2967 * @encoder: the encoding converter or NULL
2969 * Create a buffered output for the progressive saving
2970 * to a file descriptor
2972 * Returns the new parser output or NULL
2975 xmlOutputBufferCreateFd(int fd
, xmlCharEncodingHandlerPtr encoder
) {
2976 xmlOutputBufferPtr ret
;
2978 if (fd
< 0) return(NULL
);
2980 ret
= xmlAllocOutputBufferInternal(encoder
);
2982 ret
->context
= (void *) (ptrdiff_t) fd
;
2983 ret
->writecallback
= xmlFdWrite
;
2984 ret
->closecallback
= NULL
;
2989 #endif /* LIBXML_OUTPUT_ENABLED */
2992 * xmlParserInputBufferCreateIO:
2993 * @ioread: an I/O read function
2994 * @ioclose: an I/O close function
2995 * @ioctx: an I/O handler
2996 * @enc: the charset encoding if known
2998 * Create a buffered parser input for the progressive parsing for the input
2999 * from an I/O handler
3001 * Returns the new parser input or NULL
3003 xmlParserInputBufferPtr
3004 xmlParserInputBufferCreateIO(xmlInputReadCallback ioread
,
3005 xmlInputCloseCallback ioclose
, void *ioctx
, xmlCharEncoding enc
) {
3006 xmlParserInputBufferPtr ret
;
3008 if (ioread
== NULL
) return(NULL
);
3010 ret
= xmlAllocParserInputBuffer(enc
);
3012 ret
->context
= (void *) ioctx
;
3013 ret
->readcallback
= ioread
;
3014 ret
->closecallback
= ioclose
;
3020 #ifdef LIBXML_OUTPUT_ENABLED
3022 * xmlOutputBufferCreateIO:
3023 * @iowrite: an I/O write function
3024 * @ioclose: an I/O close function
3025 * @ioctx: an I/O handler
3026 * @encoder: the charset encoding if known
3028 * Create a buffered output for the progressive saving
3031 * Returns the new parser output or NULL
3034 xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite
,
3035 xmlOutputCloseCallback ioclose
, void *ioctx
,
3036 xmlCharEncodingHandlerPtr encoder
) {
3037 xmlOutputBufferPtr ret
;
3039 if (iowrite
== NULL
) return(NULL
);
3041 ret
= xmlAllocOutputBufferInternal(encoder
);
3043 ret
->context
= (void *) ioctx
;
3044 ret
->writecallback
= iowrite
;
3045 ret
->closecallback
= ioclose
;
3050 #endif /* LIBXML_OUTPUT_ENABLED */
3053 * xmlParserInputBufferCreateFilenameDefault:
3054 * @func: function pointer to the new ParserInputBufferCreateFilenameFunc
3056 * Registers a callback for URI input file handling
3058 * Returns the old value of the registration function
3060 xmlParserInputBufferCreateFilenameFunc
3061 xmlParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func
)
3063 xmlParserInputBufferCreateFilenameFunc old
= xmlParserInputBufferCreateFilenameValue
;
3065 old
= __xmlParserInputBufferCreateFilename
;
3068 xmlParserInputBufferCreateFilenameValue
= func
;
3073 * xmlOutputBufferCreateFilenameDefault:
3074 * @func: function pointer to the new OutputBufferCreateFilenameFunc
3076 * Registers a callback for URI output file handling
3078 * Returns the old value of the registration function
3080 xmlOutputBufferCreateFilenameFunc
3081 xmlOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func
)
3083 xmlOutputBufferCreateFilenameFunc old
= xmlOutputBufferCreateFilenameValue
;
3084 #ifdef LIBXML_OUTPUT_ENABLED
3086 old
= __xmlOutputBufferCreateFilename
;
3089 xmlOutputBufferCreateFilenameValue
= func
;
3094 * xmlParserInputBufferPush:
3095 * @in: a buffered parser input
3096 * @len: the size in bytes of the array.
3097 * @buf: an char array
3099 * Push the content of the arry in the input buffer
3100 * This routine handle the I18N transcoding to internal UTF-8
3101 * This is used when operating the parser in progressive (push) mode.
3103 * Returns the number of chars read and stored in the buffer, or -1
3107 xmlParserInputBufferPush(xmlParserInputBufferPtr in
,
3108 int len
, const char *buf
) {
3112 if (len
< 0) return(0);
3113 if ((in
== NULL
) || (in
->error
)) return(-1);
3114 if (in
->encoder
!= NULL
) {
3115 size_t use
, consumed
;
3118 * Store the data in the incoming raw buffer
3120 if (in
->raw
== NULL
) {
3121 in
->raw
= xmlBufCreate();
3123 ret
= xmlBufAdd(in
->raw
, (const xmlChar
*) buf
, len
);
3128 * convert as much as possible to the parser reading buffer.
3130 use
= xmlBufUse(in
->raw
);
3131 nbchars
= xmlCharEncInput(in
, 1);
3133 xmlIOErr(XML_IO_ENCODER
, NULL
);
3134 in
->error
= XML_IO_ENCODER
;
3137 consumed
= use
- xmlBufUse(in
->raw
);
3138 if ((consumed
> ULONG_MAX
) ||
3139 (in
->rawconsumed
> ULONG_MAX
- (unsigned long)consumed
))
3140 in
->rawconsumed
= ULONG_MAX
;
3142 in
->rawconsumed
+= consumed
;
3145 ret
= xmlBufAdd(in
->buffer
, (xmlChar
*) buf
, nbchars
);
3150 xmlGenericError(xmlGenericErrorContext
,
3151 "I/O: pushed %d chars, buffer %d/%d\n",
3152 nbchars
, xmlBufUse(in
->buffer
), xmlBufLength(in
->buffer
));
3160 * When reading from an Input channel indicated end of file or error
3161 * don't reread from it again.
3164 endOfInput (void * context ATTRIBUTE_UNUSED
,
3165 char * buffer ATTRIBUTE_UNUSED
,
3166 int len ATTRIBUTE_UNUSED
) {
3171 * xmlParserInputBufferGrow:
3172 * @in: a buffered parser input
3173 * @len: indicative value of the amount of chars to read
3175 * Grow up the content of the input buffer, the old data are preserved
3176 * This routine handle the I18N transcoding to internal UTF-8
3177 * This routine is used when operating the parser in normal (pull) mode
3179 * TODO: one should be able to remove one extra copy by copying directly
3180 * onto in->buffer or in->raw
3182 * Returns the number of chars read and stored in the buffer, or -1
3186 xmlParserInputBufferGrow(xmlParserInputBufferPtr in
, int len
) {
3190 if ((in
== NULL
) || (in
->error
)) return(-1);
3191 if ((len
<= MINLEN
) && (len
!= 4))
3194 if (in
->encoder
== NULL
) {
3195 if (in
->readcallback
== NULL
)
3199 if (in
->raw
== NULL
) {
3200 in
->raw
= xmlBufCreate();
3206 * Call the read method for this I/O type.
3208 if (in
->readcallback
!= NULL
) {
3209 if (xmlBufGrow(buf
, len
+ 1) < 0) {
3210 xmlIOErrMemory("growing input buffer");
3211 in
->error
= XML_ERR_NO_MEMORY
;
3215 res
= in
->readcallback(in
->context
, (char *)xmlBufEnd(buf
), len
);
3217 in
->readcallback
= endOfInput
;
3221 if (xmlBufAddLen(buf
, res
) < 0)
3226 * try to establish compressed status of input if not done already
3228 if (in
->compressed
== -1) {
3229 #ifdef LIBXML_LZMA_ENABLED
3230 if (in
->readcallback
== xmlXzfileRead
)
3231 in
->compressed
= __libxml2_xzcompressed(in
->context
);
3235 if (in
->encoder
!= NULL
) {
3236 size_t use
, consumed
;
3239 * convert as much as possible to the parser reading buffer.
3241 use
= xmlBufUse(buf
);
3242 res
= xmlCharEncInput(in
, 1);
3244 xmlIOErr(XML_IO_ENCODER
, NULL
);
3245 in
->error
= XML_IO_ENCODER
;
3248 consumed
= use
- xmlBufUse(buf
);
3249 if ((consumed
> ULONG_MAX
) ||
3250 (in
->rawconsumed
> ULONG_MAX
- (unsigned long)consumed
))
3251 in
->rawconsumed
= ULONG_MAX
;
3253 in
->rawconsumed
+= consumed
;
3256 xmlGenericError(xmlGenericErrorContext
,
3257 "I/O: read %d chars, buffer %d\n",
3258 nbchars
, xmlBufUse(in
->buffer
));
3264 * xmlParserInputBufferRead:
3265 * @in: a buffered parser input
3266 * @len: indicative value of the amount of chars to read
3268 * Refresh the content of the input buffer, the old data are considered
3270 * This routine handle the I18N transcoding to internal UTF-8
3272 * Returns the number of chars read and stored in the buffer, or -1
3276 xmlParserInputBufferRead(xmlParserInputBufferPtr in
, int len
) {
3277 return(xmlParserInputBufferGrow(in
, len
));
3280 #ifdef LIBXML_OUTPUT_ENABLED
3282 * xmlOutputBufferWrite:
3283 * @out: a buffered parser output
3284 * @len: the size in bytes of the array.
3285 * @buf: an char array
3287 * Write the content of the array in the output I/O buffer
3288 * This routine handle the I18N transcoding from internal UTF-8
3289 * The buffer is lossless, i.e. will store in case of partial
3290 * or delayed writes.
3292 * Returns the number of chars immediately written, or -1
3296 xmlOutputBufferWrite(xmlOutputBufferPtr out
, int len
, const char *buf
) {
3297 int nbchars
= 0; /* number of chars to output to I/O */
3298 int ret
; /* return from function call */
3299 int written
= 0; /* number of char written to I/O so far */
3300 int chunk
; /* number of byte current processed from buf */
3302 if ((out
== NULL
) || (out
->error
)) return(-1);
3303 if (len
< 0) return(0);
3304 if (out
->error
) return(-1);
3308 if (chunk
> 4 * MINLEN
)
3312 * first handle encoding stuff.
3314 if (out
->encoder
!= NULL
) {
3316 * Store the data in the incoming raw buffer
3318 if (out
->conv
== NULL
) {
3319 out
->conv
= xmlBufCreate();
3321 ret
= xmlBufAdd(out
->buffer
, (const xmlChar
*) buf
, chunk
);
3325 if ((xmlBufUse(out
->buffer
) < MINLEN
) && (chunk
== len
))
3329 * convert as much as possible to the parser reading buffer.
3331 ret
= xmlCharEncOutput(out
, 0);
3332 if ((ret
< 0) && (ret
!= -3)) {
3333 xmlIOErr(XML_IO_ENCODER
, NULL
);
3334 out
->error
= XML_IO_ENCODER
;
3337 if (out
->writecallback
)
3338 nbchars
= xmlBufUse(out
->conv
);
3340 nbchars
= ret
>= 0 ? ret
: 0;
3342 ret
= xmlBufAdd(out
->buffer
, (const xmlChar
*) buf
, chunk
);
3345 if (out
->writecallback
)
3346 nbchars
= xmlBufUse(out
->buffer
);
3353 if (out
->writecallback
) {
3354 if ((nbchars
< MINLEN
) && (len
<= 0))
3358 * second write the stuff to the I/O channel
3360 if (out
->encoder
!= NULL
) {
3361 ret
= out
->writecallback(out
->context
,
3362 (const char *)xmlBufContent(out
->conv
), nbchars
);
3364 xmlBufShrink(out
->conv
, ret
);
3366 ret
= out
->writecallback(out
->context
,
3367 (const char *)xmlBufContent(out
->buffer
), nbchars
);
3369 xmlBufShrink(out
->buffer
, ret
);
3372 xmlIOErr(XML_IO_WRITE
, NULL
);
3373 out
->error
= XML_IO_WRITE
;
3376 if (out
->written
> INT_MAX
- ret
)
3377 out
->written
= INT_MAX
;
3379 out
->written
+= ret
;
3386 xmlGenericError(xmlGenericErrorContext
,
3387 "I/O: wrote %d chars\n", written
);
3394 * @out: a pointer to an array of bytes to store the result
3395 * @outlen: the length of @out
3396 * @in: a pointer to an array of unescaped UTF-8 bytes
3397 * @inlen: the length of @in
3399 * Take a block of UTF-8 chars in and escape them.
3400 * Returns 0 if success, or -1 otherwise
3401 * The value of @inlen after return is the number of octets consumed
3402 * if the return value is positive, else unpredictable.
3403 * The value of @outlen after return is the number of octets consumed.
3406 xmlEscapeContent(unsigned char* out
, int *outlen
,
3407 const xmlChar
* in
, int *inlen
) {
3408 unsigned char* outstart
= out
;
3409 const unsigned char* base
= in
;
3410 unsigned char* outend
= out
+ *outlen
;
3411 const unsigned char* inend
;
3413 inend
= in
+ (*inlen
);
3415 while ((in
< inend
) && (out
< outend
)) {
3417 if (outend
- out
< 4) break;
3422 } else if (*in
== '>') {
3423 if (outend
- out
< 4) break;
3428 } else if (*in
== '&') {
3429 if (outend
- out
< 5) break;
3435 } else if (*in
== '\r') {
3436 if (outend
- out
< 5) break;
3447 *outlen
= out
- outstart
;
3453 * xmlOutputBufferWriteEscape:
3454 * @out: a buffered parser output
3455 * @str: a zero terminated UTF-8 string
3456 * @escaping: an optional escaping function (or NULL)
3458 * Write the content of the string in the output I/O buffer
3459 * This routine escapes the characters and then handle the I18N
3460 * transcoding from internal UTF-8
3461 * The buffer is lossless, i.e. will store in case of partial
3462 * or delayed writes.
3464 * Returns the number of chars immediately written, or -1
3468 xmlOutputBufferWriteEscape(xmlOutputBufferPtr out
, const xmlChar
*str
,
3469 xmlCharEncodingOutputFunc escaping
) {
3470 int nbchars
= 0; /* number of chars to output to I/O */
3471 int ret
; /* return from function call */
3472 int written
= 0; /* number of char written to I/O so far */
3473 int oldwritten
=0;/* loop guard */
3474 int chunk
; /* number of byte currently processed from str */
3475 int len
; /* number of bytes in str */
3476 int cons
; /* byte from str consumed */
3478 if ((out
== NULL
) || (out
->error
) || (str
== NULL
) ||
3479 (out
->buffer
== NULL
))
3481 len
= strlen((const char *)str
);
3482 if (len
< 0) return(0);
3483 if (out
->error
) return(-1);
3484 if (escaping
== NULL
) escaping
= xmlEscapeContent
;
3487 oldwritten
= written
;
3490 * how many bytes to consume and how many bytes to store.
3493 chunk
= xmlBufAvail(out
->buffer
);
3496 * make sure we have enough room to save first, if this is
3497 * not the case force a flush, but make sure we stay in the loop
3500 if (xmlBufGrow(out
->buffer
, 100) < 0)
3507 * first handle encoding stuff.
3509 if (out
->encoder
!= NULL
) {
3511 * Store the data in the incoming raw buffer
3513 if (out
->conv
== NULL
) {
3514 out
->conv
= xmlBufCreate();
3516 ret
= escaping(xmlBufEnd(out
->buffer
) ,
3517 &chunk
, str
, &cons
);
3518 if ((ret
< 0) || (chunk
== 0)) /* chunk==0 => nothing done */
3520 xmlBufAddLen(out
->buffer
, chunk
);
3522 if ((xmlBufUse(out
->buffer
) < MINLEN
) && (cons
== len
))
3526 * convert as much as possible to the output buffer.
3528 ret
= xmlCharEncOutput(out
, 0);
3529 if ((ret
< 0) && (ret
!= -3)) {
3530 xmlIOErr(XML_IO_ENCODER
, NULL
);
3531 out
->error
= XML_IO_ENCODER
;
3534 if (out
->writecallback
)
3535 nbchars
= xmlBufUse(out
->conv
);
3537 nbchars
= ret
>= 0 ? ret
: 0;
3539 ret
= escaping(xmlBufEnd(out
->buffer
), &chunk
, str
, &cons
);
3540 if ((ret
< 0) || (chunk
== 0)) /* chunk==0 => nothing done */
3542 xmlBufAddLen(out
->buffer
, chunk
);
3543 if (out
->writecallback
)
3544 nbchars
= xmlBufUse(out
->buffer
);
3551 if (out
->writecallback
) {
3552 if ((nbchars
< MINLEN
) && (len
<= 0))
3556 * second write the stuff to the I/O channel
3558 if (out
->encoder
!= NULL
) {
3559 ret
= out
->writecallback(out
->context
,
3560 (const char *)xmlBufContent(out
->conv
), nbchars
);
3562 xmlBufShrink(out
->conv
, ret
);
3564 ret
= out
->writecallback(out
->context
,
3565 (const char *)xmlBufContent(out
->buffer
), nbchars
);
3567 xmlBufShrink(out
->buffer
, ret
);
3570 xmlIOErr(XML_IO_WRITE
, NULL
);
3571 out
->error
= XML_IO_WRITE
;
3574 if (out
->written
> INT_MAX
- ret
)
3575 out
->written
= INT_MAX
;
3577 out
->written
+= ret
;
3578 } else if (xmlBufAvail(out
->buffer
) < MINLEN
) {
3579 xmlBufGrow(out
->buffer
, MINLEN
);
3582 } while ((len
> 0) && (oldwritten
!= written
));
3586 xmlGenericError(xmlGenericErrorContext
,
3587 "I/O: wrote %d chars\n", written
);
3593 * xmlOutputBufferWriteString:
3594 * @out: a buffered parser output
3595 * @str: a zero terminated C string
3597 * Write the content of the string in the output I/O buffer
3598 * This routine handle the I18N transcoding from internal UTF-8
3599 * The buffer is lossless, i.e. will store in case of partial
3600 * or delayed writes.
3602 * Returns the number of chars immediately written, or -1
3606 xmlOutputBufferWriteString(xmlOutputBufferPtr out
, const char *str
) {
3609 if ((out
== NULL
) || (out
->error
)) return(-1);
3615 return(xmlOutputBufferWrite(out
, len
, str
));
3620 * xmlOutputBufferFlush:
3621 * @out: a buffered output
3623 * flushes the output I/O channel
3625 * Returns the number of byte written or -1 in case of error.
3628 xmlOutputBufferFlush(xmlOutputBufferPtr out
) {
3629 int nbchars
= 0, ret
= 0;
3631 if ((out
== NULL
) || (out
->error
)) return(-1);
3633 * first handle encoding stuff.
3635 if ((out
->conv
!= NULL
) && (out
->encoder
!= NULL
)) {
3637 * convert as much as possible to the parser output buffer.
3640 nbchars
= xmlCharEncOutput(out
, 0);
3642 xmlIOErr(XML_IO_ENCODER
, NULL
);
3643 out
->error
= XML_IO_ENCODER
;
3650 * second flush the stuff to the I/O channel
3652 if ((out
->conv
!= NULL
) && (out
->encoder
!= NULL
) &&
3653 (out
->writecallback
!= NULL
)) {
3654 ret
= out
->writecallback(out
->context
,
3655 (const char *)xmlBufContent(out
->conv
),
3656 xmlBufUse(out
->conv
));
3658 xmlBufShrink(out
->conv
, ret
);
3659 } else if (out
->writecallback
!= NULL
) {
3660 ret
= out
->writecallback(out
->context
,
3661 (const char *)xmlBufContent(out
->buffer
),
3662 xmlBufUse(out
->buffer
));
3664 xmlBufShrink(out
->buffer
, ret
);
3667 xmlIOErr(XML_IO_FLUSH
, NULL
);
3668 out
->error
= XML_IO_FLUSH
;
3671 if (out
->written
> INT_MAX
- ret
)
3672 out
->written
= INT_MAX
;
3674 out
->written
+= ret
;
3677 xmlGenericError(xmlGenericErrorContext
,
3678 "I/O: flushed %d chars\n", ret
);
3682 #endif /* LIBXML_OUTPUT_ENABLED */
3685 * xmlParserGetDirectory:
3686 * @filename: the path to a file
3688 * lookup the directory for that file
3690 * Returns a new allocated string containing the directory, or NULL.
3693 xmlParserGetDirectory(const char *filename
) {
3698 if (xmlInputCallbackInitialized
== 0)
3699 xmlRegisterDefaultInputCallbacks();
3701 if (filename
== NULL
) return(NULL
);
3704 # define IS_XMLPGD_SEP(ch) ((ch=='/')||(ch=='\\'))
3706 # define IS_XMLPGD_SEP(ch) (ch=='/')
3709 strncpy(dir
, filename
, 1023);
3711 cur
= &dir
[strlen(dir
)];
3713 if (IS_XMLPGD_SEP(*cur
)) break;
3716 if (IS_XMLPGD_SEP(*cur
)) {
3717 if (cur
== dir
) dir
[1] = 0;
3719 ret
= xmlMemStrdup(dir
);
3721 if (getcwd(dir
, 1024) != NULL
) {
3723 ret
= xmlMemStrdup(dir
);
3727 #undef IS_XMLPGD_SEP
3730 /****************************************************************
3732 * External entities loading *
3734 ****************************************************************/
3737 * xmlCheckHTTPInput:
3738 * @ctxt: an XML parser context
3739 * @ret: an XML parser input
3741 * Check an input in case it was created from an HTTP stream, in that
3742 * case it will handle encoding and update of the base URL in case of
3743 * redirection. It also checks for HTTP errors in which case the input
3744 * is cleanly freed up and an appropriate error is raised in context
3746 * Returns the input or NULL in case of HTTP error.
3749 xmlCheckHTTPInput(xmlParserCtxtPtr ctxt
, xmlParserInputPtr ret
) {
3750 /* Avoid unused variable warning if features are disabled. */
3753 #ifdef LIBXML_HTTP_ENABLED
3754 if ((ret
!= NULL
) && (ret
->buf
!= NULL
) &&
3755 (ret
->buf
->readcallback
== xmlIOHTTPRead
) &&
3756 (ret
->buf
->context
!= NULL
)) {
3757 const char *encoding
;
3762 code
= xmlNanoHTTPReturnCode(ret
->buf
->context
);
3765 if (ret
->filename
!= NULL
)
3766 __xmlLoaderErr(ctxt
, "failed to load HTTP resource \"%s\"\n",
3767 (const char *) ret
->filename
);
3769 __xmlLoaderErr(ctxt
, "failed to load HTTP resource\n", NULL
);
3770 xmlFreeInputStream(ret
);
3774 mime
= xmlNanoHTTPMimeType(ret
->buf
->context
);
3775 if ((xmlStrstr(BAD_CAST mime
, BAD_CAST
"/xml")) ||
3776 (xmlStrstr(BAD_CAST mime
, BAD_CAST
"+xml"))) {
3777 encoding
= xmlNanoHTTPEncoding(ret
->buf
->context
);
3778 if (encoding
!= NULL
) {
3779 xmlCharEncodingHandlerPtr handler
;
3781 handler
= xmlFindCharEncodingHandler(encoding
);
3782 if (handler
!= NULL
) {
3783 xmlSwitchInputEncoding(ctxt
, ret
, handler
);
3785 __xmlErrEncoding(ctxt
, XML_ERR_UNKNOWN_ENCODING
,
3786 "Unknown encoding %s",
3787 BAD_CAST encoding
, NULL
);
3789 if (ret
->encoding
== NULL
)
3790 ret
->encoding
= xmlStrdup(BAD_CAST encoding
);
3793 } else if (xmlStrstr(BAD_CAST mime
, BAD_CAST
"html")) {
3796 redir
= xmlNanoHTTPRedir(ret
->buf
->context
);
3797 if (redir
!= NULL
) {
3798 if (ret
->filename
!= NULL
)
3799 xmlFree((xmlChar
*) ret
->filename
);
3800 if (ret
->directory
!= NULL
) {
3801 xmlFree((xmlChar
*) ret
->directory
);
3802 ret
->directory
= NULL
;
3805 (char *) xmlStrdup((const xmlChar
*) redir
);
3813 static int xmlNoNetExists(const char *URL
) {
3819 if (!xmlStrncasecmp(BAD_CAST URL
, BAD_CAST
"file://localhost/", 17))
3820 #if defined (_WIN32)
3825 else if (!xmlStrncasecmp(BAD_CAST URL
, BAD_CAST
"file:///", 8)) {
3826 #if defined (_WIN32)
3834 return xmlCheckFilename(path
);
3837 #ifdef LIBXML_CATALOG_ENABLED
3840 * xmlResolveResourceFromCatalog:
3841 * @URL: the URL for the entity to load
3842 * @ID: the System ID for the entity to load
3843 * @ctxt: the context in which the entity is called or NULL
3845 * Resolves the URL and ID against the appropriate catalog.
3846 * This function is used by xmlDefaultExternalEntityLoader and
3847 * xmlNoNetExternalEntityLoader.
3849 * Returns a new allocated URL, or NULL.
3852 xmlResolveResourceFromCatalog(const char *URL
, const char *ID
,
3853 xmlParserCtxtPtr ctxt
) {
3854 xmlChar
*resource
= NULL
;
3855 xmlCatalogAllow pref
;
3858 * If the resource doesn't exists as a file,
3859 * try to load it from the resource pointed in the catalogs
3861 pref
= xmlCatalogGetDefaults();
3863 if ((pref
!= XML_CATA_ALLOW_NONE
) && (!xmlNoNetExists(URL
))) {
3867 if ((ctxt
!= NULL
) && (ctxt
->catalogs
!= NULL
) &&
3868 ((pref
== XML_CATA_ALLOW_ALL
) ||
3869 (pref
== XML_CATA_ALLOW_DOCUMENT
))) {
3870 resource
= xmlCatalogLocalResolve(ctxt
->catalogs
,
3871 (const xmlChar
*)ID
,
3872 (const xmlChar
*)URL
);
3875 * Try a global lookup
3877 if ((resource
== NULL
) &&
3878 ((pref
== XML_CATA_ALLOW_ALL
) ||
3879 (pref
== XML_CATA_ALLOW_GLOBAL
))) {
3880 resource
= xmlCatalogResolve((const xmlChar
*)ID
,
3881 (const xmlChar
*)URL
);
3883 if ((resource
== NULL
) && (URL
!= NULL
))
3884 resource
= xmlStrdup((const xmlChar
*) URL
);
3887 * TODO: do an URI lookup on the reference
3889 if ((resource
!= NULL
) && (!xmlNoNetExists((const char *)resource
))) {
3890 xmlChar
*tmp
= NULL
;
3892 if ((ctxt
!= NULL
) && (ctxt
->catalogs
!= NULL
) &&
3893 ((pref
== XML_CATA_ALLOW_ALL
) ||
3894 (pref
== XML_CATA_ALLOW_DOCUMENT
))) {
3895 tmp
= xmlCatalogLocalResolveURI(ctxt
->catalogs
, resource
);
3897 if ((tmp
== NULL
) &&
3898 ((pref
== XML_CATA_ALLOW_ALL
) ||
3899 (pref
== XML_CATA_ALLOW_GLOBAL
))) {
3900 tmp
= xmlCatalogResolveURI(resource
);
3916 * xmlDefaultExternalEntityLoader:
3917 * @URL: the URL for the entity to load
3918 * @ID: the System ID for the entity to load
3919 * @ctxt: the context in which the entity is called or NULL
3921 * By default we don't load external entities, yet.
3923 * Returns a new allocated xmlParserInputPtr, or NULL.
3925 static xmlParserInputPtr
3926 xmlDefaultExternalEntityLoader(const char *URL
, const char *ID
,
3927 xmlParserCtxtPtr ctxt
)
3929 xmlParserInputPtr ret
= NULL
;
3930 xmlChar
*resource
= NULL
;
3932 #ifdef DEBUG_EXTERNAL_ENTITIES
3933 xmlGenericError(xmlGenericErrorContext
,
3934 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL
);
3936 if ((ctxt
!= NULL
) && (ctxt
->options
& XML_PARSE_NONET
)) {
3937 int options
= ctxt
->options
;
3939 ctxt
->options
-= XML_PARSE_NONET
;
3940 ret
= xmlNoNetExternalEntityLoader(URL
, ID
, ctxt
);
3941 ctxt
->options
= options
;
3944 #ifdef LIBXML_CATALOG_ENABLED
3945 resource
= xmlResolveResourceFromCatalog(URL
, ID
, ctxt
);
3948 if (resource
== NULL
)
3949 resource
= (xmlChar
*) URL
;
3951 if (resource
== NULL
) {
3954 __xmlLoaderErr(ctxt
, "failed to load external entity \"%s\"\n", ID
);
3957 ret
= xmlNewInputFromFile(ctxt
, (const char *) resource
);
3958 if ((resource
!= NULL
) && (resource
!= (xmlChar
*) URL
))
3963 static xmlExternalEntityLoader xmlCurrentExternalEntityLoader
=
3964 xmlDefaultExternalEntityLoader
;
3967 * xmlSetExternalEntityLoader:
3968 * @f: the new entity resolver function
3970 * Changes the defaultexternal entity resolver function for the application
3973 xmlSetExternalEntityLoader(xmlExternalEntityLoader f
) {
3974 xmlCurrentExternalEntityLoader
= f
;
3978 * xmlGetExternalEntityLoader:
3980 * Get the default external entity resolver function for the application
3982 * Returns the xmlExternalEntityLoader function pointer
3984 xmlExternalEntityLoader
3985 xmlGetExternalEntityLoader(void) {
3986 return(xmlCurrentExternalEntityLoader
);
3990 * xmlLoadExternalEntity:
3991 * @URL: the URL for the entity to load
3992 * @ID: the Public ID for the entity to load
3993 * @ctxt: the context in which the entity is called or NULL
3995 * Load an external entity, note that the use of this function for
3996 * unparsed entities may generate problems
3998 * Returns the xmlParserInputPtr or NULL
4001 xmlLoadExternalEntity(const char *URL
, const char *ID
,
4002 xmlParserCtxtPtr ctxt
) {
4003 if ((URL
!= NULL
) && (xmlNoNetExists(URL
) == 0)) {
4004 char *canonicFilename
;
4005 xmlParserInputPtr ret
;
4007 canonicFilename
= (char *) xmlCanonicPath((const xmlChar
*) URL
);
4008 if (canonicFilename
== NULL
) {
4009 xmlIOErrMemory("building canonical path\n");
4013 ret
= xmlCurrentExternalEntityLoader(canonicFilename
, ID
, ctxt
);
4014 xmlFree(canonicFilename
);
4017 return(xmlCurrentExternalEntityLoader(URL
, ID
, ctxt
));
4020 /************************************************************************
4022 * Disabling Network access *
4024 ************************************************************************/
4027 * xmlNoNetExternalEntityLoader:
4028 * @URL: the URL for the entity to load
4029 * @ID: the System ID for the entity to load
4030 * @ctxt: the context in which the entity is called or NULL
4032 * A specific entity loader disabling network accesses, though still
4033 * allowing local catalog accesses for resolution.
4035 * Returns a new allocated xmlParserInputPtr, or NULL.
4038 xmlNoNetExternalEntityLoader(const char *URL
, const char *ID
,
4039 xmlParserCtxtPtr ctxt
) {
4040 xmlParserInputPtr input
= NULL
;
4041 xmlChar
*resource
= NULL
;
4043 #ifdef LIBXML_CATALOG_ENABLED
4044 resource
= xmlResolveResourceFromCatalog(URL
, ID
, ctxt
);
4047 if (resource
== NULL
)
4048 resource
= (xmlChar
*) URL
;
4050 if (resource
!= NULL
) {
4051 if ((!xmlStrncasecmp(BAD_CAST resource
, BAD_CAST
"ftp://", 6)) ||
4052 (!xmlStrncasecmp(BAD_CAST resource
, BAD_CAST
"http://", 7))) {
4053 xmlIOErr(XML_IO_NETWORK_ATTEMPT
, (const char *) resource
);
4054 if (resource
!= (xmlChar
*) URL
)
4059 input
= xmlDefaultExternalEntityLoader((const char *) resource
, ID
, ctxt
);
4060 if (resource
!= (xmlChar
*) URL
)