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_TYPES_H
19 #include <sys/types.h>
21 #ifdef HAVE_SYS_STAT_H
30 #ifdef LIBXML_ZLIB_ENABLED
33 #ifdef LIBXML_LZMA_ENABLED
40 #else /* __REACTOS__ */
41 #define WIN32_LEAN_AND_MEAN
43 #endif /* __REACTOS__ */
50 # define S_ISDIR(x) _S_ISDIR(x)
51 # elif defined(S_IFDIR)
53 # define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
54 # elif defined(_S_IFMT)
55 # define S_ISDIR(m) (((m) & _S_IFMT) == S_IFDIR)
60 #include <libxml/xmlmemory.h>
61 #include <libxml/parser.h>
62 #include <libxml/parserInternals.h>
63 #include <libxml/xmlIO.h>
64 #include <libxml/uri.h>
65 #include <libxml/nanohttp.h>
66 #include <libxml/nanoftp.h>
67 #include <libxml/xmlerror.h>
68 #ifdef LIBXML_CATALOG_ENABLED
69 #include <libxml/catalog.h>
71 #include <libxml/globals.h>
76 /* #define VERBOSE_FAILURE */
77 /* #define DEBUG_EXTERNAL_ENTITIES */
78 /* #define DEBUG_INPUT */
87 * Input I/O callback sets
89 typedef struct _xmlInputCallback
{
90 xmlInputMatchCallback matchcallback
;
91 xmlInputOpenCallback opencallback
;
92 xmlInputReadCallback readcallback
;
93 xmlInputCloseCallback closecallback
;
96 #define MAX_INPUT_CALLBACK 15
98 static xmlInputCallback xmlInputCallbackTable
[MAX_INPUT_CALLBACK
];
99 static int xmlInputCallbackNr
= 0;
100 static int xmlInputCallbackInitialized
= 0;
102 #ifdef LIBXML_OUTPUT_ENABLED
104 * Output I/O callback sets
106 typedef struct _xmlOutputCallback
{
107 xmlOutputMatchCallback matchcallback
;
108 xmlOutputOpenCallback opencallback
;
109 xmlOutputWriteCallback writecallback
;
110 xmlOutputCloseCallback closecallback
;
113 #define MAX_OUTPUT_CALLBACK 15
115 static xmlOutputCallback xmlOutputCallbackTable
[MAX_OUTPUT_CALLBACK
];
116 static int xmlOutputCallbackNr
= 0;
117 static int xmlOutputCallbackInitialized
= 0;
120 xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder
);
121 #endif /* LIBXML_OUTPUT_ENABLED */
123 /************************************************************************
125 * Tree memory error handler *
127 ************************************************************************/
129 static const char* const IOerr
[] = {
130 "Unknown IO error", /* UNKNOWN */
131 "Permission denied", /* EACCES */
132 "Resource temporarily unavailable",/* EAGAIN */
133 "Bad file descriptor", /* EBADF */
134 "Bad message", /* EBADMSG */
135 "Resource busy", /* EBUSY */
136 "Operation canceled", /* ECANCELED */
137 "No child processes", /* ECHILD */
138 "Resource deadlock avoided",/* EDEADLK */
139 "Domain error", /* EDOM */
140 "File exists", /* EEXIST */
141 "Bad address", /* EFAULT */
142 "File too large", /* EFBIG */
143 "Operation in progress", /* EINPROGRESS */
144 "Interrupted function call",/* EINTR */
145 "Invalid argument", /* EINVAL */
146 "Input/output error", /* EIO */
147 "Is a directory", /* EISDIR */
148 "Too many open files", /* EMFILE */
149 "Too many links", /* EMLINK */
150 "Inappropriate message buffer length",/* EMSGSIZE */
151 "Filename too long", /* ENAMETOOLONG */
152 "Too many open files in system",/* ENFILE */
153 "No such device", /* ENODEV */
154 "No such file or directory",/* ENOENT */
155 "Exec format error", /* ENOEXEC */
156 "No locks available", /* ENOLCK */
157 "Not enough space", /* ENOMEM */
158 "No space left on device", /* ENOSPC */
159 "Function not implemented", /* ENOSYS */
160 "Not a directory", /* ENOTDIR */
161 "Directory not empty", /* ENOTEMPTY */
162 "Not supported", /* ENOTSUP */
163 "Inappropriate I/O control operation",/* ENOTTY */
164 "No such device or address",/* ENXIO */
165 "Operation not permitted", /* EPERM */
166 "Broken pipe", /* EPIPE */
167 "Result too large", /* ERANGE */
168 "Read-only file system", /* EROFS */
169 "Invalid seek", /* ESPIPE */
170 "No such process", /* ESRCH */
171 "Operation timed out", /* ETIMEDOUT */
172 "Improper link", /* EXDEV */
173 "Attempt to load network entity %s", /* XML_IO_NETWORK_ATTEMPT */
174 "encoder error", /* XML_IO_ENCODER */
180 "not a socket", /* ENOTSOCK */
181 "already connected", /* EISCONN */
182 "connection refused", /* ECONNREFUSED */
183 "unreachable network", /* ENETUNREACH */
184 "address in use", /* EADDRINUSE */
185 "already in use", /* EALREADY */
186 "unknown address family", /* EAFNOSUPPORT */
191 * __xmlIOWin32UTF8ToWChar:
192 * @u8String: uft-8 string
194 * Convert a string from utf-8 to wchar (WINDOWS ONLY!)
197 __xmlIOWin32UTF8ToWChar(const char *u8String
)
199 wchar_t *wString
= NULL
;
203 MultiByteToWideChar(CP_UTF8
, MB_ERR_INVALID_CHARS
, u8String
,
206 wString
= xmlMalloc(wLen
* sizeof(wchar_t));
208 if (MultiByteToWideChar
209 (CP_UTF8
, 0, u8String
, -1, wString
, wLen
) == 0) {
223 * @extra: extra information
225 * Handle an out of memory condition
228 xmlIOErrMemory(const char *extra
)
230 __xmlSimpleError(XML_FROM_IO
, XML_ERR_NO_MEMORY
, NULL
, NULL
, extra
);
235 * @code: the error number
237 * @extra: extra information
239 * Handle an I/O error
242 __xmlIOErr(int domain
, int code
, const char *extra
)
247 if (errno
== 0) code
= 0;
249 else if (errno
== EACCES
) code
= XML_IO_EACCES
;
252 else if (errno
== EAGAIN
) code
= XML_IO_EAGAIN
;
255 else if (errno
== EBADF
) code
= XML_IO_EBADF
;
258 else if (errno
== EBADMSG
) code
= XML_IO_EBADMSG
;
261 else if (errno
== EBUSY
) code
= XML_IO_EBUSY
;
264 else if (errno
== ECANCELED
) code
= XML_IO_ECANCELED
;
267 else if (errno
== ECHILD
) code
= XML_IO_ECHILD
;
270 else if (errno
== EDEADLK
) code
= XML_IO_EDEADLK
;
273 else if (errno
== EDOM
) code
= XML_IO_EDOM
;
276 else if (errno
== EEXIST
) code
= XML_IO_EEXIST
;
279 else if (errno
== EFAULT
) code
= XML_IO_EFAULT
;
282 else if (errno
== EFBIG
) code
= XML_IO_EFBIG
;
285 else if (errno
== EINPROGRESS
) code
= XML_IO_EINPROGRESS
;
288 else if (errno
== EINTR
) code
= XML_IO_EINTR
;
291 else if (errno
== EINVAL
) code
= XML_IO_EINVAL
;
294 else if (errno
== EIO
) code
= XML_IO_EIO
;
297 else if (errno
== EISDIR
) code
= XML_IO_EISDIR
;
300 else if (errno
== EMFILE
) code
= XML_IO_EMFILE
;
303 else if (errno
== EMLINK
) code
= XML_IO_EMLINK
;
306 else if (errno
== EMSGSIZE
) code
= XML_IO_EMSGSIZE
;
309 else if (errno
== ENAMETOOLONG
) code
= XML_IO_ENAMETOOLONG
;
312 else if (errno
== ENFILE
) code
= XML_IO_ENFILE
;
315 else if (errno
== ENODEV
) code
= XML_IO_ENODEV
;
318 else if (errno
== ENOENT
) code
= XML_IO_ENOENT
;
321 else if (errno
== ENOEXEC
) code
= XML_IO_ENOEXEC
;
324 else if (errno
== ENOLCK
) code
= XML_IO_ENOLCK
;
327 else if (errno
== ENOMEM
) code
= XML_IO_ENOMEM
;
330 else if (errno
== ENOSPC
) code
= XML_IO_ENOSPC
;
333 else if (errno
== ENOSYS
) code
= XML_IO_ENOSYS
;
336 else if (errno
== ENOTDIR
) code
= XML_IO_ENOTDIR
;
339 else if (errno
== ENOTEMPTY
) code
= XML_IO_ENOTEMPTY
;
342 else if (errno
== ENOTSUP
) code
= XML_IO_ENOTSUP
;
345 else if (errno
== ENOTTY
) code
= XML_IO_ENOTTY
;
348 else if (errno
== ENXIO
) code
= XML_IO_ENXIO
;
351 else if (errno
== EPERM
) code
= XML_IO_EPERM
;
354 else if (errno
== EPIPE
) code
= XML_IO_EPIPE
;
357 else if (errno
== ERANGE
) code
= XML_IO_ERANGE
;
360 else if (errno
== EROFS
) code
= XML_IO_EROFS
;
363 else if (errno
== ESPIPE
) code
= XML_IO_ESPIPE
;
366 else if (errno
== ESRCH
) code
= XML_IO_ESRCH
;
369 else if (errno
== ETIMEDOUT
) code
= XML_IO_ETIMEDOUT
;
372 else if (errno
== EXDEV
) code
= XML_IO_EXDEV
;
375 else if (errno
== ENOTSOCK
) code
= XML_IO_ENOTSOCK
;
378 else if (errno
== EISCONN
) code
= XML_IO_EISCONN
;
381 else if (errno
== ECONNREFUSED
) code
= XML_IO_ECONNREFUSED
;
384 else if (errno
== ETIMEDOUT
) code
= XML_IO_ETIMEDOUT
;
387 else if (errno
== ENETUNREACH
) code
= XML_IO_ENETUNREACH
;
390 else if (errno
== EADDRINUSE
) code
= XML_IO_EADDRINUSE
;
393 else if (errno
== EINPROGRESS
) code
= XML_IO_EINPROGRESS
;
396 else if (errno
== EALREADY
) code
= XML_IO_EALREADY
;
399 else if (errno
== EAFNOSUPPORT
) code
= XML_IO_EAFNOSUPPORT
;
401 else code
= XML_IO_UNKNOWN
;
404 if (code
>= XML_IO_UNKNOWN
) idx
= code
- XML_IO_UNKNOWN
;
405 if (idx
>= (sizeof(IOerr
) / sizeof(IOerr
[0]))) idx
= 0;
407 __xmlSimpleError(domain
, code
, NULL
, IOerr
[idx
], extra
);
412 * @code: the error number
413 * @extra: extra information
415 * Handle an I/O error
418 xmlIOErr(int code
, const char *extra
)
420 __xmlIOErr(XML_FROM_IO
, code
, extra
);
425 * @ctx: the parser context
426 * @extra: extra information
428 * Handle a resource access error
431 __xmlLoaderErr(void *ctx
, const char *msg
, const char *filename
)
433 xmlParserCtxtPtr ctxt
= (xmlParserCtxtPtr
) ctx
;
434 xmlStructuredErrorFunc schannel
= NULL
;
435 xmlGenericErrorFunc channel
= NULL
;
437 xmlErrorLevel level
= XML_ERR_ERROR
;
439 if ((ctxt
!= NULL
) && (ctxt
->disableSAX
!= 0) &&
440 (ctxt
->instate
== XML_PARSER_EOF
))
442 if ((ctxt
!= NULL
) && (ctxt
->sax
!= NULL
)) {
443 if (ctxt
->validate
) {
444 channel
= ctxt
->sax
->error
;
445 level
= XML_ERR_ERROR
;
447 channel
= ctxt
->sax
->warning
;
448 level
= XML_ERR_WARNING
;
450 if (ctxt
->sax
->initialized
== XML_SAX2_MAGIC
)
451 schannel
= ctxt
->sax
->serror
;
452 data
= ctxt
->userData
;
454 __xmlRaiseError(schannel
, channel
, data
, ctxt
, NULL
, XML_FROM_IO
,
455 XML_IO_LOAD_ERROR
, level
, NULL
, 0,
456 filename
, NULL
, NULL
, 0, 0,
461 /************************************************************************
463 * Tree memory error handler *
465 ************************************************************************/
467 * xmlNormalizeWindowsPath:
468 * @path: the input file path
470 * This function is obsolete. Please see xmlURIFromPath in uri.c for
473 * Returns a canonicalized version of the path
476 xmlNormalizeWindowsPath(const xmlChar
*path
)
478 return xmlCanonicPath(path
);
482 * xmlCleanupInputCallbacks:
484 * clears the entire input callback table. this includes the
488 xmlCleanupInputCallbacks(void)
492 if (!xmlInputCallbackInitialized
)
495 for (i
= xmlInputCallbackNr
- 1; i
>= 0; i
--) {
496 xmlInputCallbackTable
[i
].matchcallback
= NULL
;
497 xmlInputCallbackTable
[i
].opencallback
= NULL
;
498 xmlInputCallbackTable
[i
].readcallback
= NULL
;
499 xmlInputCallbackTable
[i
].closecallback
= NULL
;
502 xmlInputCallbackNr
= 0;
503 xmlInputCallbackInitialized
= 0;
507 * xmlPopInputCallbacks:
509 * Clear the top input callback from the input stack. this includes the
512 * Returns the number of input callback registered or -1 in case of error.
515 xmlPopInputCallbacks(void)
517 if (!xmlInputCallbackInitialized
)
520 if (xmlInputCallbackNr
<= 0)
523 xmlInputCallbackNr
--;
524 xmlInputCallbackTable
[xmlInputCallbackNr
].matchcallback
= NULL
;
525 xmlInputCallbackTable
[xmlInputCallbackNr
].opencallback
= NULL
;
526 xmlInputCallbackTable
[xmlInputCallbackNr
].readcallback
= NULL
;
527 xmlInputCallbackTable
[xmlInputCallbackNr
].closecallback
= NULL
;
529 return(xmlInputCallbackNr
);
532 #ifdef LIBXML_OUTPUT_ENABLED
534 * xmlCleanupOutputCallbacks:
536 * clears the entire output callback table. this includes the
537 * compiled-in I/O callbacks.
540 xmlCleanupOutputCallbacks(void)
544 if (!xmlOutputCallbackInitialized
)
547 for (i
= xmlOutputCallbackNr
- 1; i
>= 0; i
--) {
548 xmlOutputCallbackTable
[i
].matchcallback
= NULL
;
549 xmlOutputCallbackTable
[i
].opencallback
= NULL
;
550 xmlOutputCallbackTable
[i
].writecallback
= NULL
;
551 xmlOutputCallbackTable
[i
].closecallback
= NULL
;
554 xmlOutputCallbackNr
= 0;
555 xmlOutputCallbackInitialized
= 0;
559 * xmlPopOutputCallbacks:
561 * Remove the top output callbacks from the output stack. This includes the
564 * Returns the number of output callback registered or -1 in case of error.
567 xmlPopOutputCallbacks(void)
569 if (!xmlOutputCallbackInitialized
)
572 if (xmlOutputCallbackNr
<= 0)
575 xmlOutputCallbackNr
--;
576 xmlOutputCallbackTable
[xmlOutputCallbackNr
].matchcallback
= NULL
;
577 xmlOutputCallbackTable
[xmlOutputCallbackNr
].opencallback
= NULL
;
578 xmlOutputCallbackTable
[xmlOutputCallbackNr
].writecallback
= NULL
;
579 xmlOutputCallbackTable
[xmlOutputCallbackNr
].closecallback
= NULL
;
581 return(xmlOutputCallbackNr
);
584 #endif /* LIBXML_OUTPUT_ENABLED */
586 /************************************************************************
588 * Standard I/O for file accesses *
590 ************************************************************************/
596 * @path: the path in utf-8 encoding
597 * @mode: type of access (0 - read, 1 - write)
599 * function opens the file specified by @path
603 xmlWrapOpenUtf8(const char *path
,int mode
)
608 wPath
= __xmlIOWin32UTF8ToWChar(path
);
611 fd
= _wfopen(wPath
, mode
? L
"wb" : L
"rb");
614 /* maybe path in native encoding */
616 fd
= fopen(path
, mode
? "wb" : "rb");
621 #ifdef LIBXML_ZLIB_ENABLED
623 xmlWrapGzOpenUtf8(const char *path
, const char *mode
)
628 fd
= gzopen (path
, mode
);
632 wPath
= __xmlIOWin32UTF8ToWChar(path
);
635 int d
, m
= (strstr(mode
, "r") ? O_RDONLY
: O_RDWR
);
637 m
|= (strstr(mode
, "b") ? _O_BINARY
: 0);
639 d
= _wopen(wPath
, m
);
641 fd
= gzdopen(d
, mode
);
651 * @path: the path in utf-8 encoding
652 * @info: structure that stores results
654 * function obtains information about the file or directory
658 xmlWrapStatUtf8(const char *path
, struct _stat
*info
) {
662 wPath
= __xmlIOWin32UTF8ToWChar(path
);
664 retval
= _wstat(wPath
, info
);
667 /* maybe path in native encoding */
669 retval
= _stat(path
, info
);
677 * @path: the path to check
679 * function checks to see if @path is a valid source
680 * (file, socket...) for XML.
682 * if stat is not available on the target machine,
683 * returns 1. if stat fails, returns 0 (if calling
684 * stat on the filename fails, it can't be right).
685 * if stat succeeds and the file is a directory,
686 * returns 2. otherwise returns 1.
690 xmlCheckFilename (const char *path
)
694 struct _stat stat_buffer
;
696 struct stat stat_buffer
;
705 * On Windows stat and wstat do not work with long pathname,
706 * which start with '\\?\'
708 if ((path
[0] == '\\') && (path
[1] == '\\') && (path
[2] == '?') &&
712 if (xmlWrapStatUtf8(path
, &stat_buffer
) == -1)
715 if (stat(path
, &stat_buffer
) == -1)
719 if (S_ISDIR(stat_buffer
.st_mode
))
722 #endif /* HAVE_STAT */
727 * xmlInputReadCallbackNop:
729 * No Operation xmlInputReadCallback function, does nothing.
734 xmlInputReadCallbackNop(void *context ATTRIBUTE_UNUSED
,
735 char *buffer ATTRIBUTE_UNUSED
,
736 int len ATTRIBUTE_UNUSED
) {
742 * @context: the I/O context
743 * @buffer: where to drop data
744 * @len: number of bytes to read
746 * Read @len bytes to @buffer from the I/O channel.
748 * Returns the number of bytes written
751 xmlFdRead (void * context
, char * buffer
, int len
) {
754 ret
= read((int) (ptrdiff_t) context
, &buffer
[0], len
);
755 if (ret
< 0) xmlIOErr(0, "read()");
759 #ifdef LIBXML_OUTPUT_ENABLED
762 * @context: the I/O context
763 * @buffer: where to get data
764 * @len: number of bytes to write
766 * Write @len bytes from @buffer to the I/O channel.
768 * Returns the number of bytes written
771 xmlFdWrite (void * context
, const char * buffer
, int len
) {
775 ret
= write((int) (ptrdiff_t) context
, &buffer
[0], len
);
776 if (ret
< 0) xmlIOErr(0, "write()");
780 #endif /* LIBXML_OUTPUT_ENABLED */
784 * @context: the I/O context
786 * Close an I/O channel
788 * Returns 0 in case of success and error code otherwise
791 xmlFdClose (void * context
) {
793 ret
= close((int) (ptrdiff_t) context
);
794 if (ret
< 0) xmlIOErr(0, "close()");
800 * @filename: the URI for matching
804 * Returns 1 if matches, 0 otherwise
807 xmlFileMatch (const char *filename ATTRIBUTE_UNUSED
) {
813 * @filename: the URI for matching
815 * input from FILE *, supports compressed input
816 * if @filename is " " then the standard input is used
818 * Returns an I/O context or NULL in case of error
821 xmlFileOpen_real (const char *filename
) {
822 const char *path
= filename
;
825 if (filename
== NULL
)
828 if (!strcmp(filename
, "-")) {
833 if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file://localhost/", 17)) {
835 path
= &filename
[17];
837 path
= &filename
[16];
839 } else if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file:///", 8)) {
845 } else if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file:/", 6)) {
846 /* lots of generators seems to lazy to read RFC 1738 */
854 /* Do not check DDNAME on zOS ! */
855 #if !defined(__MVS__)
856 if (!xmlCheckFilename(path
))
861 fd
= xmlWrapOpenUtf8(path
, 0);
863 fd
= fopen(path
, "rb");
865 if (fd
== NULL
) xmlIOErr(0, path
);
871 * @filename: the URI for matching
873 * Wrapper around xmlFileOpen_real that try it with an unescaped
874 * version of @filename, if this fails fallback to @filename
876 * Returns a handler or NULL in case or failure
879 xmlFileOpen (const char *filename
) {
883 retval
= xmlFileOpen_real(filename
);
884 if (retval
== NULL
) {
885 unescaped
= xmlURIUnescapeString(filename
, 0, NULL
);
886 if (unescaped
!= NULL
) {
887 retval
= xmlFileOpen_real(unescaped
);
895 #ifdef LIBXML_OUTPUT_ENABLED
898 * @filename: the URI for matching
900 * output to from FILE *,
901 * if @filename is "-" then the standard output is used
903 * Returns an I/O context or NULL in case of error
906 xmlFileOpenW (const char *filename
) {
907 const char *path
= NULL
;
910 if (!strcmp(filename
, "-")) {
915 if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file://localhost/", 17))
917 path
= &filename
[17];
919 path
= &filename
[16];
921 else if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file:///", 8)) {
934 fd
= xmlWrapOpenUtf8(path
, 1);
936 fd
= fopen(path
, "w");
938 fd
= fopen(path
, "wb");
941 if (fd
== NULL
) xmlIOErr(0, path
);
944 #endif /* LIBXML_OUTPUT_ENABLED */
948 * @context: the I/O context
949 * @buffer: where to drop data
950 * @len: number of bytes to write
952 * Read @len bytes to @buffer from the I/O channel.
954 * Returns the number of bytes written or < 0 in case of failure
957 xmlFileRead (void * context
, char * buffer
, int len
) {
959 if ((context
== NULL
) || (buffer
== NULL
))
961 ret
= fread(&buffer
[0], 1, len
, (FILE *) context
);
962 if (ret
< 0) xmlIOErr(0, "fread()");
966 #ifdef LIBXML_OUTPUT_ENABLED
969 * @context: the I/O context
970 * @buffer: where to drop data
971 * @len: number of bytes to write
973 * Write @len bytes from @buffer to the I/O channel.
975 * Returns the number of bytes written
978 xmlFileWrite (void * context
, const char * buffer
, int len
) {
981 if ((context
== NULL
) || (buffer
== NULL
))
983 items
= fwrite(&buffer
[0], len
, 1, (FILE *) context
);
984 if ((items
== 0) && (ferror((FILE *) context
))) {
985 xmlIOErr(0, "fwrite()");
990 #endif /* LIBXML_OUTPUT_ENABLED */
994 * @context: the I/O context
996 * Close an I/O channel
998 * Returns 0 or -1 in case of error
1001 xmlFileClose (void * context
) {
1005 if (context
== NULL
)
1007 fil
= (FILE *) context
;
1008 if ((fil
== stdout
) || (fil
== stderr
)) {
1011 xmlIOErr(0, "fflush()");
1016 ret
= ( fclose((FILE *) context
) == EOF
) ? -1 : 0;
1018 xmlIOErr(0, "fclose()");
1024 * @context: the I/O context
1026 * Flush an I/O channel
1029 xmlFileFlush (void * context
) {
1032 if (context
== NULL
)
1034 ret
= ( fflush((FILE *) context
) == EOF
) ? -1 : 0;
1036 xmlIOErr(0, "fflush()");
1040 #ifdef LIBXML_OUTPUT_ENABLED
1043 * @context: the xmlBuffer
1044 * @buffer: the data to write
1045 * @len: number of bytes to write
1047 * Write @len bytes from @buffer to the xml buffer
1049 * Returns the number of bytes written
1052 xmlBufferWrite (void * context
, const char * buffer
, int len
) {
1055 ret
= xmlBufferAdd((xmlBufferPtr
) context
, (const xmlChar
*) buffer
, len
);
1062 #ifdef LIBXML_ZLIB_ENABLED
1063 /************************************************************************
1065 * I/O for compressed file accesses *
1067 ************************************************************************/
1070 * @filename: the URI for matching
1072 * input from compressed file test
1074 * Returns 1 if matches, 0 otherwise
1077 xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED
) {
1082 * xmlGzfileOpen_real:
1083 * @filename: the URI for matching
1085 * input from compressed file open
1086 * if @filename is " " then the standard input is used
1088 * Returns an I/O context or NULL in case of error
1091 xmlGzfileOpen_real (const char *filename
) {
1092 const char *path
= NULL
;
1095 if (!strcmp(filename
, "-")) {
1096 int duped_fd
= dup(fileno(stdin
));
1097 fd
= gzdopen(duped_fd
, "rb");
1098 if (fd
== Z_NULL
&& duped_fd
>= 0) {
1099 close(duped_fd
); /* gzdOpen() does not close on failure */
1102 return((void *) fd
);
1105 if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file://localhost/", 17))
1106 #if defined (_WIN32)
1107 path
= &filename
[17];
1109 path
= &filename
[16];
1111 else if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file:///", 8)) {
1112 #if defined (_WIN32)
1113 path
= &filename
[8];
1115 path
= &filename
[7];
1122 if (!xmlCheckFilename(path
))
1126 fd
= xmlWrapGzOpenUtf8(path
, "rb");
1128 fd
= gzopen(path
, "rb");
1130 return((void *) fd
);
1135 * @filename: the URI for matching
1137 * Wrapper around xmlGzfileOpen_real if the open fails, it will
1138 * try to unescape @filename
1141 xmlGzfileOpen (const char *filename
) {
1145 retval
= xmlGzfileOpen_real(filename
);
1146 if (retval
== NULL
) {
1147 unescaped
= xmlURIUnescapeString(filename
, 0, NULL
);
1148 if (unescaped
!= NULL
) {
1149 retval
= xmlGzfileOpen_real(unescaped
);
1156 #ifdef LIBXML_OUTPUT_ENABLED
1159 * @filename: the URI for matching
1160 * @compression: the compression factor (0 - 9 included)
1162 * input from compressed file open
1163 * if @filename is " " then the standard input is used
1165 * Returns an I/O context or NULL in case of error
1168 xmlGzfileOpenW (const char *filename
, int compression
) {
1169 const char *path
= NULL
;
1173 snprintf(mode
, sizeof(mode
), "wb%d", compression
);
1174 if (!strcmp(filename
, "-")) {
1175 int duped_fd
= dup(fileno(stdout
));
1176 fd
= gzdopen(duped_fd
, "rb");
1177 if (fd
== Z_NULL
&& duped_fd
>= 0) {
1178 close(duped_fd
); /* gzdOpen() does not close on failure */
1181 return((void *) fd
);
1184 if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file://localhost/", 17))
1185 #if defined (_WIN32)
1186 path
= &filename
[17];
1188 path
= &filename
[16];
1190 else if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file:///", 8)) {
1191 #if defined (_WIN32)
1192 path
= &filename
[8];
1194 path
= &filename
[7];
1203 fd
= xmlWrapGzOpenUtf8(path
, mode
);
1205 fd
= gzopen(path
, mode
);
1207 return((void *) fd
);
1209 #endif /* LIBXML_OUTPUT_ENABLED */
1213 * @context: the I/O context
1214 * @buffer: where to drop data
1215 * @len: number of bytes to write
1217 * Read @len bytes to @buffer from the compressed I/O channel.
1219 * Returns the number of bytes read.
1222 xmlGzfileRead (void * context
, char * buffer
, int len
) {
1225 ret
= gzread((gzFile
) context
, &buffer
[0], len
);
1226 if (ret
< 0) xmlIOErr(0, "gzread()");
1230 #ifdef LIBXML_OUTPUT_ENABLED
1233 * @context: the I/O context
1234 * @buffer: where to drop data
1235 * @len: number of bytes to write
1237 * Write @len bytes from @buffer to the compressed I/O channel.
1239 * Returns the number of bytes written
1242 xmlGzfileWrite (void * context
, const char * buffer
, int len
) {
1245 ret
= gzwrite((gzFile
) context
, (char *) &buffer
[0], len
);
1246 if (ret
< 0) xmlIOErr(0, "gzwrite()");
1249 #endif /* LIBXML_OUTPUT_ENABLED */
1253 * @context: the I/O context
1255 * Close a compressed I/O channel
1258 xmlGzfileClose (void * context
) {
1261 ret
= (gzclose((gzFile
) context
) == Z_OK
) ? 0 : -1;
1262 if (ret
< 0) xmlIOErr(0, "gzclose()");
1265 #endif /* LIBXML_ZLIB_ENABLED */
1267 #ifdef LIBXML_LZMA_ENABLED
1268 /************************************************************************
1270 * I/O for compressed file accesses *
1272 ************************************************************************/
1276 * @filename: the URI for matching
1278 * input from compressed file test
1280 * Returns 1 if matches, 0 otherwise
1283 xmlXzfileMatch (const char *filename ATTRIBUTE_UNUSED
) {
1288 * xmlXzFileOpen_real:
1289 * @filename: the URI for matching
1291 * input from compressed file open
1292 * if @filename is " " then the standard input is used
1294 * Returns an I/O context or NULL in case of error
1297 xmlXzfileOpen_real (const char *filename
) {
1298 const char *path
= NULL
;
1301 if (!strcmp(filename
, "-")) {
1302 fd
= __libxml2_xzdopen(dup(fileno(stdin
)), "rb");
1303 return((void *) fd
);
1306 if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file://localhost/", 17)) {
1307 path
= &filename
[16];
1308 } else if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file:///", 8)) {
1309 path
= &filename
[7];
1310 } else if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file:/", 6)) {
1311 /* lots of generators seems to lazy to read RFC 1738 */
1312 path
= &filename
[5];
1318 if (!xmlCheckFilename(path
))
1321 fd
= __libxml2_xzopen(path
, "rb");
1322 return((void *) fd
);
1327 * @filename: the URI for matching
1329 * Wrapper around xmlXzfileOpen_real that try it with an unescaped
1330 * version of @filename, if this fails fallback to @filename
1332 * Returns a handler or NULL in case or failure
1335 xmlXzfileOpen (const char *filename
) {
1339 retval
= xmlXzfileOpen_real(filename
);
1340 if (retval
== NULL
) {
1341 unescaped
= xmlURIUnescapeString(filename
, 0, NULL
);
1342 if (unescaped
!= NULL
) {
1343 retval
= xmlXzfileOpen_real(unescaped
);
1353 * @context: the I/O context
1354 * @buffer: where to drop data
1355 * @len: number of bytes to write
1357 * Read @len bytes to @buffer from the compressed I/O channel.
1359 * Returns the number of bytes written
1362 xmlXzfileRead (void * context
, char * buffer
, int len
) {
1365 ret
= __libxml2_xzread((xzFile
) context
, &buffer
[0], len
);
1366 if (ret
< 0) xmlIOErr(0, "xzread()");
1372 * @context: the I/O context
1374 * Close a compressed I/O channel
1377 xmlXzfileClose (void * context
) {
1380 ret
= (__libxml2_xzclose((xzFile
) context
) == LZMA_OK
) ? 0 : -1;
1381 if (ret
< 0) xmlIOErr(0, "xzclose()");
1384 #endif /* LIBXML_LZMA_ENABLED */
1386 #ifdef LIBXML_HTTP_ENABLED
1387 /************************************************************************
1389 * I/O for HTTP file accesses *
1391 ************************************************************************/
1393 #ifdef LIBXML_OUTPUT_ENABLED
1394 typedef struct xmlIOHTTPWriteCtxt_
1402 } xmlIOHTTPWriteCtxt
, *xmlIOHTTPWriteCtxtPtr
;
1404 #ifdef LIBXML_ZLIB_ENABLED
1406 #define DFLT_WBITS ( -15 )
1407 #define DFLT_MEM_LVL ( 8 )
1408 #define GZ_MAGIC1 ( 0x1f )
1409 #define GZ_MAGIC2 ( 0x8b )
1410 #define LXML_ZLIB_OS_CODE ( 0x03 )
1411 #define INIT_HTTP_BUFF_SIZE ( 32768 )
1412 #define DFLT_ZLIB_RATIO ( 5 )
1415 ** Data structure and functions to work with sending compressed data
1419 typedef struct xmlZMemBuff_
1424 unsigned char * zbuff
;
1427 } xmlZMemBuff
, *xmlZMemBuffPtr
;
1430 * append_reverse_ulong
1431 * @buff: Compressed memory buffer
1432 * @data: Unsigned long to append
1434 * Append a unsigned long in reverse byte order to the end of the
1438 append_reverse_ulong( xmlZMemBuff
* buff
, unsigned long data
) {
1446 ** This is plagiarized from putLong in gzio.c (zlib source) where
1447 ** the number "4" is hardcoded. If zlib is ever patched to
1448 ** support 64 bit file sizes, this code would need to be patched
1452 for ( idx
= 0; idx
< 4; idx
++ ) {
1453 *buff
->zctrl
.next_out
= ( data
& 0xff );
1455 buff
->zctrl
.next_out
++;
1464 * @buff: The memory buffer context to clear
1466 * Release all the resources associated with the compressed memory buffer.
1469 xmlFreeZMemBuff( xmlZMemBuffPtr buff
) {
1478 xmlFree( buff
->zbuff
);
1480 z_err
= deflateEnd( &buff
->zctrl
);
1481 if ( z_err
!= Z_OK
)
1482 xmlGenericError( xmlGenericErrorContext
,
1483 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
1486 deflateEnd( &buff
->zctrl
);
1495 *@compression: Compression value to use
1497 * Create a memory buffer to hold the compressed XML document. The
1498 * compressed document in memory will end up being identical to what
1499 * would be created if gzopen/gzwrite/gzclose were being used to
1500 * write the document to disk. The code for the header/trailer data to
1501 * the compression is plagiarized from the zlib source files.
1504 xmlCreateZMemBuff( int compression
) {
1508 xmlZMemBuffPtr buff
= NULL
;
1510 if ( ( compression
< 1 ) || ( compression
> 9 ) )
1513 /* Create the control and data areas */
1515 buff
= xmlMalloc( sizeof( xmlZMemBuff
) );
1516 if ( buff
== NULL
) {
1517 xmlIOErrMemory("creating buffer context");
1521 (void)memset( buff
, 0, sizeof( xmlZMemBuff
) );
1522 buff
->size
= INIT_HTTP_BUFF_SIZE
;
1523 buff
->zbuff
= xmlMalloc( buff
->size
);
1524 if ( buff
->zbuff
== NULL
) {
1525 xmlFreeZMemBuff( buff
);
1526 xmlIOErrMemory("creating buffer");
1530 z_err
= deflateInit2( &buff
->zctrl
, compression
, Z_DEFLATED
,
1531 DFLT_WBITS
, DFLT_MEM_LVL
, Z_DEFAULT_STRATEGY
);
1532 if ( z_err
!= Z_OK
) {
1534 xmlFreeZMemBuff( buff
);
1536 xmlStrPrintf(msg
, 500,
1537 "xmlCreateZMemBuff: %s %d\n",
1538 "Error initializing compression context. ZLIB error:",
1540 xmlIOErr(XML_IO_WRITE
, (const char *) msg
);
1544 /* Set the header data. The CRC will be needed for the trailer */
1545 buff
->crc
= crc32( 0L, NULL
, 0 );
1546 hdr_lgth
= snprintf( (char *)buff
->zbuff
, buff
->size
,
1547 "%c%c%c%c%c%c%c%c%c%c",
1548 GZ_MAGIC1
, GZ_MAGIC2
, Z_DEFLATED
,
1549 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE
);
1550 buff
->zctrl
.next_out
= buff
->zbuff
+ hdr_lgth
;
1551 buff
->zctrl
.avail_out
= buff
->size
- hdr_lgth
;
1558 * @buff: Buffer used to compress and consolidate data.
1559 * @ext_amt: Number of bytes to extend the buffer.
1561 * Extend the internal buffer used to store the compressed data by the
1564 * Returns 0 on success or -1 on failure to extend the buffer. On failure
1565 * the original buffer still exists at the original size.
1568 xmlZMemBuffExtend( xmlZMemBuffPtr buff
, size_t ext_amt
) {
1574 unsigned char * tmp_ptr
= NULL
;
1579 else if ( ext_amt
== 0 )
1582 cur_used
= buff
->zctrl
.next_out
- buff
->zbuff
;
1583 new_size
= buff
->size
+ ext_amt
;
1586 if ( cur_used
> new_size
)
1587 xmlGenericError( xmlGenericErrorContext
,
1588 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
1589 "Buffer overwrite detected during compressed memory",
1590 "buffer extension. Overflowed by",
1591 (cur_used
- new_size
) );
1594 tmp_ptr
= xmlRealloc( buff
->zbuff
, new_size
);
1595 if ( tmp_ptr
!= NULL
) {
1597 buff
->size
= new_size
;
1598 buff
->zbuff
= tmp_ptr
;
1599 buff
->zctrl
.next_out
= tmp_ptr
+ cur_used
;
1600 buff
->zctrl
.avail_out
= new_size
- cur_used
;
1604 xmlStrPrintf(msg
, 500,
1605 "xmlZMemBuffExtend: %s %lu bytes.\n",
1606 "Allocation failure extending output buffer to",
1607 (unsigned long) new_size
);
1608 xmlIOErr(XML_IO_WRITE
, (const char *) msg
);
1616 * @buff: Buffer used to compress and consolidate data
1617 * @src: Uncompressed source content to append to buffer
1618 * @len: Length of source data to append to buffer
1620 * Compress and append data to the internal buffer. The data buffer
1621 * will be expanded if needed to store the additional data.
1623 * Returns the number of bytes appended to the buffer or -1 on error.
1626 xmlZMemBuffAppend( xmlZMemBuffPtr buff
, const char * src
, int len
) {
1631 if ( ( buff
== NULL
) || ( src
== NULL
) )
1634 buff
->zctrl
.avail_in
= len
;
1635 buff
->zctrl
.next_in
= (unsigned char *)src
;
1636 while ( buff
->zctrl
.avail_in
> 0 ) {
1638 ** Extend the buffer prior to deflate call if a reasonable amount
1639 ** of output buffer space is not available.
1641 min_accept
= buff
->zctrl
.avail_in
/ DFLT_ZLIB_RATIO
;
1642 if ( buff
->zctrl
.avail_out
<= min_accept
) {
1643 if ( xmlZMemBuffExtend( buff
, buff
->size
) == -1 )
1647 z_err
= deflate( &buff
->zctrl
, Z_NO_FLUSH
);
1648 if ( z_err
!= Z_OK
) {
1650 xmlStrPrintf(msg
, 500,
1651 "xmlZMemBuffAppend: %s %d %s - %d",
1652 "Compression error while appending",
1653 len
, "bytes to buffer. ZLIB error", z_err
);
1654 xmlIOErr(XML_IO_WRITE
, (const char *) msg
);
1659 buff
->crc
= crc32( buff
->crc
, (unsigned char *)src
, len
);
1665 * xmlZMemBuffGetContent
1666 * @buff: Compressed memory content buffer
1667 * @data_ref: Pointer reference to point to compressed content
1669 * Flushes the compression buffers, appends gzip file trailers and
1670 * returns the compressed content and length of the compressed data.
1671 * NOTE: The gzip trailer code here is plagiarized from zlib source.
1673 * Returns the length of the compressed data or -1 on error.
1676 xmlZMemBuffGetContent( xmlZMemBuffPtr buff
, char ** data_ref
) {
1681 if ( ( buff
== NULL
) || ( data_ref
== NULL
) )
1684 /* Need to loop until compression output buffers are flushed */
1688 z_err
= deflate( &buff
->zctrl
, Z_FINISH
);
1689 if ( z_err
== Z_OK
) {
1690 /* In this case Z_OK means more buffer space needed */
1692 if ( xmlZMemBuffExtend( buff
, buff
->size
) == -1 )
1696 while ( z_err
== Z_OK
);
1698 /* If the compression state is not Z_STREAM_END, some error occurred */
1700 if ( z_err
== Z_STREAM_END
) {
1702 /* Need to append the gzip data trailer */
1704 if ( buff
->zctrl
.avail_out
< ( 2 * sizeof( unsigned long ) ) ) {
1705 if ( xmlZMemBuffExtend(buff
, (2 * sizeof(unsigned long))) == -1 )
1710 ** For whatever reason, the CRC and length data are pushed out
1711 ** in reverse byte order. So a memcpy can't be used here.
1714 append_reverse_ulong( buff
, buff
->crc
);
1715 append_reverse_ulong( buff
, buff
->zctrl
.total_in
);
1717 zlgth
= buff
->zctrl
.next_out
- buff
->zbuff
;
1718 *data_ref
= (char *)buff
->zbuff
;
1723 xmlStrPrintf(msg
, 500,
1724 "xmlZMemBuffGetContent: %s - %d\n",
1725 "Error flushing zlib buffers. Error code", z_err
);
1726 xmlIOErr(XML_IO_WRITE
, (const char *) msg
);
1731 #endif /* LIBXML_OUTPUT_ENABLED */
1732 #endif /* LIBXML_ZLIB_ENABLED */
1734 #ifdef LIBXML_OUTPUT_ENABLED
1736 * xmlFreeHTTPWriteCtxt
1737 * @ctxt: Context to cleanup
1739 * Free allocated memory and reclaim system resources.
1744 xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt
)
1746 if ( ctxt
->uri
!= NULL
)
1747 xmlFree( ctxt
->uri
);
1749 if ( ctxt
->doc_buff
!= NULL
) {
1751 #ifdef LIBXML_ZLIB_ENABLED
1752 if ( ctxt
->compression
> 0 ) {
1753 xmlFreeZMemBuff( ctxt
->doc_buff
);
1758 xmlOutputBufferClose( ctxt
->doc_buff
);
1765 #endif /* LIBXML_OUTPUT_ENABLED */
1770 * @filename: the URI for matching
1772 * check if the URI matches an HTTP one
1774 * Returns 1 if matches, 0 otherwise
1777 xmlIOHTTPMatch (const char *filename
) {
1778 if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"http://", 7))
1785 * @filename: the URI for matching
1787 * open an HTTP I/O channel
1789 * Returns an I/O context or NULL in case of error
1792 xmlIOHTTPOpen (const char *filename
) {
1793 return(xmlNanoHTTPOpen(filename
, NULL
));
1796 #ifdef LIBXML_OUTPUT_ENABLED
1799 * @post_uri: The destination URI for the document
1800 * @compression: The compression desired for the document.
1802 * Open a temporary buffer to collect the document for a subsequent HTTP POST
1803 * request. Non-static as is called from the output buffer creation routine.
1805 * Returns an I/O context or NULL in case of error.
1809 xmlIOHTTPOpenW(const char *post_uri
, int compression ATTRIBUTE_UNUSED
)
1812 xmlIOHTTPWriteCtxtPtr ctxt
= NULL
;
1814 if (post_uri
== NULL
)
1817 ctxt
= xmlMalloc(sizeof(xmlIOHTTPWriteCtxt
));
1819 xmlIOErrMemory("creating HTTP output context");
1823 (void) memset(ctxt
, 0, sizeof(xmlIOHTTPWriteCtxt
));
1825 ctxt
->uri
= (char *) xmlStrdup((const xmlChar
*)post_uri
);
1826 if (ctxt
->uri
== NULL
) {
1827 xmlIOErrMemory("copying URI");
1828 xmlFreeHTTPWriteCtxt(ctxt
);
1833 * ** Since the document length is required for an HTTP post,
1834 * ** need to put the document into a buffer. A memory buffer
1835 * ** is being used to avoid pushing the data to disk and back.
1838 #ifdef LIBXML_ZLIB_ENABLED
1839 if ((compression
> 0) && (compression
<= 9)) {
1841 ctxt
->compression
= compression
;
1842 ctxt
->doc_buff
= xmlCreateZMemBuff(compression
);
1846 /* Any character conversions should have been done before this */
1848 ctxt
->doc_buff
= xmlAllocOutputBufferInternal(NULL
);
1851 if (ctxt
->doc_buff
== NULL
) {
1852 xmlFreeHTTPWriteCtxt(ctxt
);
1858 #endif /* LIBXML_OUTPUT_ENABLED */
1860 #ifdef LIBXML_OUTPUT_ENABLED
1862 * xmlIOHTTPDfltOpenW
1863 * @post_uri: The destination URI for this document.
1865 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
1866 * HTTP post command. This function should generally not be used as
1867 * the open callback is short circuited in xmlOutputBufferCreateFile.
1869 * Returns a pointer to the new IO context.
1872 xmlIOHTTPDfltOpenW( const char * post_uri
) {
1873 return ( xmlIOHTTPOpenW( post_uri
, 0 ) );
1875 #endif /* LIBXML_OUTPUT_ENABLED */
1879 * @context: the I/O context
1880 * @buffer: where to drop data
1881 * @len: number of bytes to write
1883 * Read @len bytes to @buffer from the I/O channel.
1885 * Returns the number of bytes written
1888 xmlIOHTTPRead(void * context
, char * buffer
, int len
) {
1889 if ((buffer
== NULL
) || (len
< 0)) return(-1);
1890 return(xmlNanoHTTPRead(context
, &buffer
[0], len
));
1893 #ifdef LIBXML_OUTPUT_ENABLED
1896 * @context: previously opened writing context
1897 * @buffer: data to output to temporary buffer
1898 * @len: bytes to output
1900 * Collect data from memory buffer into a temporary file for later
1903 * Returns number of bytes written.
1907 xmlIOHTTPWrite( void * context
, const char * buffer
, int len
) {
1909 xmlIOHTTPWriteCtxtPtr ctxt
= context
;
1911 if ( ( ctxt
== NULL
) || ( ctxt
->doc_buff
== NULL
) || ( buffer
== NULL
) )
1916 /* Use gzwrite or fwrite as previously setup in the open call */
1918 #ifdef LIBXML_ZLIB_ENABLED
1919 if ( ctxt
->compression
> 0 )
1920 len
= xmlZMemBuffAppend( ctxt
->doc_buff
, buffer
, len
);
1924 len
= xmlOutputBufferWrite( ctxt
->doc_buff
, len
, buffer
);
1928 xmlStrPrintf(msg
, 500,
1929 "xmlIOHTTPWrite: %s\n%s '%s'.\n",
1930 "Error appending to internal buffer.",
1931 "Error sending document to URI",
1933 xmlIOErr(XML_IO_WRITE
, (const char *) msg
);
1939 #endif /* LIBXML_OUTPUT_ENABLED */
1944 * @context: the I/O context
1946 * Close an HTTP I/O channel
1951 xmlIOHTTPClose (void * context
) {
1952 xmlNanoHTTPClose(context
);
1956 #ifdef LIBXML_OUTPUT_ENABLED
1958 * xmlIOHTTCloseWrite
1959 * @context: The I/O context
1960 * @http_mthd: The HTTP method to be used when sending the data
1962 * Close the transmit HTTP I/O channel and actually send the data.
1965 xmlIOHTTPCloseWrite( void * context
, const char * http_mthd
) {
1969 int content_lgth
= 0;
1970 xmlIOHTTPWriteCtxtPtr ctxt
= context
;
1972 char * http_content
= NULL
;
1973 char * content_encoding
= NULL
;
1974 char * content_type
= (char *) "text/xml";
1975 void * http_ctxt
= NULL
;
1977 if ( ( ctxt
== NULL
) || ( http_mthd
== NULL
) )
1980 /* Retrieve the content from the appropriate buffer */
1982 #ifdef LIBXML_ZLIB_ENABLED
1984 if ( ctxt
->compression
> 0 ) {
1985 content_lgth
= xmlZMemBuffGetContent( ctxt
->doc_buff
, &http_content
);
1986 content_encoding
= (char *) "Content-Encoding: gzip";
1991 /* Pull the data out of the memory output buffer */
1993 xmlOutputBufferPtr dctxt
= ctxt
->doc_buff
;
1994 http_content
= (char *) xmlBufContent(dctxt
->buffer
);
1995 content_lgth
= xmlBufUse(dctxt
->buffer
);
1998 if ( http_content
== NULL
) {
2000 xmlStrPrintf(msg
, 500,
2001 "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
2002 "Error retrieving content.\nUnable to",
2003 http_mthd
, "data to URI", ctxt
->uri
);
2004 xmlIOErr(XML_IO_WRITE
, (const char *) msg
);
2009 http_ctxt
= xmlNanoHTTPMethod( ctxt
->uri
, http_mthd
, http_content
,
2010 &content_type
, content_encoding
,
2013 if ( http_ctxt
!= NULL
) {
2015 /* If testing/debugging - dump reply with request content */
2017 FILE * tst_file
= NULL
;
2018 char buffer
[ 4096 ];
2019 char * dump_name
= NULL
;
2022 xmlGenericError( xmlGenericErrorContext
,
2023 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
2024 http_mthd
, ctxt
->uri
,
2025 xmlNanoHTTPReturnCode( http_ctxt
) );
2028 ** Since either content or reply may be gzipped,
2029 ** dump them to separate files instead of the
2030 ** standard error context.
2033 dump_name
= tempnam( NULL
, "lxml" );
2034 if ( dump_name
!= NULL
) {
2035 (void)snprintf( buffer
, sizeof(buffer
), "%s.content", dump_name
);
2037 tst_file
= fopen( buffer
, "wb" );
2038 if ( tst_file
!= NULL
) {
2039 xmlGenericError( xmlGenericErrorContext
,
2040 "Transmitted content saved in file: %s\n", buffer
);
2042 fwrite( http_content
, sizeof( char ),
2043 content_lgth
, tst_file
);
2047 (void)snprintf( buffer
, sizeof(buffer
), "%s.reply", dump_name
);
2048 tst_file
= fopen( buffer
, "wb" );
2049 if ( tst_file
!= NULL
) {
2050 xmlGenericError( xmlGenericErrorContext
,
2051 "Reply content saved in file: %s\n", buffer
);
2054 while ( (avail
= xmlNanoHTTPRead( http_ctxt
,
2055 buffer
, sizeof( buffer
) )) > 0 ) {
2057 fwrite( buffer
, sizeof( char ), avail
, tst_file
);
2065 #endif /* DEBUG_HTTP */
2067 http_rtn
= xmlNanoHTTPReturnCode( http_ctxt
);
2068 if ( ( http_rtn
>= 200 ) && ( http_rtn
< 300 ) )
2072 xmlStrPrintf(msg
, 500,
2073 "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
2074 http_mthd
, content_lgth
,
2075 "bytes to URI", ctxt
->uri
,
2076 "failed. HTTP return code:", http_rtn
);
2077 xmlIOErr(XML_IO_WRITE
, (const char *) msg
);
2080 xmlNanoHTTPClose( http_ctxt
);
2081 xmlFree( content_type
);
2085 /* Final cleanups */
2087 xmlFreeHTTPWriteCtxt( ctxt
);
2089 return ( close_rc
);
2095 * @context: The I/O context
2097 * Close the transmit HTTP I/O channel and actually send data using a PUT
2101 xmlIOHTTPClosePut( void * ctxt
) {
2102 return ( xmlIOHTTPCloseWrite( ctxt
, "PUT" ) );
2107 * xmlIOHTTPClosePost
2109 * @context: The I/O context
2111 * Close the transmit HTTP I/O channel and actually send data using a POST
2115 xmlIOHTTPClosePost( void * ctxt
) {
2116 return ( xmlIOHTTPCloseWrite( ctxt
, "POST" ) );
2118 #endif /* LIBXML_OUTPUT_ENABLED */
2120 #endif /* LIBXML_HTTP_ENABLED */
2122 #ifdef LIBXML_FTP_ENABLED
2123 /************************************************************************
2125 * I/O for FTP file accesses *
2127 ************************************************************************/
2130 * @filename: the URI for matching
2132 * check if the URI matches an FTP one
2134 * Returns 1 if matches, 0 otherwise
2137 xmlIOFTPMatch (const char *filename
) {
2138 if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"ftp://", 6))
2145 * @filename: the URI for matching
2147 * open an FTP I/O channel
2149 * Returns an I/O context or NULL in case of error
2152 xmlIOFTPOpen (const char *filename
) {
2153 return(xmlNanoFTPOpen(filename
));
2158 * @context: the I/O context
2159 * @buffer: where to drop data
2160 * @len: number of bytes to write
2162 * Read @len bytes to @buffer from the I/O channel.
2164 * Returns the number of bytes written
2167 xmlIOFTPRead(void * context
, char * buffer
, int len
) {
2168 if ((buffer
== NULL
) || (len
< 0)) return(-1);
2169 return(xmlNanoFTPRead(context
, &buffer
[0], len
));
2174 * @context: the I/O context
2176 * Close an FTP I/O channel
2181 xmlIOFTPClose (void * context
) {
2182 return ( xmlNanoFTPClose(context
) );
2184 #endif /* LIBXML_FTP_ENABLED */
2188 * xmlRegisterInputCallbacks:
2189 * @matchFunc: the xmlInputMatchCallback
2190 * @openFunc: the xmlInputOpenCallback
2191 * @readFunc: the xmlInputReadCallback
2192 * @closeFunc: the xmlInputCloseCallback
2194 * Register a new set of I/O callback for handling parser input.
2196 * Returns the registered handler number or -1 in case of error
2199 xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc
,
2200 xmlInputOpenCallback openFunc
, xmlInputReadCallback readFunc
,
2201 xmlInputCloseCallback closeFunc
) {
2202 if (xmlInputCallbackNr
>= MAX_INPUT_CALLBACK
) {
2205 xmlInputCallbackTable
[xmlInputCallbackNr
].matchcallback
= matchFunc
;
2206 xmlInputCallbackTable
[xmlInputCallbackNr
].opencallback
= openFunc
;
2207 xmlInputCallbackTable
[xmlInputCallbackNr
].readcallback
= readFunc
;
2208 xmlInputCallbackTable
[xmlInputCallbackNr
].closecallback
= closeFunc
;
2209 xmlInputCallbackInitialized
= 1;
2210 return(xmlInputCallbackNr
++);
2213 #ifdef LIBXML_OUTPUT_ENABLED
2215 * xmlRegisterOutputCallbacks:
2216 * @matchFunc: the xmlOutputMatchCallback
2217 * @openFunc: the xmlOutputOpenCallback
2218 * @writeFunc: the xmlOutputWriteCallback
2219 * @closeFunc: the xmlOutputCloseCallback
2221 * Register a new set of I/O callback for handling output.
2223 * Returns the registered handler number or -1 in case of error
2226 xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc
,
2227 xmlOutputOpenCallback openFunc
, xmlOutputWriteCallback writeFunc
,
2228 xmlOutputCloseCallback closeFunc
) {
2229 if (xmlOutputCallbackNr
>= MAX_OUTPUT_CALLBACK
) {
2232 xmlOutputCallbackTable
[xmlOutputCallbackNr
].matchcallback
= matchFunc
;
2233 xmlOutputCallbackTable
[xmlOutputCallbackNr
].opencallback
= openFunc
;
2234 xmlOutputCallbackTable
[xmlOutputCallbackNr
].writecallback
= writeFunc
;
2235 xmlOutputCallbackTable
[xmlOutputCallbackNr
].closecallback
= closeFunc
;
2236 xmlOutputCallbackInitialized
= 1;
2237 return(xmlOutputCallbackNr
++);
2239 #endif /* LIBXML_OUTPUT_ENABLED */
2242 * xmlRegisterDefaultInputCallbacks:
2244 * Registers the default compiled-in I/O handlers.
2247 xmlRegisterDefaultInputCallbacks(void) {
2248 if (xmlInputCallbackInitialized
)
2251 xmlRegisterInputCallbacks(xmlFileMatch
, xmlFileOpen
,
2252 xmlFileRead
, xmlFileClose
);
2253 #ifdef LIBXML_ZLIB_ENABLED
2254 xmlRegisterInputCallbacks(xmlGzfileMatch
, xmlGzfileOpen
,
2255 xmlGzfileRead
, xmlGzfileClose
);
2256 #endif /* LIBXML_ZLIB_ENABLED */
2257 #ifdef LIBXML_LZMA_ENABLED
2258 xmlRegisterInputCallbacks(xmlXzfileMatch
, xmlXzfileOpen
,
2259 xmlXzfileRead
, xmlXzfileClose
);
2260 #endif /* LIBXML_LZMA_ENABLED */
2262 #ifdef LIBXML_HTTP_ENABLED
2263 xmlRegisterInputCallbacks(xmlIOHTTPMatch
, xmlIOHTTPOpen
,
2264 xmlIOHTTPRead
, xmlIOHTTPClose
);
2265 #endif /* LIBXML_HTTP_ENABLED */
2267 #ifdef LIBXML_FTP_ENABLED
2268 xmlRegisterInputCallbacks(xmlIOFTPMatch
, xmlIOFTPOpen
,
2269 xmlIOFTPRead
, xmlIOFTPClose
);
2270 #endif /* LIBXML_FTP_ENABLED */
2271 xmlInputCallbackInitialized
= 1;
2274 #ifdef LIBXML_OUTPUT_ENABLED
2276 * xmlRegisterDefaultOutputCallbacks:
2278 * Registers the default compiled-in I/O handlers.
2281 xmlRegisterDefaultOutputCallbacks (void) {
2282 if (xmlOutputCallbackInitialized
)
2285 xmlRegisterOutputCallbacks(xmlFileMatch
, xmlFileOpenW
,
2286 xmlFileWrite
, xmlFileClose
);
2288 #ifdef LIBXML_HTTP_ENABLED
2289 xmlRegisterOutputCallbacks(xmlIOHTTPMatch
, xmlIOHTTPDfltOpenW
,
2290 xmlIOHTTPWrite
, xmlIOHTTPClosePut
);
2293 /*********************************
2294 No way a-priori to distinguish between gzipped files from
2295 uncompressed ones except opening if existing then closing
2296 and saving with same compression ratio ... a pain.
2298 #ifdef LIBXML_ZLIB_ENABLED
2299 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
2300 xmlGzfileWrite, xmlGzfileClose);
2304 #ifdef LIBXML_FTP_ENABLED
2305 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
2306 xmlIOFTPWrite, xmlIOFTPClose);
2308 **********************************/
2309 xmlOutputCallbackInitialized
= 1;
2312 #ifdef LIBXML_HTTP_ENABLED
2314 * xmlRegisterHTTPPostCallbacks:
2316 * By default, libxml submits HTTP output requests using the "PUT" method.
2317 * Calling this method changes the HTTP output method to use the "POST"
2322 xmlRegisterHTTPPostCallbacks( void ) {
2324 /* Register defaults if not done previously */
2326 if ( xmlOutputCallbackInitialized
== 0 )
2327 xmlRegisterDefaultOutputCallbacks( );
2329 xmlRegisterOutputCallbacks(xmlIOHTTPMatch
, xmlIOHTTPDfltOpenW
,
2330 xmlIOHTTPWrite
, xmlIOHTTPClosePost
);
2334 #endif /* LIBXML_OUTPUT_ENABLED */
2337 * xmlAllocParserInputBuffer:
2338 * @enc: the charset encoding if known
2340 * Create a buffered parser input for progressive parsing
2342 * Returns the new parser input or NULL
2344 xmlParserInputBufferPtr
2345 xmlAllocParserInputBuffer(xmlCharEncoding enc
) {
2346 xmlParserInputBufferPtr ret
;
2348 ret
= (xmlParserInputBufferPtr
) xmlMalloc(sizeof(xmlParserInputBuffer
));
2350 xmlIOErrMemory("creating input buffer");
2353 memset(ret
, 0, (size_t) sizeof(xmlParserInputBuffer
));
2354 ret
->buffer
= xmlBufCreateSize(2 * xmlDefaultBufferSize
);
2355 if (ret
->buffer
== NULL
) {
2359 xmlBufSetAllocationScheme(ret
->buffer
, XML_BUFFER_ALLOC_DOUBLEIT
);
2360 ret
->encoder
= xmlGetCharEncodingHandler(enc
);
2361 if (ret
->encoder
!= NULL
)
2362 ret
->raw
= xmlBufCreateSize(2 * xmlDefaultBufferSize
);
2365 ret
->readcallback
= NULL
;
2366 ret
->closecallback
= NULL
;
2367 ret
->context
= NULL
;
2368 ret
->compressed
= -1;
2369 ret
->rawconsumed
= 0;
2374 #ifdef LIBXML_OUTPUT_ENABLED
2376 * xmlAllocOutputBuffer:
2377 * @encoder: the encoding converter or NULL
2379 * Create a buffered parser output
2381 * Returns the new parser output or NULL
2384 xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder
) {
2385 xmlOutputBufferPtr ret
;
2387 ret
= (xmlOutputBufferPtr
) xmlMalloc(sizeof(xmlOutputBuffer
));
2389 xmlIOErrMemory("creating output buffer");
2392 memset(ret
, 0, (size_t) sizeof(xmlOutputBuffer
));
2393 ret
->buffer
= xmlBufCreate();
2394 if (ret
->buffer
== NULL
) {
2398 xmlBufSetAllocationScheme(ret
->buffer
, XML_BUFFER_ALLOC_DOUBLEIT
);
2400 ret
->encoder
= encoder
;
2401 if (encoder
!= NULL
) {
2402 ret
->conv
= xmlBufCreateSize(4000);
2403 if (ret
->conv
== NULL
) {
2404 xmlBufFree(ret
->buffer
);
2410 * This call is designed to initiate the encoder state
2412 xmlCharEncOutput(ret
, 1);
2415 ret
->writecallback
= NULL
;
2416 ret
->closecallback
= NULL
;
2417 ret
->context
= NULL
;
2424 * xmlAllocOutputBufferInternal:
2425 * @encoder: the encoding converter or NULL
2427 * Create a buffered parser output
2429 * Returns the new parser output or NULL
2432 xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder
) {
2433 xmlOutputBufferPtr ret
;
2435 ret
= (xmlOutputBufferPtr
) xmlMalloc(sizeof(xmlOutputBuffer
));
2437 xmlIOErrMemory("creating output buffer");
2440 memset(ret
, 0, (size_t) sizeof(xmlOutputBuffer
));
2441 ret
->buffer
= xmlBufCreate();
2442 if (ret
->buffer
== NULL
) {
2449 * For conversion buffers we use the special IO handling
2451 xmlBufSetAllocationScheme(ret
->buffer
, XML_BUFFER_ALLOC_IO
);
2453 ret
->encoder
= encoder
;
2454 if (encoder
!= NULL
) {
2455 ret
->conv
= xmlBufCreateSize(4000);
2456 if (ret
->conv
== NULL
) {
2457 xmlBufFree(ret
->buffer
);
2463 * This call is designed to initiate the encoder state
2465 xmlCharEncOutput(ret
, 1);
2468 ret
->writecallback
= NULL
;
2469 ret
->closecallback
= NULL
;
2470 ret
->context
= NULL
;
2476 #endif /* LIBXML_OUTPUT_ENABLED */
2479 * xmlFreeParserInputBuffer:
2480 * @in: a buffered parser input
2482 * Free up the memory used by a buffered parser input
2485 xmlFreeParserInputBuffer(xmlParserInputBufferPtr in
) {
2486 if (in
== NULL
) return;
2489 xmlBufFree(in
->raw
);
2492 if (in
->encoder
!= NULL
) {
2493 xmlCharEncCloseFunc(in
->encoder
);
2495 if (in
->closecallback
!= NULL
) {
2496 in
->closecallback(in
->context
);
2498 if (in
->buffer
!= NULL
) {
2499 xmlBufFree(in
->buffer
);
2506 #ifdef LIBXML_OUTPUT_ENABLED
2508 * xmlOutputBufferClose:
2509 * @out: a buffered output
2511 * flushes and close the output I/O channel
2512 * and free up all the associated resources
2514 * Returns the number of byte written or -1 in case of error.
2517 xmlOutputBufferClose(xmlOutputBufferPtr out
)
2524 if (out
->writecallback
!= NULL
)
2525 xmlOutputBufferFlush(out
);
2526 if (out
->closecallback
!= NULL
) {
2527 err_rc
= out
->closecallback(out
->context
);
2529 written
= out
->written
;
2531 xmlBufFree(out
->conv
);
2534 if (out
->encoder
!= NULL
) {
2535 xmlCharEncCloseFunc(out
->encoder
);
2537 if (out
->buffer
!= NULL
) {
2538 xmlBufFree(out
->buffer
);
2545 return ((err_rc
== 0) ? written
: err_rc
);
2547 #endif /* LIBXML_OUTPUT_ENABLED */
2549 xmlParserInputBufferPtr
2550 __xmlParserInputBufferCreateFilename(const char *URI
, xmlCharEncoding enc
) {
2551 xmlParserInputBufferPtr ret
;
2553 void *context
= NULL
;
2555 if (xmlInputCallbackInitialized
== 0)
2556 xmlRegisterDefaultInputCallbacks();
2558 if (URI
== NULL
) return(NULL
);
2561 * Try to find one of the input accept method accepting that scheme
2562 * Go in reverse to give precedence to user defined handlers.
2564 if (context
== NULL
) {
2565 for (i
= xmlInputCallbackNr
- 1;i
>= 0;i
--) {
2566 if ((xmlInputCallbackTable
[i
].matchcallback
!= NULL
) &&
2567 (xmlInputCallbackTable
[i
].matchcallback(URI
) != 0)) {
2568 context
= xmlInputCallbackTable
[i
].opencallback(URI
);
2569 if (context
!= NULL
) {
2575 if (context
== NULL
) {
2580 * Allocate the Input buffer front-end.
2582 ret
= xmlAllocParserInputBuffer(enc
);
2584 ret
->context
= context
;
2585 ret
->readcallback
= xmlInputCallbackTable
[i
].readcallback
;
2586 ret
->closecallback
= xmlInputCallbackTable
[i
].closecallback
;
2587 #ifdef LIBXML_ZLIB_ENABLED
2588 if ((xmlInputCallbackTable
[i
].opencallback
== xmlGzfileOpen
) &&
2589 (strcmp(URI
, "-") != 0)) {
2590 #if defined(ZLIB_VERNUM) && ZLIB_VERNUM >= 0x1230
2591 ret
->compressed
= !gzdirect(context
);
2593 if (((z_stream
*)context
)->avail_in
> 4) {
2594 char *cptr
, buff4
[4];
2595 cptr
= (char *) ((z_stream
*)context
)->next_in
;
2596 if (gzread(context
, buff4
, 4) == 4) {
2597 if (strncmp(buff4
, cptr
, 4) == 0)
2598 ret
->compressed
= 0;
2600 ret
->compressed
= 1;
2607 #ifdef LIBXML_LZMA_ENABLED
2608 if ((xmlInputCallbackTable
[i
].opencallback
== xmlXzfileOpen
) &&
2609 (strcmp(URI
, "-") != 0)) {
2610 ret
->compressed
= __libxml2_xzcompressed(context
);
2615 xmlInputCallbackTable
[i
].closecallback (context
);
2621 * xmlParserInputBufferCreateFilename:
2622 * @URI: a C string containing the URI or filename
2623 * @enc: the charset encoding if known
2625 * Create a buffered parser input for the progressive parsing of a file
2626 * If filename is "-' then we use stdin as the input.
2627 * Automatic support for ZLIB/Compress compressed document is provided
2628 * by default if found at compile-time.
2629 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
2631 * Returns the new parser input or NULL
2633 xmlParserInputBufferPtr
2634 xmlParserInputBufferCreateFilename(const char *URI
, xmlCharEncoding enc
) {
2635 if ((xmlParserInputBufferCreateFilenameValue
)) {
2636 return xmlParserInputBufferCreateFilenameValue(URI
, enc
);
2638 return __xmlParserInputBufferCreateFilename(URI
, enc
);
2641 #ifdef LIBXML_OUTPUT_ENABLED
2643 __xmlOutputBufferCreateFilename(const char *URI
,
2644 xmlCharEncodingHandlerPtr encoder
,
2645 int compression ATTRIBUTE_UNUSED
) {
2646 xmlOutputBufferPtr ret
;
2649 void *context
= NULL
;
2650 char *unescaped
= NULL
;
2651 #ifdef LIBXML_ZLIB_ENABLED
2652 int is_file_uri
= 1;
2655 if (xmlOutputCallbackInitialized
== 0)
2656 xmlRegisterDefaultOutputCallbacks();
2658 if (URI
== NULL
) return(NULL
);
2660 puri
= xmlParseURI(URI
);
2662 #ifdef LIBXML_ZLIB_ENABLED
2663 if ((puri
->scheme
!= NULL
) &&
2664 (!xmlStrEqual(BAD_CAST puri
->scheme
, BAD_CAST
"file")))
2668 * try to limit the damages of the URI unescaping code.
2670 if ((puri
->scheme
== NULL
) ||
2671 (xmlStrEqual(BAD_CAST puri
->scheme
, BAD_CAST
"file")))
2672 unescaped
= xmlURIUnescapeString(URI
, 0, NULL
);
2677 * Try to find one of the output accept method accepting that scheme
2678 * Go in reverse to give precedence to user defined handlers.
2679 * try with an unescaped version of the URI
2681 if (unescaped
!= NULL
) {
2682 #ifdef LIBXML_ZLIB_ENABLED
2683 if ((compression
> 0) && (compression
<= 9) && (is_file_uri
== 1)) {
2684 context
= xmlGzfileOpenW(unescaped
, compression
);
2685 if (context
!= NULL
) {
2686 ret
= xmlAllocOutputBufferInternal(encoder
);
2688 ret
->context
= context
;
2689 ret
->writecallback
= xmlGzfileWrite
;
2690 ret
->closecallback
= xmlGzfileClose
;
2697 for (i
= xmlOutputCallbackNr
- 1;i
>= 0;i
--) {
2698 if ((xmlOutputCallbackTable
[i
].matchcallback
!= NULL
) &&
2699 (xmlOutputCallbackTable
[i
].matchcallback(unescaped
) != 0)) {
2700 #if defined(LIBXML_HTTP_ENABLED) && defined(LIBXML_ZLIB_ENABLED)
2701 /* Need to pass compression parameter into HTTP open calls */
2702 if (xmlOutputCallbackTable
[i
].matchcallback
== xmlIOHTTPMatch
)
2703 context
= xmlIOHTTPOpenW(unescaped
, compression
);
2706 context
= xmlOutputCallbackTable
[i
].opencallback(unescaped
);
2707 if (context
!= NULL
)
2715 * If this failed try with a non-escaped URI this may be a strange
2718 if (context
== NULL
) {
2719 #ifdef LIBXML_ZLIB_ENABLED
2720 if ((compression
> 0) && (compression
<= 9) && (is_file_uri
== 1)) {
2721 context
= xmlGzfileOpenW(URI
, compression
);
2722 if (context
!= NULL
) {
2723 ret
= xmlAllocOutputBufferInternal(encoder
);
2725 ret
->context
= context
;
2726 ret
->writecallback
= xmlGzfileWrite
;
2727 ret
->closecallback
= xmlGzfileClose
;
2730 xmlGzfileClose(context
);
2735 for (i
= xmlOutputCallbackNr
- 1;i
>= 0;i
--) {
2736 if ((xmlOutputCallbackTable
[i
].matchcallback
!= NULL
) &&
2737 (xmlOutputCallbackTable
[i
].matchcallback(URI
) != 0)) {
2738 #if defined(LIBXML_HTTP_ENABLED) && defined(LIBXML_ZLIB_ENABLED)
2739 /* Need to pass compression parameter into HTTP open calls */
2740 if (xmlOutputCallbackTable
[i
].matchcallback
== xmlIOHTTPMatch
)
2741 context
= xmlIOHTTPOpenW(URI
, compression
);
2744 context
= xmlOutputCallbackTable
[i
].opencallback(URI
);
2745 if (context
!= NULL
)
2751 if (context
== NULL
) {
2756 * Allocate the Output buffer front-end.
2758 ret
= xmlAllocOutputBufferInternal(encoder
);
2760 ret
->context
= context
;
2761 ret
->writecallback
= xmlOutputCallbackTable
[i
].writecallback
;
2762 ret
->closecallback
= xmlOutputCallbackTable
[i
].closecallback
;
2768 * xmlOutputBufferCreateFilename:
2769 * @URI: a C string containing the URI or filename
2770 * @encoder: the encoding converter or NULL
2771 * @compression: the compression ration (0 none, 9 max).
2773 * Create a buffered output for the progressive saving of a file
2774 * If filename is "-' then we use stdout as the output.
2775 * Automatic support for ZLIB/Compress compressed document is provided
2776 * by default if found at compile-time.
2777 * TODO: currently if compression is set, the library only support
2778 * writing to a local file.
2780 * Returns the new output or NULL
2783 xmlOutputBufferCreateFilename(const char *URI
,
2784 xmlCharEncodingHandlerPtr encoder
,
2785 int compression ATTRIBUTE_UNUSED
) {
2786 if ((xmlOutputBufferCreateFilenameValue
)) {
2787 return xmlOutputBufferCreateFilenameValue(URI
, encoder
, compression
);
2789 return __xmlOutputBufferCreateFilename(URI
, encoder
, compression
);
2791 #endif /* LIBXML_OUTPUT_ENABLED */
2794 * xmlParserInputBufferCreateFile:
2796 * @enc: the charset encoding if known
2798 * Create a buffered parser input for the progressive parsing of a FILE *
2801 * Returns the new parser input or NULL
2803 xmlParserInputBufferPtr
2804 xmlParserInputBufferCreateFile(FILE *file
, xmlCharEncoding enc
) {
2805 xmlParserInputBufferPtr ret
;
2807 if (xmlInputCallbackInitialized
== 0)
2808 xmlRegisterDefaultInputCallbacks();
2810 if (file
== NULL
) return(NULL
);
2812 ret
= xmlAllocParserInputBuffer(enc
);
2814 ret
->context
= file
;
2815 ret
->readcallback
= xmlFileRead
;
2816 ret
->closecallback
= xmlFileFlush
;
2822 #ifdef LIBXML_OUTPUT_ENABLED
2824 * xmlOutputBufferCreateFile:
2826 * @encoder: the encoding converter or NULL
2828 * Create a buffered output for the progressive saving to a FILE *
2831 * Returns the new parser output or NULL
2834 xmlOutputBufferCreateFile(FILE *file
, xmlCharEncodingHandlerPtr encoder
) {
2835 xmlOutputBufferPtr ret
;
2837 if (xmlOutputCallbackInitialized
== 0)
2838 xmlRegisterDefaultOutputCallbacks();
2840 if (file
== NULL
) return(NULL
);
2842 ret
= xmlAllocOutputBufferInternal(encoder
);
2844 ret
->context
= file
;
2845 ret
->writecallback
= xmlFileWrite
;
2846 ret
->closecallback
= xmlFileFlush
;
2853 * xmlOutputBufferCreateBuffer:
2854 * @buffer: a xmlBufferPtr
2855 * @encoder: the encoding converter or NULL
2857 * Create a buffered output for the progressive saving to a xmlBuffer
2859 * Returns the new parser output or NULL
2862 xmlOutputBufferCreateBuffer(xmlBufferPtr buffer
,
2863 xmlCharEncodingHandlerPtr encoder
) {
2864 xmlOutputBufferPtr ret
;
2866 if (buffer
== NULL
) return(NULL
);
2868 ret
= xmlOutputBufferCreateIO(xmlBufferWrite
, NULL
, (void *) buffer
,
2875 * xmlOutputBufferGetContent:
2876 * @out: an xmlOutputBufferPtr
2878 * Gives a pointer to the data currently held in the output buffer
2880 * Returns a pointer to the data or NULL in case of error
2883 xmlOutputBufferGetContent(xmlOutputBufferPtr out
) {
2884 if ((out
== NULL
) || (out
->buffer
== NULL
))
2887 return(xmlBufContent(out
->buffer
));
2891 * xmlOutputBufferGetSize:
2892 * @out: an xmlOutputBufferPtr
2894 * Gives the length of the data currently held in the output buffer
2896 * Returns 0 in case or error or no data is held, the size otherwise
2899 xmlOutputBufferGetSize(xmlOutputBufferPtr out
) {
2900 if ((out
== NULL
) || (out
->buffer
== NULL
))
2903 return(xmlBufUse(out
->buffer
));
2907 #endif /* LIBXML_OUTPUT_ENABLED */
2910 * xmlParserInputBufferCreateFd:
2911 * @fd: a file descriptor number
2912 * @enc: the charset encoding if known
2914 * Create a buffered parser input for the progressive parsing for the input
2915 * from a file descriptor
2917 * Returns the new parser input or NULL
2919 xmlParserInputBufferPtr
2920 xmlParserInputBufferCreateFd(int fd
, xmlCharEncoding enc
) {
2921 xmlParserInputBufferPtr ret
;
2923 if (fd
< 0) return(NULL
);
2925 ret
= xmlAllocParserInputBuffer(enc
);
2927 ret
->context
= (void *) (ptrdiff_t) fd
;
2928 ret
->readcallback
= xmlFdRead
;
2929 ret
->closecallback
= xmlFdClose
;
2936 * xmlParserInputBufferCreateMem:
2937 * @mem: the memory input
2938 * @size: the length of the memory block
2939 * @enc: the charset encoding if known
2941 * Create a buffered parser input for the progressive parsing for the input
2942 * from a memory area.
2944 * Returns the new parser input or NULL
2946 xmlParserInputBufferPtr
2947 xmlParserInputBufferCreateMem(const char *mem
, int size
, xmlCharEncoding enc
) {
2948 xmlParserInputBufferPtr ret
;
2951 if (size
< 0) return(NULL
);
2952 if (mem
== NULL
) return(NULL
);
2954 ret
= xmlAllocParserInputBuffer(enc
);
2956 ret
->context
= (void *) mem
;
2957 ret
->readcallback
= xmlInputReadCallbackNop
;
2958 ret
->closecallback
= NULL
;
2959 errcode
= xmlBufAdd(ret
->buffer
, (const xmlChar
*) mem
, size
);
2970 * xmlParserInputBufferCreateStatic:
2971 * @mem: the memory input
2972 * @size: the length of the memory block
2973 * @enc: the charset encoding if known
2975 * Create a buffered parser input for the progressive parsing for the input
2976 * from an immutable memory area. This will not copy the memory area to
2977 * the buffer, but the memory is expected to be available until the end of
2978 * the parsing, this is useful for example when using mmap'ed file.
2980 * Returns the new parser input or NULL
2982 xmlParserInputBufferPtr
2983 xmlParserInputBufferCreateStatic(const char *mem
, int size
,
2984 xmlCharEncoding enc
) {
2985 xmlParserInputBufferPtr ret
;
2987 if (size
< 0) return(NULL
);
2988 if (mem
== NULL
) return(NULL
);
2990 ret
= (xmlParserInputBufferPtr
) xmlMalloc(sizeof(xmlParserInputBuffer
));
2992 xmlIOErrMemory("creating input buffer");
2995 memset(ret
, 0, (size_t) sizeof(xmlParserInputBuffer
));
2996 ret
->buffer
= xmlBufCreateStatic((void *)mem
, (size_t) size
);
2997 if (ret
->buffer
== NULL
) {
3001 ret
->encoder
= xmlGetCharEncodingHandler(enc
);
3002 if (ret
->encoder
!= NULL
)
3003 ret
->raw
= xmlBufCreateSize(2 * xmlDefaultBufferSize
);
3006 ret
->compressed
= -1;
3007 ret
->context
= (void *) mem
;
3008 ret
->readcallback
= NULL
;
3009 ret
->closecallback
= NULL
;
3014 #ifdef LIBXML_OUTPUT_ENABLED
3016 * xmlOutputBufferCreateFd:
3017 * @fd: a file descriptor number
3018 * @encoder: the encoding converter or NULL
3020 * Create a buffered output for the progressive saving
3021 * to a file descriptor
3023 * Returns the new parser output or NULL
3026 xmlOutputBufferCreateFd(int fd
, xmlCharEncodingHandlerPtr encoder
) {
3027 xmlOutputBufferPtr ret
;
3029 if (fd
< 0) return(NULL
);
3031 ret
= xmlAllocOutputBufferInternal(encoder
);
3033 ret
->context
= (void *) (ptrdiff_t) fd
;
3034 ret
->writecallback
= xmlFdWrite
;
3035 ret
->closecallback
= NULL
;
3040 #endif /* LIBXML_OUTPUT_ENABLED */
3043 * xmlParserInputBufferCreateIO:
3044 * @ioread: an I/O read function
3045 * @ioclose: an I/O close function
3046 * @ioctx: an I/O handler
3047 * @enc: the charset encoding if known
3049 * Create a buffered parser input for the progressive parsing for the input
3050 * from an I/O handler
3052 * Returns the new parser input or NULL
3054 xmlParserInputBufferPtr
3055 xmlParserInputBufferCreateIO(xmlInputReadCallback ioread
,
3056 xmlInputCloseCallback ioclose
, void *ioctx
, xmlCharEncoding enc
) {
3057 xmlParserInputBufferPtr ret
;
3059 if (ioread
== NULL
) return(NULL
);
3061 ret
= xmlAllocParserInputBuffer(enc
);
3063 ret
->context
= (void *) ioctx
;
3064 ret
->readcallback
= ioread
;
3065 ret
->closecallback
= ioclose
;
3071 #ifdef LIBXML_OUTPUT_ENABLED
3073 * xmlOutputBufferCreateIO:
3074 * @iowrite: an I/O write function
3075 * @ioclose: an I/O close function
3076 * @ioctx: an I/O handler
3077 * @encoder: the charset encoding if known
3079 * Create a buffered output for the progressive saving
3082 * Returns the new parser output or NULL
3085 xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite
,
3086 xmlOutputCloseCallback ioclose
, void *ioctx
,
3087 xmlCharEncodingHandlerPtr encoder
) {
3088 xmlOutputBufferPtr ret
;
3090 if (iowrite
== NULL
) return(NULL
);
3092 ret
= xmlAllocOutputBufferInternal(encoder
);
3094 ret
->context
= (void *) ioctx
;
3095 ret
->writecallback
= iowrite
;
3096 ret
->closecallback
= ioclose
;
3101 #endif /* LIBXML_OUTPUT_ENABLED */
3104 * xmlParserInputBufferCreateFilenameDefault:
3105 * @func: function pointer to the new ParserInputBufferCreateFilenameFunc
3107 * Registers a callback for URI input file handling
3109 * Returns the old value of the registration function
3111 xmlParserInputBufferCreateFilenameFunc
3112 xmlParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func
)
3114 xmlParserInputBufferCreateFilenameFunc old
= xmlParserInputBufferCreateFilenameValue
;
3116 old
= __xmlParserInputBufferCreateFilename
;
3119 xmlParserInputBufferCreateFilenameValue
= func
;
3124 * xmlOutputBufferCreateFilenameDefault:
3125 * @func: function pointer to the new OutputBufferCreateFilenameFunc
3127 * Registers a callback for URI output file handling
3129 * Returns the old value of the registration function
3131 xmlOutputBufferCreateFilenameFunc
3132 xmlOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func
)
3134 xmlOutputBufferCreateFilenameFunc old
= xmlOutputBufferCreateFilenameValue
;
3135 #ifdef LIBXML_OUTPUT_ENABLED
3137 old
= __xmlOutputBufferCreateFilename
;
3140 xmlOutputBufferCreateFilenameValue
= func
;
3145 * xmlParserInputBufferPush:
3146 * @in: a buffered parser input
3147 * @len: the size in bytes of the array.
3148 * @buf: an char array
3150 * Push the content of the arry in the input buffer
3151 * This routine handle the I18N transcoding to internal UTF-8
3152 * This is used when operating the parser in progressive (push) mode.
3154 * Returns the number of chars read and stored in the buffer, or -1
3158 xmlParserInputBufferPush(xmlParserInputBufferPtr in
,
3159 int len
, const char *buf
) {
3163 if (len
< 0) return(0);
3164 if ((in
== NULL
) || (in
->error
)) return(-1);
3165 if (in
->encoder
!= NULL
) {
3169 * Store the data in the incoming raw buffer
3171 if (in
->raw
== NULL
) {
3172 in
->raw
= xmlBufCreate();
3174 ret
= xmlBufAdd(in
->raw
, (const xmlChar
*) buf
, len
);
3179 * convert as much as possible to the parser reading buffer.
3181 use
= xmlBufUse(in
->raw
);
3182 nbchars
= xmlCharEncInput(in
, 1);
3184 xmlIOErr(XML_IO_ENCODER
, NULL
);
3185 in
->error
= XML_IO_ENCODER
;
3188 in
->rawconsumed
+= (use
- xmlBufUse(in
->raw
));
3191 ret
= xmlBufAdd(in
->buffer
, (xmlChar
*) buf
, nbchars
);
3196 xmlGenericError(xmlGenericErrorContext
,
3197 "I/O: pushed %d chars, buffer %d/%d\n",
3198 nbchars
, xmlBufUse(in
->buffer
), xmlBufLength(in
->buffer
));
3206 * When reading from an Input channel indicated end of file or error
3207 * don't reread from it again.
3210 endOfInput (void * context ATTRIBUTE_UNUSED
,
3211 char * buffer ATTRIBUTE_UNUSED
,
3212 int len ATTRIBUTE_UNUSED
) {
3217 * xmlParserInputBufferGrow:
3218 * @in: a buffered parser input
3219 * @len: indicative value of the amount of chars to read
3221 * Grow up the content of the input buffer, the old data are preserved
3222 * This routine handle the I18N transcoding to internal UTF-8
3223 * This routine is used when operating the parser in normal (pull) mode
3225 * TODO: one should be able to remove one extra copy by copying directly
3226 * onto in->buffer or in->raw
3228 * Returns the number of chars read and stored in the buffer, or -1
3232 xmlParserInputBufferGrow(xmlParserInputBufferPtr in
, int len
) {
3233 char *buffer
= NULL
;
3237 if ((in
== NULL
) || (in
->error
)) return(-1);
3238 if ((len
<= MINLEN
) && (len
!= 4))
3241 if (xmlBufAvail(in
->buffer
) <= 0) {
3242 xmlIOErr(XML_IO_BUFFER_FULL
, NULL
);
3243 in
->error
= XML_IO_BUFFER_FULL
;
3247 if (xmlBufGrow(in
->buffer
, len
+ 1) < 0) {
3248 xmlIOErrMemory("growing input buffer");
3249 in
->error
= XML_ERR_NO_MEMORY
;
3252 buffer
= (char *)xmlBufEnd(in
->buffer
);
3255 * Call the read method for this I/O type.
3257 if (in
->readcallback
!= NULL
) {
3258 res
= in
->readcallback(in
->context
, &buffer
[0], len
);
3260 in
->readcallback
= endOfInput
;
3262 xmlIOErr(XML_IO_NO_INPUT
, NULL
);
3263 in
->error
= XML_IO_NO_INPUT
;
3271 * try to establish compressed status of input if not done already
3273 if (in
->compressed
== -1) {
3274 #ifdef LIBXML_LZMA_ENABLED
3275 if (in
->readcallback
== xmlXzfileRead
)
3276 in
->compressed
= __libxml2_xzcompressed(in
->context
);
3281 if (in
->encoder
!= NULL
) {
3285 * Store the data in the incoming raw buffer
3287 if (in
->raw
== NULL
) {
3288 in
->raw
= xmlBufCreate();
3290 res
= xmlBufAdd(in
->raw
, (const xmlChar
*) buffer
, len
);
3295 * convert as much as possible to the parser reading buffer.
3297 use
= xmlBufUse(in
->raw
);
3298 nbchars
= xmlCharEncInput(in
, 1);
3300 xmlIOErr(XML_IO_ENCODER
, NULL
);
3301 in
->error
= XML_IO_ENCODER
;
3304 in
->rawconsumed
+= (use
- xmlBufUse(in
->raw
));
3307 xmlBufAddLen(in
->buffer
, nbchars
);
3310 xmlGenericError(xmlGenericErrorContext
,
3311 "I/O: read %d chars, buffer %d\n",
3312 nbchars
, xmlBufUse(in
->buffer
));
3318 * xmlParserInputBufferRead:
3319 * @in: a buffered parser input
3320 * @len: indicative value of the amount of chars to read
3322 * Refresh the content of the input buffer, the old data are considered
3324 * This routine handle the I18N transcoding to internal UTF-8
3326 * Returns the number of chars read and stored in the buffer, or -1
3330 xmlParserInputBufferRead(xmlParserInputBufferPtr in
, int len
) {
3331 if ((in
== NULL
) || (in
->error
)) return(-1);
3332 if (in
->readcallback
!= NULL
)
3333 return(xmlParserInputBufferGrow(in
, len
));
3334 else if (xmlBufGetAllocationScheme(in
->buffer
) == XML_BUFFER_ALLOC_IMMUTABLE
)
3340 #ifdef LIBXML_OUTPUT_ENABLED
3342 * xmlOutputBufferWrite:
3343 * @out: a buffered parser output
3344 * @len: the size in bytes of the array.
3345 * @buf: an char array
3347 * Write the content of the array in the output I/O buffer
3348 * This routine handle the I18N transcoding from internal UTF-8
3349 * The buffer is lossless, i.e. will store in case of partial
3350 * or delayed writes.
3352 * Returns the number of chars immediately written, or -1
3356 xmlOutputBufferWrite(xmlOutputBufferPtr out
, int len
, const char *buf
) {
3357 int nbchars
= 0; /* number of chars to output to I/O */
3358 int ret
; /* return from function call */
3359 int written
= 0; /* number of char written to I/O so far */
3360 int chunk
; /* number of byte current processed from buf */
3362 if ((out
== NULL
) || (out
->error
)) return(-1);
3363 if (len
< 0) return(0);
3364 if (out
->error
) return(-1);
3368 if (chunk
> 4 * MINLEN
)
3372 * first handle encoding stuff.
3374 if (out
->encoder
!= NULL
) {
3376 * Store the data in the incoming raw buffer
3378 if (out
->conv
== NULL
) {
3379 out
->conv
= xmlBufCreate();
3381 ret
= xmlBufAdd(out
->buffer
, (const xmlChar
*) buf
, chunk
);
3385 if ((xmlBufUse(out
->buffer
) < MINLEN
) && (chunk
== len
))
3389 * convert as much as possible to the parser reading buffer.
3391 ret
= xmlCharEncOutput(out
, 0);
3392 if ((ret
< 0) && (ret
!= -3)) {
3393 xmlIOErr(XML_IO_ENCODER
, NULL
);
3394 out
->error
= XML_IO_ENCODER
;
3397 if (out
->writecallback
)
3398 nbchars
= xmlBufUse(out
->conv
);
3400 nbchars
= ret
>= 0 ? ret
: 0;
3402 ret
= xmlBufAdd(out
->buffer
, (const xmlChar
*) buf
, chunk
);
3405 if (out
->writecallback
)
3406 nbchars
= xmlBufUse(out
->buffer
);
3413 if (out
->writecallback
) {
3414 if ((nbchars
< MINLEN
) && (len
<= 0))
3418 * second write the stuff to the I/O channel
3420 if (out
->encoder
!= NULL
) {
3421 ret
= out
->writecallback(out
->context
,
3422 (const char *)xmlBufContent(out
->conv
), nbchars
);
3424 xmlBufShrink(out
->conv
, ret
);
3426 ret
= out
->writecallback(out
->context
,
3427 (const char *)xmlBufContent(out
->buffer
), nbchars
);
3429 xmlBufShrink(out
->buffer
, ret
);
3432 xmlIOErr(XML_IO_WRITE
, NULL
);
3433 out
->error
= XML_IO_WRITE
;
3436 if (out
->written
> INT_MAX
- ret
)
3437 out
->written
= INT_MAX
;
3439 out
->written
+= ret
;
3446 xmlGenericError(xmlGenericErrorContext
,
3447 "I/O: wrote %d chars\n", written
);
3454 * @out: a pointer to an array of bytes to store the result
3455 * @outlen: the length of @out
3456 * @in: a pointer to an array of unescaped UTF-8 bytes
3457 * @inlen: the length of @in
3459 * Take a block of UTF-8 chars in and escape them.
3460 * Returns 0 if success, or -1 otherwise
3461 * The value of @inlen after return is the number of octets consumed
3462 * if the return value is positive, else unpredictable.
3463 * The value of @outlen after return is the number of octets consumed.
3466 xmlEscapeContent(unsigned char* out
, int *outlen
,
3467 const xmlChar
* in
, int *inlen
) {
3468 unsigned char* outstart
= out
;
3469 const unsigned char* base
= in
;
3470 unsigned char* outend
= out
+ *outlen
;
3471 const unsigned char* inend
;
3473 inend
= in
+ (*inlen
);
3475 while ((in
< inend
) && (out
< outend
)) {
3477 if (outend
- out
< 4) break;
3482 } else if (*in
== '>') {
3483 if (outend
- out
< 4) break;
3488 } else if (*in
== '&') {
3489 if (outend
- out
< 5) break;
3495 } else if (*in
== '\r') {
3496 if (outend
- out
< 5) break;
3503 *out
++ = (unsigned char) *in
;
3507 *outlen
= out
- outstart
;
3513 * xmlOutputBufferWriteEscape:
3514 * @out: a buffered parser output
3515 * @str: a zero terminated UTF-8 string
3516 * @escaping: an optional escaping function (or NULL)
3518 * Write the content of the string in the output I/O buffer
3519 * This routine escapes the characters and then handle the I18N
3520 * transcoding from internal UTF-8
3521 * The buffer is lossless, i.e. will store in case of partial
3522 * or delayed writes.
3524 * Returns the number of chars immediately written, or -1
3528 xmlOutputBufferWriteEscape(xmlOutputBufferPtr out
, const xmlChar
*str
,
3529 xmlCharEncodingOutputFunc escaping
) {
3530 int nbchars
= 0; /* number of chars to output to I/O */
3531 int ret
; /* return from function call */
3532 int written
= 0; /* number of char written to I/O so far */
3533 int oldwritten
=0;/* loop guard */
3534 int chunk
; /* number of byte currently processed from str */
3535 int len
; /* number of bytes in str */
3536 int cons
; /* byte from str consumed */
3538 if ((out
== NULL
) || (out
->error
) || (str
== NULL
) ||
3539 (out
->buffer
== NULL
) ||
3540 (xmlBufGetAllocationScheme(out
->buffer
) == XML_BUFFER_ALLOC_IMMUTABLE
))
3542 len
= strlen((const char *)str
);
3543 if (len
< 0) return(0);
3544 if (out
->error
) return(-1);
3545 if (escaping
== NULL
) escaping
= xmlEscapeContent
;
3548 oldwritten
= written
;
3551 * how many bytes to consume and how many bytes to store.
3554 chunk
= xmlBufAvail(out
->buffer
);
3557 * make sure we have enough room to save first, if this is
3558 * not the case force a flush, but make sure we stay in the loop
3561 if (xmlBufGrow(out
->buffer
, 100) < 0)
3568 * first handle encoding stuff.
3570 if (out
->encoder
!= NULL
) {
3572 * Store the data in the incoming raw buffer
3574 if (out
->conv
== NULL
) {
3575 out
->conv
= xmlBufCreate();
3577 ret
= escaping(xmlBufEnd(out
->buffer
) ,
3578 &chunk
, str
, &cons
);
3579 if ((ret
< 0) || (chunk
== 0)) /* chunk==0 => nothing done */
3581 xmlBufAddLen(out
->buffer
, chunk
);
3583 if ((xmlBufUse(out
->buffer
) < MINLEN
) && (cons
== len
))
3587 * convert as much as possible to the output buffer.
3589 ret
= xmlCharEncOutput(out
, 0);
3590 if ((ret
< 0) && (ret
!= -3)) {
3591 xmlIOErr(XML_IO_ENCODER
, NULL
);
3592 out
->error
= XML_IO_ENCODER
;
3595 if (out
->writecallback
)
3596 nbchars
= xmlBufUse(out
->conv
);
3598 nbchars
= ret
>= 0 ? ret
: 0;
3600 ret
= escaping(xmlBufEnd(out
->buffer
), &chunk
, str
, &cons
);
3601 if ((ret
< 0) || (chunk
== 0)) /* chunk==0 => nothing done */
3603 xmlBufAddLen(out
->buffer
, chunk
);
3604 if (out
->writecallback
)
3605 nbchars
= xmlBufUse(out
->buffer
);
3612 if (out
->writecallback
) {
3613 if ((nbchars
< MINLEN
) && (len
<= 0))
3617 * second write the stuff to the I/O channel
3619 if (out
->encoder
!= NULL
) {
3620 ret
= out
->writecallback(out
->context
,
3621 (const char *)xmlBufContent(out
->conv
), nbchars
);
3623 xmlBufShrink(out
->conv
, ret
);
3625 ret
= out
->writecallback(out
->context
,
3626 (const char *)xmlBufContent(out
->buffer
), nbchars
);
3628 xmlBufShrink(out
->buffer
, ret
);
3631 xmlIOErr(XML_IO_WRITE
, NULL
);
3632 out
->error
= XML_IO_WRITE
;
3635 if (out
->written
> INT_MAX
- ret
)
3636 out
->written
= INT_MAX
;
3638 out
->written
+= ret
;
3639 } else if (xmlBufAvail(out
->buffer
) < MINLEN
) {
3640 xmlBufGrow(out
->buffer
, MINLEN
);
3643 } while ((len
> 0) && (oldwritten
!= written
));
3647 xmlGenericError(xmlGenericErrorContext
,
3648 "I/O: wrote %d chars\n", written
);
3654 * xmlOutputBufferWriteString:
3655 * @out: a buffered parser output
3656 * @str: a zero terminated C string
3658 * Write the content of the string in the output I/O buffer
3659 * This routine handle the I18N transcoding from internal UTF-8
3660 * The buffer is lossless, i.e. will store in case of partial
3661 * or delayed writes.
3663 * Returns the number of chars immediately written, or -1
3667 xmlOutputBufferWriteString(xmlOutputBufferPtr out
, const char *str
) {
3670 if ((out
== NULL
) || (out
->error
)) return(-1);
3676 return(xmlOutputBufferWrite(out
, len
, str
));
3681 * xmlOutputBufferFlush:
3682 * @out: a buffered output
3684 * flushes the output I/O channel
3686 * Returns the number of byte written or -1 in case of error.
3689 xmlOutputBufferFlush(xmlOutputBufferPtr out
) {
3690 int nbchars
= 0, ret
= 0;
3692 if ((out
== NULL
) || (out
->error
)) return(-1);
3694 * first handle encoding stuff.
3696 if ((out
->conv
!= NULL
) && (out
->encoder
!= NULL
)) {
3698 * convert as much as possible to the parser output buffer.
3701 nbchars
= xmlCharEncOutput(out
, 0);
3703 xmlIOErr(XML_IO_ENCODER
, NULL
);
3704 out
->error
= XML_IO_ENCODER
;
3711 * second flush the stuff to the I/O channel
3713 if ((out
->conv
!= NULL
) && (out
->encoder
!= NULL
) &&
3714 (out
->writecallback
!= NULL
)) {
3715 ret
= out
->writecallback(out
->context
,
3716 (const char *)xmlBufContent(out
->conv
),
3717 xmlBufUse(out
->conv
));
3719 xmlBufShrink(out
->conv
, ret
);
3720 } else if (out
->writecallback
!= NULL
) {
3721 ret
= out
->writecallback(out
->context
,
3722 (const char *)xmlBufContent(out
->buffer
),
3723 xmlBufUse(out
->buffer
));
3725 xmlBufShrink(out
->buffer
, ret
);
3728 xmlIOErr(XML_IO_FLUSH
, NULL
);
3729 out
->error
= XML_IO_FLUSH
;
3732 if (out
->written
> INT_MAX
- ret
)
3733 out
->written
= INT_MAX
;
3735 out
->written
+= ret
;
3738 xmlGenericError(xmlGenericErrorContext
,
3739 "I/O: flushed %d chars\n", ret
);
3743 #endif /* LIBXML_OUTPUT_ENABLED */
3746 * xmlParserGetDirectory:
3747 * @filename: the path to a file
3749 * lookup the directory for that file
3751 * Returns a new allocated string containing the directory, or NULL.
3754 xmlParserGetDirectory(const char *filename
) {
3759 if (xmlInputCallbackInitialized
== 0)
3760 xmlRegisterDefaultInputCallbacks();
3762 if (filename
== NULL
) return(NULL
);
3765 # define IS_XMLPGD_SEP(ch) ((ch=='/')||(ch=='\\'))
3767 # define IS_XMLPGD_SEP(ch) (ch=='/')
3770 strncpy(dir
, filename
, 1023);
3772 cur
= &dir
[strlen(dir
)];
3774 if (IS_XMLPGD_SEP(*cur
)) break;
3777 if (IS_XMLPGD_SEP(*cur
)) {
3778 if (cur
== dir
) dir
[1] = 0;
3780 ret
= xmlMemStrdup(dir
);
3782 if (getcwd(dir
, 1024) != NULL
) {
3784 ret
= xmlMemStrdup(dir
);
3788 #undef IS_XMLPGD_SEP
3791 /****************************************************************
3793 * External entities loading *
3795 ****************************************************************/
3798 * xmlCheckHTTPInput:
3799 * @ctxt: an XML parser context
3800 * @ret: an XML parser input
3802 * Check an input in case it was created from an HTTP stream, in that
3803 * case it will handle encoding and update of the base URL in case of
3804 * redirection. It also checks for HTTP errors in which case the input
3805 * is cleanly freed up and an appropriate error is raised in context
3807 * Returns the input or NULL in case of HTTP error.
3810 xmlCheckHTTPInput(xmlParserCtxtPtr ctxt
, xmlParserInputPtr ret
) {
3811 /* Avoid unused variable warning if features are disabled. */
3814 #ifdef LIBXML_HTTP_ENABLED
3815 if ((ret
!= NULL
) && (ret
->buf
!= NULL
) &&
3816 (ret
->buf
->readcallback
== xmlIOHTTPRead
) &&
3817 (ret
->buf
->context
!= NULL
)) {
3818 const char *encoding
;
3823 code
= xmlNanoHTTPReturnCode(ret
->buf
->context
);
3826 if (ret
->filename
!= NULL
)
3827 __xmlLoaderErr(ctxt
, "failed to load HTTP resource \"%s\"\n",
3828 (const char *) ret
->filename
);
3830 __xmlLoaderErr(ctxt
, "failed to load HTTP resource\n", NULL
);
3831 xmlFreeInputStream(ret
);
3835 mime
= xmlNanoHTTPMimeType(ret
->buf
->context
);
3836 if ((xmlStrstr(BAD_CAST mime
, BAD_CAST
"/xml")) ||
3837 (xmlStrstr(BAD_CAST mime
, BAD_CAST
"+xml"))) {
3838 encoding
= xmlNanoHTTPEncoding(ret
->buf
->context
);
3839 if (encoding
!= NULL
) {
3840 xmlCharEncodingHandlerPtr handler
;
3842 handler
= xmlFindCharEncodingHandler(encoding
);
3843 if (handler
!= NULL
) {
3844 xmlSwitchInputEncoding(ctxt
, ret
, handler
);
3846 __xmlErrEncoding(ctxt
, XML_ERR_UNKNOWN_ENCODING
,
3847 "Unknown encoding %s",
3848 BAD_CAST encoding
, NULL
);
3850 if (ret
->encoding
== NULL
)
3851 ret
->encoding
= xmlStrdup(BAD_CAST encoding
);
3854 } else if (xmlStrstr(BAD_CAST mime
, BAD_CAST
"html")) {
3857 redir
= xmlNanoHTTPRedir(ret
->buf
->context
);
3858 if (redir
!= NULL
) {
3859 if (ret
->filename
!= NULL
)
3860 xmlFree((xmlChar
*) ret
->filename
);
3861 if (ret
->directory
!= NULL
) {
3862 xmlFree((xmlChar
*) ret
->directory
);
3863 ret
->directory
= NULL
;
3866 (char *) xmlStrdup((const xmlChar
*) redir
);
3874 static int xmlNoNetExists(const char *URL
) {
3880 if (!xmlStrncasecmp(BAD_CAST URL
, BAD_CAST
"file://localhost/", 17))
3881 #if defined (_WIN32)
3886 else if (!xmlStrncasecmp(BAD_CAST URL
, BAD_CAST
"file:///", 8)) {
3887 #if defined (_WIN32)
3895 return xmlCheckFilename(path
);
3898 #ifdef LIBXML_CATALOG_ENABLED
3901 * xmlResolveResourceFromCatalog:
3902 * @URL: the URL for the entity to load
3903 * @ID: the System ID for the entity to load
3904 * @ctxt: the context in which the entity is called or NULL
3906 * Resolves the URL and ID against the appropriate catalog.
3907 * This function is used by xmlDefaultExternalEntityLoader and
3908 * xmlNoNetExternalEntityLoader.
3910 * Returns a new allocated URL, or NULL.
3913 xmlResolveResourceFromCatalog(const char *URL
, const char *ID
,
3914 xmlParserCtxtPtr ctxt
) {
3915 xmlChar
*resource
= NULL
;
3916 xmlCatalogAllow pref
;
3919 * If the resource doesn't exists as a file,
3920 * try to load it from the resource pointed in the catalogs
3922 pref
= xmlCatalogGetDefaults();
3924 if ((pref
!= XML_CATA_ALLOW_NONE
) && (!xmlNoNetExists(URL
))) {
3928 if ((ctxt
!= NULL
) && (ctxt
->catalogs
!= NULL
) &&
3929 ((pref
== XML_CATA_ALLOW_ALL
) ||
3930 (pref
== XML_CATA_ALLOW_DOCUMENT
))) {
3931 resource
= xmlCatalogLocalResolve(ctxt
->catalogs
,
3932 (const xmlChar
*)ID
,
3933 (const xmlChar
*)URL
);
3936 * Try a global lookup
3938 if ((resource
== NULL
) &&
3939 ((pref
== XML_CATA_ALLOW_ALL
) ||
3940 (pref
== XML_CATA_ALLOW_GLOBAL
))) {
3941 resource
= xmlCatalogResolve((const xmlChar
*)ID
,
3942 (const xmlChar
*)URL
);
3944 if ((resource
== NULL
) && (URL
!= NULL
))
3945 resource
= xmlStrdup((const xmlChar
*) URL
);
3948 * TODO: do an URI lookup on the reference
3950 if ((resource
!= NULL
) && (!xmlNoNetExists((const char *)resource
))) {
3951 xmlChar
*tmp
= NULL
;
3953 if ((ctxt
!= NULL
) && (ctxt
->catalogs
!= NULL
) &&
3954 ((pref
== XML_CATA_ALLOW_ALL
) ||
3955 (pref
== XML_CATA_ALLOW_DOCUMENT
))) {
3956 tmp
= xmlCatalogLocalResolveURI(ctxt
->catalogs
, resource
);
3958 if ((tmp
== NULL
) &&
3959 ((pref
== XML_CATA_ALLOW_ALL
) ||
3960 (pref
== XML_CATA_ALLOW_GLOBAL
))) {
3961 tmp
= xmlCatalogResolveURI(resource
);
3977 * xmlDefaultExternalEntityLoader:
3978 * @URL: the URL for the entity to load
3979 * @ID: the System ID for the entity to load
3980 * @ctxt: the context in which the entity is called or NULL
3982 * By default we don't load external entities, yet.
3984 * Returns a new allocated xmlParserInputPtr, or NULL.
3986 static xmlParserInputPtr
3987 xmlDefaultExternalEntityLoader(const char *URL
, const char *ID
,
3988 xmlParserCtxtPtr ctxt
)
3990 xmlParserInputPtr ret
= NULL
;
3991 xmlChar
*resource
= NULL
;
3993 #ifdef DEBUG_EXTERNAL_ENTITIES
3994 xmlGenericError(xmlGenericErrorContext
,
3995 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL
);
3997 if ((ctxt
!= NULL
) && (ctxt
->options
& XML_PARSE_NONET
)) {
3998 int options
= ctxt
->options
;
4000 ctxt
->options
-= XML_PARSE_NONET
;
4001 ret
= xmlNoNetExternalEntityLoader(URL
, ID
, ctxt
);
4002 ctxt
->options
= options
;
4005 #ifdef LIBXML_CATALOG_ENABLED
4006 resource
= xmlResolveResourceFromCatalog(URL
, ID
, ctxt
);
4009 if (resource
== NULL
)
4010 resource
= (xmlChar
*) URL
;
4012 if (resource
== NULL
) {
4015 __xmlLoaderErr(ctxt
, "failed to load external entity \"%s\"\n", ID
);
4018 ret
= xmlNewInputFromFile(ctxt
, (const char *) resource
);
4019 if ((resource
!= NULL
) && (resource
!= (xmlChar
*) URL
))
4024 static xmlExternalEntityLoader xmlCurrentExternalEntityLoader
=
4025 xmlDefaultExternalEntityLoader
;
4028 * xmlSetExternalEntityLoader:
4029 * @f: the new entity resolver function
4031 * Changes the defaultexternal entity resolver function for the application
4034 xmlSetExternalEntityLoader(xmlExternalEntityLoader f
) {
4035 xmlCurrentExternalEntityLoader
= f
;
4039 * xmlGetExternalEntityLoader:
4041 * Get the default external entity resolver function for the application
4043 * Returns the xmlExternalEntityLoader function pointer
4045 xmlExternalEntityLoader
4046 xmlGetExternalEntityLoader(void) {
4047 return(xmlCurrentExternalEntityLoader
);
4051 * xmlLoadExternalEntity:
4052 * @URL: the URL for the entity to load
4053 * @ID: the Public ID for the entity to load
4054 * @ctxt: the context in which the entity is called or NULL
4056 * Load an external entity, note that the use of this function for
4057 * unparsed entities may generate problems
4059 * Returns the xmlParserInputPtr or NULL
4062 xmlLoadExternalEntity(const char *URL
, const char *ID
,
4063 xmlParserCtxtPtr ctxt
) {
4064 if ((URL
!= NULL
) && (xmlNoNetExists(URL
) == 0)) {
4065 char *canonicFilename
;
4066 xmlParserInputPtr ret
;
4068 canonicFilename
= (char *) xmlCanonicPath((const xmlChar
*) URL
);
4069 if (canonicFilename
== NULL
) {
4070 xmlIOErrMemory("building canonical path\n");
4074 ret
= xmlCurrentExternalEntityLoader(canonicFilename
, ID
, ctxt
);
4075 xmlFree(canonicFilename
);
4078 return(xmlCurrentExternalEntityLoader(URL
, ID
, ctxt
));
4081 /************************************************************************
4083 * Disabling Network access *
4085 ************************************************************************/
4088 * xmlNoNetExternalEntityLoader:
4089 * @URL: the URL for the entity to load
4090 * @ID: the System ID for the entity to load
4091 * @ctxt: the context in which the entity is called or NULL
4093 * A specific entity loader disabling network accesses, though still
4094 * allowing local catalog accesses for resolution.
4096 * Returns a new allocated xmlParserInputPtr, or NULL.
4099 xmlNoNetExternalEntityLoader(const char *URL
, const char *ID
,
4100 xmlParserCtxtPtr ctxt
) {
4101 xmlParserInputPtr input
= NULL
;
4102 xmlChar
*resource
= NULL
;
4104 #ifdef LIBXML_CATALOG_ENABLED
4105 resource
= xmlResolveResourceFromCatalog(URL
, ID
, ctxt
);
4108 if (resource
== NULL
)
4109 resource
= (xmlChar
*) URL
;
4111 if (resource
!= NULL
) {
4112 if ((!xmlStrncasecmp(BAD_CAST resource
, BAD_CAST
"ftp://", 6)) ||
4113 (!xmlStrncasecmp(BAD_CAST resource
, BAD_CAST
"http://", 7))) {
4114 xmlIOErr(XML_IO_NETWORK_ATTEMPT
, (const char *) resource
);
4115 if (resource
!= (xmlChar
*) URL
)
4120 input
= xmlDefaultExternalEntityLoader((const char *) resource
, ID
, ctxt
);
4121 if (resource
!= (xmlChar
*) URL
)