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
20 #ifdef HAVE_SYS_TYPES_H
21 #include <sys/types.h>
23 #ifdef HAVE_SYS_STAT_H
42 #if defined(WIN32) || defined(_WIN32)
43 //#include <windows.h>
47 #if defined(_WIN32_WCE)
48 #include <winnls.h> /* for CP_UTF8 */
51 /* Figure a portable way to know if a file is a directory. */
54 /* MS C library seems to define stat and _stat. The definition
55 is identical. Still, mapping them to each other causes a warning. */
57 # define stat(x,y) _stat(x,y)
63 # if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
71 # define S_ISDIR(x) _S_ISDIR(x)
76 # define S_IFMT _S_IFMT
80 # define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
87 #include <libxml/xmlmemory.h>
88 #include <libxml/parser.h>
89 #include <libxml/parserInternals.h>
90 #include <libxml/xmlIO.h>
91 #include <libxml/uri.h>
92 #include <libxml/nanohttp.h>
93 #include <libxml/nanoftp.h>
94 #include <libxml/xmlerror.h>
95 #ifdef LIBXML_CATALOG_ENABLED
96 #include <libxml/catalog.h>
98 #include <libxml/globals.h>
103 /* #define VERBOSE_FAILURE */
104 /* #define DEBUG_EXTERNAL_ENTITIES */
105 /* #define DEBUG_INPUT */
114 * Input I/O callback sets
116 typedef struct _xmlInputCallback
{
117 xmlInputMatchCallback matchcallback
;
118 xmlInputOpenCallback opencallback
;
119 xmlInputReadCallback readcallback
;
120 xmlInputCloseCallback closecallback
;
123 #define MAX_INPUT_CALLBACK 15
125 static xmlInputCallback xmlInputCallbackTable
[MAX_INPUT_CALLBACK
];
126 static int xmlInputCallbackNr
= 0;
127 static int xmlInputCallbackInitialized
= 0;
129 #ifdef LIBXML_OUTPUT_ENABLED
131 * Output I/O callback sets
133 typedef struct _xmlOutputCallback
{
134 xmlOutputMatchCallback matchcallback
;
135 xmlOutputOpenCallback opencallback
;
136 xmlOutputWriteCallback writecallback
;
137 xmlOutputCloseCallback closecallback
;
140 #define MAX_OUTPUT_CALLBACK 15
142 static xmlOutputCallback xmlOutputCallbackTable
[MAX_OUTPUT_CALLBACK
];
143 static int xmlOutputCallbackNr
= 0;
144 static int xmlOutputCallbackInitialized
= 0;
147 xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder
);
148 #endif /* LIBXML_OUTPUT_ENABLED */
150 /************************************************************************
152 * Tree memory error handler *
154 ************************************************************************/
156 static const char *IOerr
[] = {
157 "Unknown IO error", /* UNKNOWN */
158 "Permission denied", /* EACCES */
159 "Resource temporarily unavailable",/* EAGAIN */
160 "Bad file descriptor", /* EBADF */
161 "Bad message", /* EBADMSG */
162 "Resource busy", /* EBUSY */
163 "Operation canceled", /* ECANCELED */
164 "No child processes", /* ECHILD */
165 "Resource deadlock avoided",/* EDEADLK */
166 "Domain error", /* EDOM */
167 "File exists", /* EEXIST */
168 "Bad address", /* EFAULT */
169 "File too large", /* EFBIG */
170 "Operation in progress", /* EINPROGRESS */
171 "Interrupted function call",/* EINTR */
172 "Invalid argument", /* EINVAL */
173 "Input/output error", /* EIO */
174 "Is a directory", /* EISDIR */
175 "Too many open files", /* EMFILE */
176 "Too many links", /* EMLINK */
177 "Inappropriate message buffer length",/* EMSGSIZE */
178 "Filename too long", /* ENAMETOOLONG */
179 "Too many open files in system",/* ENFILE */
180 "No such device", /* ENODEV */
181 "No such file or directory",/* ENOENT */
182 "Exec format error", /* ENOEXEC */
183 "No locks available", /* ENOLCK */
184 "Not enough space", /* ENOMEM */
185 "No space left on device", /* ENOSPC */
186 "Function not implemented", /* ENOSYS */
187 "Not a directory", /* ENOTDIR */
188 "Directory not empty", /* ENOTEMPTY */
189 "Not supported", /* ENOTSUP */
190 "Inappropriate I/O control operation",/* ENOTTY */
191 "No such device or address",/* ENXIO */
192 "Operation not permitted", /* EPERM */
193 "Broken pipe", /* EPIPE */
194 "Result too large", /* ERANGE */
195 "Read-only file system", /* EROFS */
196 "Invalid seek", /* ESPIPE */
197 "No such process", /* ESRCH */
198 "Operation timed out", /* ETIMEDOUT */
199 "Improper link", /* EXDEV */
200 "Attempt to load network entity %s", /* XML_IO_NETWORK_ATTEMPT */
201 "encoder error", /* XML_IO_ENCODER */
207 "not a socket", /* ENOTSOCK */
208 "already connected", /* EISCONN */
209 "connection refused", /* ECONNREFUSED */
210 "unreachable network", /* ENETUNREACH */
211 "adddress in use", /* EADDRINUSE */
212 "already in use", /* EALREADY */
213 "unknown address familly", /* EAFNOSUPPORT */
216 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
218 * __xmlIOWin32UTF8ToWChar:
219 * @u8String: uft-8 string
221 * Convert a string from utf-8 to wchar (WINDOWS ONLY!)
224 __xmlIOWin32UTF8ToWChar(const char *u8String
)
226 wchar_t *wString
= NULL
;
230 MultiByteToWideChar(CP_UTF8
, MB_ERR_INVALID_CHARS
, u8String
,
233 wString
= xmlMalloc(wLen
* sizeof(wchar_t));
235 if (MultiByteToWideChar
236 (CP_UTF8
, 0, u8String
, -1, wString
, wLen
) == 0) {
250 * @extra: extra informations
252 * Handle an out of memory condition
255 xmlIOErrMemory(const char *extra
)
257 __xmlSimpleError(XML_FROM_IO
, XML_ERR_NO_MEMORY
, NULL
, NULL
, extra
);
262 * @code: the error number
264 * @extra: extra informations
266 * Handle an I/O error
269 __xmlIOErr(int domain
, int code
, const char *extra
)
275 if (errno
== 0) code
= 0;
277 else if (errno
== EACCES
) code
= XML_IO_EACCES
;
280 else if (errno
== EAGAIN
) code
= XML_IO_EAGAIN
;
283 else if (errno
== EBADF
) code
= XML_IO_EBADF
;
286 else if (errno
== EBADMSG
) code
= XML_IO_EBADMSG
;
289 else if (errno
== EBUSY
) code
= XML_IO_EBUSY
;
292 else if (errno
== ECANCELED
) code
= XML_IO_ECANCELED
;
295 else if (errno
== ECHILD
) code
= XML_IO_ECHILD
;
298 else if (errno
== EDEADLK
) code
= XML_IO_EDEADLK
;
301 else if (errno
== EDOM
) code
= XML_IO_EDOM
;
304 else if (errno
== EEXIST
) code
= XML_IO_EEXIST
;
307 else if (errno
== EFAULT
) code
= XML_IO_EFAULT
;
310 else if (errno
== EFBIG
) code
= XML_IO_EFBIG
;
313 else if (errno
== EINPROGRESS
) code
= XML_IO_EINPROGRESS
;
316 else if (errno
== EINTR
) code
= XML_IO_EINTR
;
319 else if (errno
== EINVAL
) code
= XML_IO_EINVAL
;
322 else if (errno
== EIO
) code
= XML_IO_EIO
;
325 else if (errno
== EISDIR
) code
= XML_IO_EISDIR
;
328 else if (errno
== EMFILE
) code
= XML_IO_EMFILE
;
331 else if (errno
== EMLINK
) code
= XML_IO_EMLINK
;
334 else if (errno
== EMSGSIZE
) code
= XML_IO_EMSGSIZE
;
337 else if (errno
== ENAMETOOLONG
) code
= XML_IO_ENAMETOOLONG
;
340 else if (errno
== ENFILE
) code
= XML_IO_ENFILE
;
343 else if (errno
== ENODEV
) code
= XML_IO_ENODEV
;
346 else if (errno
== ENOENT
) code
= XML_IO_ENOENT
;
349 else if (errno
== ENOEXEC
) code
= XML_IO_ENOEXEC
;
352 else if (errno
== ENOLCK
) code
= XML_IO_ENOLCK
;
355 else if (errno
== ENOMEM
) code
= XML_IO_ENOMEM
;
358 else if (errno
== ENOSPC
) code
= XML_IO_ENOSPC
;
361 else if (errno
== ENOSYS
) code
= XML_IO_ENOSYS
;
364 else if (errno
== ENOTDIR
) code
= XML_IO_ENOTDIR
;
367 else if (errno
== ENOTEMPTY
) code
= XML_IO_ENOTEMPTY
;
370 else if (errno
== ENOTSUP
) code
= XML_IO_ENOTSUP
;
373 else if (errno
== ENOTTY
) code
= XML_IO_ENOTTY
;
376 else if (errno
== ENXIO
) code
= XML_IO_ENXIO
;
379 else if (errno
== EPERM
) code
= XML_IO_EPERM
;
382 else if (errno
== EPIPE
) code
= XML_IO_EPIPE
;
385 else if (errno
== ERANGE
) code
= XML_IO_ERANGE
;
388 else if (errno
== EROFS
) code
= XML_IO_EROFS
;
391 else if (errno
== ESPIPE
) code
= XML_IO_ESPIPE
;
394 else if (errno
== ESRCH
) code
= XML_IO_ESRCH
;
397 else if (errno
== ETIMEDOUT
) code
= XML_IO_ETIMEDOUT
;
400 else if (errno
== EXDEV
) code
= XML_IO_EXDEV
;
403 else if (errno
== ENOTSOCK
) code
= XML_IO_ENOTSOCK
;
406 else if (errno
== EISCONN
) code
= XML_IO_EISCONN
;
409 else if (errno
== ECONNREFUSED
) code
= XML_IO_ECONNREFUSED
;
412 else if (errno
== ETIMEDOUT
) code
= XML_IO_ETIMEDOUT
;
415 else if (errno
== ENETUNREACH
) code
= XML_IO_ENETUNREACH
;
418 else if (errno
== EADDRINUSE
) code
= XML_IO_EADDRINUSE
;
421 else if (errno
== EINPROGRESS
) code
= XML_IO_EINPROGRESS
;
424 else if (errno
== EALREADY
) code
= XML_IO_EALREADY
;
427 else if (errno
== EAFNOSUPPORT
) code
= XML_IO_EAFNOSUPPORT
;
429 else code
= XML_IO_UNKNOWN
;
430 #endif /* HAVE_ERRNO_H */
433 if (code
>= XML_IO_UNKNOWN
) idx
= code
- XML_IO_UNKNOWN
;
434 if (idx
>= (sizeof(IOerr
) / sizeof(IOerr
[0]))) idx
= 0;
436 __xmlSimpleError(domain
, code
, NULL
, IOerr
[idx
], extra
);
441 * @code: the error number
442 * @extra: extra informations
444 * Handle an I/O error
447 xmlIOErr(int code
, const char *extra
)
449 __xmlIOErr(XML_FROM_IO
, code
, extra
);
454 * @ctx: the parser context
455 * @extra: extra informations
457 * Handle a resource access error
460 __xmlLoaderErr(void *ctx
, const char *msg
, const char *filename
)
462 xmlParserCtxtPtr ctxt
= (xmlParserCtxtPtr
) ctx
;
463 xmlStructuredErrorFunc schannel
= NULL
;
464 xmlGenericErrorFunc channel
= NULL
;
466 xmlErrorLevel level
= XML_ERR_ERROR
;
468 if ((ctxt
!= NULL
) && (ctxt
->disableSAX
!= 0) &&
469 (ctxt
->instate
== XML_PARSER_EOF
))
471 if ((ctxt
!= NULL
) && (ctxt
->sax
!= NULL
)) {
472 if (ctxt
->validate
) {
473 channel
= ctxt
->sax
->error
;
474 level
= XML_ERR_ERROR
;
476 channel
= ctxt
->sax
->warning
;
477 level
= XML_ERR_WARNING
;
479 if (ctxt
->sax
->initialized
== XML_SAX2_MAGIC
)
480 schannel
= ctxt
->sax
->serror
;
481 data
= ctxt
->userData
;
483 __xmlRaiseError(schannel
, channel
, data
, ctxt
, NULL
, XML_FROM_IO
,
484 XML_IO_LOAD_ERROR
, level
, NULL
, 0,
485 filename
, NULL
, NULL
, 0, 0,
490 /************************************************************************
492 * Tree memory error handler *
494 ************************************************************************/
496 * xmlNormalizeWindowsPath:
497 * @path: the input file path
499 * This function is obsolete. Please see xmlURIFromPath in uri.c for
502 * Returns a canonicalized version of the path
505 xmlNormalizeWindowsPath(const xmlChar
*path
)
507 return xmlCanonicPath(path
);
511 * xmlCleanupInputCallbacks:
513 * clears the entire input callback table. this includes the
517 xmlCleanupInputCallbacks(void)
521 if (!xmlInputCallbackInitialized
)
524 for (i
= xmlInputCallbackNr
- 1; i
>= 0; i
--) {
525 xmlInputCallbackTable
[i
].matchcallback
= NULL
;
526 xmlInputCallbackTable
[i
].opencallback
= NULL
;
527 xmlInputCallbackTable
[i
].readcallback
= NULL
;
528 xmlInputCallbackTable
[i
].closecallback
= NULL
;
531 xmlInputCallbackNr
= 0;
532 xmlInputCallbackInitialized
= 0;
536 * xmlPopInputCallbacks:
538 * Clear the top input callback from the input stack. this includes the
541 * Returns the number of input callback registered or -1 in case of error.
544 xmlPopInputCallbacks(void)
546 if (!xmlInputCallbackInitialized
)
549 if (xmlInputCallbackNr
<= 0)
552 xmlInputCallbackNr
--;
553 xmlInputCallbackTable
[xmlInputCallbackNr
].matchcallback
= NULL
;
554 xmlInputCallbackTable
[xmlInputCallbackNr
].opencallback
= NULL
;
555 xmlInputCallbackTable
[xmlInputCallbackNr
].readcallback
= NULL
;
556 xmlInputCallbackTable
[xmlInputCallbackNr
].closecallback
= NULL
;
558 return(xmlInputCallbackNr
);
561 #ifdef LIBXML_OUTPUT_ENABLED
563 * xmlCleanupOutputCallbacks:
565 * clears the entire output callback table. this includes the
566 * compiled-in I/O callbacks.
569 xmlCleanupOutputCallbacks(void)
573 if (!xmlOutputCallbackInitialized
)
576 for (i
= xmlOutputCallbackNr
- 1; i
>= 0; i
--) {
577 xmlOutputCallbackTable
[i
].matchcallback
= NULL
;
578 xmlOutputCallbackTable
[i
].opencallback
= NULL
;
579 xmlOutputCallbackTable
[i
].writecallback
= NULL
;
580 xmlOutputCallbackTable
[i
].closecallback
= NULL
;
583 xmlOutputCallbackNr
= 0;
584 xmlOutputCallbackInitialized
= 0;
586 #endif /* LIBXML_OUTPUT_ENABLED */
588 /************************************************************************
590 * Standard I/O for file accesses *
592 ************************************************************************/
594 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
598 * @path: the path in utf-8 encoding
599 * @mode: type of access (0 - read, 1 - write)
601 * function opens the file specified by @path
605 xmlWrapOpenUtf8(const char *path
,int mode
)
610 wPath
= __xmlIOWin32UTF8ToWChar(path
);
613 fd
= _wfopen(wPath
, mode
? L
"wb" : L
"rb");
616 /* maybe path in native encoding */
618 fd
= fopen(path
, mode
? "wb" : "rb");
625 xmlWrapGzOpenUtf8(const char *path
, const char *mode
)
630 fd
= gzopen (path
, mode
);
634 wPath
= __xmlIOWin32UTF8ToWChar(path
);
637 int d
, m
= (strstr(mode
, "r") ? O_RDONLY
: O_RDWR
);
639 m
|= (strstr(mode
, "b") ? _O_BINARY
: 0);
641 d
= _wopen(wPath
, m
);
643 fd
= gzdopen(d
, mode
);
653 * @path: the path in utf-8 encoding
654 * @info: structure that stores results
656 * function obtains information about the file or directory
660 xmlWrapStatUtf8(const char *path
,struct stat
*info
)
666 wPath
= __xmlIOWin32UTF8ToWChar(path
);
669 retval
= _wstat(wPath
,info
);
672 /* maybe path in native encoding */
674 retval
= stat(path
,info
);
684 * @mode: type of access (0 - read, 1 - write)
686 * function opens the file specified by @path
690 xmlWrapOpenNative(const char *path
,int mode
)
692 return fopen(path
,mode
? "wb" : "rb");
698 * @info: structure that stores results
700 * function obtains information about the file or directory
704 xmlWrapStatNative(const char *path
,struct stat
*info
)
707 return stat(path
,info
);
713 typedef int (* xmlWrapStatFunc
) (const char *f
, struct stat
*s
);
714 static xmlWrapStatFunc xmlWrapStat
= xmlWrapStatNative
;
715 typedef FILE* (* xmlWrapOpenFunc
)(const char *f
,int mode
);
716 static xmlWrapOpenFunc xmlWrapOpen
= xmlWrapOpenNative
;
718 typedef gzFile (* xmlWrapGzOpenFunc
) (const char *f
, const char *mode
);
719 static xmlWrapGzOpenFunc xmlWrapGzOpen
= gzopen
;
722 * xmlInitPlatformSpecificIo:
724 * Initialize platform specific features.
727 xmlInitPlatformSpecificIo(void)
729 static int xmlPlatformIoInitialized
= 0;
732 if(xmlPlatformIoInitialized
)
735 osvi
.dwOSVersionInfoSize
= sizeof(osvi
);
737 if(GetVersionEx(&osvi
) && (osvi
.dwPlatformId
== VER_PLATFORM_WIN32_NT
)) {
738 xmlWrapStat
= xmlWrapStatUtf8
;
739 xmlWrapOpen
= xmlWrapOpenUtf8
;
741 xmlWrapGzOpen
= xmlWrapGzOpenUtf8
;
744 xmlWrapStat
= xmlWrapStatNative
;
745 xmlWrapOpen
= xmlWrapOpenNative
;
747 xmlWrapGzOpen
= gzopen
;
751 xmlPlatformIoInitialized
= 1;
759 * @path: the path to check
761 * function checks to see if @path is a valid source
762 * (file, socket...) for XML.
764 * if stat is not available on the target machine,
765 * returns 1. if stat fails, returns 0 (if calling
766 * stat on the filename fails, it can't be right).
767 * if stat succeeds and the file is a directory,
768 * returns 2. otherwise returns 1.
772 xmlCheckFilename (const char *path
)
775 struct stat stat_buffer
;
781 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
783 * On Windows stat and wstat do not work with long pathname,
784 * which start with '\\?\'
786 if ((path
[0] == '\\') && (path
[1] == '\\') && (path
[2] == '?') &&
790 if (xmlWrapStat(path
, &stat_buffer
) == -1)
793 if (stat(path
, &stat_buffer
) == -1)
797 if (S_ISDIR(stat_buffer
.st_mode
))
800 #endif /* HAVE_STAT */
807 * No Operation function, does nothing, no input
818 * @context: the I/O context
819 * @buffer: where to drop data
820 * @len: number of bytes to read
822 * Read @len bytes to @buffer from the I/O channel.
824 * Returns the number of bytes written
827 xmlFdRead (void * context
, char * buffer
, int len
) {
830 ret
= read((int) (long) context
, &buffer
[0], len
);
831 if (ret
< 0) xmlIOErr(0, "read()");
835 #ifdef LIBXML_OUTPUT_ENABLED
838 * @context: the I/O context
839 * @buffer: where to get data
840 * @len: number of bytes to write
842 * Write @len bytes from @buffer to the I/O channel.
844 * Returns the number of bytes written
847 xmlFdWrite (void * context
, const char * buffer
, int len
) {
851 ret
= write((int) (long) context
, &buffer
[0], len
);
852 if (ret
< 0) xmlIOErr(0, "write()");
856 #endif /* LIBXML_OUTPUT_ENABLED */
860 * @context: the I/O context
862 * Close an I/O channel
864 * Returns 0 in case of success and error code otherwise
867 xmlFdClose (void * context
) {
869 ret
= close((int) (long) context
);
870 if (ret
< 0) xmlIOErr(0, "close()");
876 * @filename: the URI for matching
880 * Returns 1 if matches, 0 otherwise
883 xmlFileMatch (const char *filename ATTRIBUTE_UNUSED
) {
889 * @filename: the URI for matching
891 * input from FILE *, supports compressed input
892 * if @filename is " " then the standard input is used
894 * Returns an I/O context or NULL in case of error
897 xmlFileOpen_real (const char *filename
) {
898 const char *path
= filename
;
901 if (filename
== NULL
)
904 if (!strcmp(filename
, "-")) {
909 if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file://localhost/", 17)) {
910 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
911 path
= &filename
[17];
913 path
= &filename
[16];
915 } else if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file:///", 8)) {
916 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
921 } else if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file:/", 6)) {
922 /* lots of generators seems to lazy to read RFC 1738 */
923 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
930 if (!xmlCheckFilename(path
))
933 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
934 fd
= xmlWrapOpen(path
, 0);
936 fd
= fopen(path
, "r");
938 if (fd
== NULL
) xmlIOErr(0, path
);
944 * @filename: the URI for matching
946 * Wrapper around xmlFileOpen_real that try it with an unescaped
947 * version of @filename, if this fails fallback to @filename
949 * Returns a handler or NULL in case or failure
952 xmlFileOpen (const char *filename
) {
956 retval
= xmlFileOpen_real(filename
);
957 if (retval
== NULL
) {
958 unescaped
= xmlURIUnescapeString(filename
, 0, NULL
);
959 if (unescaped
!= NULL
) {
960 retval
= xmlFileOpen_real(unescaped
);
968 #ifdef LIBXML_OUTPUT_ENABLED
971 * @filename: the URI for matching
973 * output to from FILE *,
974 * if @filename is "-" then the standard output is used
976 * Returns an I/O context or NULL in case of error
979 xmlFileOpenW (const char *filename
) {
980 const char *path
= NULL
;
983 if (!strcmp(filename
, "-")) {
988 if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file://localhost/", 17))
989 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
990 path
= &filename
[17];
992 path
= &filename
[16];
994 else if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file:///", 8)) {
995 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
1006 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
1007 fd
= xmlWrapOpen(path
, 1);
1009 fd
= fopen(path
, "wb");
1012 if (fd
== NULL
) xmlIOErr(0, path
);
1013 return((void *) fd
);
1015 #endif /* LIBXML_OUTPUT_ENABLED */
1019 * @context: the I/O context
1020 * @buffer: where to drop data
1021 * @len: number of bytes to write
1023 * Read @len bytes to @buffer from the I/O channel.
1025 * Returns the number of bytes written or < 0 in case of failure
1028 xmlFileRead (void * context
, char * buffer
, int len
) {
1030 if ((context
== NULL
) || (buffer
== NULL
))
1032 ret
= fread(&buffer
[0], 1, len
, (FILE *) context
);
1033 if (ret
< 0) xmlIOErr(0, "fread()");
1037 #ifdef LIBXML_OUTPUT_ENABLED
1040 * @context: the I/O context
1041 * @buffer: where to drop data
1042 * @len: number of bytes to write
1044 * Write @len bytes from @buffer to the I/O channel.
1046 * Returns the number of bytes written
1049 xmlFileWrite (void * context
, const char * buffer
, int len
) {
1052 if ((context
== NULL
) || (buffer
== NULL
))
1054 items
= fwrite(&buffer
[0], len
, 1, (FILE *) context
);
1055 if ((items
== 0) && (ferror((FILE *) context
))) {
1056 xmlIOErr(0, "fwrite()");
1059 return(items
* len
);
1061 #endif /* LIBXML_OUTPUT_ENABLED */
1065 * @context: the I/O context
1067 * Close an I/O channel
1069 * Returns 0 or -1 in case of error
1072 xmlFileClose (void * context
) {
1076 if (context
== NULL
)
1078 fil
= (FILE *) context
;
1079 if ((fil
== stdout
) || (fil
== stderr
)) {
1082 xmlIOErr(0, "fflush()");
1087 ret
= ( fclose((FILE *) context
) == EOF
) ? -1 : 0;
1089 xmlIOErr(0, "fclose()");
1095 * @context: the I/O context
1097 * Flush an I/O channel
1100 xmlFileFlush (void * context
) {
1103 if (context
== NULL
)
1105 ret
= ( fflush((FILE *) context
) == EOF
) ? -1 : 0;
1107 xmlIOErr(0, "fflush()");
1111 #ifdef LIBXML_OUTPUT_ENABLED
1114 * @context: the xmlBuffer
1115 * @buffer: the data to write
1116 * @len: number of bytes to write
1118 * Write @len bytes from @buffer to the xml buffer
1120 * Returns the number of bytes written
1123 xmlBufferWrite (void * context
, const char * buffer
, int len
) {
1126 ret
= xmlBufferAdd((xmlBufferPtr
) context
, (const xmlChar
*) buffer
, len
);
1134 /************************************************************************
1136 * I/O for compressed file accesses *
1138 ************************************************************************/
1141 * @filename: the URI for matching
1143 * input from compressed file test
1145 * Returns 1 if matches, 0 otherwise
1148 xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED
) {
1153 * xmlGzfileOpen_real:
1154 * @filename: the URI for matching
1156 * input from compressed file open
1157 * if @filename is " " then the standard input is used
1159 * Returns an I/O context or NULL in case of error
1162 xmlGzfileOpen_real (const char *filename
) {
1163 const char *path
= NULL
;
1166 if (!strcmp(filename
, "-")) {
1167 int duped_fd
= dup(fileno(stdin
));
1168 fd
= gzdopen(duped_fd
, "rb");
1169 if (fd
== Z_NULL
&& duped_fd
>= 0) {
1170 close(duped_fd
); /* gzdOpen() does not close on failure */
1173 return((void *) fd
);
1176 if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file://localhost/", 17))
1177 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
1178 path
= &filename
[17];
1180 path
= &filename
[16];
1182 else if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file:///", 8)) {
1183 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
1184 path
= &filename
[8];
1186 path
= &filename
[7];
1193 if (!xmlCheckFilename(path
))
1196 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
1197 fd
= xmlWrapGzOpen(path
, "rb");
1199 fd
= gzopen(path
, "rb");
1201 return((void *) fd
);
1206 * @filename: the URI for matching
1208 * Wrapper around xmlGzfileOpen if the open fais, it will
1209 * try to unescape @filename
1212 xmlGzfileOpen (const char *filename
) {
1216 retval
= xmlGzfileOpen_real(filename
);
1217 if (retval
== NULL
) {
1218 unescaped
= xmlURIUnescapeString(filename
, 0, NULL
);
1219 if (unescaped
!= NULL
) {
1220 retval
= xmlGzfileOpen_real(unescaped
);
1227 #ifdef LIBXML_OUTPUT_ENABLED
1230 * @filename: the URI for matching
1231 * @compression: the compression factor (0 - 9 included)
1233 * input from compressed file open
1234 * if @filename is " " then the standard input is used
1236 * Returns an I/O context or NULL in case of error
1239 xmlGzfileOpenW (const char *filename
, int compression
) {
1240 const char *path
= NULL
;
1244 snprintf(mode
, sizeof(mode
), "wb%d", compression
);
1245 if (!strcmp(filename
, "-")) {
1246 int duped_fd
= dup(fileno(stdout
));
1247 fd
= gzdopen(duped_fd
, "rb");
1248 if (fd
== Z_NULL
&& duped_fd
>= 0) {
1249 close(duped_fd
); /* gzdOpen() does not close on failure */
1252 return((void *) fd
);
1255 if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file://localhost/", 17))
1256 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
1257 path
= &filename
[17];
1259 path
= &filename
[16];
1261 else if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file:///", 8)) {
1262 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
1263 path
= &filename
[8];
1265 path
= &filename
[7];
1273 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
1274 fd
= xmlWrapGzOpen(path
, mode
);
1276 fd
= gzopen(path
, mode
);
1278 return((void *) fd
);
1280 #endif /* LIBXML_OUTPUT_ENABLED */
1284 * @context: the I/O context
1285 * @buffer: where to drop data
1286 * @len: number of bytes to write
1288 * Read @len bytes to @buffer from the compressed I/O channel.
1290 * Returns the number of bytes written
1293 xmlGzfileRead (void * context
, char * buffer
, int len
) {
1296 ret
= gzread((gzFile
) context
, &buffer
[0], len
);
1297 if (ret
< 0) xmlIOErr(0, "gzread()");
1301 #ifdef LIBXML_OUTPUT_ENABLED
1304 * @context: the I/O context
1305 * @buffer: where to drop data
1306 * @len: number of bytes to write
1308 * Write @len bytes from @buffer to the compressed I/O channel.
1310 * Returns the number of bytes written
1313 xmlGzfileWrite (void * context
, const char * buffer
, int len
) {
1316 ret
= gzwrite((gzFile
) context
, (char *) &buffer
[0], len
);
1317 if (ret
< 0) xmlIOErr(0, "gzwrite()");
1320 #endif /* LIBXML_OUTPUT_ENABLED */
1324 * @context: the I/O context
1326 * Close a compressed I/O channel
1329 xmlGzfileClose (void * context
) {
1332 ret
= (gzclose((gzFile
) context
) == Z_OK
) ? 0 : -1;
1333 if (ret
< 0) xmlIOErr(0, "gzclose()");
1336 #endif /* HAVE_ZLIB_H */
1339 /************************************************************************
1341 * I/O for compressed file accesses *
1343 ************************************************************************/
1347 * @filename: the URI for matching
1349 * input from compressed file test
1351 * Returns 1 if matches, 0 otherwise
1354 xmlXzfileMatch (const char *filename ATTRIBUTE_UNUSED
) {
1359 * xmlXzFileOpen_real:
1360 * @filename: the URI for matching
1362 * input from compressed file open
1363 * if @filename is " " then the standard input is used
1365 * Returns an I/O context or NULL in case of error
1368 xmlXzfileOpen_real (const char *filename
) {
1369 const char *path
= NULL
;
1372 if (!strcmp(filename
, "-")) {
1373 fd
= __libxml2_xzdopen(dup(fileno(stdin
)), "rb");
1374 return((void *) fd
);
1377 if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file://localhost/", 17)) {
1378 path
= &filename
[16];
1379 } else if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file:///", 8)) {
1380 path
= &filename
[7];
1381 } else if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file:/", 6)) {
1382 /* lots of generators seems to lazy to read RFC 1738 */
1383 path
= &filename
[5];
1389 if (!xmlCheckFilename(path
))
1392 fd
= __libxml2_xzopen(path
, "rb");
1393 return((void *) fd
);
1398 * @filename: the URI for matching
1400 * Wrapper around xmlXzfileOpen_real that try it with an unescaped
1401 * version of @filename, if this fails fallback to @filename
1403 * Returns a handler or NULL in case or failure
1406 xmlXzfileOpen (const char *filename
) {
1410 retval
= xmlXzfileOpen_real(filename
);
1411 if (retval
== NULL
) {
1412 unescaped
= xmlURIUnescapeString(filename
, 0, NULL
);
1413 if (unescaped
!= NULL
) {
1414 retval
= xmlXzfileOpen_real(unescaped
);
1424 * @context: the I/O context
1425 * @buffer: where to drop data
1426 * @len: number of bytes to write
1428 * Read @len bytes to @buffer from the compressed I/O channel.
1430 * Returns the number of bytes written
1433 xmlXzfileRead (void * context
, char * buffer
, int len
) {
1436 ret
= __libxml2_xzread((xzFile
) context
, &buffer
[0], len
);
1437 if (ret
< 0) xmlIOErr(0, "xzread()");
1443 * @context: the I/O context
1445 * Close a compressed I/O channel
1448 xmlXzfileClose (void * context
) {
1451 ret
= (__libxml2_xzclose((xzFile
) context
) == LZMA_OK
) ? 0 : -1;
1452 if (ret
< 0) xmlIOErr(0, "xzclose()");
1455 #endif /* HAVE_LZMA_H */
1457 #ifdef LIBXML_HTTP_ENABLED
1458 /************************************************************************
1460 * I/O for HTTP file accesses *
1462 ************************************************************************/
1464 #ifdef LIBXML_OUTPUT_ENABLED
1465 typedef struct xmlIOHTTPWriteCtxt_
1473 } xmlIOHTTPWriteCtxt
, *xmlIOHTTPWriteCtxtPtr
;
1477 #define DFLT_WBITS ( -15 )
1478 #define DFLT_MEM_LVL ( 8 )
1479 #define GZ_MAGIC1 ( 0x1f )
1480 #define GZ_MAGIC2 ( 0x8b )
1481 #define LXML_ZLIB_OS_CODE ( 0x03 )
1482 #define INIT_HTTP_BUFF_SIZE ( 32768 )
1483 #define DFLT_ZLIB_RATIO ( 5 )
1486 ** Data structure and functions to work with sending compressed data
1490 typedef struct xmlZMemBuff_
1495 unsigned char * zbuff
;
1498 } xmlZMemBuff
, *xmlZMemBuffPtr
;
1501 * append_reverse_ulong
1502 * @buff: Compressed memory buffer
1503 * @data: Unsigned long to append
1505 * Append a unsigned long in reverse byte order to the end of the
1509 append_reverse_ulong( xmlZMemBuff
* buff
, unsigned long data
) {
1517 ** This is plagiarized from putLong in gzio.c (zlib source) where
1518 ** the number "4" is hardcoded. If zlib is ever patched to
1519 ** support 64 bit file sizes, this code would need to be patched
1523 for ( idx
= 0; idx
< 4; idx
++ ) {
1524 *buff
->zctrl
.next_out
= ( data
& 0xff );
1526 buff
->zctrl
.next_out
++;
1535 * @buff: The memory buffer context to clear
1537 * Release all the resources associated with the compressed memory buffer.
1540 xmlFreeZMemBuff( xmlZMemBuffPtr buff
) {
1549 xmlFree( buff
->zbuff
);
1551 z_err
= deflateEnd( &buff
->zctrl
);
1552 if ( z_err
!= Z_OK
)
1553 xmlGenericError( xmlGenericErrorContext
,
1554 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
1557 deflateEnd( &buff
->zctrl
);
1566 *@compression: Compression value to use
1568 * Create a memory buffer to hold the compressed XML document. The
1569 * compressed document in memory will end up being identical to what
1570 * would be created if gzopen/gzwrite/gzclose were being used to
1571 * write the document to disk. The code for the header/trailer data to
1572 * the compression is plagiarized from the zlib source files.
1575 xmlCreateZMemBuff( int compression
) {
1579 xmlZMemBuffPtr buff
= NULL
;
1581 if ( ( compression
< 1 ) || ( compression
> 9 ) )
1584 /* Create the control and data areas */
1586 buff
= xmlMalloc( sizeof( xmlZMemBuff
) );
1587 if ( buff
== NULL
) {
1588 xmlIOErrMemory("creating buffer context");
1592 (void)memset( buff
, 0, sizeof( xmlZMemBuff
) );
1593 buff
->size
= INIT_HTTP_BUFF_SIZE
;
1594 buff
->zbuff
= xmlMalloc( buff
->size
);
1595 if ( buff
->zbuff
== NULL
) {
1596 xmlFreeZMemBuff( buff
);
1597 xmlIOErrMemory("creating buffer");
1601 z_err
= deflateInit2( &buff
->zctrl
, compression
, Z_DEFLATED
,
1602 DFLT_WBITS
, DFLT_MEM_LVL
, Z_DEFAULT_STRATEGY
);
1603 if ( z_err
!= Z_OK
) {
1605 xmlFreeZMemBuff( buff
);
1607 xmlStrPrintf(msg
, 500,
1608 (const xmlChar
*) "xmlCreateZMemBuff: %s %d\n",
1609 "Error initializing compression context. ZLIB error:",
1611 xmlIOErr(XML_IO_WRITE
, (const char *) msg
);
1615 /* Set the header data. The CRC will be needed for the trailer */
1616 buff
->crc
= crc32( 0L, NULL
, 0 );
1617 hdr_lgth
= snprintf( (char *)buff
->zbuff
, buff
->size
,
1618 "%c%c%c%c%c%c%c%c%c%c",
1619 GZ_MAGIC1
, GZ_MAGIC2
, Z_DEFLATED
,
1620 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE
);
1621 buff
->zctrl
.next_out
= buff
->zbuff
+ hdr_lgth
;
1622 buff
->zctrl
.avail_out
= buff
->size
- hdr_lgth
;
1629 * @buff: Buffer used to compress and consolidate data.
1630 * @ext_amt: Number of bytes to extend the buffer.
1632 * Extend the internal buffer used to store the compressed data by the
1635 * Returns 0 on success or -1 on failure to extend the buffer. On failure
1636 * the original buffer still exists at the original size.
1639 xmlZMemBuffExtend( xmlZMemBuffPtr buff
, size_t ext_amt
) {
1645 unsigned char * tmp_ptr
= NULL
;
1650 else if ( ext_amt
== 0 )
1653 cur_used
= buff
->zctrl
.next_out
- buff
->zbuff
;
1654 new_size
= buff
->size
+ ext_amt
;
1657 if ( cur_used
> new_size
)
1658 xmlGenericError( xmlGenericErrorContext
,
1659 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
1660 "Buffer overwrite detected during compressed memory",
1661 "buffer extension. Overflowed by",
1662 (cur_used
- new_size
) );
1665 tmp_ptr
= xmlRealloc( buff
->zbuff
, new_size
);
1666 if ( tmp_ptr
!= NULL
) {
1668 buff
->size
= new_size
;
1669 buff
->zbuff
= tmp_ptr
;
1670 buff
->zctrl
.next_out
= tmp_ptr
+ cur_used
;
1671 buff
->zctrl
.avail_out
= new_size
- cur_used
;
1675 xmlStrPrintf(msg
, 500,
1676 (const xmlChar
*) "xmlZMemBuffExtend: %s %lu bytes.\n",
1677 "Allocation failure extending output buffer to",
1679 xmlIOErr(XML_IO_WRITE
, (const char *) msg
);
1687 * @buff: Buffer used to compress and consolidate data
1688 * @src: Uncompressed source content to append to buffer
1689 * @len: Length of source data to append to buffer
1691 * Compress and append data to the internal buffer. The data buffer
1692 * will be expanded if needed to store the additional data.
1694 * Returns the number of bytes appended to the buffer or -1 on error.
1697 xmlZMemBuffAppend( xmlZMemBuffPtr buff
, const char * src
, int len
) {
1702 if ( ( buff
== NULL
) || ( src
== NULL
) )
1705 buff
->zctrl
.avail_in
= len
;
1706 buff
->zctrl
.next_in
= (unsigned char *)src
;
1707 while ( buff
->zctrl
.avail_in
> 0 ) {
1709 ** Extend the buffer prior to deflate call if a reasonable amount
1710 ** of output buffer space is not available.
1712 min_accept
= buff
->zctrl
.avail_in
/ DFLT_ZLIB_RATIO
;
1713 if ( buff
->zctrl
.avail_out
<= min_accept
) {
1714 if ( xmlZMemBuffExtend( buff
, buff
->size
) == -1 )
1718 z_err
= deflate( &buff
->zctrl
, Z_NO_FLUSH
);
1719 if ( z_err
!= Z_OK
) {
1721 xmlStrPrintf(msg
, 500,
1722 (const xmlChar
*) "xmlZMemBuffAppend: %s %d %s - %d",
1723 "Compression error while appending",
1724 len
, "bytes to buffer. ZLIB error", z_err
);
1725 xmlIOErr(XML_IO_WRITE
, (const char *) msg
);
1730 buff
->crc
= crc32( buff
->crc
, (unsigned char *)src
, len
);
1736 * xmlZMemBuffGetContent
1737 * @buff: Compressed memory content buffer
1738 * @data_ref: Pointer reference to point to compressed content
1740 * Flushes the compression buffers, appends gzip file trailers and
1741 * returns the compressed content and length of the compressed data.
1742 * NOTE: The gzip trailer code here is plagiarized from zlib source.
1744 * Returns the length of the compressed data or -1 on error.
1747 xmlZMemBuffGetContent( xmlZMemBuffPtr buff
, char ** data_ref
) {
1752 if ( ( buff
== NULL
) || ( data_ref
== NULL
) )
1755 /* Need to loop until compression output buffers are flushed */
1759 z_err
= deflate( &buff
->zctrl
, Z_FINISH
);
1760 if ( z_err
== Z_OK
) {
1761 /* In this case Z_OK means more buffer space needed */
1763 if ( xmlZMemBuffExtend( buff
, buff
->size
) == -1 )
1767 while ( z_err
== Z_OK
);
1769 /* If the compression state is not Z_STREAM_END, some error occurred */
1771 if ( z_err
== Z_STREAM_END
) {
1773 /* Need to append the gzip data trailer */
1775 if ( buff
->zctrl
.avail_out
< ( 2 * sizeof( unsigned long ) ) ) {
1776 if ( xmlZMemBuffExtend(buff
, (2 * sizeof(unsigned long))) == -1 )
1781 ** For whatever reason, the CRC and length data are pushed out
1782 ** in reverse byte order. So a memcpy can't be used here.
1785 append_reverse_ulong( buff
, buff
->crc
);
1786 append_reverse_ulong( buff
, buff
->zctrl
.total_in
);
1788 zlgth
= buff
->zctrl
.next_out
- buff
->zbuff
;
1789 *data_ref
= (char *)buff
->zbuff
;
1794 xmlStrPrintf(msg
, 500,
1795 (const xmlChar
*) "xmlZMemBuffGetContent: %s - %d\n",
1796 "Error flushing zlib buffers. Error code", z_err
);
1797 xmlIOErr(XML_IO_WRITE
, (const char *) msg
);
1802 #endif /* LIBXML_OUTPUT_ENABLED */
1803 #endif /* HAVE_ZLIB_H */
1805 #ifdef LIBXML_OUTPUT_ENABLED
1807 * xmlFreeHTTPWriteCtxt
1808 * @ctxt: Context to cleanup
1810 * Free allocated memory and reclaim system resources.
1815 xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt
)
1817 if ( ctxt
->uri
!= NULL
)
1818 xmlFree( ctxt
->uri
);
1820 if ( ctxt
->doc_buff
!= NULL
) {
1823 if ( ctxt
->compression
> 0 ) {
1824 xmlFreeZMemBuff( ctxt
->doc_buff
);
1829 xmlOutputBufferClose( ctxt
->doc_buff
);
1836 #endif /* LIBXML_OUTPUT_ENABLED */
1841 * @filename: the URI for matching
1843 * check if the URI matches an HTTP one
1845 * Returns 1 if matches, 0 otherwise
1848 xmlIOHTTPMatch (const char *filename
) {
1849 if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"http://", 7))
1856 * @filename: the URI for matching
1858 * open an HTTP I/O channel
1860 * Returns an I/O context or NULL in case of error
1863 xmlIOHTTPOpen (const char *filename
) {
1864 return(xmlNanoHTTPOpen(filename
, NULL
));
1867 #ifdef LIBXML_OUTPUT_ENABLED
1870 * @post_uri: The destination URI for the document
1871 * @compression: The compression desired for the document.
1873 * Open a temporary buffer to collect the document for a subsequent HTTP POST
1874 * request. Non-static as is called from the output buffer creation routine.
1876 * Returns an I/O context or NULL in case of error.
1880 xmlIOHTTPOpenW(const char *post_uri
, int compression
)
1883 xmlIOHTTPWriteCtxtPtr ctxt
= NULL
;
1885 if (post_uri
== NULL
)
1888 ctxt
= xmlMalloc(sizeof(xmlIOHTTPWriteCtxt
));
1890 xmlIOErrMemory("creating HTTP output context");
1894 (void) memset(ctxt
, 0, sizeof(xmlIOHTTPWriteCtxt
));
1896 ctxt
->uri
= (char *) xmlStrdup((const xmlChar
*)post_uri
);
1897 if (ctxt
->uri
== NULL
) {
1898 xmlIOErrMemory("copying URI");
1899 xmlFreeHTTPWriteCtxt(ctxt
);
1904 * ** Since the document length is required for an HTTP post,
1905 * ** need to put the document into a buffer. A memory buffer
1906 * ** is being used to avoid pushing the data to disk and back.
1910 if ((compression
> 0) && (compression
<= 9)) {
1912 ctxt
->compression
= compression
;
1913 ctxt
->doc_buff
= xmlCreateZMemBuff(compression
);
1917 /* Any character conversions should have been done before this */
1919 ctxt
->doc_buff
= xmlAllocOutputBufferInternal(NULL
);
1922 if (ctxt
->doc_buff
== NULL
) {
1923 xmlFreeHTTPWriteCtxt(ctxt
);
1929 #endif /* LIBXML_OUTPUT_ENABLED */
1931 #ifdef LIBXML_OUTPUT_ENABLED
1933 * xmlIOHTTPDfltOpenW
1934 * @post_uri: The destination URI for this document.
1936 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
1937 * HTTP post command. This function should generally not be used as
1938 * the open callback is short circuited in xmlOutputBufferCreateFile.
1940 * Returns a pointer to the new IO context.
1943 xmlIOHTTPDfltOpenW( const char * post_uri
) {
1944 return ( xmlIOHTTPOpenW( post_uri
, 0 ) );
1946 #endif /* LIBXML_OUTPUT_ENABLED */
1950 * @context: the I/O context
1951 * @buffer: where to drop data
1952 * @len: number of bytes to write
1954 * Read @len bytes to @buffer from the I/O channel.
1956 * Returns the number of bytes written
1959 xmlIOHTTPRead(void * context
, char * buffer
, int len
) {
1960 if ((buffer
== NULL
) || (len
< 0)) return(-1);
1961 return(xmlNanoHTTPRead(context
, &buffer
[0], len
));
1964 #ifdef LIBXML_OUTPUT_ENABLED
1967 * @context: previously opened writing context
1968 * @buffer: data to output to temporary buffer
1969 * @len: bytes to output
1971 * Collect data from memory buffer into a temporary file for later
1974 * Returns number of bytes written.
1978 xmlIOHTTPWrite( void * context
, const char * buffer
, int len
) {
1980 xmlIOHTTPWriteCtxtPtr ctxt
= context
;
1982 if ( ( ctxt
== NULL
) || ( ctxt
->doc_buff
== NULL
) || ( buffer
== NULL
) )
1987 /* Use gzwrite or fwrite as previously setup in the open call */
1990 if ( ctxt
->compression
> 0 )
1991 len
= xmlZMemBuffAppend( ctxt
->doc_buff
, buffer
, len
);
1995 len
= xmlOutputBufferWrite( ctxt
->doc_buff
, len
, buffer
);
1999 xmlStrPrintf(msg
, 500,
2000 (const xmlChar
*) "xmlIOHTTPWrite: %s\n%s '%s'.\n",
2001 "Error appending to internal buffer.",
2002 "Error sending document to URI",
2004 xmlIOErr(XML_IO_WRITE
, (const char *) msg
);
2010 #endif /* LIBXML_OUTPUT_ENABLED */
2015 * @context: the I/O context
2017 * Close an HTTP I/O channel
2022 xmlIOHTTPClose (void * context
) {
2023 xmlNanoHTTPClose(context
);
2027 #ifdef LIBXML_OUTPUT_ENABLED
2029 * xmlIOHTTCloseWrite
2030 * @context: The I/O context
2031 * @http_mthd: The HTTP method to be used when sending the data
2033 * Close the transmit HTTP I/O channel and actually send the data.
2036 xmlIOHTTPCloseWrite( void * context
, const char * http_mthd
) {
2040 int content_lgth
= 0;
2041 xmlIOHTTPWriteCtxtPtr ctxt
= context
;
2043 char * http_content
= NULL
;
2044 char * content_encoding
= NULL
;
2045 char * content_type
= (char *) "text/xml";
2046 void * http_ctxt
= NULL
;
2048 if ( ( ctxt
== NULL
) || ( http_mthd
== NULL
) )
2051 /* Retrieve the content from the appropriate buffer */
2055 if ( ctxt
->compression
> 0 ) {
2056 content_lgth
= xmlZMemBuffGetContent( ctxt
->doc_buff
, &http_content
);
2057 content_encoding
= (char *) "Content-Encoding: gzip";
2062 /* Pull the data out of the memory output buffer */
2064 xmlOutputBufferPtr dctxt
= ctxt
->doc_buff
;
2065 http_content
= (char *) xmlBufContent(dctxt
->buffer
);
2066 content_lgth
= xmlBufUse(dctxt
->buffer
);
2069 if ( http_content
== NULL
) {
2071 xmlStrPrintf(msg
, 500,
2072 (const xmlChar
*) "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
2073 "Error retrieving content.\nUnable to",
2074 http_mthd
, "data to URI", ctxt
->uri
);
2075 xmlIOErr(XML_IO_WRITE
, (const char *) msg
);
2080 http_ctxt
= xmlNanoHTTPMethod( ctxt
->uri
, http_mthd
, http_content
,
2081 &content_type
, content_encoding
,
2084 if ( http_ctxt
!= NULL
) {
2086 /* If testing/debugging - dump reply with request content */
2088 FILE * tst_file
= NULL
;
2089 char buffer
[ 4096 ];
2090 char * dump_name
= NULL
;
2093 xmlGenericError( xmlGenericErrorContext
,
2094 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
2095 http_mthd
, ctxt
->uri
,
2096 xmlNanoHTTPReturnCode( http_ctxt
) );
2099 ** Since either content or reply may be gzipped,
2100 ** dump them to separate files instead of the
2101 ** standard error context.
2104 dump_name
= tempnam( NULL
, "lxml" );
2105 if ( dump_name
!= NULL
) {
2106 (void)snprintf( buffer
, sizeof(buffer
), "%s.content", dump_name
);
2108 tst_file
= fopen( buffer
, "wb" );
2109 if ( tst_file
!= NULL
) {
2110 xmlGenericError( xmlGenericErrorContext
,
2111 "Transmitted content saved in file: %s\n", buffer
);
2113 fwrite( http_content
, sizeof( char ),
2114 content_lgth
, tst_file
);
2118 (void)snprintf( buffer
, sizeof(buffer
), "%s.reply", dump_name
);
2119 tst_file
= fopen( buffer
, "wb" );
2120 if ( tst_file
!= NULL
) {
2121 xmlGenericError( xmlGenericErrorContext
,
2122 "Reply content saved in file: %s\n", buffer
);
2125 while ( (avail
= xmlNanoHTTPRead( http_ctxt
,
2126 buffer
, sizeof( buffer
) )) > 0 ) {
2128 fwrite( buffer
, sizeof( char ), avail
, tst_file
);
2136 #endif /* DEBUG_HTTP */
2138 http_rtn
= xmlNanoHTTPReturnCode( http_ctxt
);
2139 if ( ( http_rtn
>= 200 ) && ( http_rtn
< 300 ) )
2143 xmlStrPrintf(msg
, 500,
2144 (const xmlChar
*) "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
2145 http_mthd
, content_lgth
,
2146 "bytes to URI", ctxt
->uri
,
2147 "failed. HTTP return code:", http_rtn
);
2148 xmlIOErr(XML_IO_WRITE
, (const char *) msg
);
2151 xmlNanoHTTPClose( http_ctxt
);
2152 xmlFree( content_type
);
2156 /* Final cleanups */
2158 xmlFreeHTTPWriteCtxt( ctxt
);
2160 return ( close_rc
);
2166 * @context: The I/O context
2168 * Close the transmit HTTP I/O channel and actually send data using a PUT
2172 xmlIOHTTPClosePut( void * ctxt
) {
2173 return ( xmlIOHTTPCloseWrite( ctxt
, "PUT" ) );
2178 * xmlIOHTTPClosePost
2180 * @context: The I/O context
2182 * Close the transmit HTTP I/O channel and actually send data using a POST
2186 xmlIOHTTPClosePost( void * ctxt
) {
2187 return ( xmlIOHTTPCloseWrite( ctxt
, "POST" ) );
2189 #endif /* LIBXML_OUTPUT_ENABLED */
2191 #endif /* LIBXML_HTTP_ENABLED */
2193 #ifdef LIBXML_FTP_ENABLED
2194 /************************************************************************
2196 * I/O for FTP file accesses *
2198 ************************************************************************/
2201 * @filename: the URI for matching
2203 * check if the URI matches an FTP one
2205 * Returns 1 if matches, 0 otherwise
2208 xmlIOFTPMatch (const char *filename
) {
2209 if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"ftp://", 6))
2216 * @filename: the URI for matching
2218 * open an FTP I/O channel
2220 * Returns an I/O context or NULL in case of error
2223 xmlIOFTPOpen (const char *filename
) {
2224 return(xmlNanoFTPOpen(filename
));
2229 * @context: the I/O context
2230 * @buffer: where to drop data
2231 * @len: number of bytes to write
2233 * Read @len bytes to @buffer from the I/O channel.
2235 * Returns the number of bytes written
2238 xmlIOFTPRead(void * context
, char * buffer
, int len
) {
2239 if ((buffer
== NULL
) || (len
< 0)) return(-1);
2240 return(xmlNanoFTPRead(context
, &buffer
[0], len
));
2245 * @context: the I/O context
2247 * Close an FTP I/O channel
2252 xmlIOFTPClose (void * context
) {
2253 return ( xmlNanoFTPClose(context
) );
2255 #endif /* LIBXML_FTP_ENABLED */
2259 * xmlRegisterInputCallbacks:
2260 * @matchFunc: the xmlInputMatchCallback
2261 * @openFunc: the xmlInputOpenCallback
2262 * @readFunc: the xmlInputReadCallback
2263 * @closeFunc: the xmlInputCloseCallback
2265 * Register a new set of I/O callback for handling parser input.
2267 * Returns the registered handler number or -1 in case of error
2270 xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc
,
2271 xmlInputOpenCallback openFunc
, xmlInputReadCallback readFunc
,
2272 xmlInputCloseCallback closeFunc
) {
2273 if (xmlInputCallbackNr
>= MAX_INPUT_CALLBACK
) {
2276 xmlInputCallbackTable
[xmlInputCallbackNr
].matchcallback
= matchFunc
;
2277 xmlInputCallbackTable
[xmlInputCallbackNr
].opencallback
= openFunc
;
2278 xmlInputCallbackTable
[xmlInputCallbackNr
].readcallback
= readFunc
;
2279 xmlInputCallbackTable
[xmlInputCallbackNr
].closecallback
= closeFunc
;
2280 xmlInputCallbackInitialized
= 1;
2281 return(xmlInputCallbackNr
++);
2284 #ifdef LIBXML_OUTPUT_ENABLED
2286 * xmlRegisterOutputCallbacks:
2287 * @matchFunc: the xmlOutputMatchCallback
2288 * @openFunc: the xmlOutputOpenCallback
2289 * @writeFunc: the xmlOutputWriteCallback
2290 * @closeFunc: the xmlOutputCloseCallback
2292 * Register a new set of I/O callback for handling output.
2294 * Returns the registered handler number or -1 in case of error
2297 xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc
,
2298 xmlOutputOpenCallback openFunc
, xmlOutputWriteCallback writeFunc
,
2299 xmlOutputCloseCallback closeFunc
) {
2300 if (xmlOutputCallbackNr
>= MAX_OUTPUT_CALLBACK
) {
2303 xmlOutputCallbackTable
[xmlOutputCallbackNr
].matchcallback
= matchFunc
;
2304 xmlOutputCallbackTable
[xmlOutputCallbackNr
].opencallback
= openFunc
;
2305 xmlOutputCallbackTable
[xmlOutputCallbackNr
].writecallback
= writeFunc
;
2306 xmlOutputCallbackTable
[xmlOutputCallbackNr
].closecallback
= closeFunc
;
2307 xmlOutputCallbackInitialized
= 1;
2308 return(xmlOutputCallbackNr
++);
2310 #endif /* LIBXML_OUTPUT_ENABLED */
2313 * xmlRegisterDefaultInputCallbacks:
2315 * Registers the default compiled-in I/O handlers.
2318 xmlRegisterDefaultInputCallbacks(void) {
2319 if (xmlInputCallbackInitialized
)
2322 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
2323 xmlInitPlatformSpecificIo();
2326 xmlRegisterInputCallbacks(xmlFileMatch
, xmlFileOpen
,
2327 xmlFileRead
, xmlFileClose
);
2329 xmlRegisterInputCallbacks(xmlGzfileMatch
, xmlGzfileOpen
,
2330 xmlGzfileRead
, xmlGzfileClose
);
2331 #endif /* HAVE_ZLIB_H */
2333 xmlRegisterInputCallbacks(xmlXzfileMatch
, xmlXzfileOpen
,
2334 xmlXzfileRead
, xmlXzfileClose
);
2335 #endif /* HAVE_ZLIB_H */
2337 #ifdef LIBXML_HTTP_ENABLED
2338 xmlRegisterInputCallbacks(xmlIOHTTPMatch
, xmlIOHTTPOpen
,
2339 xmlIOHTTPRead
, xmlIOHTTPClose
);
2340 #endif /* LIBXML_HTTP_ENABLED */
2342 #ifdef LIBXML_FTP_ENABLED
2343 xmlRegisterInputCallbacks(xmlIOFTPMatch
, xmlIOFTPOpen
,
2344 xmlIOFTPRead
, xmlIOFTPClose
);
2345 #endif /* LIBXML_FTP_ENABLED */
2346 xmlInputCallbackInitialized
= 1;
2349 #ifdef LIBXML_OUTPUT_ENABLED
2351 * xmlRegisterDefaultOutputCallbacks:
2353 * Registers the default compiled-in I/O handlers.
2356 xmlRegisterDefaultOutputCallbacks (void) {
2357 if (xmlOutputCallbackInitialized
)
2360 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
2361 xmlInitPlatformSpecificIo();
2364 xmlRegisterOutputCallbacks(xmlFileMatch
, xmlFileOpenW
,
2365 xmlFileWrite
, xmlFileClose
);
2367 #ifdef LIBXML_HTTP_ENABLED
2368 xmlRegisterOutputCallbacks(xmlIOHTTPMatch
, xmlIOHTTPDfltOpenW
,
2369 xmlIOHTTPWrite
, xmlIOHTTPClosePut
);
2372 /*********************************
2373 No way a-priori to distinguish between gzipped files from
2374 uncompressed ones except opening if existing then closing
2375 and saving with same compression ratio ... a pain.
2378 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
2379 xmlGzfileWrite, xmlGzfileClose);
2383 #ifdef LIBXML_FTP_ENABLED
2384 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
2385 xmlIOFTPWrite, xmlIOFTPClose);
2387 **********************************/
2388 xmlOutputCallbackInitialized
= 1;
2391 #ifdef LIBXML_HTTP_ENABLED
2393 * xmlRegisterHTTPPostCallbacks:
2395 * By default, libxml submits HTTP output requests using the "PUT" method.
2396 * Calling this method changes the HTTP output method to use the "POST"
2401 xmlRegisterHTTPPostCallbacks( void ) {
2403 /* Register defaults if not done previously */
2405 if ( xmlOutputCallbackInitialized
== 0 )
2406 xmlRegisterDefaultOutputCallbacks( );
2408 xmlRegisterOutputCallbacks(xmlIOHTTPMatch
, xmlIOHTTPDfltOpenW
,
2409 xmlIOHTTPWrite
, xmlIOHTTPClosePost
);
2413 #endif /* LIBXML_OUTPUT_ENABLED */
2416 * xmlAllocParserInputBuffer:
2417 * @enc: the charset encoding if known
2419 * Create a buffered parser input for progressive parsing
2421 * Returns the new parser input or NULL
2423 xmlParserInputBufferPtr
2424 xmlAllocParserInputBuffer(xmlCharEncoding enc
) {
2425 xmlParserInputBufferPtr ret
;
2427 ret
= (xmlParserInputBufferPtr
) xmlMalloc(sizeof(xmlParserInputBuffer
));
2429 xmlIOErrMemory("creating input buffer");
2432 memset(ret
, 0, (size_t) sizeof(xmlParserInputBuffer
));
2433 ret
->buffer
= xmlBufCreateSize(2 * xmlDefaultBufferSize
);
2434 if (ret
->buffer
== NULL
) {
2438 xmlBufSetAllocationScheme(ret
->buffer
, XML_BUFFER_ALLOC_DOUBLEIT
);
2439 ret
->encoder
= xmlGetCharEncodingHandler(enc
);
2440 if (ret
->encoder
!= NULL
)
2441 ret
->raw
= xmlBufCreateSize(2 * xmlDefaultBufferSize
);
2444 ret
->readcallback
= NULL
;
2445 ret
->closecallback
= NULL
;
2446 ret
->context
= NULL
;
2447 ret
->compressed
= -1;
2448 ret
->rawconsumed
= 0;
2453 #ifdef LIBXML_OUTPUT_ENABLED
2455 * xmlAllocOutputBuffer:
2456 * @encoder: the encoding converter or NULL
2458 * Create a buffered parser output
2460 * Returns the new parser output or NULL
2463 xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder
) {
2464 xmlOutputBufferPtr ret
;
2466 ret
= (xmlOutputBufferPtr
) xmlMalloc(sizeof(xmlOutputBuffer
));
2468 xmlIOErrMemory("creating output buffer");
2471 memset(ret
, 0, (size_t) sizeof(xmlOutputBuffer
));
2472 ret
->buffer
= xmlBufCreate();
2473 if (ret
->buffer
== NULL
) {
2478 /* try to avoid a performance problem with Windows realloc() */
2479 if (xmlBufGetAllocationScheme(ret
->buffer
) == XML_BUFFER_ALLOC_EXACT
)
2480 xmlBufSetAllocationScheme(ret
->buffer
, XML_BUFFER_ALLOC_DOUBLEIT
);
2482 ret
->encoder
= encoder
;
2483 if (encoder
!= NULL
) {
2484 ret
->conv
= xmlBufCreateSize(4000);
2485 if (ret
->conv
== NULL
) {
2491 * This call is designed to initiate the encoder state
2493 xmlCharEncOutput(ret
, 1);
2496 ret
->writecallback
= NULL
;
2497 ret
->closecallback
= NULL
;
2498 ret
->context
= NULL
;
2505 * xmlAllocOutputBufferInternal:
2506 * @encoder: the encoding converter or NULL
2508 * Create a buffered parser output
2510 * Returns the new parser output or NULL
2513 xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder
) {
2514 xmlOutputBufferPtr ret
;
2516 ret
= (xmlOutputBufferPtr
) xmlMalloc(sizeof(xmlOutputBuffer
));
2518 xmlIOErrMemory("creating output buffer");
2521 memset(ret
, 0, (size_t) sizeof(xmlOutputBuffer
));
2522 ret
->buffer
= xmlBufCreate();
2523 if (ret
->buffer
== NULL
) {
2530 * For conversion buffers we use the special IO handling
2532 xmlBufSetAllocationScheme(ret
->buffer
, XML_BUFFER_ALLOC_IO
);
2534 ret
->encoder
= encoder
;
2535 if (encoder
!= NULL
) {
2536 ret
->conv
= xmlBufCreateSize(4000);
2537 if (ret
->conv
== NULL
) {
2543 * This call is designed to initiate the encoder state
2545 xmlCharEncOutput(ret
, 1);
2548 ret
->writecallback
= NULL
;
2549 ret
->closecallback
= NULL
;
2550 ret
->context
= NULL
;
2556 #endif /* LIBXML_OUTPUT_ENABLED */
2559 * xmlFreeParserInputBuffer:
2560 * @in: a buffered parser input
2562 * Free up the memory used by a buffered parser input
2565 xmlFreeParserInputBuffer(xmlParserInputBufferPtr in
) {
2566 if (in
== NULL
) return;
2569 xmlBufFree(in
->raw
);
2572 if (in
->encoder
!= NULL
) {
2573 xmlCharEncCloseFunc(in
->encoder
);
2575 if (in
->closecallback
!= NULL
) {
2576 in
->closecallback(in
->context
);
2578 if (in
->buffer
!= NULL
) {
2579 xmlBufFree(in
->buffer
);
2586 #ifdef LIBXML_OUTPUT_ENABLED
2588 * xmlOutputBufferClose:
2589 * @out: a buffered output
2591 * flushes and close the output I/O channel
2592 * and free up all the associated resources
2594 * Returns the number of byte written or -1 in case of error.
2597 xmlOutputBufferClose(xmlOutputBufferPtr out
)
2604 if (out
->writecallback
!= NULL
)
2605 xmlOutputBufferFlush(out
);
2606 if (out
->closecallback
!= NULL
) {
2607 err_rc
= out
->closecallback(out
->context
);
2609 written
= out
->written
;
2611 xmlBufFree(out
->conv
);
2614 if (out
->encoder
!= NULL
) {
2615 xmlCharEncCloseFunc(out
->encoder
);
2617 if (out
->buffer
!= NULL
) {
2618 xmlBufFree(out
->buffer
);
2625 return ((err_rc
== 0) ? written
: err_rc
);
2627 #endif /* LIBXML_OUTPUT_ENABLED */
2629 xmlParserInputBufferPtr
2630 __xmlParserInputBufferCreateFilename(const char *URI
, xmlCharEncoding enc
) {
2631 xmlParserInputBufferPtr ret
;
2633 void *context
= NULL
;
2635 if (xmlInputCallbackInitialized
== 0)
2636 xmlRegisterDefaultInputCallbacks();
2638 if (URI
== NULL
) return(NULL
);
2641 * Try to find one of the input accept method accepting that scheme
2642 * Go in reverse to give precedence to user defined handlers.
2644 if (context
== NULL
) {
2645 for (i
= xmlInputCallbackNr
- 1;i
>= 0;i
--) {
2646 if ((xmlInputCallbackTable
[i
].matchcallback
!= NULL
) &&
2647 (xmlInputCallbackTable
[i
].matchcallback(URI
) != 0)) {
2648 context
= xmlInputCallbackTable
[i
].opencallback(URI
);
2649 if (context
!= NULL
) {
2655 if (context
== NULL
) {
2660 * Allocate the Input buffer front-end.
2662 ret
= xmlAllocParserInputBuffer(enc
);
2664 ret
->context
= context
;
2665 ret
->readcallback
= xmlInputCallbackTable
[i
].readcallback
;
2666 ret
->closecallback
= xmlInputCallbackTable
[i
].closecallback
;
2668 if ((xmlInputCallbackTable
[i
].opencallback
== xmlGzfileOpen
) &&
2669 (strcmp(URI
, "-") != 0)) {
2670 #if defined(ZLIB_VERNUM) && ZLIB_VERNUM >= 0x1230
2671 ret
->compressed
= !gzdirect(context
);
2673 if (((z_stream
*)context
)->avail_in
> 4) {
2674 char *cptr
, buff4
[4];
2675 cptr
= (char *) ((z_stream
*)context
)->next_in
;
2676 if (gzread(context
, buff4
, 4) == 4) {
2677 if (strncmp(buff4
, cptr
, 4) == 0)
2678 ret
->compressed
= 0;
2680 ret
->compressed
= 1;
2688 if ((xmlInputCallbackTable
[i
].opencallback
== xmlXzfileOpen
) &&
2689 (strcmp(URI
, "-") != 0)) {
2690 ret
->compressed
= __libxml2_xzcompressed(context
);
2695 xmlInputCallbackTable
[i
].closecallback (context
);
2701 * xmlParserInputBufferCreateFilename:
2702 * @URI: a C string containing the URI or filename
2703 * @enc: the charset encoding if known
2705 * Create a buffered parser input for the progressive parsing of a file
2706 * If filename is "-' then we use stdin as the input.
2707 * Automatic support for ZLIB/Compress compressed document is provided
2708 * by default if found at compile-time.
2709 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
2711 * Returns the new parser input or NULL
2713 xmlParserInputBufferPtr
2714 xmlParserInputBufferCreateFilename(const char *URI
, xmlCharEncoding enc
) {
2715 if ((xmlParserInputBufferCreateFilenameValue
)) {
2716 return xmlParserInputBufferCreateFilenameValue(URI
, enc
);
2718 return __xmlParserInputBufferCreateFilename(URI
, enc
);
2721 #ifdef LIBXML_OUTPUT_ENABLED
2723 __xmlOutputBufferCreateFilename(const char *URI
,
2724 xmlCharEncodingHandlerPtr encoder
,
2725 int compression ATTRIBUTE_UNUSED
) {
2726 xmlOutputBufferPtr ret
;
2729 void *context
= NULL
;
2730 char *unescaped
= NULL
;
2732 int is_file_uri
= 1;
2735 if (xmlOutputCallbackInitialized
== 0)
2736 xmlRegisterDefaultOutputCallbacks();
2738 if (URI
== NULL
) return(NULL
);
2740 puri
= xmlParseURI(URI
);
2743 if ((puri
->scheme
!= NULL
) &&
2744 (!xmlStrEqual(BAD_CAST puri
->scheme
, BAD_CAST
"file")))
2748 * try to limit the damages of the URI unescaping code.
2750 if ((puri
->scheme
== NULL
) ||
2751 (xmlStrEqual(BAD_CAST puri
->scheme
, BAD_CAST
"file")))
2752 unescaped
= xmlURIUnescapeString(URI
, 0, NULL
);
2757 * Try to find one of the output accept method accepting that scheme
2758 * Go in reverse to give precedence to user defined handlers.
2759 * try with an unescaped version of the URI
2761 if (unescaped
!= NULL
) {
2763 if ((compression
> 0) && (compression
<= 9) && (is_file_uri
== 1)) {
2764 context
= xmlGzfileOpenW(unescaped
, compression
);
2765 if (context
!= NULL
) {
2766 ret
= xmlAllocOutputBufferInternal(encoder
);
2768 ret
->context
= context
;
2769 ret
->writecallback
= xmlGzfileWrite
;
2770 ret
->closecallback
= xmlGzfileClose
;
2777 for (i
= xmlOutputCallbackNr
- 1;i
>= 0;i
--) {
2778 if ((xmlOutputCallbackTable
[i
].matchcallback
!= NULL
) &&
2779 (xmlOutputCallbackTable
[i
].matchcallback(unescaped
) != 0)) {
2780 #if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2781 /* Need to pass compression parameter into HTTP open calls */
2782 if (xmlOutputCallbackTable
[i
].matchcallback
== xmlIOHTTPMatch
)
2783 context
= xmlIOHTTPOpenW(unescaped
, compression
);
2786 context
= xmlOutputCallbackTable
[i
].opencallback(unescaped
);
2787 if (context
!= NULL
)
2795 * If this failed try with a non-escaped URI this may be a strange
2798 if (context
== NULL
) {
2800 if ((compression
> 0) && (compression
<= 9) && (is_file_uri
== 1)) {
2801 context
= xmlGzfileOpenW(URI
, compression
);
2802 if (context
!= NULL
) {
2803 ret
= xmlAllocOutputBufferInternal(encoder
);
2805 ret
->context
= context
;
2806 ret
->writecallback
= xmlGzfileWrite
;
2807 ret
->closecallback
= xmlGzfileClose
;
2813 for (i
= xmlOutputCallbackNr
- 1;i
>= 0;i
--) {
2814 if ((xmlOutputCallbackTable
[i
].matchcallback
!= NULL
) &&
2815 (xmlOutputCallbackTable
[i
].matchcallback(URI
) != 0)) {
2816 #if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2817 /* Need to pass compression parameter into HTTP open calls */
2818 if (xmlOutputCallbackTable
[i
].matchcallback
== xmlIOHTTPMatch
)
2819 context
= xmlIOHTTPOpenW(URI
, compression
);
2822 context
= xmlOutputCallbackTable
[i
].opencallback(URI
);
2823 if (context
!= NULL
)
2829 if (context
== NULL
) {
2834 * Allocate the Output buffer front-end.
2836 ret
= xmlAllocOutputBufferInternal(encoder
);
2838 ret
->context
= context
;
2839 ret
->writecallback
= xmlOutputCallbackTable
[i
].writecallback
;
2840 ret
->closecallback
= xmlOutputCallbackTable
[i
].closecallback
;
2846 * xmlOutputBufferCreateFilename:
2847 * @URI: a C string containing the URI or filename
2848 * @encoder: the encoding converter or NULL
2849 * @compression: the compression ration (0 none, 9 max).
2851 * Create a buffered output for the progressive saving of a file
2852 * If filename is "-' then we use stdout as the output.
2853 * Automatic support for ZLIB/Compress compressed document is provided
2854 * by default if found at compile-time.
2855 * TODO: currently if compression is set, the library only support
2856 * writing to a local file.
2858 * Returns the new output or NULL
2861 xmlOutputBufferCreateFilename(const char *URI
,
2862 xmlCharEncodingHandlerPtr encoder
,
2863 int compression ATTRIBUTE_UNUSED
) {
2864 if ((xmlOutputBufferCreateFilenameValue
)) {
2865 return xmlOutputBufferCreateFilenameValue(URI
, encoder
, compression
);
2867 return __xmlOutputBufferCreateFilename(URI
, encoder
, compression
);
2869 #endif /* LIBXML_OUTPUT_ENABLED */
2872 * xmlParserInputBufferCreateFile:
2874 * @enc: the charset encoding if known
2876 * Create a buffered parser input for the progressive parsing of a FILE *
2879 * Returns the new parser input or NULL
2881 xmlParserInputBufferPtr
2882 xmlParserInputBufferCreateFile(FILE *file
, xmlCharEncoding enc
) {
2883 xmlParserInputBufferPtr ret
;
2885 if (xmlInputCallbackInitialized
== 0)
2886 xmlRegisterDefaultInputCallbacks();
2888 if (file
== NULL
) return(NULL
);
2890 ret
= xmlAllocParserInputBuffer(enc
);
2892 ret
->context
= file
;
2893 ret
->readcallback
= xmlFileRead
;
2894 ret
->closecallback
= xmlFileFlush
;
2900 #ifdef LIBXML_OUTPUT_ENABLED
2902 * xmlOutputBufferCreateFile:
2904 * @encoder: the encoding converter or NULL
2906 * Create a buffered output for the progressive saving to a FILE *
2909 * Returns the new parser output or NULL
2912 xmlOutputBufferCreateFile(FILE *file
, xmlCharEncodingHandlerPtr encoder
) {
2913 xmlOutputBufferPtr ret
;
2915 if (xmlOutputCallbackInitialized
== 0)
2916 xmlRegisterDefaultOutputCallbacks();
2918 if (file
== NULL
) return(NULL
);
2920 ret
= xmlAllocOutputBufferInternal(encoder
);
2922 ret
->context
= file
;
2923 ret
->writecallback
= xmlFileWrite
;
2924 ret
->closecallback
= xmlFileFlush
;
2931 * xmlOutputBufferCreateBuffer:
2932 * @buffer: a xmlBufferPtr
2933 * @encoder: the encoding converter or NULL
2935 * Create a buffered output for the progressive saving to a xmlBuffer
2937 * Returns the new parser output or NULL
2940 xmlOutputBufferCreateBuffer(xmlBufferPtr buffer
,
2941 xmlCharEncodingHandlerPtr encoder
) {
2942 xmlOutputBufferPtr ret
;
2944 if (buffer
== NULL
) return(NULL
);
2946 ret
= xmlOutputBufferCreateIO((xmlOutputWriteCallback
)
2948 (xmlOutputCloseCallback
)
2949 NULL
, (void *) buffer
, encoder
);
2955 * xmlOutputBufferGetContent:
2956 * @out: an xmlOutputBufferPtr
2958 * Gives a pointer to the data currently held in the output buffer
2960 * Returns a pointer to the data or NULL in case of error
2963 xmlOutputBufferGetContent(xmlOutputBufferPtr out
) {
2964 if ((out
== NULL
) || (out
->buffer
== NULL
))
2967 return(xmlBufContent(out
->buffer
));
2971 * xmlOutputBufferGetSize:
2972 * @out: an xmlOutputBufferPtr
2974 * Gives the length of the data currently held in the output buffer
2976 * Returns 0 in case or error or no data is held, the size otherwise
2979 xmlOutputBufferGetSize(xmlOutputBufferPtr out
) {
2980 if ((out
== NULL
) || (out
->buffer
== NULL
))
2983 return(xmlBufUse(out
->buffer
));
2987 #endif /* LIBXML_OUTPUT_ENABLED */
2990 * xmlParserInputBufferCreateFd:
2991 * @fd: a file descriptor number
2992 * @enc: the charset encoding if known
2994 * Create a buffered parser input for the progressive parsing for the input
2995 * from a file descriptor
2997 * Returns the new parser input or NULL
2999 xmlParserInputBufferPtr
3000 xmlParserInputBufferCreateFd(int fd
, xmlCharEncoding enc
) {
3001 xmlParserInputBufferPtr ret
;
3003 if (fd
< 0) return(NULL
);
3005 ret
= xmlAllocParserInputBuffer(enc
);
3007 ret
->context
= (void *) (long) fd
;
3008 ret
->readcallback
= xmlFdRead
;
3009 ret
->closecallback
= xmlFdClose
;
3016 * xmlParserInputBufferCreateMem:
3017 * @mem: the memory input
3018 * @size: the length of the memory block
3019 * @enc: the charset encoding if known
3021 * Create a buffered parser input for the progressive parsing for the input
3022 * from a memory area.
3024 * Returns the new parser input or NULL
3026 xmlParserInputBufferPtr
3027 xmlParserInputBufferCreateMem(const char *mem
, int size
, xmlCharEncoding enc
) {
3028 xmlParserInputBufferPtr ret
;
3031 if (size
<= 0) return(NULL
);
3032 if (mem
== NULL
) return(NULL
);
3034 ret
= xmlAllocParserInputBuffer(enc
);
3036 ret
->context
= (void *) mem
;
3037 ret
->readcallback
= (xmlInputReadCallback
) xmlNop
;
3038 ret
->closecallback
= NULL
;
3039 errcode
= xmlBufAdd(ret
->buffer
, (const xmlChar
*) mem
, size
);
3050 * xmlParserInputBufferCreateStatic:
3051 * @mem: the memory input
3052 * @size: the length of the memory block
3053 * @enc: the charset encoding if known
3055 * Create a buffered parser input for the progressive parsing for the input
3056 * from an immutable memory area. This will not copy the memory area to
3057 * the buffer, but the memory is expected to be available until the end of
3058 * the parsing, this is useful for example when using mmap'ed file.
3060 * Returns the new parser input or NULL
3062 xmlParserInputBufferPtr
3063 xmlParserInputBufferCreateStatic(const char *mem
, int size
,
3064 xmlCharEncoding enc
) {
3065 xmlParserInputBufferPtr ret
;
3067 if (size
<= 0) return(NULL
);
3068 if (mem
== NULL
) return(NULL
);
3070 ret
= (xmlParserInputBufferPtr
) xmlMalloc(sizeof(xmlParserInputBuffer
));
3072 xmlIOErrMemory("creating input buffer");
3075 memset(ret
, 0, (size_t) sizeof(xmlParserInputBuffer
));
3076 ret
->buffer
= xmlBufCreateStatic((void *)mem
, (size_t) size
);
3077 if (ret
->buffer
== NULL
) {
3081 ret
->encoder
= xmlGetCharEncodingHandler(enc
);
3082 if (ret
->encoder
!= NULL
)
3083 ret
->raw
= xmlBufCreateSize(2 * xmlDefaultBufferSize
);
3086 ret
->compressed
= -1;
3087 ret
->context
= (void *) mem
;
3088 ret
->readcallback
= NULL
;
3089 ret
->closecallback
= NULL
;
3094 #ifdef LIBXML_OUTPUT_ENABLED
3096 * xmlOutputBufferCreateFd:
3097 * @fd: a file descriptor number
3098 * @encoder: the encoding converter or NULL
3100 * Create a buffered output for the progressive saving
3101 * to a file descriptor
3103 * Returns the new parser output or NULL
3106 xmlOutputBufferCreateFd(int fd
, xmlCharEncodingHandlerPtr encoder
) {
3107 xmlOutputBufferPtr ret
;
3109 if (fd
< 0) return(NULL
);
3111 ret
= xmlAllocOutputBufferInternal(encoder
);
3113 ret
->context
= (void *) (long) fd
;
3114 ret
->writecallback
= xmlFdWrite
;
3115 ret
->closecallback
= NULL
;
3120 #endif /* LIBXML_OUTPUT_ENABLED */
3123 * xmlParserInputBufferCreateIO:
3124 * @ioread: an I/O read function
3125 * @ioclose: an I/O close function
3126 * @ioctx: an I/O handler
3127 * @enc: the charset encoding if known
3129 * Create a buffered parser input for the progressive parsing for the input
3130 * from an I/O handler
3132 * Returns the new parser input or NULL
3134 xmlParserInputBufferPtr
3135 xmlParserInputBufferCreateIO(xmlInputReadCallback ioread
,
3136 xmlInputCloseCallback ioclose
, void *ioctx
, xmlCharEncoding enc
) {
3137 xmlParserInputBufferPtr ret
;
3139 if (ioread
== NULL
) return(NULL
);
3141 ret
= xmlAllocParserInputBuffer(enc
);
3143 ret
->context
= (void *) ioctx
;
3144 ret
->readcallback
= ioread
;
3145 ret
->closecallback
= ioclose
;
3151 #ifdef LIBXML_OUTPUT_ENABLED
3153 * xmlOutputBufferCreateIO:
3154 * @iowrite: an I/O write function
3155 * @ioclose: an I/O close function
3156 * @ioctx: an I/O handler
3157 * @encoder: the charset encoding if known
3159 * Create a buffered output for the progressive saving
3162 * Returns the new parser output or NULL
3165 xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite
,
3166 xmlOutputCloseCallback ioclose
, void *ioctx
,
3167 xmlCharEncodingHandlerPtr encoder
) {
3168 xmlOutputBufferPtr ret
;
3170 if (iowrite
== NULL
) return(NULL
);
3172 ret
= xmlAllocOutputBufferInternal(encoder
);
3174 ret
->context
= (void *) ioctx
;
3175 ret
->writecallback
= iowrite
;
3176 ret
->closecallback
= ioclose
;
3181 #endif /* LIBXML_OUTPUT_ENABLED */
3184 * xmlParserInputBufferCreateFilenameDefault:
3185 * @func: function pointer to the new ParserInputBufferCreateFilenameFunc
3187 * Registers a callback for URI input file handling
3189 * Returns the old value of the registration function
3191 xmlParserInputBufferCreateFilenameFunc
3192 xmlParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func
)
3194 xmlParserInputBufferCreateFilenameFunc old
= xmlParserInputBufferCreateFilenameValue
;
3196 old
= __xmlParserInputBufferCreateFilename
;
3199 xmlParserInputBufferCreateFilenameValue
= func
;
3204 * xmlOutputBufferCreateFilenameDefault:
3205 * @func: function pointer to the new OutputBufferCreateFilenameFunc
3207 * Registers a callback for URI output file handling
3209 * Returns the old value of the registration function
3211 xmlOutputBufferCreateFilenameFunc
3212 xmlOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func
)
3214 xmlOutputBufferCreateFilenameFunc old
= xmlOutputBufferCreateFilenameValue
;
3215 #ifdef LIBXML_OUTPUT_ENABLED
3217 old
= __xmlOutputBufferCreateFilename
;
3220 xmlOutputBufferCreateFilenameValue
= func
;
3225 * xmlParserInputBufferPush:
3226 * @in: a buffered parser input
3227 * @len: the size in bytes of the array.
3228 * @buf: an char array
3230 * Push the content of the arry in the input buffer
3231 * This routine handle the I18N transcoding to internal UTF-8
3232 * This is used when operating the parser in progressive (push) mode.
3234 * Returns the number of chars read and stored in the buffer, or -1
3238 xmlParserInputBufferPush(xmlParserInputBufferPtr in
,
3239 int len
, const char *buf
) {
3243 if (len
< 0) return(0);
3244 if ((in
== NULL
) || (in
->error
)) return(-1);
3245 if (in
->encoder
!= NULL
) {
3249 * Store the data in the incoming raw buffer
3251 if (in
->raw
== NULL
) {
3252 in
->raw
= xmlBufCreate();
3254 ret
= xmlBufAdd(in
->raw
, (const xmlChar
*) buf
, len
);
3259 * convert as much as possible to the parser reading buffer.
3261 use
= xmlBufUse(in
->raw
);
3262 nbchars
= xmlCharEncInput(in
, 1);
3264 xmlIOErr(XML_IO_ENCODER
, NULL
);
3265 in
->error
= XML_IO_ENCODER
;
3268 in
->rawconsumed
+= (use
- xmlBufUse(in
->raw
));
3271 ret
= xmlBufAdd(in
->buffer
, (xmlChar
*) buf
, nbchars
);
3276 xmlGenericError(xmlGenericErrorContext
,
3277 "I/O: pushed %d chars, buffer %d/%d\n",
3278 nbchars
, xmlBufUse(in
->buffer
), xmlBufLength(in
->buffer
));
3286 * When reading from an Input channel indicated end of file or error
3287 * don't reread from it again.
3290 endOfInput (void * context ATTRIBUTE_UNUSED
,
3291 char * buffer ATTRIBUTE_UNUSED
,
3292 int len ATTRIBUTE_UNUSED
) {
3297 * xmlParserInputBufferGrow:
3298 * @in: a buffered parser input
3299 * @len: indicative value of the amount of chars to read
3301 * Grow up the content of the input buffer, the old data are preserved
3302 * This routine handle the I18N transcoding to internal UTF-8
3303 * This routine is used when operating the parser in normal (pull) mode
3305 * TODO: one should be able to remove one extra copy by copying directly
3306 * onto in->buffer or in->raw
3308 * Returns the number of chars read and stored in the buffer, or -1
3312 xmlParserInputBufferGrow(xmlParserInputBufferPtr in
, int len
) {
3313 char *buffer
= NULL
;
3317 if ((in
== NULL
) || (in
->error
)) return(-1);
3318 if ((len
<= MINLEN
) && (len
!= 4))
3321 if (xmlBufAvail(in
->buffer
) <= 0) {
3322 xmlIOErr(XML_IO_BUFFER_FULL
, NULL
);
3323 in
->error
= XML_IO_BUFFER_FULL
;
3327 if (xmlBufGrow(in
->buffer
, len
+ 1) < 0) {
3328 xmlIOErrMemory("growing input buffer");
3329 in
->error
= XML_ERR_NO_MEMORY
;
3332 buffer
= (char *)xmlBufEnd(in
->buffer
);
3335 * Call the read method for this I/O type.
3337 if (in
->readcallback
!= NULL
) {
3338 res
= in
->readcallback(in
->context
, &buffer
[0], len
);
3340 in
->readcallback
= endOfInput
;
3342 xmlIOErr(XML_IO_NO_INPUT
, NULL
);
3343 in
->error
= XML_IO_NO_INPUT
;
3351 * try to establish compressed status of input if not done already
3353 if (in
->compressed
== -1) {
3355 if (in
->readcallback
== xmlXzfileRead
)
3356 in
->compressed
= __libxml2_xzcompressed(in
->context
);
3361 if (in
->encoder
!= NULL
) {
3365 * Store the data in the incoming raw buffer
3367 if (in
->raw
== NULL
) {
3368 in
->raw
= xmlBufCreate();
3370 res
= xmlBufAdd(in
->raw
, (const xmlChar
*) buffer
, len
);
3375 * convert as much as possible to the parser reading buffer.
3377 use
= xmlBufUse(in
->raw
);
3378 nbchars
= xmlCharEncInput(in
, 1);
3380 xmlIOErr(XML_IO_ENCODER
, NULL
);
3381 in
->error
= XML_IO_ENCODER
;
3384 in
->rawconsumed
+= (use
- xmlBufUse(in
->raw
));
3387 xmlBufAddLen(in
->buffer
, nbchars
);
3390 xmlGenericError(xmlGenericErrorContext
,
3391 "I/O: read %d chars, buffer %d\n",
3392 nbchars
, xmlBufUse(in
->buffer
));
3398 * xmlParserInputBufferRead:
3399 * @in: a buffered parser input
3400 * @len: indicative value of the amount of chars to read
3402 * Refresh the content of the input buffer, the old data are considered
3404 * This routine handle the I18N transcoding to internal UTF-8
3406 * Returns the number of chars read and stored in the buffer, or -1
3410 xmlParserInputBufferRead(xmlParserInputBufferPtr in
, int len
) {
3411 if ((in
== NULL
) || (in
->error
)) return(-1);
3412 if (in
->readcallback
!= NULL
)
3413 return(xmlParserInputBufferGrow(in
, len
));
3414 else if (xmlBufGetAllocationScheme(in
->buffer
) == XML_BUFFER_ALLOC_IMMUTABLE
)
3420 #ifdef LIBXML_OUTPUT_ENABLED
3422 * xmlOutputBufferWrite:
3423 * @out: a buffered parser output
3424 * @len: the size in bytes of the array.
3425 * @buf: an char array
3427 * Write the content of the array in the output I/O buffer
3428 * This routine handle the I18N transcoding from internal UTF-8
3429 * The buffer is lossless, i.e. will store in case of partial
3430 * or delayed writes.
3432 * Returns the number of chars immediately written, or -1
3436 xmlOutputBufferWrite(xmlOutputBufferPtr out
, int len
, const char *buf
) {
3437 int nbchars
= 0; /* number of chars to output to I/O */
3438 int ret
; /* return from function call */
3439 int written
= 0; /* number of char written to I/O so far */
3440 int chunk
; /* number of byte curreent processed from buf */
3442 if ((out
== NULL
) || (out
->error
)) return(-1);
3443 if (len
< 0) return(0);
3444 if (out
->error
) return(-1);
3448 if (chunk
> 4 * MINLEN
)
3452 * first handle encoding stuff.
3454 if (out
->encoder
!= NULL
) {
3456 * Store the data in the incoming raw buffer
3458 if (out
->conv
== NULL
) {
3459 out
->conv
= xmlBufCreate();
3461 ret
= xmlBufAdd(out
->buffer
, (const xmlChar
*) buf
, chunk
);
3465 if ((xmlBufUse(out
->buffer
) < MINLEN
) && (chunk
== len
))
3469 * convert as much as possible to the parser reading buffer.
3471 ret
= xmlCharEncOutput(out
, 0);
3472 if ((ret
< 0) && (ret
!= -3)) {
3473 xmlIOErr(XML_IO_ENCODER
, NULL
);
3474 out
->error
= XML_IO_ENCODER
;
3477 nbchars
= xmlBufUse(out
->conv
);
3479 ret
= xmlBufAdd(out
->buffer
, (const xmlChar
*) buf
, chunk
);
3482 nbchars
= xmlBufUse(out
->buffer
);
3487 if ((nbchars
< MINLEN
) && (len
<= 0))
3490 if (out
->writecallback
) {
3492 * second write the stuff to the I/O channel
3494 if (out
->encoder
!= NULL
) {
3495 ret
= out
->writecallback(out
->context
,
3496 (const char *)xmlBufContent(out
->conv
), nbchars
);
3498 xmlBufShrink(out
->conv
, ret
);
3500 ret
= out
->writecallback(out
->context
,
3501 (const char *)xmlBufContent(out
->buffer
), nbchars
);
3503 xmlBufShrink(out
->buffer
, ret
);
3506 xmlIOErr(XML_IO_WRITE
, NULL
);
3507 out
->error
= XML_IO_WRITE
;
3510 out
->written
+= ret
;
3517 xmlGenericError(xmlGenericErrorContext
,
3518 "I/O: wrote %d chars\n", written
);
3525 * @out: a pointer to an array of bytes to store the result
3526 * @outlen: the length of @out
3527 * @in: a pointer to an array of unescaped UTF-8 bytes
3528 * @inlen: the length of @in
3530 * Take a block of UTF-8 chars in and escape them.
3531 * Returns 0 if success, or -1 otherwise
3532 * The value of @inlen after return is the number of octets consumed
3533 * if the return value is positive, else unpredictable.
3534 * The value of @outlen after return is the number of octets consumed.
3537 xmlEscapeContent(unsigned char* out
, int *outlen
,
3538 const xmlChar
* in
, int *inlen
) {
3539 unsigned char* outstart
= out
;
3540 const unsigned char* base
= in
;
3541 unsigned char* outend
= out
+ *outlen
;
3542 const unsigned char* inend
;
3544 inend
= in
+ (*inlen
);
3546 while ((in
< inend
) && (out
< outend
)) {
3548 if (outend
- out
< 4) break;
3553 } else if (*in
== '>') {
3554 if (outend
- out
< 4) break;
3559 } else if (*in
== '&') {
3560 if (outend
- out
< 5) break;
3566 } else if (*in
== '\r') {
3567 if (outend
- out
< 5) break;
3574 *out
++ = (unsigned char) *in
;
3578 *outlen
= out
- outstart
;
3584 * xmlOutputBufferWriteEscape:
3585 * @out: a buffered parser output
3586 * @str: a zero terminated UTF-8 string
3587 * @escaping: an optional escaping function (or NULL)
3589 * Write the content of the string in the output I/O buffer
3590 * This routine escapes the caracters and then handle the I18N
3591 * transcoding from internal UTF-8
3592 * The buffer is lossless, i.e. will store in case of partial
3593 * or delayed writes.
3595 * Returns the number of chars immediately written, or -1
3599 xmlOutputBufferWriteEscape(xmlOutputBufferPtr out
, const xmlChar
*str
,
3600 xmlCharEncodingOutputFunc escaping
) {
3601 int nbchars
= 0; /* number of chars to output to I/O */
3602 int ret
; /* return from function call */
3603 int written
= 0; /* number of char written to I/O so far */
3604 int oldwritten
=0;/* loop guard */
3605 int chunk
; /* number of byte currently processed from str */
3606 int len
; /* number of bytes in str */
3607 int cons
; /* byte from str consumed */
3609 if ((out
== NULL
) || (out
->error
) || (str
== NULL
) ||
3610 (out
->buffer
== NULL
) ||
3611 (xmlBufGetAllocationScheme(out
->buffer
) == XML_BUFFER_ALLOC_IMMUTABLE
))
3613 len
= strlen((const char *)str
);
3614 if (len
< 0) return(0);
3615 if (out
->error
) return(-1);
3616 if (escaping
== NULL
) escaping
= xmlEscapeContent
;
3619 oldwritten
= written
;
3622 * how many bytes to consume and how many bytes to store.
3625 chunk
= xmlBufAvail(out
->buffer
) - 1;
3628 * make sure we have enough room to save first, if this is
3629 * not the case force a flush, but make sure we stay in the loop
3632 if (xmlBufGrow(out
->buffer
, 100) < 0)
3639 * first handle encoding stuff.
3641 if (out
->encoder
!= NULL
) {
3643 * Store the data in the incoming raw buffer
3645 if (out
->conv
== NULL
) {
3646 out
->conv
= xmlBufCreate();
3648 ret
= escaping(xmlBufEnd(out
->buffer
) ,
3649 &chunk
, str
, &cons
);
3650 if ((ret
< 0) || (chunk
== 0)) /* chunk==0 => nothing done */
3652 xmlBufAddLen(out
->buffer
, chunk
);
3654 if ((xmlBufUse(out
->buffer
) < MINLEN
) && (cons
== len
))
3658 * convert as much as possible to the output buffer.
3660 ret
= xmlCharEncOutput(out
, 0);
3661 if ((ret
< 0) && (ret
!= -3)) {
3662 xmlIOErr(XML_IO_ENCODER
, NULL
);
3663 out
->error
= XML_IO_ENCODER
;
3666 nbchars
= xmlBufUse(out
->conv
);
3668 ret
= escaping(xmlBufEnd(out
->buffer
), &chunk
, str
, &cons
);
3669 if ((ret
< 0) || (chunk
== 0)) /* chunk==0 => nothing done */
3671 xmlBufAddLen(out
->buffer
, chunk
);
3672 nbchars
= xmlBufUse(out
->buffer
);
3677 if ((nbchars
< MINLEN
) && (len
<= 0))
3680 if (out
->writecallback
) {
3682 * second write the stuff to the I/O channel
3684 if (out
->encoder
!= NULL
) {
3685 ret
= out
->writecallback(out
->context
,
3686 (const char *)xmlBufContent(out
->conv
), nbchars
);
3688 xmlBufShrink(out
->conv
, ret
);
3690 ret
= out
->writecallback(out
->context
,
3691 (const char *)xmlBufContent(out
->buffer
), nbchars
);
3693 xmlBufShrink(out
->buffer
, ret
);
3696 xmlIOErr(XML_IO_WRITE
, NULL
);
3697 out
->error
= XML_IO_WRITE
;
3700 out
->written
+= ret
;
3701 } else if (xmlBufAvail(out
->buffer
) < MINLEN
) {
3702 xmlBufGrow(out
->buffer
, MINLEN
);
3705 } while ((len
> 0) && (oldwritten
!= written
));
3709 xmlGenericError(xmlGenericErrorContext
,
3710 "I/O: wrote %d chars\n", written
);
3716 * xmlOutputBufferWriteString:
3717 * @out: a buffered parser output
3718 * @str: a zero terminated C string
3720 * Write the content of the string in the output I/O buffer
3721 * This routine handle the I18N transcoding from internal UTF-8
3722 * The buffer is lossless, i.e. will store in case of partial
3723 * or delayed writes.
3725 * Returns the number of chars immediately written, or -1
3729 xmlOutputBufferWriteString(xmlOutputBufferPtr out
, const char *str
) {
3732 if ((out
== NULL
) || (out
->error
)) return(-1);
3738 return(xmlOutputBufferWrite(out
, len
, str
));
3743 * xmlOutputBufferFlush:
3744 * @out: a buffered output
3746 * flushes the output I/O channel
3748 * Returns the number of byte written or -1 in case of error.
3751 xmlOutputBufferFlush(xmlOutputBufferPtr out
) {
3752 int nbchars
= 0, ret
= 0;
3754 if ((out
== NULL
) || (out
->error
)) return(-1);
3756 * first handle encoding stuff.
3758 if ((out
->conv
!= NULL
) && (out
->encoder
!= NULL
)) {
3760 * convert as much as possible to the parser output buffer.
3763 nbchars
= xmlCharEncOutput(out
, 0);
3765 xmlIOErr(XML_IO_ENCODER
, NULL
);
3766 out
->error
= XML_IO_ENCODER
;
3773 * second flush the stuff to the I/O channel
3775 if ((out
->conv
!= NULL
) && (out
->encoder
!= NULL
) &&
3776 (out
->writecallback
!= NULL
)) {
3777 ret
= out
->writecallback(out
->context
,
3778 (const char *)xmlBufContent(out
->conv
),
3779 xmlBufUse(out
->conv
));
3781 xmlBufShrink(out
->conv
, ret
);
3782 } else if (out
->writecallback
!= NULL
) {
3783 ret
= out
->writecallback(out
->context
,
3784 (const char *)xmlBufContent(out
->buffer
),
3785 xmlBufUse(out
->buffer
));
3787 xmlBufShrink(out
->buffer
, ret
);
3790 xmlIOErr(XML_IO_FLUSH
, NULL
);
3791 out
->error
= XML_IO_FLUSH
;
3794 out
->written
+= ret
;
3797 xmlGenericError(xmlGenericErrorContext
,
3798 "I/O: flushed %d chars\n", ret
);
3802 #endif /* LIBXML_OUTPUT_ENABLED */
3805 * xmlParserGetDirectory:
3806 * @filename: the path to a file
3808 * lookup the directory for that file
3810 * Returns a new allocated string containing the directory, or NULL.
3813 xmlParserGetDirectory(const char *filename
) {
3818 #ifdef _WIN32_WCE /* easy way by now ... wince does not have dirs! */
3822 if (xmlInputCallbackInitialized
== 0)
3823 xmlRegisterDefaultInputCallbacks();
3825 if (filename
== NULL
) return(NULL
);
3827 #if defined(WIN32) && !defined(__CYGWIN__)
3828 # define IS_XMLPGD_SEP(ch) ((ch=='/')||(ch=='\\'))
3830 # define IS_XMLPGD_SEP(ch) (ch=='/')
3833 strncpy(dir
, filename
, 1023);
3835 cur
= &dir
[strlen(dir
)];
3837 if (IS_XMLPGD_SEP(*cur
)) break;
3840 if (IS_XMLPGD_SEP(*cur
)) {
3841 if (cur
== dir
) dir
[1] = 0;
3843 ret
= xmlMemStrdup(dir
);
3845 if (getcwd(dir
, 1024) != NULL
) {
3847 ret
= xmlMemStrdup(dir
);
3851 #undef IS_XMLPGD_SEP
3854 /****************************************************************
3856 * External entities loading *
3858 ****************************************************************/
3861 * xmlCheckHTTPInput:
3862 * @ctxt: an XML parser context
3863 * @ret: an XML parser input
3865 * Check an input in case it was created from an HTTP stream, in that
3866 * case it will handle encoding and update of the base URL in case of
3867 * redirection. It also checks for HTTP errors in which case the input
3868 * is cleanly freed up and an appropriate error is raised in context
3870 * Returns the input or NULL in case of HTTP error.
3873 xmlCheckHTTPInput(xmlParserCtxtPtr ctxt
, xmlParserInputPtr ret
) {
3874 #ifdef LIBXML_HTTP_ENABLED
3875 if ((ret
!= NULL
) && (ret
->buf
!= NULL
) &&
3876 (ret
->buf
->readcallback
== xmlIOHTTPRead
) &&
3877 (ret
->buf
->context
!= NULL
)) {
3878 const char *encoding
;
3883 code
= xmlNanoHTTPReturnCode(ret
->buf
->context
);
3886 if (ret
->filename
!= NULL
)
3887 __xmlLoaderErr(ctxt
, "failed to load HTTP resource \"%s\"\n",
3888 (const char *) ret
->filename
);
3890 __xmlLoaderErr(ctxt
, "failed to load HTTP resource\n", NULL
);
3891 xmlFreeInputStream(ret
);
3895 mime
= xmlNanoHTTPMimeType(ret
->buf
->context
);
3896 if ((xmlStrstr(BAD_CAST mime
, BAD_CAST
"/xml")) ||
3897 (xmlStrstr(BAD_CAST mime
, BAD_CAST
"+xml"))) {
3898 encoding
= xmlNanoHTTPEncoding(ret
->buf
->context
);
3899 if (encoding
!= NULL
) {
3900 xmlCharEncodingHandlerPtr handler
;
3902 handler
= xmlFindCharEncodingHandler(encoding
);
3903 if (handler
!= NULL
) {
3904 xmlSwitchInputEncoding(ctxt
, ret
, handler
);
3906 __xmlErrEncoding(ctxt
, XML_ERR_UNKNOWN_ENCODING
,
3907 "Unknown encoding %s",
3908 BAD_CAST encoding
, NULL
);
3910 if (ret
->encoding
== NULL
)
3911 ret
->encoding
= xmlStrdup(BAD_CAST encoding
);
3914 } else if (xmlStrstr(BAD_CAST mime
, BAD_CAST
"html")) {
3917 redir
= xmlNanoHTTPRedir(ret
->buf
->context
);
3918 if (redir
!= NULL
) {
3919 if (ret
->filename
!= NULL
)
3920 xmlFree((xmlChar
*) ret
->filename
);
3921 if (ret
->directory
!= NULL
) {
3922 xmlFree((xmlChar
*) ret
->directory
);
3923 ret
->directory
= NULL
;
3926 (char *) xmlStrdup((const xmlChar
*) redir
);
3934 static int xmlNoNetExists(const char *URL
) {
3940 if (!xmlStrncasecmp(BAD_CAST URL
, BAD_CAST
"file://localhost/", 17))
3941 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
3946 else if (!xmlStrncasecmp(BAD_CAST URL
, BAD_CAST
"file:///", 8)) {
3947 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
3955 return xmlCheckFilename(path
);
3958 #ifdef LIBXML_CATALOG_ENABLED
3961 * xmlResolveResourceFromCatalog:
3962 * @URL: the URL for the entity to load
3963 * @ID: the System ID for the entity to load
3964 * @ctxt: the context in which the entity is called or NULL
3966 * Resolves the URL and ID against the appropriate catalog.
3967 * This function is used by xmlDefaultExternalEntityLoader and
3968 * xmlNoNetExternalEntityLoader.
3970 * Returns a new allocated URL, or NULL.
3973 xmlResolveResourceFromCatalog(const char *URL
, const char *ID
,
3974 xmlParserCtxtPtr ctxt
) {
3975 xmlChar
*resource
= NULL
;
3976 xmlCatalogAllow pref
;
3979 * If the resource doesn't exists as a file,
3980 * try to load it from the resource pointed in the catalogs
3982 pref
= xmlCatalogGetDefaults();
3984 if ((pref
!= XML_CATA_ALLOW_NONE
) && (!xmlNoNetExists(URL
))) {
3988 if ((ctxt
!= NULL
) && (ctxt
->catalogs
!= NULL
) &&
3989 ((pref
== XML_CATA_ALLOW_ALL
) ||
3990 (pref
== XML_CATA_ALLOW_DOCUMENT
))) {
3991 resource
= xmlCatalogLocalResolve(ctxt
->catalogs
,
3992 (const xmlChar
*)ID
,
3993 (const xmlChar
*)URL
);
3996 * Try a global lookup
3998 if ((resource
== NULL
) &&
3999 ((pref
== XML_CATA_ALLOW_ALL
) ||
4000 (pref
== XML_CATA_ALLOW_GLOBAL
))) {
4001 resource
= xmlCatalogResolve((const xmlChar
*)ID
,
4002 (const xmlChar
*)URL
);
4004 if ((resource
== NULL
) && (URL
!= NULL
))
4005 resource
= xmlStrdup((const xmlChar
*) URL
);
4008 * TODO: do an URI lookup on the reference
4010 if ((resource
!= NULL
) && (!xmlNoNetExists((const char *)resource
))) {
4011 xmlChar
*tmp
= NULL
;
4013 if ((ctxt
!= NULL
) && (ctxt
->catalogs
!= NULL
) &&
4014 ((pref
== XML_CATA_ALLOW_ALL
) ||
4015 (pref
== XML_CATA_ALLOW_DOCUMENT
))) {
4016 tmp
= xmlCatalogLocalResolveURI(ctxt
->catalogs
, resource
);
4018 if ((tmp
== NULL
) &&
4019 ((pref
== XML_CATA_ALLOW_ALL
) ||
4020 (pref
== XML_CATA_ALLOW_GLOBAL
))) {
4021 tmp
= xmlCatalogResolveURI(resource
);
4037 * xmlDefaultExternalEntityLoader:
4038 * @URL: the URL for the entity to load
4039 * @ID: the System ID for the entity to load
4040 * @ctxt: the context in which the entity is called or NULL
4042 * By default we don't load external entitites, yet.
4044 * Returns a new allocated xmlParserInputPtr, or NULL.
4046 static xmlParserInputPtr
4047 xmlDefaultExternalEntityLoader(const char *URL
, const char *ID
,
4048 xmlParserCtxtPtr ctxt
)
4050 xmlParserInputPtr ret
= NULL
;
4051 xmlChar
*resource
= NULL
;
4053 #ifdef DEBUG_EXTERNAL_ENTITIES
4054 xmlGenericError(xmlGenericErrorContext
,
4055 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL
);
4057 if ((ctxt
!= NULL
) && (ctxt
->options
& XML_PARSE_NONET
)) {
4058 int options
= ctxt
->options
;
4060 ctxt
->options
-= XML_PARSE_NONET
;
4061 ret
= xmlNoNetExternalEntityLoader(URL
, ID
, ctxt
);
4062 ctxt
->options
= options
;
4065 #ifdef LIBXML_CATALOG_ENABLED
4066 resource
= xmlResolveResourceFromCatalog(URL
, ID
, ctxt
);
4069 if (resource
== NULL
)
4070 resource
= (xmlChar
*) URL
;
4072 if (resource
== NULL
) {
4075 __xmlLoaderErr(ctxt
, "failed to load external entity \"%s\"\n", ID
);
4078 ret
= xmlNewInputFromFile(ctxt
, (const char *) resource
);
4079 if ((resource
!= NULL
) && (resource
!= (xmlChar
*) URL
))
4084 static xmlExternalEntityLoader xmlCurrentExternalEntityLoader
=
4085 xmlDefaultExternalEntityLoader
;
4088 * xmlSetExternalEntityLoader:
4089 * @f: the new entity resolver function
4091 * Changes the defaultexternal entity resolver function for the application
4094 xmlSetExternalEntityLoader(xmlExternalEntityLoader f
) {
4095 xmlCurrentExternalEntityLoader
= f
;
4099 * xmlGetExternalEntityLoader:
4101 * Get the default external entity resolver function for the application
4103 * Returns the xmlExternalEntityLoader function pointer
4105 xmlExternalEntityLoader
4106 xmlGetExternalEntityLoader(void) {
4107 return(xmlCurrentExternalEntityLoader
);
4111 * xmlLoadExternalEntity:
4112 * @URL: the URL for the entity to load
4113 * @ID: the Public ID for the entity to load
4114 * @ctxt: the context in which the entity is called or NULL
4116 * Load an external entity, note that the use of this function for
4117 * unparsed entities may generate problems
4119 * Returns the xmlParserInputPtr or NULL
4122 xmlLoadExternalEntity(const char *URL
, const char *ID
,
4123 xmlParserCtxtPtr ctxt
) {
4124 if ((URL
!= NULL
) && (xmlNoNetExists(URL
) == 0)) {
4125 char *canonicFilename
;
4126 xmlParserInputPtr ret
;
4128 canonicFilename
= (char *) xmlCanonicPath((const xmlChar
*) URL
);
4129 if (canonicFilename
== NULL
) {
4130 xmlIOErrMemory("building canonical path\n");
4134 ret
= xmlCurrentExternalEntityLoader(canonicFilename
, ID
, ctxt
);
4135 xmlFree(canonicFilename
);
4138 return(xmlCurrentExternalEntityLoader(URL
, ID
, ctxt
));
4141 /************************************************************************
4143 * Disabling Network access *
4145 ************************************************************************/
4148 * xmlNoNetExternalEntityLoader:
4149 * @URL: the URL for the entity to load
4150 * @ID: the System ID for the entity to load
4151 * @ctxt: the context in which the entity is called or NULL
4153 * A specific entity loader disabling network accesses, though still
4154 * allowing local catalog accesses for resolution.
4156 * Returns a new allocated xmlParserInputPtr, or NULL.
4159 xmlNoNetExternalEntityLoader(const char *URL
, const char *ID
,
4160 xmlParserCtxtPtr ctxt
) {
4161 xmlParserInputPtr input
= NULL
;
4162 xmlChar
*resource
= NULL
;
4164 #ifdef LIBXML_CATALOG_ENABLED
4165 resource
= xmlResolveResourceFromCatalog(URL
, ID
, ctxt
);
4168 if (resource
== NULL
)
4169 resource
= (xmlChar
*) URL
;
4171 if (resource
!= NULL
) {
4172 if ((!xmlStrncasecmp(BAD_CAST resource
, BAD_CAST
"ftp://", 6)) ||
4173 (!xmlStrncasecmp(BAD_CAST resource
, BAD_CAST
"http://", 7))) {
4174 xmlIOErr(XML_IO_NETWORK_ATTEMPT
, (const char *) resource
);
4175 if (resource
!= (xmlChar
*) URL
)
4180 input
= xmlDefaultExternalEntityLoader((const char *) resource
, ID
, ctxt
);
4181 if (resource
!= (xmlChar
*) URL
)
4186 #define bottom_xmlIO
4187 #include "elfgcchack.h"