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
21 #ifdef HAVE_SYS_TYPES_H
22 #include <sys/types.h>
24 #ifdef HAVE_SYS_STAT_H
36 #ifdef LIBXML_ZLIB_ENABLED
39 #ifdef LIBXML_LZMA_ENABLED
43 #if defined(_WIN32) && !defined(__CYGWIN__)
44 #define WIN32_LEAN_AND_MEAN
48 #if defined(_WIN32_WCE)
49 #include <winnls.h> /* for CP_UTF8 */
54 # define S_ISDIR(x) _S_ISDIR(x)
55 # elif defined(S_IFDIR)
57 # define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
58 # elif defined(_S_IFMT)
59 # define S_ISDIR(m) (((m) & _S_IFMT) == S_IFDIR)
64 #include <libxml/xmlmemory.h>
65 #include <libxml/parser.h>
66 #include <libxml/parserInternals.h>
67 #include <libxml/xmlIO.h>
68 #include <libxml/uri.h>
69 #include <libxml/nanohttp.h>
70 #include <libxml/nanoftp.h>
71 #include <libxml/xmlerror.h>
72 #ifdef LIBXML_CATALOG_ENABLED
73 #include <libxml/catalog.h>
75 #include <libxml/globals.h>
80 /* #define VERBOSE_FAILURE */
81 /* #define DEBUG_EXTERNAL_ENTITIES */
82 /* #define DEBUG_INPUT */
91 * Input I/O callback sets
93 typedef struct _xmlInputCallback
{
94 xmlInputMatchCallback matchcallback
;
95 xmlInputOpenCallback opencallback
;
96 xmlInputReadCallback readcallback
;
97 xmlInputCloseCallback closecallback
;
100 #define MAX_INPUT_CALLBACK 15
102 static xmlInputCallback xmlInputCallbackTable
[MAX_INPUT_CALLBACK
];
103 static int xmlInputCallbackNr
= 0;
104 static int xmlInputCallbackInitialized
= 0;
106 #ifdef LIBXML_OUTPUT_ENABLED
108 * Output I/O callback sets
110 typedef struct _xmlOutputCallback
{
111 xmlOutputMatchCallback matchcallback
;
112 xmlOutputOpenCallback opencallback
;
113 xmlOutputWriteCallback writecallback
;
114 xmlOutputCloseCallback closecallback
;
117 #define MAX_OUTPUT_CALLBACK 15
119 static xmlOutputCallback xmlOutputCallbackTable
[MAX_OUTPUT_CALLBACK
];
120 static int xmlOutputCallbackNr
= 0;
121 static int xmlOutputCallbackInitialized
= 0;
124 xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder
);
125 #endif /* LIBXML_OUTPUT_ENABLED */
127 /************************************************************************
129 * Tree memory error handler *
131 ************************************************************************/
133 static const char *IOerr
[] = {
134 "Unknown IO error", /* UNKNOWN */
135 "Permission denied", /* EACCES */
136 "Resource temporarily unavailable",/* EAGAIN */
137 "Bad file descriptor", /* EBADF */
138 "Bad message", /* EBADMSG */
139 "Resource busy", /* EBUSY */
140 "Operation canceled", /* ECANCELED */
141 "No child processes", /* ECHILD */
142 "Resource deadlock avoided",/* EDEADLK */
143 "Domain error", /* EDOM */
144 "File exists", /* EEXIST */
145 "Bad address", /* EFAULT */
146 "File too large", /* EFBIG */
147 "Operation in progress", /* EINPROGRESS */
148 "Interrupted function call",/* EINTR */
149 "Invalid argument", /* EINVAL */
150 "Input/output error", /* EIO */
151 "Is a directory", /* EISDIR */
152 "Too many open files", /* EMFILE */
153 "Too many links", /* EMLINK */
154 "Inappropriate message buffer length",/* EMSGSIZE */
155 "Filename too long", /* ENAMETOOLONG */
156 "Too many open files in system",/* ENFILE */
157 "No such device", /* ENODEV */
158 "No such file or directory",/* ENOENT */
159 "Exec format error", /* ENOEXEC */
160 "No locks available", /* ENOLCK */
161 "Not enough space", /* ENOMEM */
162 "No space left on device", /* ENOSPC */
163 "Function not implemented", /* ENOSYS */
164 "Not a directory", /* ENOTDIR */
165 "Directory not empty", /* ENOTEMPTY */
166 "Not supported", /* ENOTSUP */
167 "Inappropriate I/O control operation",/* ENOTTY */
168 "No such device or address",/* ENXIO */
169 "Operation not permitted", /* EPERM */
170 "Broken pipe", /* EPIPE */
171 "Result too large", /* ERANGE */
172 "Read-only file system", /* EROFS */
173 "Invalid seek", /* ESPIPE */
174 "No such process", /* ESRCH */
175 "Operation timed out", /* ETIMEDOUT */
176 "Improper link", /* EXDEV */
177 "Attempt to load network entity %s", /* XML_IO_NETWORK_ATTEMPT */
178 "encoder error", /* XML_IO_ENCODER */
184 "not a socket", /* ENOTSOCK */
185 "already connected", /* EISCONN */
186 "connection refused", /* ECONNREFUSED */
187 "unreachable network", /* ENETUNREACH */
188 "address in use", /* EADDRINUSE */
189 "already in use", /* EALREADY */
190 "unknown address family", /* EAFNOSUPPORT */
193 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
195 * __xmlIOWin32UTF8ToWChar:
196 * @u8String: uft-8 string
198 * Convert a string from utf-8 to wchar (WINDOWS ONLY!)
201 __xmlIOWin32UTF8ToWChar(const char *u8String
)
203 wchar_t *wString
= NULL
;
207 MultiByteToWideChar(CP_UTF8
, MB_ERR_INVALID_CHARS
, u8String
,
210 wString
= xmlMalloc(wLen
* sizeof(wchar_t));
212 if (MultiByteToWideChar
213 (CP_UTF8
, 0, u8String
, -1, wString
, wLen
) == 0) {
227 * @extra: extra information
229 * Handle an out of memory condition
232 xmlIOErrMemory(const char *extra
)
234 __xmlSimpleError(XML_FROM_IO
, XML_ERR_NO_MEMORY
, NULL
, NULL
, extra
);
239 * @code: the error number
241 * @extra: extra information
243 * Handle an I/O error
246 __xmlIOErr(int domain
, int code
, const char *extra
)
252 if (errno
== 0) code
= 0;
254 else if (errno
== EACCES
) code
= XML_IO_EACCES
;
257 else if (errno
== EAGAIN
) code
= XML_IO_EAGAIN
;
260 else if (errno
== EBADF
) code
= XML_IO_EBADF
;
263 else if (errno
== EBADMSG
) code
= XML_IO_EBADMSG
;
266 else if (errno
== EBUSY
) code
= XML_IO_EBUSY
;
269 else if (errno
== ECANCELED
) code
= XML_IO_ECANCELED
;
272 else if (errno
== ECHILD
) code
= XML_IO_ECHILD
;
275 else if (errno
== EDEADLK
) code
= XML_IO_EDEADLK
;
278 else if (errno
== EDOM
) code
= XML_IO_EDOM
;
281 else if (errno
== EEXIST
) code
= XML_IO_EEXIST
;
284 else if (errno
== EFAULT
) code
= XML_IO_EFAULT
;
287 else if (errno
== EFBIG
) code
= XML_IO_EFBIG
;
290 else if (errno
== EINPROGRESS
) code
= XML_IO_EINPROGRESS
;
293 else if (errno
== EINTR
) code
= XML_IO_EINTR
;
296 else if (errno
== EINVAL
) code
= XML_IO_EINVAL
;
299 else if (errno
== EIO
) code
= XML_IO_EIO
;
302 else if (errno
== EISDIR
) code
= XML_IO_EISDIR
;
305 else if (errno
== EMFILE
) code
= XML_IO_EMFILE
;
308 else if (errno
== EMLINK
) code
= XML_IO_EMLINK
;
311 else if (errno
== EMSGSIZE
) code
= XML_IO_EMSGSIZE
;
314 else if (errno
== ENAMETOOLONG
) code
= XML_IO_ENAMETOOLONG
;
317 else if (errno
== ENFILE
) code
= XML_IO_ENFILE
;
320 else if (errno
== ENODEV
) code
= XML_IO_ENODEV
;
323 else if (errno
== ENOENT
) code
= XML_IO_ENOENT
;
326 else if (errno
== ENOEXEC
) code
= XML_IO_ENOEXEC
;
329 else if (errno
== ENOLCK
) code
= XML_IO_ENOLCK
;
332 else if (errno
== ENOMEM
) code
= XML_IO_ENOMEM
;
335 else if (errno
== ENOSPC
) code
= XML_IO_ENOSPC
;
338 else if (errno
== ENOSYS
) code
= XML_IO_ENOSYS
;
341 else if (errno
== ENOTDIR
) code
= XML_IO_ENOTDIR
;
344 else if (errno
== ENOTEMPTY
) code
= XML_IO_ENOTEMPTY
;
347 else if (errno
== ENOTSUP
) code
= XML_IO_ENOTSUP
;
350 else if (errno
== ENOTTY
) code
= XML_IO_ENOTTY
;
353 else if (errno
== ENXIO
) code
= XML_IO_ENXIO
;
356 else if (errno
== EPERM
) code
= XML_IO_EPERM
;
359 else if (errno
== EPIPE
) code
= XML_IO_EPIPE
;
362 else if (errno
== ERANGE
) code
= XML_IO_ERANGE
;
365 else if (errno
== EROFS
) code
= XML_IO_EROFS
;
368 else if (errno
== ESPIPE
) code
= XML_IO_ESPIPE
;
371 else if (errno
== ESRCH
) code
= XML_IO_ESRCH
;
374 else if (errno
== ETIMEDOUT
) code
= XML_IO_ETIMEDOUT
;
377 else if (errno
== EXDEV
) code
= XML_IO_EXDEV
;
380 else if (errno
== ENOTSOCK
) code
= XML_IO_ENOTSOCK
;
383 else if (errno
== EISCONN
) code
= XML_IO_EISCONN
;
386 else if (errno
== ECONNREFUSED
) code
= XML_IO_ECONNREFUSED
;
389 else if (errno
== ETIMEDOUT
) code
= XML_IO_ETIMEDOUT
;
392 else if (errno
== ENETUNREACH
) code
= XML_IO_ENETUNREACH
;
395 else if (errno
== EADDRINUSE
) code
= XML_IO_EADDRINUSE
;
398 else if (errno
== EINPROGRESS
) code
= XML_IO_EINPROGRESS
;
401 else if (errno
== EALREADY
) code
= XML_IO_EALREADY
;
404 else if (errno
== EAFNOSUPPORT
) code
= XML_IO_EAFNOSUPPORT
;
406 else code
= XML_IO_UNKNOWN
;
407 #endif /* HAVE_ERRNO_H */
410 if (code
>= XML_IO_UNKNOWN
) idx
= code
- XML_IO_UNKNOWN
;
411 if (idx
>= (sizeof(IOerr
) / sizeof(IOerr
[0]))) idx
= 0;
413 __xmlSimpleError(domain
, code
, NULL
, IOerr
[idx
], extra
);
418 * @code: the error number
419 * @extra: extra information
421 * Handle an I/O error
424 xmlIOErr(int code
, const char *extra
)
426 __xmlIOErr(XML_FROM_IO
, code
, extra
);
431 * @ctx: the parser context
432 * @extra: extra information
434 * Handle a resource access error
437 __xmlLoaderErr(void *ctx
, const char *msg
, const char *filename
)
439 xmlParserCtxtPtr ctxt
= (xmlParserCtxtPtr
) ctx
;
440 xmlStructuredErrorFunc schannel
= NULL
;
441 xmlGenericErrorFunc channel
= NULL
;
443 xmlErrorLevel level
= XML_ERR_ERROR
;
445 if ((ctxt
!= NULL
) && (ctxt
->disableSAX
!= 0) &&
446 (ctxt
->instate
== XML_PARSER_EOF
))
448 if ((ctxt
!= NULL
) && (ctxt
->sax
!= NULL
)) {
449 if (ctxt
->validate
) {
450 channel
= ctxt
->sax
->error
;
451 level
= XML_ERR_ERROR
;
453 channel
= ctxt
->sax
->warning
;
454 level
= XML_ERR_WARNING
;
456 if (ctxt
->sax
->initialized
== XML_SAX2_MAGIC
)
457 schannel
= ctxt
->sax
->serror
;
458 data
= ctxt
->userData
;
460 __xmlRaiseError(schannel
, channel
, data
, ctxt
, NULL
, XML_FROM_IO
,
461 XML_IO_LOAD_ERROR
, level
, NULL
, 0,
462 filename
, NULL
, NULL
, 0, 0,
467 /************************************************************************
469 * Tree memory error handler *
471 ************************************************************************/
473 * xmlNormalizeWindowsPath:
474 * @path: the input file path
476 * This function is obsolete. Please see xmlURIFromPath in uri.c for
479 * Returns a canonicalized version of the path
482 xmlNormalizeWindowsPath(const xmlChar
*path
)
484 return xmlCanonicPath(path
);
488 * xmlCleanupInputCallbacks:
490 * clears the entire input callback table. this includes the
494 xmlCleanupInputCallbacks(void)
498 if (!xmlInputCallbackInitialized
)
501 for (i
= xmlInputCallbackNr
- 1; i
>= 0; i
--) {
502 xmlInputCallbackTable
[i
].matchcallback
= NULL
;
503 xmlInputCallbackTable
[i
].opencallback
= NULL
;
504 xmlInputCallbackTable
[i
].readcallback
= NULL
;
505 xmlInputCallbackTable
[i
].closecallback
= NULL
;
508 xmlInputCallbackNr
= 0;
509 xmlInputCallbackInitialized
= 0;
513 * xmlPopInputCallbacks:
515 * Clear the top input callback from the input stack. this includes the
518 * Returns the number of input callback registered or -1 in case of error.
521 xmlPopInputCallbacks(void)
523 if (!xmlInputCallbackInitialized
)
526 if (xmlInputCallbackNr
<= 0)
529 xmlInputCallbackNr
--;
530 xmlInputCallbackTable
[xmlInputCallbackNr
].matchcallback
= NULL
;
531 xmlInputCallbackTable
[xmlInputCallbackNr
].opencallback
= NULL
;
532 xmlInputCallbackTable
[xmlInputCallbackNr
].readcallback
= NULL
;
533 xmlInputCallbackTable
[xmlInputCallbackNr
].closecallback
= NULL
;
535 return(xmlInputCallbackNr
);
538 #ifdef LIBXML_OUTPUT_ENABLED
540 * xmlCleanupOutputCallbacks:
542 * clears the entire output callback table. this includes the
543 * compiled-in I/O callbacks.
546 xmlCleanupOutputCallbacks(void)
550 if (!xmlOutputCallbackInitialized
)
553 for (i
= xmlOutputCallbackNr
- 1; i
>= 0; i
--) {
554 xmlOutputCallbackTable
[i
].matchcallback
= NULL
;
555 xmlOutputCallbackTable
[i
].opencallback
= NULL
;
556 xmlOutputCallbackTable
[i
].writecallback
= NULL
;
557 xmlOutputCallbackTable
[i
].closecallback
= NULL
;
560 xmlOutputCallbackNr
= 0;
561 xmlOutputCallbackInitialized
= 0;
565 * xmlPopOutputCallbacks:
567 * Remove the top output callbacks from the output stack. This includes the
570 * Returns the number of output callback registered or -1 in case of error.
573 xmlPopOutputCallbacks(void)
575 if (!xmlOutputCallbackInitialized
)
578 if (xmlOutputCallbackNr
<= 0)
581 xmlOutputCallbackNr
--;
582 xmlOutputCallbackTable
[xmlOutputCallbackNr
].matchcallback
= NULL
;
583 xmlOutputCallbackTable
[xmlOutputCallbackNr
].opencallback
= NULL
;
584 xmlOutputCallbackTable
[xmlOutputCallbackNr
].writecallback
= NULL
;
585 xmlOutputCallbackTable
[xmlOutputCallbackNr
].closecallback
= NULL
;
587 return(xmlOutputCallbackNr
);
590 #endif /* LIBXML_OUTPUT_ENABLED */
592 /************************************************************************
594 * Standard I/O for file accesses *
596 ************************************************************************/
598 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
602 * @path: the path in utf-8 encoding
603 * @mode: type of access (0 - read, 1 - write)
605 * function opens the file specified by @path
609 xmlWrapOpenUtf8(const char *path
,int mode
)
614 wPath
= __xmlIOWin32UTF8ToWChar(path
);
617 fd
= _wfopen(wPath
, mode
? L
"wb" : L
"rb");
620 /* maybe path in native encoding */
622 fd
= fopen(path
, mode
? "wb" : "rb");
627 #ifdef LIBXML_ZLIB_ENABLED
629 xmlWrapGzOpenUtf8(const char *path
, const char *mode
)
634 fd
= gzopen (path
, mode
);
638 wPath
= __xmlIOWin32UTF8ToWChar(path
);
641 int d
, m
= (strstr(mode
, "r") ? O_RDONLY
: O_RDWR
);
643 m
|= (strstr(mode
, "b") ? _O_BINARY
: 0);
645 d
= _wopen(wPath
, m
);
647 fd
= gzdopen(d
, mode
);
657 * @path: the path in utf-8 encoding
658 * @info: structure that stores results
660 * function obtains information about the file or directory
664 xmlWrapStatUtf8(const char *path
, struct _stat
*info
) {
668 wPath
= __xmlIOWin32UTF8ToWChar(path
);
670 retval
= _wstat(wPath
, info
);
673 /* maybe path in native encoding */
675 retval
= _stat(path
, info
);
683 * @path: the path to check
685 * function checks to see if @path is a valid source
686 * (file, socket...) for XML.
688 * if stat is not available on the target machine,
689 * returns 1. if stat fails, returns 0 (if calling
690 * stat on the filename fails, it can't be right).
691 * if stat succeeds and the file is a directory,
692 * returns 2. otherwise returns 1.
696 xmlCheckFilename (const char *path
)
699 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
700 struct _stat stat_buffer
;
702 struct stat stat_buffer
;
709 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
711 * On Windows stat and wstat do not work with long pathname,
712 * which start with '\\?\'
714 if ((path
[0] == '\\') && (path
[1] == '\\') && (path
[2] == '?') &&
718 if (xmlWrapStatUtf8(path
, &stat_buffer
) == -1)
721 if (stat(path
, &stat_buffer
) == -1)
725 if (S_ISDIR(stat_buffer
.st_mode
))
728 #endif /* HAVE_STAT */
733 * xmlInputReadCallbackNop:
735 * No Operation xmlInputReadCallback function, does nothing.
740 xmlInputReadCallbackNop(void *context ATTRIBUTE_UNUSED
,
741 char *buffer ATTRIBUTE_UNUSED
,
742 int len ATTRIBUTE_UNUSED
) {
748 * @context: the I/O context
749 * @buffer: where to drop data
750 * @len: number of bytes to read
752 * Read @len bytes to @buffer from the I/O channel.
754 * Returns the number of bytes written
757 xmlFdRead (void * context
, char * buffer
, int len
) {
760 ret
= read((int) (ptrdiff_t) context
, &buffer
[0], len
);
761 if (ret
< 0) xmlIOErr(0, "read()");
765 #ifdef LIBXML_OUTPUT_ENABLED
768 * @context: the I/O context
769 * @buffer: where to get data
770 * @len: number of bytes to write
772 * Write @len bytes from @buffer to the I/O channel.
774 * Returns the number of bytes written
777 xmlFdWrite (void * context
, const char * buffer
, int len
) {
781 ret
= write((int) (ptrdiff_t) context
, &buffer
[0], len
);
782 if (ret
< 0) xmlIOErr(0, "write()");
786 #endif /* LIBXML_OUTPUT_ENABLED */
790 * @context: the I/O context
792 * Close an I/O channel
794 * Returns 0 in case of success and error code otherwise
797 xmlFdClose (void * context
) {
799 ret
= close((int) (ptrdiff_t) context
);
800 if (ret
< 0) xmlIOErr(0, "close()");
806 * @filename: the URI for matching
810 * Returns 1 if matches, 0 otherwise
813 xmlFileMatch (const char *filename ATTRIBUTE_UNUSED
) {
819 * @filename: the URI for matching
821 * input from FILE *, supports compressed input
822 * if @filename is " " then the standard input is used
824 * Returns an I/O context or NULL in case of error
827 xmlFileOpen_real (const char *filename
) {
828 const char *path
= filename
;
831 if (filename
== NULL
)
834 if (!strcmp(filename
, "-")) {
839 if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file://localhost/", 17)) {
840 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
841 path
= &filename
[17];
843 path
= &filename
[16];
845 } else if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file:///", 8)) {
846 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
851 } else if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file:/", 6)) {
852 /* lots of generators seems to lazy to read RFC 1738 */
853 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
860 /* Do not check DDNAME on zOS ! */
861 #if !defined(__MVS__)
862 if (!xmlCheckFilename(path
))
866 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
867 fd
= xmlWrapOpenUtf8(path
, 0);
869 fd
= fopen(path
, "r");
871 if (fd
== NULL
) xmlIOErr(0, path
);
877 * @filename: the URI for matching
879 * Wrapper around xmlFileOpen_real that try it with an unescaped
880 * version of @filename, if this fails fallback to @filename
882 * Returns a handler or NULL in case or failure
885 xmlFileOpen (const char *filename
) {
889 retval
= xmlFileOpen_real(filename
);
890 if (retval
== NULL
) {
891 unescaped
= xmlURIUnescapeString(filename
, 0, NULL
);
892 if (unescaped
!= NULL
) {
893 retval
= xmlFileOpen_real(unescaped
);
901 #ifdef LIBXML_OUTPUT_ENABLED
904 * @filename: the URI for matching
906 * output to from FILE *,
907 * if @filename is "-" then the standard output is used
909 * Returns an I/O context or NULL in case of error
912 xmlFileOpenW (const char *filename
) {
913 const char *path
= NULL
;
916 if (!strcmp(filename
, "-")) {
921 if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file://localhost/", 17))
922 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
923 path
= &filename
[17];
925 path
= &filename
[16];
927 else if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file:///", 8)) {
928 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
939 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
940 fd
= xmlWrapOpenUtf8(path
, 1);
942 fd
= fopen(path
, "w");
944 fd
= fopen(path
, "wb");
947 if (fd
== NULL
) xmlIOErr(0, path
);
950 #endif /* LIBXML_OUTPUT_ENABLED */
954 * @context: the I/O context
955 * @buffer: where to drop data
956 * @len: number of bytes to write
958 * Read @len bytes to @buffer from the I/O channel.
960 * Returns the number of bytes written or < 0 in case of failure
963 xmlFileRead (void * context
, char * buffer
, int len
) {
965 if ((context
== NULL
) || (buffer
== NULL
))
967 ret
= fread(&buffer
[0], 1, len
, (FILE *) context
);
968 if (ret
< 0) xmlIOErr(0, "fread()");
972 #ifdef LIBXML_OUTPUT_ENABLED
975 * @context: the I/O context
976 * @buffer: where to drop data
977 * @len: number of bytes to write
979 * Write @len bytes from @buffer to the I/O channel.
981 * Returns the number of bytes written
984 xmlFileWrite (void * context
, const char * buffer
, int len
) {
987 if ((context
== NULL
) || (buffer
== NULL
))
989 items
= fwrite(&buffer
[0], len
, 1, (FILE *) context
);
990 if ((items
== 0) && (ferror((FILE *) context
))) {
991 xmlIOErr(0, "fwrite()");
996 #endif /* LIBXML_OUTPUT_ENABLED */
1000 * @context: the I/O context
1002 * Close an I/O channel
1004 * Returns 0 or -1 in case of error
1007 xmlFileClose (void * context
) {
1011 if (context
== NULL
)
1013 fil
= (FILE *) context
;
1014 if ((fil
== stdout
) || (fil
== stderr
)) {
1017 xmlIOErr(0, "fflush()");
1022 ret
= ( fclose((FILE *) context
) == EOF
) ? -1 : 0;
1024 xmlIOErr(0, "fclose()");
1030 * @context: the I/O context
1032 * Flush an I/O channel
1035 xmlFileFlush (void * context
) {
1038 if (context
== NULL
)
1040 ret
= ( fflush((FILE *) context
) == EOF
) ? -1 : 0;
1042 xmlIOErr(0, "fflush()");
1046 #ifdef LIBXML_OUTPUT_ENABLED
1049 * @context: the xmlBuffer
1050 * @buffer: the data to write
1051 * @len: number of bytes to write
1053 * Write @len bytes from @buffer to the xml buffer
1055 * Returns the number of bytes written
1058 xmlBufferWrite (void * context
, const char * buffer
, int len
) {
1061 ret
= xmlBufferAdd((xmlBufferPtr
) context
, (const xmlChar
*) buffer
, len
);
1068 #ifdef LIBXML_ZLIB_ENABLED
1069 /************************************************************************
1071 * I/O for compressed file accesses *
1073 ************************************************************************/
1076 * @filename: the URI for matching
1078 * input from compressed file test
1080 * Returns 1 if matches, 0 otherwise
1083 xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED
) {
1088 * xmlGzfileOpen_real:
1089 * @filename: the URI for matching
1091 * input from compressed file open
1092 * if @filename is " " then the standard input is used
1094 * Returns an I/O context or NULL in case of error
1097 xmlGzfileOpen_real (const char *filename
) {
1098 const char *path
= NULL
;
1101 if (!strcmp(filename
, "-")) {
1102 int duped_fd
= dup(fileno(stdin
));
1103 fd
= gzdopen(duped_fd
, "rb");
1104 if (fd
== Z_NULL
&& duped_fd
>= 0) {
1105 close(duped_fd
); /* gzdOpen() does not close on failure */
1108 return((void *) fd
);
1111 if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file://localhost/", 17))
1112 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
1113 path
= &filename
[17];
1115 path
= &filename
[16];
1117 else if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file:///", 8)) {
1118 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
1119 path
= &filename
[8];
1121 path
= &filename
[7];
1128 if (!xmlCheckFilename(path
))
1131 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
1132 fd
= xmlWrapGzOpenUtf8(path
, "rb");
1134 fd
= gzopen(path
, "rb");
1136 return((void *) fd
);
1141 * @filename: the URI for matching
1143 * Wrapper around xmlGzfileOpen if the open fais, it will
1144 * try to unescape @filename
1147 xmlGzfileOpen (const char *filename
) {
1151 retval
= xmlGzfileOpen_real(filename
);
1152 if (retval
== NULL
) {
1153 unescaped
= xmlURIUnescapeString(filename
, 0, NULL
);
1154 if (unescaped
!= NULL
) {
1155 retval
= xmlGzfileOpen_real(unescaped
);
1162 #ifdef LIBXML_OUTPUT_ENABLED
1165 * @filename: the URI for matching
1166 * @compression: the compression factor (0 - 9 included)
1168 * input from compressed file open
1169 * if @filename is " " then the standard input is used
1171 * Returns an I/O context or NULL in case of error
1174 xmlGzfileOpenW (const char *filename
, int compression
) {
1175 const char *path
= NULL
;
1179 snprintf(mode
, sizeof(mode
), "wb%d", compression
);
1180 if (!strcmp(filename
, "-")) {
1181 int duped_fd
= dup(fileno(stdout
));
1182 fd
= gzdopen(duped_fd
, "rb");
1183 if (fd
== Z_NULL
&& duped_fd
>= 0) {
1184 close(duped_fd
); /* gzdOpen() does not close on failure */
1187 return((void *) fd
);
1190 if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file://localhost/", 17))
1191 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
1192 path
= &filename
[17];
1194 path
= &filename
[16];
1196 else if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file:///", 8)) {
1197 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
1198 path
= &filename
[8];
1200 path
= &filename
[7];
1208 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
1209 fd
= xmlWrapGzOpenUtf8(path
, mode
);
1211 fd
= gzopen(path
, mode
);
1213 return((void *) fd
);
1215 #endif /* LIBXML_OUTPUT_ENABLED */
1219 * @context: the I/O context
1220 * @buffer: where to drop data
1221 * @len: number of bytes to write
1223 * Read @len bytes to @buffer from the compressed I/O channel.
1225 * Returns the number of bytes read.
1228 xmlGzfileRead (void * context
, char * buffer
, int len
) {
1231 ret
= gzread((gzFile
) context
, &buffer
[0], len
);
1232 if (ret
< 0) xmlIOErr(0, "gzread()");
1236 #ifdef LIBXML_OUTPUT_ENABLED
1239 * @context: the I/O context
1240 * @buffer: where to drop data
1241 * @len: number of bytes to write
1243 * Write @len bytes from @buffer to the compressed I/O channel.
1245 * Returns the number of bytes written
1248 xmlGzfileWrite (void * context
, const char * buffer
, int len
) {
1251 ret
= gzwrite((gzFile
) context
, (char *) &buffer
[0], len
);
1252 if (ret
< 0) xmlIOErr(0, "gzwrite()");
1255 #endif /* LIBXML_OUTPUT_ENABLED */
1259 * @context: the I/O context
1261 * Close a compressed I/O channel
1264 xmlGzfileClose (void * context
) {
1267 ret
= (gzclose((gzFile
) context
) == Z_OK
) ? 0 : -1;
1268 if (ret
< 0) xmlIOErr(0, "gzclose()");
1271 #endif /* LIBXML_ZLIB_ENABLED */
1273 #ifdef LIBXML_LZMA_ENABLED
1274 /************************************************************************
1276 * I/O for compressed file accesses *
1278 ************************************************************************/
1282 * @filename: the URI for matching
1284 * input from compressed file test
1286 * Returns 1 if matches, 0 otherwise
1289 xmlXzfileMatch (const char *filename ATTRIBUTE_UNUSED
) {
1294 * xmlXzFileOpen_real:
1295 * @filename: the URI for matching
1297 * input from compressed file open
1298 * if @filename is " " then the standard input is used
1300 * Returns an I/O context or NULL in case of error
1303 xmlXzfileOpen_real (const char *filename
) {
1304 const char *path
= NULL
;
1307 if (!strcmp(filename
, "-")) {
1308 fd
= __libxml2_xzdopen(dup(fileno(stdin
)), "rb");
1309 return((void *) fd
);
1312 if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file://localhost/", 17)) {
1313 path
= &filename
[16];
1314 } else if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file:///", 8)) {
1315 path
= &filename
[7];
1316 } else if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file:/", 6)) {
1317 /* lots of generators seems to lazy to read RFC 1738 */
1318 path
= &filename
[5];
1324 if (!xmlCheckFilename(path
))
1327 fd
= __libxml2_xzopen(path
, "rb");
1328 return((void *) fd
);
1333 * @filename: the URI for matching
1335 * Wrapper around xmlXzfileOpen_real that try it with an unescaped
1336 * version of @filename, if this fails fallback to @filename
1338 * Returns a handler or NULL in case or failure
1341 xmlXzfileOpen (const char *filename
) {
1345 retval
= xmlXzfileOpen_real(filename
);
1346 if (retval
== NULL
) {
1347 unescaped
= xmlURIUnescapeString(filename
, 0, NULL
);
1348 if (unescaped
!= NULL
) {
1349 retval
= xmlXzfileOpen_real(unescaped
);
1359 * @context: the I/O context
1360 * @buffer: where to drop data
1361 * @len: number of bytes to write
1363 * Read @len bytes to @buffer from the compressed I/O channel.
1365 * Returns the number of bytes written
1368 xmlXzfileRead (void * context
, char * buffer
, int len
) {
1371 ret
= __libxml2_xzread((xzFile
) context
, &buffer
[0], len
);
1372 if (ret
< 0) xmlIOErr(0, "xzread()");
1378 * @context: the I/O context
1380 * Close a compressed I/O channel
1383 xmlXzfileClose (void * context
) {
1386 ret
= (__libxml2_xzclose((xzFile
) context
) == LZMA_OK
) ? 0 : -1;
1387 if (ret
< 0) xmlIOErr(0, "xzclose()");
1390 #endif /* LIBXML_LZMA_ENABLED */
1392 #ifdef LIBXML_HTTP_ENABLED
1393 /************************************************************************
1395 * I/O for HTTP file accesses *
1397 ************************************************************************/
1399 #ifdef LIBXML_OUTPUT_ENABLED
1400 typedef struct xmlIOHTTPWriteCtxt_
1408 } xmlIOHTTPWriteCtxt
, *xmlIOHTTPWriteCtxtPtr
;
1410 #ifdef LIBXML_ZLIB_ENABLED
1412 #define DFLT_WBITS ( -15 )
1413 #define DFLT_MEM_LVL ( 8 )
1414 #define GZ_MAGIC1 ( 0x1f )
1415 #define GZ_MAGIC2 ( 0x8b )
1416 #define LXML_ZLIB_OS_CODE ( 0x03 )
1417 #define INIT_HTTP_BUFF_SIZE ( 32768 )
1418 #define DFLT_ZLIB_RATIO ( 5 )
1421 ** Data structure and functions to work with sending compressed data
1425 typedef struct xmlZMemBuff_
1430 unsigned char * zbuff
;
1433 } xmlZMemBuff
, *xmlZMemBuffPtr
;
1436 * append_reverse_ulong
1437 * @buff: Compressed memory buffer
1438 * @data: Unsigned long to append
1440 * Append a unsigned long in reverse byte order to the end of the
1444 append_reverse_ulong( xmlZMemBuff
* buff
, unsigned long data
) {
1452 ** This is plagiarized from putLong in gzio.c (zlib source) where
1453 ** the number "4" is hardcoded. If zlib is ever patched to
1454 ** support 64 bit file sizes, this code would need to be patched
1458 for ( idx
= 0; idx
< 4; idx
++ ) {
1459 *buff
->zctrl
.next_out
= ( data
& 0xff );
1461 buff
->zctrl
.next_out
++;
1470 * @buff: The memory buffer context to clear
1472 * Release all the resources associated with the compressed memory buffer.
1475 xmlFreeZMemBuff( xmlZMemBuffPtr buff
) {
1484 xmlFree( buff
->zbuff
);
1486 z_err
= deflateEnd( &buff
->zctrl
);
1487 if ( z_err
!= Z_OK
)
1488 xmlGenericError( xmlGenericErrorContext
,
1489 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
1492 deflateEnd( &buff
->zctrl
);
1501 *@compression: Compression value to use
1503 * Create a memory buffer to hold the compressed XML document. The
1504 * compressed document in memory will end up being identical to what
1505 * would be created if gzopen/gzwrite/gzclose were being used to
1506 * write the document to disk. The code for the header/trailer data to
1507 * the compression is plagiarized from the zlib source files.
1510 xmlCreateZMemBuff( int compression
) {
1514 xmlZMemBuffPtr buff
= NULL
;
1516 if ( ( compression
< 1 ) || ( compression
> 9 ) )
1519 /* Create the control and data areas */
1521 buff
= xmlMalloc( sizeof( xmlZMemBuff
) );
1522 if ( buff
== NULL
) {
1523 xmlIOErrMemory("creating buffer context");
1527 (void)memset( buff
, 0, sizeof( xmlZMemBuff
) );
1528 buff
->size
= INIT_HTTP_BUFF_SIZE
;
1529 buff
->zbuff
= xmlMalloc( buff
->size
);
1530 if ( buff
->zbuff
== NULL
) {
1531 xmlFreeZMemBuff( buff
);
1532 xmlIOErrMemory("creating buffer");
1536 z_err
= deflateInit2( &buff
->zctrl
, compression
, Z_DEFLATED
,
1537 DFLT_WBITS
, DFLT_MEM_LVL
, Z_DEFAULT_STRATEGY
);
1538 if ( z_err
!= Z_OK
) {
1540 xmlFreeZMemBuff( buff
);
1542 xmlStrPrintf(msg
, 500,
1543 "xmlCreateZMemBuff: %s %d\n",
1544 "Error initializing compression context. ZLIB error:",
1546 xmlIOErr(XML_IO_WRITE
, (const char *) msg
);
1550 /* Set the header data. The CRC will be needed for the trailer */
1551 buff
->crc
= crc32( 0L, NULL
, 0 );
1552 hdr_lgth
= snprintf( (char *)buff
->zbuff
, buff
->size
,
1553 "%c%c%c%c%c%c%c%c%c%c",
1554 GZ_MAGIC1
, GZ_MAGIC2
, Z_DEFLATED
,
1555 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE
);
1556 buff
->zctrl
.next_out
= buff
->zbuff
+ hdr_lgth
;
1557 buff
->zctrl
.avail_out
= buff
->size
- hdr_lgth
;
1564 * @buff: Buffer used to compress and consolidate data.
1565 * @ext_amt: Number of bytes to extend the buffer.
1567 * Extend the internal buffer used to store the compressed data by the
1570 * Returns 0 on success or -1 on failure to extend the buffer. On failure
1571 * the original buffer still exists at the original size.
1574 xmlZMemBuffExtend( xmlZMemBuffPtr buff
, size_t ext_amt
) {
1580 unsigned char * tmp_ptr
= NULL
;
1585 else if ( ext_amt
== 0 )
1588 cur_used
= buff
->zctrl
.next_out
- buff
->zbuff
;
1589 new_size
= buff
->size
+ ext_amt
;
1592 if ( cur_used
> new_size
)
1593 xmlGenericError( xmlGenericErrorContext
,
1594 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
1595 "Buffer overwrite detected during compressed memory",
1596 "buffer extension. Overflowed by",
1597 (cur_used
- new_size
) );
1600 tmp_ptr
= xmlRealloc( buff
->zbuff
, new_size
);
1601 if ( tmp_ptr
!= NULL
) {
1603 buff
->size
= new_size
;
1604 buff
->zbuff
= tmp_ptr
;
1605 buff
->zctrl
.next_out
= tmp_ptr
+ cur_used
;
1606 buff
->zctrl
.avail_out
= new_size
- cur_used
;
1610 xmlStrPrintf(msg
, 500,
1611 "xmlZMemBuffExtend: %s %lu bytes.\n",
1612 "Allocation failure extending output buffer to",
1613 (unsigned long) new_size
);
1614 xmlIOErr(XML_IO_WRITE
, (const char *) msg
);
1622 * @buff: Buffer used to compress and consolidate data
1623 * @src: Uncompressed source content to append to buffer
1624 * @len: Length of source data to append to buffer
1626 * Compress and append data to the internal buffer. The data buffer
1627 * will be expanded if needed to store the additional data.
1629 * Returns the number of bytes appended to the buffer or -1 on error.
1632 xmlZMemBuffAppend( xmlZMemBuffPtr buff
, const char * src
, int len
) {
1637 if ( ( buff
== NULL
) || ( src
== NULL
) )
1640 buff
->zctrl
.avail_in
= len
;
1641 buff
->zctrl
.next_in
= (unsigned char *)src
;
1642 while ( buff
->zctrl
.avail_in
> 0 ) {
1644 ** Extend the buffer prior to deflate call if a reasonable amount
1645 ** of output buffer space is not available.
1647 min_accept
= buff
->zctrl
.avail_in
/ DFLT_ZLIB_RATIO
;
1648 if ( buff
->zctrl
.avail_out
<= min_accept
) {
1649 if ( xmlZMemBuffExtend( buff
, buff
->size
) == -1 )
1653 z_err
= deflate( &buff
->zctrl
, Z_NO_FLUSH
);
1654 if ( z_err
!= Z_OK
) {
1656 xmlStrPrintf(msg
, 500,
1657 "xmlZMemBuffAppend: %s %d %s - %d",
1658 "Compression error while appending",
1659 len
, "bytes to buffer. ZLIB error", z_err
);
1660 xmlIOErr(XML_IO_WRITE
, (const char *) msg
);
1665 buff
->crc
= crc32( buff
->crc
, (unsigned char *)src
, len
);
1671 * xmlZMemBuffGetContent
1672 * @buff: Compressed memory content buffer
1673 * @data_ref: Pointer reference to point to compressed content
1675 * Flushes the compression buffers, appends gzip file trailers and
1676 * returns the compressed content and length of the compressed data.
1677 * NOTE: The gzip trailer code here is plagiarized from zlib source.
1679 * Returns the length of the compressed data or -1 on error.
1682 xmlZMemBuffGetContent( xmlZMemBuffPtr buff
, char ** data_ref
) {
1687 if ( ( buff
== NULL
) || ( data_ref
== NULL
) )
1690 /* Need to loop until compression output buffers are flushed */
1694 z_err
= deflate( &buff
->zctrl
, Z_FINISH
);
1695 if ( z_err
== Z_OK
) {
1696 /* In this case Z_OK means more buffer space needed */
1698 if ( xmlZMemBuffExtend( buff
, buff
->size
) == -1 )
1702 while ( z_err
== Z_OK
);
1704 /* If the compression state is not Z_STREAM_END, some error occurred */
1706 if ( z_err
== Z_STREAM_END
) {
1708 /* Need to append the gzip data trailer */
1710 if ( buff
->zctrl
.avail_out
< ( 2 * sizeof( unsigned long ) ) ) {
1711 if ( xmlZMemBuffExtend(buff
, (2 * sizeof(unsigned long))) == -1 )
1716 ** For whatever reason, the CRC and length data are pushed out
1717 ** in reverse byte order. So a memcpy can't be used here.
1720 append_reverse_ulong( buff
, buff
->crc
);
1721 append_reverse_ulong( buff
, buff
->zctrl
.total_in
);
1723 zlgth
= buff
->zctrl
.next_out
- buff
->zbuff
;
1724 *data_ref
= (char *)buff
->zbuff
;
1729 xmlStrPrintf(msg
, 500,
1730 "xmlZMemBuffGetContent: %s - %d\n",
1731 "Error flushing zlib buffers. Error code", z_err
);
1732 xmlIOErr(XML_IO_WRITE
, (const char *) msg
);
1737 #endif /* LIBXML_OUTPUT_ENABLED */
1738 #endif /* LIBXML_ZLIB_ENABLED */
1740 #ifdef LIBXML_OUTPUT_ENABLED
1742 * xmlFreeHTTPWriteCtxt
1743 * @ctxt: Context to cleanup
1745 * Free allocated memory and reclaim system resources.
1750 xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt
)
1752 if ( ctxt
->uri
!= NULL
)
1753 xmlFree( ctxt
->uri
);
1755 if ( ctxt
->doc_buff
!= NULL
) {
1757 #ifdef LIBXML_ZLIB_ENABLED
1758 if ( ctxt
->compression
> 0 ) {
1759 xmlFreeZMemBuff( ctxt
->doc_buff
);
1764 xmlOutputBufferClose( ctxt
->doc_buff
);
1771 #endif /* LIBXML_OUTPUT_ENABLED */
1776 * @filename: the URI for matching
1778 * check if the URI matches an HTTP one
1780 * Returns 1 if matches, 0 otherwise
1783 xmlIOHTTPMatch (const char *filename
) {
1784 if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"http://", 7))
1791 * @filename: the URI for matching
1793 * open an HTTP I/O channel
1795 * Returns an I/O context or NULL in case of error
1798 xmlIOHTTPOpen (const char *filename
) {
1799 return(xmlNanoHTTPOpen(filename
, NULL
));
1802 #ifdef LIBXML_OUTPUT_ENABLED
1805 * @post_uri: The destination URI for the document
1806 * @compression: The compression desired for the document.
1808 * Open a temporary buffer to collect the document for a subsequent HTTP POST
1809 * request. Non-static as is called from the output buffer creation routine.
1811 * Returns an I/O context or NULL in case of error.
1815 xmlIOHTTPOpenW(const char *post_uri
, int compression ATTRIBUTE_UNUSED
)
1818 xmlIOHTTPWriteCtxtPtr ctxt
= NULL
;
1820 if (post_uri
== NULL
)
1823 ctxt
= xmlMalloc(sizeof(xmlIOHTTPWriteCtxt
));
1825 xmlIOErrMemory("creating HTTP output context");
1829 (void) memset(ctxt
, 0, sizeof(xmlIOHTTPWriteCtxt
));
1831 ctxt
->uri
= (char *) xmlStrdup((const xmlChar
*)post_uri
);
1832 if (ctxt
->uri
== NULL
) {
1833 xmlIOErrMemory("copying URI");
1834 xmlFreeHTTPWriteCtxt(ctxt
);
1839 * ** Since the document length is required for an HTTP post,
1840 * ** need to put the document into a buffer. A memory buffer
1841 * ** is being used to avoid pushing the data to disk and back.
1844 #ifdef LIBXML_ZLIB_ENABLED
1845 if ((compression
> 0) && (compression
<= 9)) {
1847 ctxt
->compression
= compression
;
1848 ctxt
->doc_buff
= xmlCreateZMemBuff(compression
);
1852 /* Any character conversions should have been done before this */
1854 ctxt
->doc_buff
= xmlAllocOutputBufferInternal(NULL
);
1857 if (ctxt
->doc_buff
== NULL
) {
1858 xmlFreeHTTPWriteCtxt(ctxt
);
1864 #endif /* LIBXML_OUTPUT_ENABLED */
1866 #ifdef LIBXML_OUTPUT_ENABLED
1868 * xmlIOHTTPDfltOpenW
1869 * @post_uri: The destination URI for this document.
1871 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
1872 * HTTP post command. This function should generally not be used as
1873 * the open callback is short circuited in xmlOutputBufferCreateFile.
1875 * Returns a pointer to the new IO context.
1878 xmlIOHTTPDfltOpenW( const char * post_uri
) {
1879 return ( xmlIOHTTPOpenW( post_uri
, 0 ) );
1881 #endif /* LIBXML_OUTPUT_ENABLED */
1885 * @context: the I/O context
1886 * @buffer: where to drop data
1887 * @len: number of bytes to write
1889 * Read @len bytes to @buffer from the I/O channel.
1891 * Returns the number of bytes written
1894 xmlIOHTTPRead(void * context
, char * buffer
, int len
) {
1895 if ((buffer
== NULL
) || (len
< 0)) return(-1);
1896 return(xmlNanoHTTPRead(context
, &buffer
[0], len
));
1899 #ifdef LIBXML_OUTPUT_ENABLED
1902 * @context: previously opened writing context
1903 * @buffer: data to output to temporary buffer
1904 * @len: bytes to output
1906 * Collect data from memory buffer into a temporary file for later
1909 * Returns number of bytes written.
1913 xmlIOHTTPWrite( void * context
, const char * buffer
, int len
) {
1915 xmlIOHTTPWriteCtxtPtr ctxt
= context
;
1917 if ( ( ctxt
== NULL
) || ( ctxt
->doc_buff
== NULL
) || ( buffer
== NULL
) )
1922 /* Use gzwrite or fwrite as previously setup in the open call */
1924 #ifdef LIBXML_ZLIB_ENABLED
1925 if ( ctxt
->compression
> 0 )
1926 len
= xmlZMemBuffAppend( ctxt
->doc_buff
, buffer
, len
);
1930 len
= xmlOutputBufferWrite( ctxt
->doc_buff
, len
, buffer
);
1934 xmlStrPrintf(msg
, 500,
1935 "xmlIOHTTPWrite: %s\n%s '%s'.\n",
1936 "Error appending to internal buffer.",
1937 "Error sending document to URI",
1939 xmlIOErr(XML_IO_WRITE
, (const char *) msg
);
1945 #endif /* LIBXML_OUTPUT_ENABLED */
1950 * @context: the I/O context
1952 * Close an HTTP I/O channel
1957 xmlIOHTTPClose (void * context
) {
1958 xmlNanoHTTPClose(context
);
1962 #ifdef LIBXML_OUTPUT_ENABLED
1964 * xmlIOHTTCloseWrite
1965 * @context: The I/O context
1966 * @http_mthd: The HTTP method to be used when sending the data
1968 * Close the transmit HTTP I/O channel and actually send the data.
1971 xmlIOHTTPCloseWrite( void * context
, const char * http_mthd
) {
1975 int content_lgth
= 0;
1976 xmlIOHTTPWriteCtxtPtr ctxt
= context
;
1978 char * http_content
= NULL
;
1979 char * content_encoding
= NULL
;
1980 char * content_type
= (char *) "text/xml";
1981 void * http_ctxt
= NULL
;
1983 if ( ( ctxt
== NULL
) || ( http_mthd
== NULL
) )
1986 /* Retrieve the content from the appropriate buffer */
1988 #ifdef LIBXML_ZLIB_ENABLED
1990 if ( ctxt
->compression
> 0 ) {
1991 content_lgth
= xmlZMemBuffGetContent( ctxt
->doc_buff
, &http_content
);
1992 content_encoding
= (char *) "Content-Encoding: gzip";
1997 /* Pull the data out of the memory output buffer */
1999 xmlOutputBufferPtr dctxt
= ctxt
->doc_buff
;
2000 http_content
= (char *) xmlBufContent(dctxt
->buffer
);
2001 content_lgth
= xmlBufUse(dctxt
->buffer
);
2004 if ( http_content
== NULL
) {
2006 xmlStrPrintf(msg
, 500,
2007 "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
2008 "Error retrieving content.\nUnable to",
2009 http_mthd
, "data to URI", ctxt
->uri
);
2010 xmlIOErr(XML_IO_WRITE
, (const char *) msg
);
2015 http_ctxt
= xmlNanoHTTPMethod( ctxt
->uri
, http_mthd
, http_content
,
2016 &content_type
, content_encoding
,
2019 if ( http_ctxt
!= NULL
) {
2021 /* If testing/debugging - dump reply with request content */
2023 FILE * tst_file
= NULL
;
2024 char buffer
[ 4096 ];
2025 char * dump_name
= NULL
;
2028 xmlGenericError( xmlGenericErrorContext
,
2029 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
2030 http_mthd
, ctxt
->uri
,
2031 xmlNanoHTTPReturnCode( http_ctxt
) );
2034 ** Since either content or reply may be gzipped,
2035 ** dump them to separate files instead of the
2036 ** standard error context.
2039 dump_name
= tempnam( NULL
, "lxml" );
2040 if ( dump_name
!= NULL
) {
2041 (void)snprintf( buffer
, sizeof(buffer
), "%s.content", dump_name
);
2043 tst_file
= fopen( buffer
, "wb" );
2044 if ( tst_file
!= NULL
) {
2045 xmlGenericError( xmlGenericErrorContext
,
2046 "Transmitted content saved in file: %s\n", buffer
);
2048 fwrite( http_content
, sizeof( char ),
2049 content_lgth
, tst_file
);
2053 (void)snprintf( buffer
, sizeof(buffer
), "%s.reply", dump_name
);
2054 tst_file
= fopen( buffer
, "wb" );
2055 if ( tst_file
!= NULL
) {
2056 xmlGenericError( xmlGenericErrorContext
,
2057 "Reply content saved in file: %s\n", buffer
);
2060 while ( (avail
= xmlNanoHTTPRead( http_ctxt
,
2061 buffer
, sizeof( buffer
) )) > 0 ) {
2063 fwrite( buffer
, sizeof( char ), avail
, tst_file
);
2071 #endif /* DEBUG_HTTP */
2073 http_rtn
= xmlNanoHTTPReturnCode( http_ctxt
);
2074 if ( ( http_rtn
>= 200 ) && ( http_rtn
< 300 ) )
2078 xmlStrPrintf(msg
, 500,
2079 "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
2080 http_mthd
, content_lgth
,
2081 "bytes to URI", ctxt
->uri
,
2082 "failed. HTTP return code:", http_rtn
);
2083 xmlIOErr(XML_IO_WRITE
, (const char *) msg
);
2086 xmlNanoHTTPClose( http_ctxt
);
2087 xmlFree( content_type
);
2091 /* Final cleanups */
2093 xmlFreeHTTPWriteCtxt( ctxt
);
2095 return ( close_rc
);
2101 * @context: The I/O context
2103 * Close the transmit HTTP I/O channel and actually send data using a PUT
2107 xmlIOHTTPClosePut( void * ctxt
) {
2108 return ( xmlIOHTTPCloseWrite( ctxt
, "PUT" ) );
2113 * xmlIOHTTPClosePost
2115 * @context: The I/O context
2117 * Close the transmit HTTP I/O channel and actually send data using a POST
2121 xmlIOHTTPClosePost( void * ctxt
) {
2122 return ( xmlIOHTTPCloseWrite( ctxt
, "POST" ) );
2124 #endif /* LIBXML_OUTPUT_ENABLED */
2126 #endif /* LIBXML_HTTP_ENABLED */
2128 #ifdef LIBXML_FTP_ENABLED
2129 /************************************************************************
2131 * I/O for FTP file accesses *
2133 ************************************************************************/
2136 * @filename: the URI for matching
2138 * check if the URI matches an FTP one
2140 * Returns 1 if matches, 0 otherwise
2143 xmlIOFTPMatch (const char *filename
) {
2144 if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"ftp://", 6))
2151 * @filename: the URI for matching
2153 * open an FTP I/O channel
2155 * Returns an I/O context or NULL in case of error
2158 xmlIOFTPOpen (const char *filename
) {
2159 return(xmlNanoFTPOpen(filename
));
2164 * @context: the I/O context
2165 * @buffer: where to drop data
2166 * @len: number of bytes to write
2168 * Read @len bytes to @buffer from the I/O channel.
2170 * Returns the number of bytes written
2173 xmlIOFTPRead(void * context
, char * buffer
, int len
) {
2174 if ((buffer
== NULL
) || (len
< 0)) return(-1);
2175 return(xmlNanoFTPRead(context
, &buffer
[0], len
));
2180 * @context: the I/O context
2182 * Close an FTP I/O channel
2187 xmlIOFTPClose (void * context
) {
2188 return ( xmlNanoFTPClose(context
) );
2190 #endif /* LIBXML_FTP_ENABLED */
2194 * xmlRegisterInputCallbacks:
2195 * @matchFunc: the xmlInputMatchCallback
2196 * @openFunc: the xmlInputOpenCallback
2197 * @readFunc: the xmlInputReadCallback
2198 * @closeFunc: the xmlInputCloseCallback
2200 * Register a new set of I/O callback for handling parser input.
2202 * Returns the registered handler number or -1 in case of error
2205 xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc
,
2206 xmlInputOpenCallback openFunc
, xmlInputReadCallback readFunc
,
2207 xmlInputCloseCallback closeFunc
) {
2208 if (xmlInputCallbackNr
>= MAX_INPUT_CALLBACK
) {
2211 xmlInputCallbackTable
[xmlInputCallbackNr
].matchcallback
= matchFunc
;
2212 xmlInputCallbackTable
[xmlInputCallbackNr
].opencallback
= openFunc
;
2213 xmlInputCallbackTable
[xmlInputCallbackNr
].readcallback
= readFunc
;
2214 xmlInputCallbackTable
[xmlInputCallbackNr
].closecallback
= closeFunc
;
2215 xmlInputCallbackInitialized
= 1;
2216 return(xmlInputCallbackNr
++);
2219 #ifdef LIBXML_OUTPUT_ENABLED
2221 * xmlRegisterOutputCallbacks:
2222 * @matchFunc: the xmlOutputMatchCallback
2223 * @openFunc: the xmlOutputOpenCallback
2224 * @writeFunc: the xmlOutputWriteCallback
2225 * @closeFunc: the xmlOutputCloseCallback
2227 * Register a new set of I/O callback for handling output.
2229 * Returns the registered handler number or -1 in case of error
2232 xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc
,
2233 xmlOutputOpenCallback openFunc
, xmlOutputWriteCallback writeFunc
,
2234 xmlOutputCloseCallback closeFunc
) {
2235 if (xmlOutputCallbackNr
>= MAX_OUTPUT_CALLBACK
) {
2238 xmlOutputCallbackTable
[xmlOutputCallbackNr
].matchcallback
= matchFunc
;
2239 xmlOutputCallbackTable
[xmlOutputCallbackNr
].opencallback
= openFunc
;
2240 xmlOutputCallbackTable
[xmlOutputCallbackNr
].writecallback
= writeFunc
;
2241 xmlOutputCallbackTable
[xmlOutputCallbackNr
].closecallback
= closeFunc
;
2242 xmlOutputCallbackInitialized
= 1;
2243 return(xmlOutputCallbackNr
++);
2245 #endif /* LIBXML_OUTPUT_ENABLED */
2248 * xmlRegisterDefaultInputCallbacks:
2250 * Registers the default compiled-in I/O handlers.
2253 xmlRegisterDefaultInputCallbacks(void) {
2254 if (xmlInputCallbackInitialized
)
2257 xmlRegisterInputCallbacks(xmlFileMatch
, xmlFileOpen
,
2258 xmlFileRead
, xmlFileClose
);
2259 #ifdef LIBXML_ZLIB_ENABLED
2260 xmlRegisterInputCallbacks(xmlGzfileMatch
, xmlGzfileOpen
,
2261 xmlGzfileRead
, xmlGzfileClose
);
2262 #endif /* LIBXML_ZLIB_ENABLED */
2263 #ifdef LIBXML_LZMA_ENABLED
2264 xmlRegisterInputCallbacks(xmlXzfileMatch
, xmlXzfileOpen
,
2265 xmlXzfileRead
, xmlXzfileClose
);
2266 #endif /* LIBXML_LZMA_ENABLED */
2268 #ifdef LIBXML_HTTP_ENABLED
2269 xmlRegisterInputCallbacks(xmlIOHTTPMatch
, xmlIOHTTPOpen
,
2270 xmlIOHTTPRead
, xmlIOHTTPClose
);
2271 #endif /* LIBXML_HTTP_ENABLED */
2273 #ifdef LIBXML_FTP_ENABLED
2274 xmlRegisterInputCallbacks(xmlIOFTPMatch
, xmlIOFTPOpen
,
2275 xmlIOFTPRead
, xmlIOFTPClose
);
2276 #endif /* LIBXML_FTP_ENABLED */
2277 xmlInputCallbackInitialized
= 1;
2280 #ifdef LIBXML_OUTPUT_ENABLED
2282 * xmlRegisterDefaultOutputCallbacks:
2284 * Registers the default compiled-in I/O handlers.
2287 xmlRegisterDefaultOutputCallbacks (void) {
2288 if (xmlOutputCallbackInitialized
)
2291 xmlRegisterOutputCallbacks(xmlFileMatch
, xmlFileOpenW
,
2292 xmlFileWrite
, xmlFileClose
);
2294 #ifdef LIBXML_HTTP_ENABLED
2295 xmlRegisterOutputCallbacks(xmlIOHTTPMatch
, xmlIOHTTPDfltOpenW
,
2296 xmlIOHTTPWrite
, xmlIOHTTPClosePut
);
2299 /*********************************
2300 No way a-priori to distinguish between gzipped files from
2301 uncompressed ones except opening if existing then closing
2302 and saving with same compression ratio ... a pain.
2304 #ifdef LIBXML_ZLIB_ENABLED
2305 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
2306 xmlGzfileWrite, xmlGzfileClose);
2310 #ifdef LIBXML_FTP_ENABLED
2311 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
2312 xmlIOFTPWrite, xmlIOFTPClose);
2314 **********************************/
2315 xmlOutputCallbackInitialized
= 1;
2318 #ifdef LIBXML_HTTP_ENABLED
2320 * xmlRegisterHTTPPostCallbacks:
2322 * By default, libxml submits HTTP output requests using the "PUT" method.
2323 * Calling this method changes the HTTP output method to use the "POST"
2328 xmlRegisterHTTPPostCallbacks( void ) {
2330 /* Register defaults if not done previously */
2332 if ( xmlOutputCallbackInitialized
== 0 )
2333 xmlRegisterDefaultOutputCallbacks( );
2335 xmlRegisterOutputCallbacks(xmlIOHTTPMatch
, xmlIOHTTPDfltOpenW
,
2336 xmlIOHTTPWrite
, xmlIOHTTPClosePost
);
2340 #endif /* LIBXML_OUTPUT_ENABLED */
2343 * xmlAllocParserInputBuffer:
2344 * @enc: the charset encoding if known
2346 * Create a buffered parser input for progressive parsing
2348 * Returns the new parser input or NULL
2350 xmlParserInputBufferPtr
2351 xmlAllocParserInputBuffer(xmlCharEncoding enc
) {
2352 xmlParserInputBufferPtr ret
;
2354 ret
= (xmlParserInputBufferPtr
) xmlMalloc(sizeof(xmlParserInputBuffer
));
2356 xmlIOErrMemory("creating input buffer");
2359 memset(ret
, 0, (size_t) sizeof(xmlParserInputBuffer
));
2360 ret
->buffer
= xmlBufCreateSize(2 * xmlDefaultBufferSize
);
2361 if (ret
->buffer
== NULL
) {
2365 xmlBufSetAllocationScheme(ret
->buffer
, XML_BUFFER_ALLOC_DOUBLEIT
);
2366 ret
->encoder
= xmlGetCharEncodingHandler(enc
);
2367 if (ret
->encoder
!= NULL
)
2368 ret
->raw
= xmlBufCreateSize(2 * xmlDefaultBufferSize
);
2371 ret
->readcallback
= NULL
;
2372 ret
->closecallback
= NULL
;
2373 ret
->context
= NULL
;
2374 ret
->compressed
= -1;
2375 ret
->rawconsumed
= 0;
2380 #ifdef LIBXML_OUTPUT_ENABLED
2382 * xmlAllocOutputBuffer:
2383 * @encoder: the encoding converter or NULL
2385 * Create a buffered parser output
2387 * Returns the new parser output or NULL
2390 xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder
) {
2391 xmlOutputBufferPtr ret
;
2393 ret
= (xmlOutputBufferPtr
) xmlMalloc(sizeof(xmlOutputBuffer
));
2395 xmlIOErrMemory("creating output buffer");
2398 memset(ret
, 0, (size_t) sizeof(xmlOutputBuffer
));
2399 ret
->buffer
= xmlBufCreate();
2400 if (ret
->buffer
== NULL
) {
2405 /* try to avoid a performance problem with Windows realloc() */
2406 if (xmlBufGetAllocationScheme(ret
->buffer
) == XML_BUFFER_ALLOC_EXACT
)
2407 xmlBufSetAllocationScheme(ret
->buffer
, XML_BUFFER_ALLOC_DOUBLEIT
);
2409 ret
->encoder
= encoder
;
2410 if (encoder
!= NULL
) {
2411 ret
->conv
= xmlBufCreateSize(4000);
2412 if (ret
->conv
== NULL
) {
2413 xmlBufFree(ret
->buffer
);
2419 * This call is designed to initiate the encoder state
2421 xmlCharEncOutput(ret
, 1);
2424 ret
->writecallback
= NULL
;
2425 ret
->closecallback
= NULL
;
2426 ret
->context
= NULL
;
2433 * xmlAllocOutputBufferInternal:
2434 * @encoder: the encoding converter or NULL
2436 * Create a buffered parser output
2438 * Returns the new parser output or NULL
2441 xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder
) {
2442 xmlOutputBufferPtr ret
;
2444 ret
= (xmlOutputBufferPtr
) xmlMalloc(sizeof(xmlOutputBuffer
));
2446 xmlIOErrMemory("creating output buffer");
2449 memset(ret
, 0, (size_t) sizeof(xmlOutputBuffer
));
2450 ret
->buffer
= xmlBufCreate();
2451 if (ret
->buffer
== NULL
) {
2458 * For conversion buffers we use the special IO handling
2460 xmlBufSetAllocationScheme(ret
->buffer
, XML_BUFFER_ALLOC_IO
);
2462 ret
->encoder
= encoder
;
2463 if (encoder
!= NULL
) {
2464 ret
->conv
= xmlBufCreateSize(4000);
2465 if (ret
->conv
== NULL
) {
2466 xmlBufFree(ret
->buffer
);
2472 * This call is designed to initiate the encoder state
2474 xmlCharEncOutput(ret
, 1);
2477 ret
->writecallback
= NULL
;
2478 ret
->closecallback
= NULL
;
2479 ret
->context
= NULL
;
2485 #endif /* LIBXML_OUTPUT_ENABLED */
2488 * xmlFreeParserInputBuffer:
2489 * @in: a buffered parser input
2491 * Free up the memory used by a buffered parser input
2494 xmlFreeParserInputBuffer(xmlParserInputBufferPtr in
) {
2495 if (in
== NULL
) return;
2498 xmlBufFree(in
->raw
);
2501 if (in
->encoder
!= NULL
) {
2502 xmlCharEncCloseFunc(in
->encoder
);
2504 if (in
->closecallback
!= NULL
) {
2505 in
->closecallback(in
->context
);
2507 if (in
->buffer
!= NULL
) {
2508 xmlBufFree(in
->buffer
);
2515 #ifdef LIBXML_OUTPUT_ENABLED
2517 * xmlOutputBufferClose:
2518 * @out: a buffered output
2520 * flushes and close the output I/O channel
2521 * and free up all the associated resources
2523 * Returns the number of byte written or -1 in case of error.
2526 xmlOutputBufferClose(xmlOutputBufferPtr out
)
2533 if (out
->writecallback
!= NULL
)
2534 xmlOutputBufferFlush(out
);
2535 if (out
->closecallback
!= NULL
) {
2536 err_rc
= out
->closecallback(out
->context
);
2538 written
= out
->written
;
2540 xmlBufFree(out
->conv
);
2543 if (out
->encoder
!= NULL
) {
2544 xmlCharEncCloseFunc(out
->encoder
);
2546 if (out
->buffer
!= NULL
) {
2547 xmlBufFree(out
->buffer
);
2554 return ((err_rc
== 0) ? written
: err_rc
);
2556 #endif /* LIBXML_OUTPUT_ENABLED */
2558 xmlParserInputBufferPtr
2559 __xmlParserInputBufferCreateFilename(const char *URI
, xmlCharEncoding enc
) {
2560 xmlParserInputBufferPtr ret
;
2562 void *context
= NULL
;
2564 if (xmlInputCallbackInitialized
== 0)
2565 xmlRegisterDefaultInputCallbacks();
2567 if (URI
== NULL
) return(NULL
);
2570 * Try to find one of the input accept method accepting that scheme
2571 * Go in reverse to give precedence to user defined handlers.
2573 if (context
== NULL
) {
2574 for (i
= xmlInputCallbackNr
- 1;i
>= 0;i
--) {
2575 if ((xmlInputCallbackTable
[i
].matchcallback
!= NULL
) &&
2576 (xmlInputCallbackTable
[i
].matchcallback(URI
) != 0)) {
2577 context
= xmlInputCallbackTable
[i
].opencallback(URI
);
2578 if (context
!= NULL
) {
2584 if (context
== NULL
) {
2589 * Allocate the Input buffer front-end.
2591 ret
= xmlAllocParserInputBuffer(enc
);
2593 ret
->context
= context
;
2594 ret
->readcallback
= xmlInputCallbackTable
[i
].readcallback
;
2595 ret
->closecallback
= xmlInputCallbackTable
[i
].closecallback
;
2596 #ifdef LIBXML_ZLIB_ENABLED
2597 if ((xmlInputCallbackTable
[i
].opencallback
== xmlGzfileOpen
) &&
2598 (strcmp(URI
, "-") != 0)) {
2599 #if defined(ZLIB_VERNUM) && ZLIB_VERNUM >= 0x1230
2600 ret
->compressed
= !gzdirect(context
);
2602 if (((z_stream
*)context
)->avail_in
> 4) {
2603 char *cptr
, buff4
[4];
2604 cptr
= (char *) ((z_stream
*)context
)->next_in
;
2605 if (gzread(context
, buff4
, 4) == 4) {
2606 if (strncmp(buff4
, cptr
, 4) == 0)
2607 ret
->compressed
= 0;
2609 ret
->compressed
= 1;
2616 #ifdef LIBXML_LZMA_ENABLED
2617 if ((xmlInputCallbackTable
[i
].opencallback
== xmlXzfileOpen
) &&
2618 (strcmp(URI
, "-") != 0)) {
2619 ret
->compressed
= __libxml2_xzcompressed(context
);
2624 xmlInputCallbackTable
[i
].closecallback (context
);
2630 * xmlParserInputBufferCreateFilename:
2631 * @URI: a C string containing the URI or filename
2632 * @enc: the charset encoding if known
2634 * Create a buffered parser input for the progressive parsing of a file
2635 * If filename is "-' then we use stdin as the input.
2636 * Automatic support for ZLIB/Compress compressed document is provided
2637 * by default if found at compile-time.
2638 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
2640 * Returns the new parser input or NULL
2642 xmlParserInputBufferPtr
2643 xmlParserInputBufferCreateFilename(const char *URI
, xmlCharEncoding enc
) {
2644 if ((xmlParserInputBufferCreateFilenameValue
)) {
2645 return xmlParserInputBufferCreateFilenameValue(URI
, enc
);
2647 return __xmlParserInputBufferCreateFilename(URI
, enc
);
2650 #ifdef LIBXML_OUTPUT_ENABLED
2652 __xmlOutputBufferCreateFilename(const char *URI
,
2653 xmlCharEncodingHandlerPtr encoder
,
2654 int compression ATTRIBUTE_UNUSED
) {
2655 xmlOutputBufferPtr ret
;
2658 void *context
= NULL
;
2659 char *unescaped
= NULL
;
2660 #ifdef LIBXML_ZLIB_ENABLED
2661 int is_file_uri
= 1;
2664 if (xmlOutputCallbackInitialized
== 0)
2665 xmlRegisterDefaultOutputCallbacks();
2667 if (URI
== NULL
) return(NULL
);
2669 puri
= xmlParseURI(URI
);
2671 #ifdef LIBXML_ZLIB_ENABLED
2672 if ((puri
->scheme
!= NULL
) &&
2673 (!xmlStrEqual(BAD_CAST puri
->scheme
, BAD_CAST
"file")))
2677 * try to limit the damages of the URI unescaping code.
2679 if ((puri
->scheme
== NULL
) ||
2680 (xmlStrEqual(BAD_CAST puri
->scheme
, BAD_CAST
"file")))
2681 unescaped
= xmlURIUnescapeString(URI
, 0, NULL
);
2686 * Try to find one of the output accept method accepting that scheme
2687 * Go in reverse to give precedence to user defined handlers.
2688 * try with an unescaped version of the URI
2690 if (unescaped
!= NULL
) {
2691 #ifdef LIBXML_ZLIB_ENABLED
2692 if ((compression
> 0) && (compression
<= 9) && (is_file_uri
== 1)) {
2693 context
= xmlGzfileOpenW(unescaped
, compression
);
2694 if (context
!= NULL
) {
2695 ret
= xmlAllocOutputBufferInternal(encoder
);
2697 ret
->context
= context
;
2698 ret
->writecallback
= xmlGzfileWrite
;
2699 ret
->closecallback
= xmlGzfileClose
;
2706 for (i
= xmlOutputCallbackNr
- 1;i
>= 0;i
--) {
2707 if ((xmlOutputCallbackTable
[i
].matchcallback
!= NULL
) &&
2708 (xmlOutputCallbackTable
[i
].matchcallback(unescaped
) != 0)) {
2709 #if defined(LIBXML_HTTP_ENABLED) && defined(LIBXML_ZLIB_ENABLED)
2710 /* Need to pass compression parameter into HTTP open calls */
2711 if (xmlOutputCallbackTable
[i
].matchcallback
== xmlIOHTTPMatch
)
2712 context
= xmlIOHTTPOpenW(unescaped
, compression
);
2715 context
= xmlOutputCallbackTable
[i
].opencallback(unescaped
);
2716 if (context
!= NULL
)
2724 * If this failed try with a non-escaped URI this may be a strange
2727 if (context
== NULL
) {
2728 #ifdef LIBXML_ZLIB_ENABLED
2729 if ((compression
> 0) && (compression
<= 9) && (is_file_uri
== 1)) {
2730 context
= xmlGzfileOpenW(URI
, compression
);
2731 if (context
!= NULL
) {
2732 ret
= xmlAllocOutputBufferInternal(encoder
);
2734 ret
->context
= context
;
2735 ret
->writecallback
= xmlGzfileWrite
;
2736 ret
->closecallback
= xmlGzfileClose
;
2739 xmlGzfileClose(context
);
2744 for (i
= xmlOutputCallbackNr
- 1;i
>= 0;i
--) {
2745 if ((xmlOutputCallbackTable
[i
].matchcallback
!= NULL
) &&
2746 (xmlOutputCallbackTable
[i
].matchcallback(URI
) != 0)) {
2747 #if defined(LIBXML_HTTP_ENABLED) && defined(LIBXML_ZLIB_ENABLED)
2748 /* Need to pass compression parameter into HTTP open calls */
2749 if (xmlOutputCallbackTable
[i
].matchcallback
== xmlIOHTTPMatch
)
2750 context
= xmlIOHTTPOpenW(URI
, compression
);
2753 context
= xmlOutputCallbackTable
[i
].opencallback(URI
);
2754 if (context
!= NULL
)
2760 if (context
== NULL
) {
2765 * Allocate the Output buffer front-end.
2767 ret
= xmlAllocOutputBufferInternal(encoder
);
2769 ret
->context
= context
;
2770 ret
->writecallback
= xmlOutputCallbackTable
[i
].writecallback
;
2771 ret
->closecallback
= xmlOutputCallbackTable
[i
].closecallback
;
2777 * xmlOutputBufferCreateFilename:
2778 * @URI: a C string containing the URI or filename
2779 * @encoder: the encoding converter or NULL
2780 * @compression: the compression ration (0 none, 9 max).
2782 * Create a buffered output for the progressive saving of a file
2783 * If filename is "-' then we use stdout as the output.
2784 * Automatic support for ZLIB/Compress compressed document is provided
2785 * by default if found at compile-time.
2786 * TODO: currently if compression is set, the library only support
2787 * writing to a local file.
2789 * Returns the new output or NULL
2792 xmlOutputBufferCreateFilename(const char *URI
,
2793 xmlCharEncodingHandlerPtr encoder
,
2794 int compression ATTRIBUTE_UNUSED
) {
2795 if ((xmlOutputBufferCreateFilenameValue
)) {
2796 return xmlOutputBufferCreateFilenameValue(URI
, encoder
, compression
);
2798 return __xmlOutputBufferCreateFilename(URI
, encoder
, compression
);
2800 #endif /* LIBXML_OUTPUT_ENABLED */
2803 * xmlParserInputBufferCreateFile:
2805 * @enc: the charset encoding if known
2807 * Create a buffered parser input for the progressive parsing of a FILE *
2810 * Returns the new parser input or NULL
2812 xmlParserInputBufferPtr
2813 xmlParserInputBufferCreateFile(FILE *file
, xmlCharEncoding enc
) {
2814 xmlParserInputBufferPtr ret
;
2816 if (xmlInputCallbackInitialized
== 0)
2817 xmlRegisterDefaultInputCallbacks();
2819 if (file
== NULL
) return(NULL
);
2821 ret
= xmlAllocParserInputBuffer(enc
);
2823 ret
->context
= file
;
2824 ret
->readcallback
= xmlFileRead
;
2825 ret
->closecallback
= xmlFileFlush
;
2831 #ifdef LIBXML_OUTPUT_ENABLED
2833 * xmlOutputBufferCreateFile:
2835 * @encoder: the encoding converter or NULL
2837 * Create a buffered output for the progressive saving to a FILE *
2840 * Returns the new parser output or NULL
2843 xmlOutputBufferCreateFile(FILE *file
, xmlCharEncodingHandlerPtr encoder
) {
2844 xmlOutputBufferPtr ret
;
2846 if (xmlOutputCallbackInitialized
== 0)
2847 xmlRegisterDefaultOutputCallbacks();
2849 if (file
== NULL
) return(NULL
);
2851 ret
= xmlAllocOutputBufferInternal(encoder
);
2853 ret
->context
= file
;
2854 ret
->writecallback
= xmlFileWrite
;
2855 ret
->closecallback
= xmlFileFlush
;
2862 * xmlOutputBufferCreateBuffer:
2863 * @buffer: a xmlBufferPtr
2864 * @encoder: the encoding converter or NULL
2866 * Create a buffered output for the progressive saving to a xmlBuffer
2868 * Returns the new parser output or NULL
2871 xmlOutputBufferCreateBuffer(xmlBufferPtr buffer
,
2872 xmlCharEncodingHandlerPtr encoder
) {
2873 xmlOutputBufferPtr ret
;
2875 if (buffer
== NULL
) return(NULL
);
2877 ret
= xmlOutputBufferCreateIO(xmlBufferWrite
, NULL
, (void *) buffer
,
2884 * xmlOutputBufferGetContent:
2885 * @out: an xmlOutputBufferPtr
2887 * Gives a pointer to the data currently held in the output buffer
2889 * Returns a pointer to the data or NULL in case of error
2892 xmlOutputBufferGetContent(xmlOutputBufferPtr out
) {
2893 if ((out
== NULL
) || (out
->buffer
== NULL
))
2896 return(xmlBufContent(out
->buffer
));
2900 * xmlOutputBufferGetSize:
2901 * @out: an xmlOutputBufferPtr
2903 * Gives the length of the data currently held in the output buffer
2905 * Returns 0 in case or error or no data is held, the size otherwise
2908 xmlOutputBufferGetSize(xmlOutputBufferPtr out
) {
2909 if ((out
== NULL
) || (out
->buffer
== NULL
))
2912 return(xmlBufUse(out
->buffer
));
2916 #endif /* LIBXML_OUTPUT_ENABLED */
2919 * xmlParserInputBufferCreateFd:
2920 * @fd: a file descriptor number
2921 * @enc: the charset encoding if known
2923 * Create a buffered parser input for the progressive parsing for the input
2924 * from a file descriptor
2926 * Returns the new parser input or NULL
2928 xmlParserInputBufferPtr
2929 xmlParserInputBufferCreateFd(int fd
, xmlCharEncoding enc
) {
2930 xmlParserInputBufferPtr ret
;
2932 if (fd
< 0) return(NULL
);
2934 ret
= xmlAllocParserInputBuffer(enc
);
2936 ret
->context
= (void *) (ptrdiff_t) fd
;
2937 ret
->readcallback
= xmlFdRead
;
2938 ret
->closecallback
= xmlFdClose
;
2945 * xmlParserInputBufferCreateMem:
2946 * @mem: the memory input
2947 * @size: the length of the memory block
2948 * @enc: the charset encoding if known
2950 * Create a buffered parser input for the progressive parsing for the input
2951 * from a memory area.
2953 * Returns the new parser input or NULL
2955 xmlParserInputBufferPtr
2956 xmlParserInputBufferCreateMem(const char *mem
, int size
, xmlCharEncoding enc
) {
2957 xmlParserInputBufferPtr ret
;
2960 if (size
< 0) return(NULL
);
2961 if (mem
== NULL
) return(NULL
);
2963 ret
= xmlAllocParserInputBuffer(enc
);
2965 ret
->context
= (void *) mem
;
2966 ret
->readcallback
= xmlInputReadCallbackNop
;
2967 ret
->closecallback
= NULL
;
2968 errcode
= xmlBufAdd(ret
->buffer
, (const xmlChar
*) mem
, size
);
2979 * xmlParserInputBufferCreateStatic:
2980 * @mem: the memory input
2981 * @size: the length of the memory block
2982 * @enc: the charset encoding if known
2984 * Create a buffered parser input for the progressive parsing for the input
2985 * from an immutable memory area. This will not copy the memory area to
2986 * the buffer, but the memory is expected to be available until the end of
2987 * the parsing, this is useful for example when using mmap'ed file.
2989 * Returns the new parser input or NULL
2991 xmlParserInputBufferPtr
2992 xmlParserInputBufferCreateStatic(const char *mem
, int size
,
2993 xmlCharEncoding enc
) {
2994 xmlParserInputBufferPtr ret
;
2996 if (size
< 0) return(NULL
);
2997 if (mem
== NULL
) return(NULL
);
2999 ret
= (xmlParserInputBufferPtr
) xmlMalloc(sizeof(xmlParserInputBuffer
));
3001 xmlIOErrMemory("creating input buffer");
3004 memset(ret
, 0, (size_t) sizeof(xmlParserInputBuffer
));
3005 ret
->buffer
= xmlBufCreateStatic((void *)mem
, (size_t) size
);
3006 if (ret
->buffer
== NULL
) {
3010 ret
->encoder
= xmlGetCharEncodingHandler(enc
);
3011 if (ret
->encoder
!= NULL
)
3012 ret
->raw
= xmlBufCreateSize(2 * xmlDefaultBufferSize
);
3015 ret
->compressed
= -1;
3016 ret
->context
= (void *) mem
;
3017 ret
->readcallback
= NULL
;
3018 ret
->closecallback
= NULL
;
3023 #ifdef LIBXML_OUTPUT_ENABLED
3025 * xmlOutputBufferCreateFd:
3026 * @fd: a file descriptor number
3027 * @encoder: the encoding converter or NULL
3029 * Create a buffered output for the progressive saving
3030 * to a file descriptor
3032 * Returns the new parser output or NULL
3035 xmlOutputBufferCreateFd(int fd
, xmlCharEncodingHandlerPtr encoder
) {
3036 xmlOutputBufferPtr ret
;
3038 if (fd
< 0) return(NULL
);
3040 ret
= xmlAllocOutputBufferInternal(encoder
);
3042 ret
->context
= (void *) (ptrdiff_t) fd
;
3043 ret
->writecallback
= xmlFdWrite
;
3044 ret
->closecallback
= NULL
;
3049 #endif /* LIBXML_OUTPUT_ENABLED */
3052 * xmlParserInputBufferCreateIO:
3053 * @ioread: an I/O read function
3054 * @ioclose: an I/O close function
3055 * @ioctx: an I/O handler
3056 * @enc: the charset encoding if known
3058 * Create a buffered parser input for the progressive parsing for the input
3059 * from an I/O handler
3061 * Returns the new parser input or NULL
3063 xmlParserInputBufferPtr
3064 xmlParserInputBufferCreateIO(xmlInputReadCallback ioread
,
3065 xmlInputCloseCallback ioclose
, void *ioctx
, xmlCharEncoding enc
) {
3066 xmlParserInputBufferPtr ret
;
3068 if (ioread
== NULL
) return(NULL
);
3070 ret
= xmlAllocParserInputBuffer(enc
);
3072 ret
->context
= (void *) ioctx
;
3073 ret
->readcallback
= ioread
;
3074 ret
->closecallback
= ioclose
;
3080 #ifdef LIBXML_OUTPUT_ENABLED
3082 * xmlOutputBufferCreateIO:
3083 * @iowrite: an I/O write function
3084 * @ioclose: an I/O close function
3085 * @ioctx: an I/O handler
3086 * @encoder: the charset encoding if known
3088 * Create a buffered output for the progressive saving
3091 * Returns the new parser output or NULL
3094 xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite
,
3095 xmlOutputCloseCallback ioclose
, void *ioctx
,
3096 xmlCharEncodingHandlerPtr encoder
) {
3097 xmlOutputBufferPtr ret
;
3099 if (iowrite
== NULL
) return(NULL
);
3101 ret
= xmlAllocOutputBufferInternal(encoder
);
3103 ret
->context
= (void *) ioctx
;
3104 ret
->writecallback
= iowrite
;
3105 ret
->closecallback
= ioclose
;
3110 #endif /* LIBXML_OUTPUT_ENABLED */
3113 * xmlParserInputBufferCreateFilenameDefault:
3114 * @func: function pointer to the new ParserInputBufferCreateFilenameFunc
3116 * Registers a callback for URI input file handling
3118 * Returns the old value of the registration function
3120 xmlParserInputBufferCreateFilenameFunc
3121 xmlParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func
)
3123 xmlParserInputBufferCreateFilenameFunc old
= xmlParserInputBufferCreateFilenameValue
;
3125 old
= __xmlParserInputBufferCreateFilename
;
3128 xmlParserInputBufferCreateFilenameValue
= func
;
3133 * xmlOutputBufferCreateFilenameDefault:
3134 * @func: function pointer to the new OutputBufferCreateFilenameFunc
3136 * Registers a callback for URI output file handling
3138 * Returns the old value of the registration function
3140 xmlOutputBufferCreateFilenameFunc
3141 xmlOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func
)
3143 xmlOutputBufferCreateFilenameFunc old
= xmlOutputBufferCreateFilenameValue
;
3144 #ifdef LIBXML_OUTPUT_ENABLED
3146 old
= __xmlOutputBufferCreateFilename
;
3149 xmlOutputBufferCreateFilenameValue
= func
;
3154 * xmlParserInputBufferPush:
3155 * @in: a buffered parser input
3156 * @len: the size in bytes of the array.
3157 * @buf: an char array
3159 * Push the content of the arry in the input buffer
3160 * This routine handle the I18N transcoding to internal UTF-8
3161 * This is used when operating the parser in progressive (push) mode.
3163 * Returns the number of chars read and stored in the buffer, or -1
3167 xmlParserInputBufferPush(xmlParserInputBufferPtr in
,
3168 int len
, const char *buf
) {
3172 if (len
< 0) return(0);
3173 if ((in
== NULL
) || (in
->error
)) return(-1);
3174 if (in
->encoder
!= NULL
) {
3178 * Store the data in the incoming raw buffer
3180 if (in
->raw
== NULL
) {
3181 in
->raw
= xmlBufCreate();
3183 ret
= xmlBufAdd(in
->raw
, (const xmlChar
*) buf
, len
);
3188 * convert as much as possible to the parser reading buffer.
3190 use
= xmlBufUse(in
->raw
);
3191 nbchars
= xmlCharEncInput(in
, 1);
3193 xmlIOErr(XML_IO_ENCODER
, NULL
);
3194 in
->error
= XML_IO_ENCODER
;
3197 in
->rawconsumed
+= (use
- xmlBufUse(in
->raw
));
3200 ret
= xmlBufAdd(in
->buffer
, (xmlChar
*) buf
, nbchars
);
3205 xmlGenericError(xmlGenericErrorContext
,
3206 "I/O: pushed %d chars, buffer %d/%d\n",
3207 nbchars
, xmlBufUse(in
->buffer
), xmlBufLength(in
->buffer
));
3215 * When reading from an Input channel indicated end of file or error
3216 * don't reread from it again.
3219 endOfInput (void * context ATTRIBUTE_UNUSED
,
3220 char * buffer ATTRIBUTE_UNUSED
,
3221 int len ATTRIBUTE_UNUSED
) {
3226 * xmlParserInputBufferGrow:
3227 * @in: a buffered parser input
3228 * @len: indicative value of the amount of chars to read
3230 * Grow up the content of the input buffer, the old data are preserved
3231 * This routine handle the I18N transcoding to internal UTF-8
3232 * This routine is used when operating the parser in normal (pull) mode
3234 * TODO: one should be able to remove one extra copy by copying directly
3235 * onto in->buffer or in->raw
3237 * Returns the number of chars read and stored in the buffer, or -1
3241 xmlParserInputBufferGrow(xmlParserInputBufferPtr in
, int len
) {
3242 char *buffer
= NULL
;
3246 if ((in
== NULL
) || (in
->error
)) return(-1);
3247 if ((len
<= MINLEN
) && (len
!= 4))
3250 if (xmlBufAvail(in
->buffer
) <= 0) {
3251 xmlIOErr(XML_IO_BUFFER_FULL
, NULL
);
3252 in
->error
= XML_IO_BUFFER_FULL
;
3256 if (xmlBufGrow(in
->buffer
, len
+ 1) < 0) {
3257 xmlIOErrMemory("growing input buffer");
3258 in
->error
= XML_ERR_NO_MEMORY
;
3261 buffer
= (char *)xmlBufEnd(in
->buffer
);
3264 * Call the read method for this I/O type.
3266 if (in
->readcallback
!= NULL
) {
3267 res
= in
->readcallback(in
->context
, &buffer
[0], len
);
3269 in
->readcallback
= endOfInput
;
3271 xmlIOErr(XML_IO_NO_INPUT
, NULL
);
3272 in
->error
= XML_IO_NO_INPUT
;
3280 * try to establish compressed status of input if not done already
3282 if (in
->compressed
== -1) {
3283 #ifdef LIBXML_LZMA_ENABLED
3284 if (in
->readcallback
== xmlXzfileRead
)
3285 in
->compressed
= __libxml2_xzcompressed(in
->context
);
3290 if (in
->encoder
!= NULL
) {
3294 * Store the data in the incoming raw buffer
3296 if (in
->raw
== NULL
) {
3297 in
->raw
= xmlBufCreate();
3299 res
= xmlBufAdd(in
->raw
, (const xmlChar
*) buffer
, len
);
3304 * convert as much as possible to the parser reading buffer.
3306 use
= xmlBufUse(in
->raw
);
3307 nbchars
= xmlCharEncInput(in
, 1);
3309 xmlIOErr(XML_IO_ENCODER
, NULL
);
3310 in
->error
= XML_IO_ENCODER
;
3313 in
->rawconsumed
+= (use
- xmlBufUse(in
->raw
));
3316 xmlBufAddLen(in
->buffer
, nbchars
);
3319 xmlGenericError(xmlGenericErrorContext
,
3320 "I/O: read %d chars, buffer %d\n",
3321 nbchars
, xmlBufUse(in
->buffer
));
3327 * xmlParserInputBufferRead:
3328 * @in: a buffered parser input
3329 * @len: indicative value of the amount of chars to read
3331 * Refresh the content of the input buffer, the old data are considered
3333 * This routine handle the I18N transcoding to internal UTF-8
3335 * Returns the number of chars read and stored in the buffer, or -1
3339 xmlParserInputBufferRead(xmlParserInputBufferPtr in
, int len
) {
3340 if ((in
== NULL
) || (in
->error
)) return(-1);
3341 if (in
->readcallback
!= NULL
)
3342 return(xmlParserInputBufferGrow(in
, len
));
3343 else if (xmlBufGetAllocationScheme(in
->buffer
) == XML_BUFFER_ALLOC_IMMUTABLE
)
3349 #ifdef LIBXML_OUTPUT_ENABLED
3351 * xmlOutputBufferWrite:
3352 * @out: a buffered parser output
3353 * @len: the size in bytes of the array.
3354 * @buf: an char array
3356 * Write the content of the array in the output I/O buffer
3357 * This routine handle the I18N transcoding from internal UTF-8
3358 * The buffer is lossless, i.e. will store in case of partial
3359 * or delayed writes.
3361 * Returns the number of chars immediately written, or -1
3365 xmlOutputBufferWrite(xmlOutputBufferPtr out
, int len
, const char *buf
) {
3366 int nbchars
= 0; /* number of chars to output to I/O */
3367 int ret
; /* return from function call */
3368 int written
= 0; /* number of char written to I/O so far */
3369 int chunk
; /* number of byte current processed from buf */
3371 if ((out
== NULL
) || (out
->error
)) return(-1);
3372 if (len
< 0) return(0);
3373 if (out
->error
) return(-1);
3377 if (chunk
> 4 * MINLEN
)
3381 * first handle encoding stuff.
3383 if (out
->encoder
!= NULL
) {
3385 * Store the data in the incoming raw buffer
3387 if (out
->conv
== NULL
) {
3388 out
->conv
= xmlBufCreate();
3390 ret
= xmlBufAdd(out
->buffer
, (const xmlChar
*) buf
, chunk
);
3394 if ((xmlBufUse(out
->buffer
) < MINLEN
) && (chunk
== len
))
3398 * convert as much as possible to the parser reading buffer.
3400 ret
= xmlCharEncOutput(out
, 0);
3401 if ((ret
< 0) && (ret
!= -3)) {
3402 xmlIOErr(XML_IO_ENCODER
, NULL
);
3403 out
->error
= XML_IO_ENCODER
;
3406 if (out
->writecallback
)
3407 nbchars
= xmlBufUse(out
->conv
);
3409 nbchars
= ret
>= 0 ? ret
: 0;
3411 ret
= xmlBufAdd(out
->buffer
, (const xmlChar
*) buf
, chunk
);
3414 if (out
->writecallback
)
3415 nbchars
= xmlBufUse(out
->buffer
);
3422 if (out
->writecallback
) {
3423 if ((nbchars
< MINLEN
) && (len
<= 0))
3427 * second write the stuff to the I/O channel
3429 if (out
->encoder
!= NULL
) {
3430 ret
= out
->writecallback(out
->context
,
3431 (const char *)xmlBufContent(out
->conv
), nbchars
);
3433 xmlBufShrink(out
->conv
, ret
);
3435 ret
= out
->writecallback(out
->context
,
3436 (const char *)xmlBufContent(out
->buffer
), nbchars
);
3438 xmlBufShrink(out
->buffer
, ret
);
3441 xmlIOErr(XML_IO_WRITE
, NULL
);
3442 out
->error
= XML_IO_WRITE
;
3445 if (out
->written
> INT_MAX
- ret
)
3446 out
->written
= INT_MAX
;
3448 out
->written
+= ret
;
3455 xmlGenericError(xmlGenericErrorContext
,
3456 "I/O: wrote %d chars\n", written
);
3463 * @out: a pointer to an array of bytes to store the result
3464 * @outlen: the length of @out
3465 * @in: a pointer to an array of unescaped UTF-8 bytes
3466 * @inlen: the length of @in
3468 * Take a block of UTF-8 chars in and escape them.
3469 * Returns 0 if success, or -1 otherwise
3470 * The value of @inlen after return is the number of octets consumed
3471 * if the return value is positive, else unpredictable.
3472 * The value of @outlen after return is the number of octets consumed.
3475 xmlEscapeContent(unsigned char* out
, int *outlen
,
3476 const xmlChar
* in
, int *inlen
) {
3477 unsigned char* outstart
= out
;
3478 const unsigned char* base
= in
;
3479 unsigned char* outend
= out
+ *outlen
;
3480 const unsigned char* inend
;
3482 inend
= in
+ (*inlen
);
3484 while ((in
< inend
) && (out
< outend
)) {
3486 if (outend
- out
< 4) break;
3491 } else if (*in
== '>') {
3492 if (outend
- out
< 4) break;
3497 } else if (*in
== '&') {
3498 if (outend
- out
< 5) break;
3504 } else if (*in
== '\r') {
3505 if (outend
- out
< 5) break;
3512 *out
++ = (unsigned char) *in
;
3516 *outlen
= out
- outstart
;
3522 * xmlOutputBufferWriteEscape:
3523 * @out: a buffered parser output
3524 * @str: a zero terminated UTF-8 string
3525 * @escaping: an optional escaping function (or NULL)
3527 * Write the content of the string in the output I/O buffer
3528 * This routine escapes the characters and then handle the I18N
3529 * transcoding from internal UTF-8
3530 * The buffer is lossless, i.e. will store in case of partial
3531 * or delayed writes.
3533 * Returns the number of chars immediately written, or -1
3537 xmlOutputBufferWriteEscape(xmlOutputBufferPtr out
, const xmlChar
*str
,
3538 xmlCharEncodingOutputFunc escaping
) {
3539 int nbchars
= 0; /* number of chars to output to I/O */
3540 int ret
; /* return from function call */
3541 int written
= 0; /* number of char written to I/O so far */
3542 int oldwritten
=0;/* loop guard */
3543 int chunk
; /* number of byte currently processed from str */
3544 int len
; /* number of bytes in str */
3545 int cons
; /* byte from str consumed */
3547 if ((out
== NULL
) || (out
->error
) || (str
== NULL
) ||
3548 (out
->buffer
== NULL
) ||
3549 (xmlBufGetAllocationScheme(out
->buffer
) == XML_BUFFER_ALLOC_IMMUTABLE
))
3551 len
= strlen((const char *)str
);
3552 if (len
< 0) return(0);
3553 if (out
->error
) return(-1);
3554 if (escaping
== NULL
) escaping
= xmlEscapeContent
;
3557 oldwritten
= written
;
3560 * how many bytes to consume and how many bytes to store.
3563 chunk
= xmlBufAvail(out
->buffer
) - 1;
3566 * make sure we have enough room to save first, if this is
3567 * not the case force a flush, but make sure we stay in the loop
3570 if (xmlBufGrow(out
->buffer
, 100) < 0)
3577 * first handle encoding stuff.
3579 if (out
->encoder
!= NULL
) {
3581 * Store the data in the incoming raw buffer
3583 if (out
->conv
== NULL
) {
3584 out
->conv
= xmlBufCreate();
3586 ret
= escaping(xmlBufEnd(out
->buffer
) ,
3587 &chunk
, str
, &cons
);
3588 if ((ret
< 0) || (chunk
== 0)) /* chunk==0 => nothing done */
3590 xmlBufAddLen(out
->buffer
, chunk
);
3592 if ((xmlBufUse(out
->buffer
) < MINLEN
) && (cons
== len
))
3596 * convert as much as possible to the output buffer.
3598 ret
= xmlCharEncOutput(out
, 0);
3599 if ((ret
< 0) && (ret
!= -3)) {
3600 xmlIOErr(XML_IO_ENCODER
, NULL
);
3601 out
->error
= XML_IO_ENCODER
;
3604 if (out
->writecallback
)
3605 nbchars
= xmlBufUse(out
->conv
);
3607 nbchars
= ret
>= 0 ? ret
: 0;
3609 ret
= escaping(xmlBufEnd(out
->buffer
), &chunk
, str
, &cons
);
3610 if ((ret
< 0) || (chunk
== 0)) /* chunk==0 => nothing done */
3612 xmlBufAddLen(out
->buffer
, chunk
);
3613 if (out
->writecallback
)
3614 nbchars
= xmlBufUse(out
->buffer
);
3621 if (out
->writecallback
) {
3622 if ((nbchars
< MINLEN
) && (len
<= 0))
3626 * second write the stuff to the I/O channel
3628 if (out
->encoder
!= NULL
) {
3629 ret
= out
->writecallback(out
->context
,
3630 (const char *)xmlBufContent(out
->conv
), nbchars
);
3632 xmlBufShrink(out
->conv
, ret
);
3634 ret
= out
->writecallback(out
->context
,
3635 (const char *)xmlBufContent(out
->buffer
), nbchars
);
3637 xmlBufShrink(out
->buffer
, ret
);
3640 xmlIOErr(XML_IO_WRITE
, NULL
);
3641 out
->error
= XML_IO_WRITE
;
3644 if (out
->written
> INT_MAX
- ret
)
3645 out
->written
= INT_MAX
;
3647 out
->written
+= ret
;
3648 } else if (xmlBufAvail(out
->buffer
) < MINLEN
) {
3649 xmlBufGrow(out
->buffer
, MINLEN
);
3652 } while ((len
> 0) && (oldwritten
!= written
));
3656 xmlGenericError(xmlGenericErrorContext
,
3657 "I/O: wrote %d chars\n", written
);
3663 * xmlOutputBufferWriteString:
3664 * @out: a buffered parser output
3665 * @str: a zero terminated C string
3667 * Write the content of the string in the output I/O buffer
3668 * This routine handle the I18N transcoding from internal UTF-8
3669 * The buffer is lossless, i.e. will store in case of partial
3670 * or delayed writes.
3672 * Returns the number of chars immediately written, or -1
3676 xmlOutputBufferWriteString(xmlOutputBufferPtr out
, const char *str
) {
3679 if ((out
== NULL
) || (out
->error
)) return(-1);
3685 return(xmlOutputBufferWrite(out
, len
, str
));
3690 * xmlOutputBufferFlush:
3691 * @out: a buffered output
3693 * flushes the output I/O channel
3695 * Returns the number of byte written or -1 in case of error.
3698 xmlOutputBufferFlush(xmlOutputBufferPtr out
) {
3699 int nbchars
= 0, ret
= 0;
3701 if ((out
== NULL
) || (out
->error
)) return(-1);
3703 * first handle encoding stuff.
3705 if ((out
->conv
!= NULL
) && (out
->encoder
!= NULL
)) {
3707 * convert as much as possible to the parser output buffer.
3710 nbchars
= xmlCharEncOutput(out
, 0);
3712 xmlIOErr(XML_IO_ENCODER
, NULL
);
3713 out
->error
= XML_IO_ENCODER
;
3720 * second flush the stuff to the I/O channel
3722 if ((out
->conv
!= NULL
) && (out
->encoder
!= NULL
) &&
3723 (out
->writecallback
!= NULL
)) {
3724 ret
= out
->writecallback(out
->context
,
3725 (const char *)xmlBufContent(out
->conv
),
3726 xmlBufUse(out
->conv
));
3728 xmlBufShrink(out
->conv
, ret
);
3729 } else if (out
->writecallback
!= NULL
) {
3730 ret
= out
->writecallback(out
->context
,
3731 (const char *)xmlBufContent(out
->buffer
),
3732 xmlBufUse(out
->buffer
));
3734 xmlBufShrink(out
->buffer
, ret
);
3737 xmlIOErr(XML_IO_FLUSH
, NULL
);
3738 out
->error
= XML_IO_FLUSH
;
3741 if (out
->written
> INT_MAX
- ret
)
3742 out
->written
= INT_MAX
;
3744 out
->written
+= ret
;
3747 xmlGenericError(xmlGenericErrorContext
,
3748 "I/O: flushed %d chars\n", ret
);
3752 #endif /* LIBXML_OUTPUT_ENABLED */
3755 * xmlParserGetDirectory:
3756 * @filename: the path to a file
3758 * lookup the directory for that file
3760 * Returns a new allocated string containing the directory, or NULL.
3763 xmlParserGetDirectory(const char *filename
) {
3768 #ifdef _WIN32_WCE /* easy way by now ... wince does not have dirs! */
3772 if (xmlInputCallbackInitialized
== 0)
3773 xmlRegisterDefaultInputCallbacks();
3775 if (filename
== NULL
) return(NULL
);
3777 #if defined(_WIN32) && !defined(__CYGWIN__)
3778 # define IS_XMLPGD_SEP(ch) ((ch=='/')||(ch=='\\'))
3780 # define IS_XMLPGD_SEP(ch) (ch=='/')
3783 strncpy(dir
, filename
, 1023);
3785 cur
= &dir
[strlen(dir
)];
3787 if (IS_XMLPGD_SEP(*cur
)) break;
3790 if (IS_XMLPGD_SEP(*cur
)) {
3791 if (cur
== dir
) dir
[1] = 0;
3793 ret
= xmlMemStrdup(dir
);
3795 if (getcwd(dir
, 1024) != NULL
) {
3797 ret
= xmlMemStrdup(dir
);
3801 #undef IS_XMLPGD_SEP
3804 /****************************************************************
3806 * External entities loading *
3808 ****************************************************************/
3811 * xmlCheckHTTPInput:
3812 * @ctxt: an XML parser context
3813 * @ret: an XML parser input
3815 * Check an input in case it was created from an HTTP stream, in that
3816 * case it will handle encoding and update of the base URL in case of
3817 * redirection. It also checks for HTTP errors in which case the input
3818 * is cleanly freed up and an appropriate error is raised in context
3820 * Returns the input or NULL in case of HTTP error.
3823 xmlCheckHTTPInput(xmlParserCtxtPtr ctxt
, xmlParserInputPtr ret
) {
3824 #ifdef LIBXML_HTTP_ENABLED
3825 if ((ret
!= NULL
) && (ret
->buf
!= NULL
) &&
3826 (ret
->buf
->readcallback
== xmlIOHTTPRead
) &&
3827 (ret
->buf
->context
!= NULL
)) {
3828 const char *encoding
;
3833 code
= xmlNanoHTTPReturnCode(ret
->buf
->context
);
3836 if (ret
->filename
!= NULL
)
3837 __xmlLoaderErr(ctxt
, "failed to load HTTP resource \"%s\"\n",
3838 (const char *) ret
->filename
);
3840 __xmlLoaderErr(ctxt
, "failed to load HTTP resource\n", NULL
);
3841 xmlFreeInputStream(ret
);
3845 mime
= xmlNanoHTTPMimeType(ret
->buf
->context
);
3846 if ((xmlStrstr(BAD_CAST mime
, BAD_CAST
"/xml")) ||
3847 (xmlStrstr(BAD_CAST mime
, BAD_CAST
"+xml"))) {
3848 encoding
= xmlNanoHTTPEncoding(ret
->buf
->context
);
3849 if (encoding
!= NULL
) {
3850 xmlCharEncodingHandlerPtr handler
;
3852 handler
= xmlFindCharEncodingHandler(encoding
);
3853 if (handler
!= NULL
) {
3854 xmlSwitchInputEncoding(ctxt
, ret
, handler
);
3856 __xmlErrEncoding(ctxt
, XML_ERR_UNKNOWN_ENCODING
,
3857 "Unknown encoding %s",
3858 BAD_CAST encoding
, NULL
);
3860 if (ret
->encoding
== NULL
)
3861 ret
->encoding
= xmlStrdup(BAD_CAST encoding
);
3864 } else if (xmlStrstr(BAD_CAST mime
, BAD_CAST
"html")) {
3867 redir
= xmlNanoHTTPRedir(ret
->buf
->context
);
3868 if (redir
!= NULL
) {
3869 if (ret
->filename
!= NULL
)
3870 xmlFree((xmlChar
*) ret
->filename
);
3871 if (ret
->directory
!= NULL
) {
3872 xmlFree((xmlChar
*) ret
->directory
);
3873 ret
->directory
= NULL
;
3876 (char *) xmlStrdup((const xmlChar
*) redir
);
3884 static int xmlNoNetExists(const char *URL
) {
3890 if (!xmlStrncasecmp(BAD_CAST URL
, BAD_CAST
"file://localhost/", 17))
3891 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
3896 else if (!xmlStrncasecmp(BAD_CAST URL
, BAD_CAST
"file:///", 8)) {
3897 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
3905 return xmlCheckFilename(path
);
3908 #ifdef LIBXML_CATALOG_ENABLED
3911 * xmlResolveResourceFromCatalog:
3912 * @URL: the URL for the entity to load
3913 * @ID: the System ID for the entity to load
3914 * @ctxt: the context in which the entity is called or NULL
3916 * Resolves the URL and ID against the appropriate catalog.
3917 * This function is used by xmlDefaultExternalEntityLoader and
3918 * xmlNoNetExternalEntityLoader.
3920 * Returns a new allocated URL, or NULL.
3923 xmlResolveResourceFromCatalog(const char *URL
, const char *ID
,
3924 xmlParserCtxtPtr ctxt
) {
3925 xmlChar
*resource
= NULL
;
3926 xmlCatalogAllow pref
;
3929 * If the resource doesn't exists as a file,
3930 * try to load it from the resource pointed in the catalogs
3932 pref
= xmlCatalogGetDefaults();
3934 if ((pref
!= XML_CATA_ALLOW_NONE
) && (!xmlNoNetExists(URL
))) {
3938 if ((ctxt
!= NULL
) && (ctxt
->catalogs
!= NULL
) &&
3939 ((pref
== XML_CATA_ALLOW_ALL
) ||
3940 (pref
== XML_CATA_ALLOW_DOCUMENT
))) {
3941 resource
= xmlCatalogLocalResolve(ctxt
->catalogs
,
3942 (const xmlChar
*)ID
,
3943 (const xmlChar
*)URL
);
3946 * Try a global lookup
3948 if ((resource
== NULL
) &&
3949 ((pref
== XML_CATA_ALLOW_ALL
) ||
3950 (pref
== XML_CATA_ALLOW_GLOBAL
))) {
3951 resource
= xmlCatalogResolve((const xmlChar
*)ID
,
3952 (const xmlChar
*)URL
);
3954 if ((resource
== NULL
) && (URL
!= NULL
))
3955 resource
= xmlStrdup((const xmlChar
*) URL
);
3958 * TODO: do an URI lookup on the reference
3960 if ((resource
!= NULL
) && (!xmlNoNetExists((const char *)resource
))) {
3961 xmlChar
*tmp
= NULL
;
3963 if ((ctxt
!= NULL
) && (ctxt
->catalogs
!= NULL
) &&
3964 ((pref
== XML_CATA_ALLOW_ALL
) ||
3965 (pref
== XML_CATA_ALLOW_DOCUMENT
))) {
3966 tmp
= xmlCatalogLocalResolveURI(ctxt
->catalogs
, resource
);
3968 if ((tmp
== NULL
) &&
3969 ((pref
== XML_CATA_ALLOW_ALL
) ||
3970 (pref
== XML_CATA_ALLOW_GLOBAL
))) {
3971 tmp
= xmlCatalogResolveURI(resource
);
3987 * xmlDefaultExternalEntityLoader:
3988 * @URL: the URL for the entity to load
3989 * @ID: the System ID for the entity to load
3990 * @ctxt: the context in which the entity is called or NULL
3992 * By default we don't load external entities, yet.
3994 * Returns a new allocated xmlParserInputPtr, or NULL.
3996 static xmlParserInputPtr
3997 xmlDefaultExternalEntityLoader(const char *URL
, const char *ID
,
3998 xmlParserCtxtPtr ctxt
)
4000 xmlParserInputPtr ret
= NULL
;
4001 xmlChar
*resource
= NULL
;
4003 #ifdef DEBUG_EXTERNAL_ENTITIES
4004 xmlGenericError(xmlGenericErrorContext
,
4005 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL
);
4007 if ((ctxt
!= NULL
) && (ctxt
->options
& XML_PARSE_NONET
)) {
4008 int options
= ctxt
->options
;
4010 ctxt
->options
-= XML_PARSE_NONET
;
4011 ret
= xmlNoNetExternalEntityLoader(URL
, ID
, ctxt
);
4012 ctxt
->options
= options
;
4015 #ifdef LIBXML_CATALOG_ENABLED
4016 resource
= xmlResolveResourceFromCatalog(URL
, ID
, ctxt
);
4019 if (resource
== NULL
)
4020 resource
= (xmlChar
*) URL
;
4022 if (resource
== NULL
) {
4025 __xmlLoaderErr(ctxt
, "failed to load external entity \"%s\"\n", ID
);
4028 ret
= xmlNewInputFromFile(ctxt
, (const char *) resource
);
4029 if ((resource
!= NULL
) && (resource
!= (xmlChar
*) URL
))
4034 static xmlExternalEntityLoader xmlCurrentExternalEntityLoader
=
4035 xmlDefaultExternalEntityLoader
;
4038 * xmlSetExternalEntityLoader:
4039 * @f: the new entity resolver function
4041 * Changes the defaultexternal entity resolver function for the application
4044 xmlSetExternalEntityLoader(xmlExternalEntityLoader f
) {
4045 xmlCurrentExternalEntityLoader
= f
;
4049 * xmlGetExternalEntityLoader:
4051 * Get the default external entity resolver function for the application
4053 * Returns the xmlExternalEntityLoader function pointer
4055 xmlExternalEntityLoader
4056 xmlGetExternalEntityLoader(void) {
4057 return(xmlCurrentExternalEntityLoader
);
4061 * xmlLoadExternalEntity:
4062 * @URL: the URL for the entity to load
4063 * @ID: the Public ID for the entity to load
4064 * @ctxt: the context in which the entity is called or NULL
4066 * Load an external entity, note that the use of this function for
4067 * unparsed entities may generate problems
4069 * Returns the xmlParserInputPtr or NULL
4072 xmlLoadExternalEntity(const char *URL
, const char *ID
,
4073 xmlParserCtxtPtr ctxt
) {
4074 if ((URL
!= NULL
) && (xmlNoNetExists(URL
) == 0)) {
4075 char *canonicFilename
;
4076 xmlParserInputPtr ret
;
4078 canonicFilename
= (char *) xmlCanonicPath((const xmlChar
*) URL
);
4079 if (canonicFilename
== NULL
) {
4080 xmlIOErrMemory("building canonical path\n");
4084 ret
= xmlCurrentExternalEntityLoader(canonicFilename
, ID
, ctxt
);
4085 xmlFree(canonicFilename
);
4088 return(xmlCurrentExternalEntityLoader(URL
, ID
, ctxt
));
4091 /************************************************************************
4093 * Disabling Network access *
4095 ************************************************************************/
4098 * xmlNoNetExternalEntityLoader:
4099 * @URL: the URL for the entity to load
4100 * @ID: the System ID for the entity to load
4101 * @ctxt: the context in which the entity is called or NULL
4103 * A specific entity loader disabling network accesses, though still
4104 * allowing local catalog accesses for resolution.
4106 * Returns a new allocated xmlParserInputPtr, or NULL.
4109 xmlNoNetExternalEntityLoader(const char *URL
, const char *ID
,
4110 xmlParserCtxtPtr ctxt
) {
4111 xmlParserInputPtr input
= NULL
;
4112 xmlChar
*resource
= NULL
;
4114 #ifdef LIBXML_CATALOG_ENABLED
4115 resource
= xmlResolveResourceFromCatalog(URL
, ID
, ctxt
);
4118 if (resource
== NULL
)
4119 resource
= (xmlChar
*) URL
;
4121 if (resource
!= NULL
) {
4122 if ((!xmlStrncasecmp(BAD_CAST resource
, BAD_CAST
"ftp://", 6)) ||
4123 (!xmlStrncasecmp(BAD_CAST resource
, BAD_CAST
"http://", 7))) {
4124 xmlIOErr(XML_IO_NETWORK_ATTEMPT
, (const char *) resource
);
4125 if (resource
!= (xmlChar
*) URL
)
4130 input
= xmlDefaultExternalEntityLoader((const char *) resource
, ID
, ctxt
);
4131 if (resource
!= (xmlChar
*) URL
)
4136 #define bottom_xmlIO
4137 #include "elfgcchack.h"