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
43 #if defined(_WIN32) && !defined(__CYGWIN__)
44 //#define WIN32_LEAN_AND_MEAN
45 //#include <windows.h>
49 #if defined(_WIN32_WCE)
50 #include <winnls.h> /* for CP_UTF8 */
55 # define S_ISDIR(x) _S_ISDIR(x)
56 # elif defined(S_IFDIR)
58 # define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
59 # elif defined(_S_IFMT)
60 # define S_ISDIR(m) (((m) & _S_IFMT) == S_IFDIR)
65 #include <libxml/xmlmemory.h>
66 #include <libxml/parser.h>
67 #include <libxml/parserInternals.h>
68 #include <libxml/xmlIO.h>
69 #include <libxml/uri.h>
70 #include <libxml/nanohttp.h>
71 #include <libxml/nanoftp.h>
72 #include <libxml/xmlerror.h>
73 #ifdef LIBXML_CATALOG_ENABLED
74 #include <libxml/catalog.h>
76 #include <libxml/globals.h>
81 /* #define VERBOSE_FAILURE */
82 /* #define DEBUG_EXTERNAL_ENTITIES */
83 /* #define DEBUG_INPUT */
92 * Input I/O callback sets
94 typedef struct _xmlInputCallback
{
95 xmlInputMatchCallback matchcallback
;
96 xmlInputOpenCallback opencallback
;
97 xmlInputReadCallback readcallback
;
98 xmlInputCloseCallback closecallback
;
101 #define MAX_INPUT_CALLBACK 15
103 static xmlInputCallback xmlInputCallbackTable
[MAX_INPUT_CALLBACK
];
104 static int xmlInputCallbackNr
= 0;
105 static int xmlInputCallbackInitialized
= 0;
107 #ifdef LIBXML_OUTPUT_ENABLED
109 * Output I/O callback sets
111 typedef struct _xmlOutputCallback
{
112 xmlOutputMatchCallback matchcallback
;
113 xmlOutputOpenCallback opencallback
;
114 xmlOutputWriteCallback writecallback
;
115 xmlOutputCloseCallback closecallback
;
118 #define MAX_OUTPUT_CALLBACK 15
120 static xmlOutputCallback xmlOutputCallbackTable
[MAX_OUTPUT_CALLBACK
];
121 static int xmlOutputCallbackNr
= 0;
122 static int xmlOutputCallbackInitialized
= 0;
125 xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder
);
126 #endif /* LIBXML_OUTPUT_ENABLED */
128 /************************************************************************
130 * Tree memory error handler *
132 ************************************************************************/
134 static const char *IOerr
[] = {
135 "Unknown IO error", /* UNKNOWN */
136 "Permission denied", /* EACCES */
137 "Resource temporarily unavailable",/* EAGAIN */
138 "Bad file descriptor", /* EBADF */
139 "Bad message", /* EBADMSG */
140 "Resource busy", /* EBUSY */
141 "Operation canceled", /* ECANCELED */
142 "No child processes", /* ECHILD */
143 "Resource deadlock avoided",/* EDEADLK */
144 "Domain error", /* EDOM */
145 "File exists", /* EEXIST */
146 "Bad address", /* EFAULT */
147 "File too large", /* EFBIG */
148 "Operation in progress", /* EINPROGRESS */
149 "Interrupted function call",/* EINTR */
150 "Invalid argument", /* EINVAL */
151 "Input/output error", /* EIO */
152 "Is a directory", /* EISDIR */
153 "Too many open files", /* EMFILE */
154 "Too many links", /* EMLINK */
155 "Inappropriate message buffer length",/* EMSGSIZE */
156 "Filename too long", /* ENAMETOOLONG */
157 "Too many open files in system",/* ENFILE */
158 "No such device", /* ENODEV */
159 "No such file or directory",/* ENOENT */
160 "Exec format error", /* ENOEXEC */
161 "No locks available", /* ENOLCK */
162 "Not enough space", /* ENOMEM */
163 "No space left on device", /* ENOSPC */
164 "Function not implemented", /* ENOSYS */
165 "Not a directory", /* ENOTDIR */
166 "Directory not empty", /* ENOTEMPTY */
167 "Not supported", /* ENOTSUP */
168 "Inappropriate I/O control operation",/* ENOTTY */
169 "No such device or address",/* ENXIO */
170 "Operation not permitted", /* EPERM */
171 "Broken pipe", /* EPIPE */
172 "Result too large", /* ERANGE */
173 "Read-only file system", /* EROFS */
174 "Invalid seek", /* ESPIPE */
175 "No such process", /* ESRCH */
176 "Operation timed out", /* ETIMEDOUT */
177 "Improper link", /* EXDEV */
178 "Attempt to load network entity %s", /* XML_IO_NETWORK_ATTEMPT */
179 "encoder error", /* XML_IO_ENCODER */
185 "not a socket", /* ENOTSOCK */
186 "already connected", /* EISCONN */
187 "connection refused", /* ECONNREFUSED */
188 "unreachable network", /* ENETUNREACH */
189 "adddress in use", /* EADDRINUSE */
190 "already in use", /* EALREADY */
191 "unknown address familly", /* EAFNOSUPPORT */
194 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
196 * __xmlIOWin32UTF8ToWChar:
197 * @u8String: uft-8 string
199 * Convert a string from utf-8 to wchar (WINDOWS ONLY!)
202 __xmlIOWin32UTF8ToWChar(const char *u8String
)
204 wchar_t *wString
= NULL
;
208 MultiByteToWideChar(CP_UTF8
, MB_ERR_INVALID_CHARS
, u8String
,
211 wString
= xmlMalloc(wLen
* sizeof(wchar_t));
213 if (MultiByteToWideChar
214 (CP_UTF8
, 0, u8String
, -1, wString
, wLen
) == 0) {
228 * @extra: extra informations
230 * Handle an out of memory condition
233 xmlIOErrMemory(const char *extra
)
235 __xmlSimpleError(XML_FROM_IO
, XML_ERR_NO_MEMORY
, NULL
, NULL
, extra
);
240 * @code: the error number
242 * @extra: extra informations
244 * Handle an I/O error
247 __xmlIOErr(int domain
, int code
, const char *extra
)
253 if (errno
== 0) code
= 0;
255 else if (errno
== EACCES
) code
= XML_IO_EACCES
;
258 else if (errno
== EAGAIN
) code
= XML_IO_EAGAIN
;
261 else if (errno
== EBADF
) code
= XML_IO_EBADF
;
264 else if (errno
== EBADMSG
) code
= XML_IO_EBADMSG
;
267 else if (errno
== EBUSY
) code
= XML_IO_EBUSY
;
270 else if (errno
== ECANCELED
) code
= XML_IO_ECANCELED
;
273 else if (errno
== ECHILD
) code
= XML_IO_ECHILD
;
276 else if (errno
== EDEADLK
) code
= XML_IO_EDEADLK
;
279 else if (errno
== EDOM
) code
= XML_IO_EDOM
;
282 else if (errno
== EEXIST
) code
= XML_IO_EEXIST
;
285 else if (errno
== EFAULT
) code
= XML_IO_EFAULT
;
288 else if (errno
== EFBIG
) code
= XML_IO_EFBIG
;
291 else if (errno
== EINPROGRESS
) code
= XML_IO_EINPROGRESS
;
294 else if (errno
== EINTR
) code
= XML_IO_EINTR
;
297 else if (errno
== EINVAL
) code
= XML_IO_EINVAL
;
300 else if (errno
== EIO
) code
= XML_IO_EIO
;
303 else if (errno
== EISDIR
) code
= XML_IO_EISDIR
;
306 else if (errno
== EMFILE
) code
= XML_IO_EMFILE
;
309 else if (errno
== EMLINK
) code
= XML_IO_EMLINK
;
312 else if (errno
== EMSGSIZE
) code
= XML_IO_EMSGSIZE
;
315 else if (errno
== ENAMETOOLONG
) code
= XML_IO_ENAMETOOLONG
;
318 else if (errno
== ENFILE
) code
= XML_IO_ENFILE
;
321 else if (errno
== ENODEV
) code
= XML_IO_ENODEV
;
324 else if (errno
== ENOENT
) code
= XML_IO_ENOENT
;
327 else if (errno
== ENOEXEC
) code
= XML_IO_ENOEXEC
;
330 else if (errno
== ENOLCK
) code
= XML_IO_ENOLCK
;
333 else if (errno
== ENOMEM
) code
= XML_IO_ENOMEM
;
336 else if (errno
== ENOSPC
) code
= XML_IO_ENOSPC
;
339 else if (errno
== ENOSYS
) code
= XML_IO_ENOSYS
;
342 else if (errno
== ENOTDIR
) code
= XML_IO_ENOTDIR
;
345 else if (errno
== ENOTEMPTY
) code
= XML_IO_ENOTEMPTY
;
348 else if (errno
== ENOTSUP
) code
= XML_IO_ENOTSUP
;
351 else if (errno
== ENOTTY
) code
= XML_IO_ENOTTY
;
354 else if (errno
== ENXIO
) code
= XML_IO_ENXIO
;
357 else if (errno
== EPERM
) code
= XML_IO_EPERM
;
360 else if (errno
== EPIPE
) code
= XML_IO_EPIPE
;
363 else if (errno
== ERANGE
) code
= XML_IO_ERANGE
;
366 else if (errno
== EROFS
) code
= XML_IO_EROFS
;
369 else if (errno
== ESPIPE
) code
= XML_IO_ESPIPE
;
372 else if (errno
== ESRCH
) code
= XML_IO_ESRCH
;
375 else if (errno
== ETIMEDOUT
) code
= XML_IO_ETIMEDOUT
;
378 else if (errno
== EXDEV
) code
= XML_IO_EXDEV
;
381 else if (errno
== ENOTSOCK
) code
= XML_IO_ENOTSOCK
;
384 else if (errno
== EISCONN
) code
= XML_IO_EISCONN
;
387 else if (errno
== ECONNREFUSED
) code
= XML_IO_ECONNREFUSED
;
390 else if (errno
== ETIMEDOUT
) code
= XML_IO_ETIMEDOUT
;
393 else if (errno
== ENETUNREACH
) code
= XML_IO_ENETUNREACH
;
396 else if (errno
== EADDRINUSE
) code
= XML_IO_EADDRINUSE
;
399 else if (errno
== EINPROGRESS
) code
= XML_IO_EINPROGRESS
;
402 else if (errno
== EALREADY
) code
= XML_IO_EALREADY
;
405 else if (errno
== EAFNOSUPPORT
) code
= XML_IO_EAFNOSUPPORT
;
407 else code
= XML_IO_UNKNOWN
;
408 #endif /* HAVE_ERRNO_H */
411 if (code
>= XML_IO_UNKNOWN
) idx
= code
- XML_IO_UNKNOWN
;
412 if (idx
>= (sizeof(IOerr
) / sizeof(IOerr
[0]))) idx
= 0;
414 __xmlSimpleError(domain
, code
, NULL
, IOerr
[idx
], extra
);
419 * @code: the error number
420 * @extra: extra informations
422 * Handle an I/O error
425 xmlIOErr(int code
, const char *extra
)
427 __xmlIOErr(XML_FROM_IO
, code
, extra
);
432 * @ctx: the parser context
433 * @extra: extra informations
435 * Handle a resource access error
438 __xmlLoaderErr(void *ctx
, const char *msg
, const char *filename
)
440 xmlParserCtxtPtr ctxt
= (xmlParserCtxtPtr
) ctx
;
441 xmlStructuredErrorFunc schannel
= NULL
;
442 xmlGenericErrorFunc channel
= NULL
;
444 xmlErrorLevel level
= XML_ERR_ERROR
;
446 if ((ctxt
!= NULL
) && (ctxt
->disableSAX
!= 0) &&
447 (ctxt
->instate
== XML_PARSER_EOF
))
449 if ((ctxt
!= NULL
) && (ctxt
->sax
!= NULL
)) {
450 if (ctxt
->validate
) {
451 channel
= ctxt
->sax
->error
;
452 level
= XML_ERR_ERROR
;
454 channel
= ctxt
->sax
->warning
;
455 level
= XML_ERR_WARNING
;
457 if (ctxt
->sax
->initialized
== XML_SAX2_MAGIC
)
458 schannel
= ctxt
->sax
->serror
;
459 data
= ctxt
->userData
;
461 __xmlRaiseError(schannel
, channel
, data
, ctxt
, NULL
, XML_FROM_IO
,
462 XML_IO_LOAD_ERROR
, level
, NULL
, 0,
463 filename
, NULL
, NULL
, 0, 0,
468 /************************************************************************
470 * Tree memory error handler *
472 ************************************************************************/
474 * xmlNormalizeWindowsPath:
475 * @path: the input file path
477 * This function is obsolete. Please see xmlURIFromPath in uri.c for
480 * Returns a canonicalized version of the path
483 xmlNormalizeWindowsPath(const xmlChar
*path
)
485 return xmlCanonicPath(path
);
489 * xmlCleanupInputCallbacks:
491 * clears the entire input callback table. this includes the
495 xmlCleanupInputCallbacks(void)
499 if (!xmlInputCallbackInitialized
)
502 for (i
= xmlInputCallbackNr
- 1; i
>= 0; i
--) {
503 xmlInputCallbackTable
[i
].matchcallback
= NULL
;
504 xmlInputCallbackTable
[i
].opencallback
= NULL
;
505 xmlInputCallbackTable
[i
].readcallback
= NULL
;
506 xmlInputCallbackTable
[i
].closecallback
= NULL
;
509 xmlInputCallbackNr
= 0;
510 xmlInputCallbackInitialized
= 0;
514 * xmlPopInputCallbacks:
516 * Clear the top input callback from the input stack. this includes the
519 * Returns the number of input callback registered or -1 in case of error.
522 xmlPopInputCallbacks(void)
524 if (!xmlInputCallbackInitialized
)
527 if (xmlInputCallbackNr
<= 0)
530 xmlInputCallbackNr
--;
531 xmlInputCallbackTable
[xmlInputCallbackNr
].matchcallback
= NULL
;
532 xmlInputCallbackTable
[xmlInputCallbackNr
].opencallback
= NULL
;
533 xmlInputCallbackTable
[xmlInputCallbackNr
].readcallback
= NULL
;
534 xmlInputCallbackTable
[xmlInputCallbackNr
].closecallback
= NULL
;
536 return(xmlInputCallbackNr
);
539 #ifdef LIBXML_OUTPUT_ENABLED
541 * xmlCleanupOutputCallbacks:
543 * clears the entire output callback table. this includes the
544 * compiled-in I/O callbacks.
547 xmlCleanupOutputCallbacks(void)
551 if (!xmlOutputCallbackInitialized
)
554 for (i
= xmlOutputCallbackNr
- 1; i
>= 0; i
--) {
555 xmlOutputCallbackTable
[i
].matchcallback
= NULL
;
556 xmlOutputCallbackTable
[i
].opencallback
= NULL
;
557 xmlOutputCallbackTable
[i
].writecallback
= NULL
;
558 xmlOutputCallbackTable
[i
].closecallback
= NULL
;
561 xmlOutputCallbackNr
= 0;
562 xmlOutputCallbackInitialized
= 0;
564 #endif /* LIBXML_OUTPUT_ENABLED */
566 /************************************************************************
568 * Standard I/O for file accesses *
570 ************************************************************************/
572 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
576 * @path: the path in utf-8 encoding
577 * @mode: type of access (0 - read, 1 - write)
579 * function opens the file specified by @path
583 xmlWrapOpenUtf8(const char *path
,int mode
)
588 wPath
= __xmlIOWin32UTF8ToWChar(path
);
591 fd
= _wfopen(wPath
, mode
? L
"wb" : L
"rb");
594 /* maybe path in native encoding */
596 fd
= fopen(path
, mode
? "wb" : "rb");
603 xmlWrapGzOpenUtf8(const char *path
, const char *mode
)
608 fd
= gzopen (path
, mode
);
612 wPath
= __xmlIOWin32UTF8ToWChar(path
);
615 int d
, m
= (strstr(mode
, "r") ? O_RDONLY
: O_RDWR
);
617 m
|= (strstr(mode
, "b") ? _O_BINARY
: 0);
619 d
= _wopen(wPath
, m
);
621 fd
= gzdopen(d
, mode
);
631 * @path: the path in utf-8 encoding
632 * @info: structure that stores results
634 * function obtains information about the file or directory
638 xmlWrapStatUtf8(const char *path
, struct _stat
*info
) {
642 wPath
= __xmlIOWin32UTF8ToWChar(path
);
644 retval
= _wstat(wPath
, info
);
647 /* maybe path in native encoding */
649 retval
= _stat(path
, info
);
657 * @path: the path to check
659 * function checks to see if @path is a valid source
660 * (file, socket...) for XML.
662 * if stat is not available on the target machine,
663 * returns 1. if stat fails, returns 0 (if calling
664 * stat on the filename fails, it can't be right).
665 * if stat succeeds and the file is a directory,
666 * returns 2. otherwise returns 1.
670 xmlCheckFilename (const char *path
)
673 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
674 struct _stat stat_buffer
;
676 struct stat stat_buffer
;
683 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
685 * On Windows stat and wstat do not work with long pathname,
686 * which start with '\\?\'
688 if ((path
[0] == '\\') && (path
[1] == '\\') && (path
[2] == '?') &&
692 if (xmlWrapStatUtf8(path
, &stat_buffer
) == -1)
695 if (stat(path
, &stat_buffer
) == -1)
699 if (S_ISDIR(stat_buffer
.st_mode
))
702 #endif /* HAVE_STAT */
709 * No Operation function, does nothing, no input
720 * @context: the I/O context
721 * @buffer: where to drop data
722 * @len: number of bytes to read
724 * Read @len bytes to @buffer from the I/O channel.
726 * Returns the number of bytes written
729 xmlFdRead (void * context
, char * buffer
, int len
) {
732 ret
= read((int) (ptrdiff_t) context
, &buffer
[0], len
);
733 if (ret
< 0) xmlIOErr(0, "read()");
737 #ifdef LIBXML_OUTPUT_ENABLED
740 * @context: the I/O context
741 * @buffer: where to get data
742 * @len: number of bytes to write
744 * Write @len bytes from @buffer to the I/O channel.
746 * Returns the number of bytes written
749 xmlFdWrite (void * context
, const char * buffer
, int len
) {
753 ret
= write((int) (ptrdiff_t) context
, &buffer
[0], len
);
754 if (ret
< 0) xmlIOErr(0, "write()");
758 #endif /* LIBXML_OUTPUT_ENABLED */
762 * @context: the I/O context
764 * Close an I/O channel
766 * Returns 0 in case of success and error code otherwise
769 xmlFdClose (void * context
) {
771 ret
= close((int) (ptrdiff_t) context
);
772 if (ret
< 0) xmlIOErr(0, "close()");
778 * @filename: the URI for matching
782 * Returns 1 if matches, 0 otherwise
785 xmlFileMatch (const char *filename ATTRIBUTE_UNUSED
) {
791 * @filename: the URI for matching
793 * input from FILE *, supports compressed input
794 * if @filename is " " then the standard input is used
796 * Returns an I/O context or NULL in case of error
799 xmlFileOpen_real (const char *filename
) {
800 const char *path
= filename
;
803 if (filename
== NULL
)
806 if (!strcmp(filename
, "-")) {
811 if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file://localhost/", 17)) {
812 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
813 path
= &filename
[17];
815 path
= &filename
[16];
817 } else if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file:///", 8)) {
818 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
823 } else if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file:/", 6)) {
824 /* lots of generators seems to lazy to read RFC 1738 */
825 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
832 /* Do not check DDNAME on zOS ! */
833 #if !defined(__MVS__)
834 if (!xmlCheckFilename(path
))
838 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
839 fd
= xmlWrapOpenUtf8(path
, 0);
841 fd
= fopen(path
, "r");
843 if (fd
== NULL
) xmlIOErr(0, path
);
849 * @filename: the URI for matching
851 * Wrapper around xmlFileOpen_real that try it with an unescaped
852 * version of @filename, if this fails fallback to @filename
854 * Returns a handler or NULL in case or failure
857 xmlFileOpen (const char *filename
) {
861 retval
= xmlFileOpen_real(filename
);
862 if (retval
== NULL
) {
863 unescaped
= xmlURIUnescapeString(filename
, 0, NULL
);
864 if (unescaped
!= NULL
) {
865 retval
= xmlFileOpen_real(unescaped
);
873 #ifdef LIBXML_OUTPUT_ENABLED
876 * @filename: the URI for matching
878 * output to from FILE *,
879 * if @filename is "-" then the standard output is used
881 * Returns an I/O context or NULL in case of error
884 xmlFileOpenW (const char *filename
) {
885 const char *path
= NULL
;
888 if (!strcmp(filename
, "-")) {
893 if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file://localhost/", 17))
894 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
895 path
= &filename
[17];
897 path
= &filename
[16];
899 else if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file:///", 8)) {
900 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
911 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
912 fd
= xmlWrapOpenUtf8(path
, 1);
914 fd
= fopen(path
, "w");
916 fd
= fopen(path
, "wb");
919 if (fd
== NULL
) xmlIOErr(0, path
);
922 #endif /* LIBXML_OUTPUT_ENABLED */
926 * @context: the I/O context
927 * @buffer: where to drop data
928 * @len: number of bytes to write
930 * Read @len bytes to @buffer from the I/O channel.
932 * Returns the number of bytes written or < 0 in case of failure
935 xmlFileRead (void * context
, char * buffer
, int len
) {
937 if ((context
== NULL
) || (buffer
== NULL
))
939 ret
= fread(&buffer
[0], 1, len
, (FILE *) context
);
940 if (ret
< 0) xmlIOErr(0, "fread()");
944 #ifdef LIBXML_OUTPUT_ENABLED
947 * @context: the I/O context
948 * @buffer: where to drop data
949 * @len: number of bytes to write
951 * Write @len bytes from @buffer to the I/O channel.
953 * Returns the number of bytes written
956 xmlFileWrite (void * context
, const char * buffer
, int len
) {
959 if ((context
== NULL
) || (buffer
== NULL
))
961 items
= fwrite(&buffer
[0], len
, 1, (FILE *) context
);
962 if ((items
== 0) && (ferror((FILE *) context
))) {
963 xmlIOErr(0, "fwrite()");
968 #endif /* LIBXML_OUTPUT_ENABLED */
972 * @context: the I/O context
974 * Close an I/O channel
976 * Returns 0 or -1 in case of error
979 xmlFileClose (void * context
) {
985 fil
= (FILE *) context
;
986 if ((fil
== stdout
) || (fil
== stderr
)) {
989 xmlIOErr(0, "fflush()");
994 ret
= ( fclose((FILE *) context
) == EOF
) ? -1 : 0;
996 xmlIOErr(0, "fclose()");
1002 * @context: the I/O context
1004 * Flush an I/O channel
1007 xmlFileFlush (void * context
) {
1010 if (context
== NULL
)
1012 ret
= ( fflush((FILE *) context
) == EOF
) ? -1 : 0;
1014 xmlIOErr(0, "fflush()");
1018 #ifdef LIBXML_OUTPUT_ENABLED
1021 * @context: the xmlBuffer
1022 * @buffer: the data to write
1023 * @len: number of bytes to write
1025 * Write @len bytes from @buffer to the xml buffer
1027 * Returns the number of bytes written
1030 xmlBufferWrite (void * context
, const char * buffer
, int len
) {
1033 ret
= xmlBufferAdd((xmlBufferPtr
) context
, (const xmlChar
*) buffer
, len
);
1041 /************************************************************************
1043 * I/O for compressed file accesses *
1045 ************************************************************************/
1048 * @filename: the URI for matching
1050 * input from compressed file test
1052 * Returns 1 if matches, 0 otherwise
1055 xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED
) {
1060 * xmlGzfileOpen_real:
1061 * @filename: the URI for matching
1063 * input from compressed file open
1064 * if @filename is " " then the standard input is used
1066 * Returns an I/O context or NULL in case of error
1069 xmlGzfileOpen_real (const char *filename
) {
1070 const char *path
= NULL
;
1073 if (!strcmp(filename
, "-")) {
1074 int duped_fd
= dup(fileno(stdin
));
1075 fd
= gzdopen(duped_fd
, "rb");
1076 if (fd
== Z_NULL
&& duped_fd
>= 0) {
1077 close(duped_fd
); /* gzdOpen() does not close on failure */
1080 return((void *) fd
);
1083 if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file://localhost/", 17))
1084 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
1085 path
= &filename
[17];
1087 path
= &filename
[16];
1089 else if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file:///", 8)) {
1090 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
1091 path
= &filename
[8];
1093 path
= &filename
[7];
1100 if (!xmlCheckFilename(path
))
1103 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
1104 fd
= xmlWrapGzOpenUtf8(path
, "rb");
1106 fd
= gzopen(path
, "rb");
1108 return((void *) fd
);
1113 * @filename: the URI for matching
1115 * Wrapper around xmlGzfileOpen if the open fais, it will
1116 * try to unescape @filename
1119 xmlGzfileOpen (const char *filename
) {
1123 retval
= xmlGzfileOpen_real(filename
);
1124 if (retval
== NULL
) {
1125 unescaped
= xmlURIUnescapeString(filename
, 0, NULL
);
1126 if (unescaped
!= NULL
) {
1127 retval
= xmlGzfileOpen_real(unescaped
);
1134 #ifdef LIBXML_OUTPUT_ENABLED
1137 * @filename: the URI for matching
1138 * @compression: the compression factor (0 - 9 included)
1140 * input from compressed file open
1141 * if @filename is " " then the standard input is used
1143 * Returns an I/O context or NULL in case of error
1146 xmlGzfileOpenW (const char *filename
, int compression
) {
1147 const char *path
= NULL
;
1151 snprintf(mode
, sizeof(mode
), "wb%d", compression
);
1152 if (!strcmp(filename
, "-")) {
1153 int duped_fd
= dup(fileno(stdout
));
1154 fd
= gzdopen(duped_fd
, "rb");
1155 if (fd
== Z_NULL
&& duped_fd
>= 0) {
1156 close(duped_fd
); /* gzdOpen() does not close on failure */
1159 return((void *) fd
);
1162 if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file://localhost/", 17))
1163 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
1164 path
= &filename
[17];
1166 path
= &filename
[16];
1168 else if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file:///", 8)) {
1169 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
1170 path
= &filename
[8];
1172 path
= &filename
[7];
1180 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
1181 fd
= xmlWrapGzOpenUtf8(path
, mode
);
1183 fd
= gzopen(path
, mode
);
1185 return((void *) fd
);
1187 #endif /* LIBXML_OUTPUT_ENABLED */
1191 * @context: the I/O context
1192 * @buffer: where to drop data
1193 * @len: number of bytes to write
1195 * Read @len bytes to @buffer from the compressed I/O channel.
1197 * Returns the number of bytes read.
1200 xmlGzfileRead (void * context
, char * buffer
, int len
) {
1203 ret
= gzread((gzFile
) context
, &buffer
[0], len
);
1204 if (ret
< 0) xmlIOErr(0, "gzread()");
1208 #ifdef LIBXML_OUTPUT_ENABLED
1211 * @context: the I/O context
1212 * @buffer: where to drop data
1213 * @len: number of bytes to write
1215 * Write @len bytes from @buffer to the compressed I/O channel.
1217 * Returns the number of bytes written
1220 xmlGzfileWrite (void * context
, const char * buffer
, int len
) {
1223 ret
= gzwrite((gzFile
) context
, (char *) &buffer
[0], len
);
1224 if (ret
< 0) xmlIOErr(0, "gzwrite()");
1227 #endif /* LIBXML_OUTPUT_ENABLED */
1231 * @context: the I/O context
1233 * Close a compressed I/O channel
1236 xmlGzfileClose (void * context
) {
1239 ret
= (gzclose((gzFile
) context
) == Z_OK
) ? 0 : -1;
1240 if (ret
< 0) xmlIOErr(0, "gzclose()");
1243 #endif /* HAVE_ZLIB_H */
1245 #ifdef LIBXML_LZMA_ENABLED
1246 /************************************************************************
1248 * I/O for compressed file accesses *
1250 ************************************************************************/
1254 * @filename: the URI for matching
1256 * input from compressed file test
1258 * Returns 1 if matches, 0 otherwise
1261 xmlXzfileMatch (const char *filename ATTRIBUTE_UNUSED
) {
1266 * xmlXzFileOpen_real:
1267 * @filename: the URI for matching
1269 * input from compressed file open
1270 * if @filename is " " then the standard input is used
1272 * Returns an I/O context or NULL in case of error
1275 xmlXzfileOpen_real (const char *filename
) {
1276 const char *path
= NULL
;
1279 if (!strcmp(filename
, "-")) {
1280 fd
= __libxml2_xzdopen(dup(fileno(stdin
)), "rb");
1281 return((void *) fd
);
1284 if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file://localhost/", 17)) {
1285 path
= &filename
[16];
1286 } else if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file:///", 8)) {
1287 path
= &filename
[7];
1288 } else if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file:/", 6)) {
1289 /* lots of generators seems to lazy to read RFC 1738 */
1290 path
= &filename
[5];
1296 if (!xmlCheckFilename(path
))
1299 fd
= __libxml2_xzopen(path
, "rb");
1300 return((void *) fd
);
1305 * @filename: the URI for matching
1307 * Wrapper around xmlXzfileOpen_real that try it with an unescaped
1308 * version of @filename, if this fails fallback to @filename
1310 * Returns a handler or NULL in case or failure
1313 xmlXzfileOpen (const char *filename
) {
1317 retval
= xmlXzfileOpen_real(filename
);
1318 if (retval
== NULL
) {
1319 unescaped
= xmlURIUnescapeString(filename
, 0, NULL
);
1320 if (unescaped
!= NULL
) {
1321 retval
= xmlXzfileOpen_real(unescaped
);
1331 * @context: the I/O context
1332 * @buffer: where to drop data
1333 * @len: number of bytes to write
1335 * Read @len bytes to @buffer from the compressed I/O channel.
1337 * Returns the number of bytes written
1340 xmlXzfileRead (void * context
, char * buffer
, int len
) {
1343 ret
= __libxml2_xzread((xzFile
) context
, &buffer
[0], len
);
1344 if (ret
< 0) xmlIOErr(0, "xzread()");
1350 * @context: the I/O context
1352 * Close a compressed I/O channel
1355 xmlXzfileClose (void * context
) {
1358 ret
= (__libxml2_xzclose((xzFile
) context
) == LZMA_OK
) ? 0 : -1;
1359 if (ret
< 0) xmlIOErr(0, "xzclose()");
1362 #endif /* LIBXML_LZMA_ENABLED */
1364 #ifdef LIBXML_HTTP_ENABLED
1365 /************************************************************************
1367 * I/O for HTTP file accesses *
1369 ************************************************************************/
1371 #ifdef LIBXML_OUTPUT_ENABLED
1372 typedef struct xmlIOHTTPWriteCtxt_
1380 } xmlIOHTTPWriteCtxt
, *xmlIOHTTPWriteCtxtPtr
;
1384 #define DFLT_WBITS ( -15 )
1385 #define DFLT_MEM_LVL ( 8 )
1386 #define GZ_MAGIC1 ( 0x1f )
1387 #define GZ_MAGIC2 ( 0x8b )
1388 #define LXML_ZLIB_OS_CODE ( 0x03 )
1389 #define INIT_HTTP_BUFF_SIZE ( 32768 )
1390 #define DFLT_ZLIB_RATIO ( 5 )
1393 ** Data structure and functions to work with sending compressed data
1397 typedef struct xmlZMemBuff_
1402 unsigned char * zbuff
;
1405 } xmlZMemBuff
, *xmlZMemBuffPtr
;
1408 * append_reverse_ulong
1409 * @buff: Compressed memory buffer
1410 * @data: Unsigned long to append
1412 * Append a unsigned long in reverse byte order to the end of the
1416 append_reverse_ulong( xmlZMemBuff
* buff
, unsigned long data
) {
1424 ** This is plagiarized from putLong in gzio.c (zlib source) where
1425 ** the number "4" is hardcoded. If zlib is ever patched to
1426 ** support 64 bit file sizes, this code would need to be patched
1430 for ( idx
= 0; idx
< 4; idx
++ ) {
1431 *buff
->zctrl
.next_out
= ( data
& 0xff );
1433 buff
->zctrl
.next_out
++;
1442 * @buff: The memory buffer context to clear
1444 * Release all the resources associated with the compressed memory buffer.
1447 xmlFreeZMemBuff( xmlZMemBuffPtr buff
) {
1456 xmlFree( buff
->zbuff
);
1458 z_err
= deflateEnd( &buff
->zctrl
);
1459 if ( z_err
!= Z_OK
)
1460 xmlGenericError( xmlGenericErrorContext
,
1461 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
1464 deflateEnd( &buff
->zctrl
);
1473 *@compression: Compression value to use
1475 * Create a memory buffer to hold the compressed XML document. The
1476 * compressed document in memory will end up being identical to what
1477 * would be created if gzopen/gzwrite/gzclose were being used to
1478 * write the document to disk. The code for the header/trailer data to
1479 * the compression is plagiarized from the zlib source files.
1482 xmlCreateZMemBuff( int compression
) {
1486 xmlZMemBuffPtr buff
= NULL
;
1488 if ( ( compression
< 1 ) || ( compression
> 9 ) )
1491 /* Create the control and data areas */
1493 buff
= xmlMalloc( sizeof( xmlZMemBuff
) );
1494 if ( buff
== NULL
) {
1495 xmlIOErrMemory("creating buffer context");
1499 (void)memset( buff
, 0, sizeof( xmlZMemBuff
) );
1500 buff
->size
= INIT_HTTP_BUFF_SIZE
;
1501 buff
->zbuff
= xmlMalloc( buff
->size
);
1502 if ( buff
->zbuff
== NULL
) {
1503 xmlFreeZMemBuff( buff
);
1504 xmlIOErrMemory("creating buffer");
1508 z_err
= deflateInit2( &buff
->zctrl
, compression
, Z_DEFLATED
,
1509 DFLT_WBITS
, DFLT_MEM_LVL
, Z_DEFAULT_STRATEGY
);
1510 if ( z_err
!= Z_OK
) {
1512 xmlFreeZMemBuff( buff
);
1514 xmlStrPrintf(msg
, 500,
1515 "xmlCreateZMemBuff: %s %d\n",
1516 "Error initializing compression context. ZLIB error:",
1518 xmlIOErr(XML_IO_WRITE
, (const char *) msg
);
1522 /* Set the header data. The CRC will be needed for the trailer */
1523 buff
->crc
= crc32( 0L, NULL
, 0 );
1524 hdr_lgth
= snprintf( (char *)buff
->zbuff
, buff
->size
,
1525 "%c%c%c%c%c%c%c%c%c%c",
1526 GZ_MAGIC1
, GZ_MAGIC2
, Z_DEFLATED
,
1527 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE
);
1528 buff
->zctrl
.next_out
= buff
->zbuff
+ hdr_lgth
;
1529 buff
->zctrl
.avail_out
= buff
->size
- hdr_lgth
;
1536 * @buff: Buffer used to compress and consolidate data.
1537 * @ext_amt: Number of bytes to extend the buffer.
1539 * Extend the internal buffer used to store the compressed data by the
1542 * Returns 0 on success or -1 on failure to extend the buffer. On failure
1543 * the original buffer still exists at the original size.
1546 xmlZMemBuffExtend( xmlZMemBuffPtr buff
, size_t ext_amt
) {
1552 unsigned char * tmp_ptr
= NULL
;
1557 else if ( ext_amt
== 0 )
1560 cur_used
= buff
->zctrl
.next_out
- buff
->zbuff
;
1561 new_size
= buff
->size
+ ext_amt
;
1564 if ( cur_used
> new_size
)
1565 xmlGenericError( xmlGenericErrorContext
,
1566 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
1567 "Buffer overwrite detected during compressed memory",
1568 "buffer extension. Overflowed by",
1569 (cur_used
- new_size
) );
1572 tmp_ptr
= xmlRealloc( buff
->zbuff
, new_size
);
1573 if ( tmp_ptr
!= NULL
) {
1575 buff
->size
= new_size
;
1576 buff
->zbuff
= tmp_ptr
;
1577 buff
->zctrl
.next_out
= tmp_ptr
+ cur_used
;
1578 buff
->zctrl
.avail_out
= new_size
- cur_used
;
1582 xmlStrPrintf(msg
, 500,
1583 "xmlZMemBuffExtend: %s %lu bytes.\n",
1584 "Allocation failure extending output buffer to",
1585 (unsigned long) new_size
);
1586 xmlIOErr(XML_IO_WRITE
, (const char *) msg
);
1594 * @buff: Buffer used to compress and consolidate data
1595 * @src: Uncompressed source content to append to buffer
1596 * @len: Length of source data to append to buffer
1598 * Compress and append data to the internal buffer. The data buffer
1599 * will be expanded if needed to store the additional data.
1601 * Returns the number of bytes appended to the buffer or -1 on error.
1604 xmlZMemBuffAppend( xmlZMemBuffPtr buff
, const char * src
, int len
) {
1609 if ( ( buff
== NULL
) || ( src
== NULL
) )
1612 buff
->zctrl
.avail_in
= len
;
1613 buff
->zctrl
.next_in
= (unsigned char *)src
;
1614 while ( buff
->zctrl
.avail_in
> 0 ) {
1616 ** Extend the buffer prior to deflate call if a reasonable amount
1617 ** of output buffer space is not available.
1619 min_accept
= buff
->zctrl
.avail_in
/ DFLT_ZLIB_RATIO
;
1620 if ( buff
->zctrl
.avail_out
<= min_accept
) {
1621 if ( xmlZMemBuffExtend( buff
, buff
->size
) == -1 )
1625 z_err
= deflate( &buff
->zctrl
, Z_NO_FLUSH
);
1626 if ( z_err
!= Z_OK
) {
1628 xmlStrPrintf(msg
, 500,
1629 "xmlZMemBuffAppend: %s %d %s - %d",
1630 "Compression error while appending",
1631 len
, "bytes to buffer. ZLIB error", z_err
);
1632 xmlIOErr(XML_IO_WRITE
, (const char *) msg
);
1637 buff
->crc
= crc32( buff
->crc
, (unsigned char *)src
, len
);
1643 * xmlZMemBuffGetContent
1644 * @buff: Compressed memory content buffer
1645 * @data_ref: Pointer reference to point to compressed content
1647 * Flushes the compression buffers, appends gzip file trailers and
1648 * returns the compressed content and length of the compressed data.
1649 * NOTE: The gzip trailer code here is plagiarized from zlib source.
1651 * Returns the length of the compressed data or -1 on error.
1654 xmlZMemBuffGetContent( xmlZMemBuffPtr buff
, char ** data_ref
) {
1659 if ( ( buff
== NULL
) || ( data_ref
== NULL
) )
1662 /* Need to loop until compression output buffers are flushed */
1666 z_err
= deflate( &buff
->zctrl
, Z_FINISH
);
1667 if ( z_err
== Z_OK
) {
1668 /* In this case Z_OK means more buffer space needed */
1670 if ( xmlZMemBuffExtend( buff
, buff
->size
) == -1 )
1674 while ( z_err
== Z_OK
);
1676 /* If the compression state is not Z_STREAM_END, some error occurred */
1678 if ( z_err
== Z_STREAM_END
) {
1680 /* Need to append the gzip data trailer */
1682 if ( buff
->zctrl
.avail_out
< ( 2 * sizeof( unsigned long ) ) ) {
1683 if ( xmlZMemBuffExtend(buff
, (2 * sizeof(unsigned long))) == -1 )
1688 ** For whatever reason, the CRC and length data are pushed out
1689 ** in reverse byte order. So a memcpy can't be used here.
1692 append_reverse_ulong( buff
, buff
->crc
);
1693 append_reverse_ulong( buff
, buff
->zctrl
.total_in
);
1695 zlgth
= buff
->zctrl
.next_out
- buff
->zbuff
;
1696 *data_ref
= (char *)buff
->zbuff
;
1701 xmlStrPrintf(msg
, 500,
1702 "xmlZMemBuffGetContent: %s - %d\n",
1703 "Error flushing zlib buffers. Error code", z_err
);
1704 xmlIOErr(XML_IO_WRITE
, (const char *) msg
);
1709 #endif /* LIBXML_OUTPUT_ENABLED */
1710 #endif /* HAVE_ZLIB_H */
1712 #ifdef LIBXML_OUTPUT_ENABLED
1714 * xmlFreeHTTPWriteCtxt
1715 * @ctxt: Context to cleanup
1717 * Free allocated memory and reclaim system resources.
1722 xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt
)
1724 if ( ctxt
->uri
!= NULL
)
1725 xmlFree( ctxt
->uri
);
1727 if ( ctxt
->doc_buff
!= NULL
) {
1730 if ( ctxt
->compression
> 0 ) {
1731 xmlFreeZMemBuff( ctxt
->doc_buff
);
1736 xmlOutputBufferClose( ctxt
->doc_buff
);
1743 #endif /* LIBXML_OUTPUT_ENABLED */
1748 * @filename: the URI for matching
1750 * check if the URI matches an HTTP one
1752 * Returns 1 if matches, 0 otherwise
1755 xmlIOHTTPMatch (const char *filename
) {
1756 if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"http://", 7))
1763 * @filename: the URI for matching
1765 * open an HTTP I/O channel
1767 * Returns an I/O context or NULL in case of error
1770 xmlIOHTTPOpen (const char *filename
) {
1771 return(xmlNanoHTTPOpen(filename
, NULL
));
1774 #ifdef LIBXML_OUTPUT_ENABLED
1777 * @post_uri: The destination URI for the document
1778 * @compression: The compression desired for the document.
1780 * Open a temporary buffer to collect the document for a subsequent HTTP POST
1781 * request. Non-static as is called from the output buffer creation routine.
1783 * Returns an I/O context or NULL in case of error.
1787 xmlIOHTTPOpenW(const char *post_uri
, int compression ATTRIBUTE_UNUSED
)
1790 xmlIOHTTPWriteCtxtPtr ctxt
= NULL
;
1792 if (post_uri
== NULL
)
1795 ctxt
= xmlMalloc(sizeof(xmlIOHTTPWriteCtxt
));
1797 xmlIOErrMemory("creating HTTP output context");
1801 (void) memset(ctxt
, 0, sizeof(xmlIOHTTPWriteCtxt
));
1803 ctxt
->uri
= (char *) xmlStrdup((const xmlChar
*)post_uri
);
1804 if (ctxt
->uri
== NULL
) {
1805 xmlIOErrMemory("copying URI");
1806 xmlFreeHTTPWriteCtxt(ctxt
);
1811 * ** Since the document length is required for an HTTP post,
1812 * ** need to put the document into a buffer. A memory buffer
1813 * ** is being used to avoid pushing the data to disk and back.
1817 if ((compression
> 0) && (compression
<= 9)) {
1819 ctxt
->compression
= compression
;
1820 ctxt
->doc_buff
= xmlCreateZMemBuff(compression
);
1824 /* Any character conversions should have been done before this */
1826 ctxt
->doc_buff
= xmlAllocOutputBufferInternal(NULL
);
1829 if (ctxt
->doc_buff
== NULL
) {
1830 xmlFreeHTTPWriteCtxt(ctxt
);
1836 #endif /* LIBXML_OUTPUT_ENABLED */
1838 #ifdef LIBXML_OUTPUT_ENABLED
1840 * xmlIOHTTPDfltOpenW
1841 * @post_uri: The destination URI for this document.
1843 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
1844 * HTTP post command. This function should generally not be used as
1845 * the open callback is short circuited in xmlOutputBufferCreateFile.
1847 * Returns a pointer to the new IO context.
1850 xmlIOHTTPDfltOpenW( const char * post_uri
) {
1851 return ( xmlIOHTTPOpenW( post_uri
, 0 ) );
1853 #endif /* LIBXML_OUTPUT_ENABLED */
1857 * @context: the I/O context
1858 * @buffer: where to drop data
1859 * @len: number of bytes to write
1861 * Read @len bytes to @buffer from the I/O channel.
1863 * Returns the number of bytes written
1866 xmlIOHTTPRead(void * context
, char * buffer
, int len
) {
1867 if ((buffer
== NULL
) || (len
< 0)) return(-1);
1868 return(xmlNanoHTTPRead(context
, &buffer
[0], len
));
1871 #ifdef LIBXML_OUTPUT_ENABLED
1874 * @context: previously opened writing context
1875 * @buffer: data to output to temporary buffer
1876 * @len: bytes to output
1878 * Collect data from memory buffer into a temporary file for later
1881 * Returns number of bytes written.
1885 xmlIOHTTPWrite( void * context
, const char * buffer
, int len
) {
1887 xmlIOHTTPWriteCtxtPtr ctxt
= context
;
1889 if ( ( ctxt
== NULL
) || ( ctxt
->doc_buff
== NULL
) || ( buffer
== NULL
) )
1894 /* Use gzwrite or fwrite as previously setup in the open call */
1897 if ( ctxt
->compression
> 0 )
1898 len
= xmlZMemBuffAppend( ctxt
->doc_buff
, buffer
, len
);
1902 len
= xmlOutputBufferWrite( ctxt
->doc_buff
, len
, buffer
);
1906 xmlStrPrintf(msg
, 500,
1907 "xmlIOHTTPWrite: %s\n%s '%s'.\n",
1908 "Error appending to internal buffer.",
1909 "Error sending document to URI",
1911 xmlIOErr(XML_IO_WRITE
, (const char *) msg
);
1917 #endif /* LIBXML_OUTPUT_ENABLED */
1922 * @context: the I/O context
1924 * Close an HTTP I/O channel
1929 xmlIOHTTPClose (void * context
) {
1930 xmlNanoHTTPClose(context
);
1934 #ifdef LIBXML_OUTPUT_ENABLED
1936 * xmlIOHTTCloseWrite
1937 * @context: The I/O context
1938 * @http_mthd: The HTTP method to be used when sending the data
1940 * Close the transmit HTTP I/O channel and actually send the data.
1943 xmlIOHTTPCloseWrite( void * context
, const char * http_mthd
) {
1947 int content_lgth
= 0;
1948 xmlIOHTTPWriteCtxtPtr ctxt
= context
;
1950 char * http_content
= NULL
;
1951 char * content_encoding
= NULL
;
1952 char * content_type
= (char *) "text/xml";
1953 void * http_ctxt
= NULL
;
1955 if ( ( ctxt
== NULL
) || ( http_mthd
== NULL
) )
1958 /* Retrieve the content from the appropriate buffer */
1962 if ( ctxt
->compression
> 0 ) {
1963 content_lgth
= xmlZMemBuffGetContent( ctxt
->doc_buff
, &http_content
);
1964 content_encoding
= (char *) "Content-Encoding: gzip";
1969 /* Pull the data out of the memory output buffer */
1971 xmlOutputBufferPtr dctxt
= ctxt
->doc_buff
;
1972 http_content
= (char *) xmlBufContent(dctxt
->buffer
);
1973 content_lgth
= xmlBufUse(dctxt
->buffer
);
1976 if ( http_content
== NULL
) {
1978 xmlStrPrintf(msg
, 500,
1979 "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
1980 "Error retrieving content.\nUnable to",
1981 http_mthd
, "data to URI", ctxt
->uri
);
1982 xmlIOErr(XML_IO_WRITE
, (const char *) msg
);
1987 http_ctxt
= xmlNanoHTTPMethod( ctxt
->uri
, http_mthd
, http_content
,
1988 &content_type
, content_encoding
,
1991 if ( http_ctxt
!= NULL
) {
1993 /* If testing/debugging - dump reply with request content */
1995 FILE * tst_file
= NULL
;
1996 char buffer
[ 4096 ];
1997 char * dump_name
= NULL
;
2000 xmlGenericError( xmlGenericErrorContext
,
2001 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
2002 http_mthd
, ctxt
->uri
,
2003 xmlNanoHTTPReturnCode( http_ctxt
) );
2006 ** Since either content or reply may be gzipped,
2007 ** dump them to separate files instead of the
2008 ** standard error context.
2011 dump_name
= tempnam( NULL
, "lxml" );
2012 if ( dump_name
!= NULL
) {
2013 (void)snprintf( buffer
, sizeof(buffer
), "%s.content", dump_name
);
2015 tst_file
= fopen( buffer
, "wb" );
2016 if ( tst_file
!= NULL
) {
2017 xmlGenericError( xmlGenericErrorContext
,
2018 "Transmitted content saved in file: %s\n", buffer
);
2020 fwrite( http_content
, sizeof( char ),
2021 content_lgth
, tst_file
);
2025 (void)snprintf( buffer
, sizeof(buffer
), "%s.reply", dump_name
);
2026 tst_file
= fopen( buffer
, "wb" );
2027 if ( tst_file
!= NULL
) {
2028 xmlGenericError( xmlGenericErrorContext
,
2029 "Reply content saved in file: %s\n", buffer
);
2032 while ( (avail
= xmlNanoHTTPRead( http_ctxt
,
2033 buffer
, sizeof( buffer
) )) > 0 ) {
2035 fwrite( buffer
, sizeof( char ), avail
, tst_file
);
2043 #endif /* DEBUG_HTTP */
2045 http_rtn
= xmlNanoHTTPReturnCode( http_ctxt
);
2046 if ( ( http_rtn
>= 200 ) && ( http_rtn
< 300 ) )
2050 xmlStrPrintf(msg
, 500,
2051 "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
2052 http_mthd
, content_lgth
,
2053 "bytes to URI", ctxt
->uri
,
2054 "failed. HTTP return code:", http_rtn
);
2055 xmlIOErr(XML_IO_WRITE
, (const char *) msg
);
2058 xmlNanoHTTPClose( http_ctxt
);
2059 xmlFree( content_type
);
2063 /* Final cleanups */
2065 xmlFreeHTTPWriteCtxt( ctxt
);
2067 return ( close_rc
);
2073 * @context: The I/O context
2075 * Close the transmit HTTP I/O channel and actually send data using a PUT
2079 xmlIOHTTPClosePut( void * ctxt
) {
2080 return ( xmlIOHTTPCloseWrite( ctxt
, "PUT" ) );
2085 * xmlIOHTTPClosePost
2087 * @context: The I/O context
2089 * Close the transmit HTTP I/O channel and actually send data using a POST
2093 xmlIOHTTPClosePost( void * ctxt
) {
2094 return ( xmlIOHTTPCloseWrite( ctxt
, "POST" ) );
2096 #endif /* LIBXML_OUTPUT_ENABLED */
2098 #endif /* LIBXML_HTTP_ENABLED */
2100 #ifdef LIBXML_FTP_ENABLED
2101 /************************************************************************
2103 * I/O for FTP file accesses *
2105 ************************************************************************/
2108 * @filename: the URI for matching
2110 * check if the URI matches an FTP one
2112 * Returns 1 if matches, 0 otherwise
2115 xmlIOFTPMatch (const char *filename
) {
2116 if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"ftp://", 6))
2123 * @filename: the URI for matching
2125 * open an FTP I/O channel
2127 * Returns an I/O context or NULL in case of error
2130 xmlIOFTPOpen (const char *filename
) {
2131 return(xmlNanoFTPOpen(filename
));
2136 * @context: the I/O context
2137 * @buffer: where to drop data
2138 * @len: number of bytes to write
2140 * Read @len bytes to @buffer from the I/O channel.
2142 * Returns the number of bytes written
2145 xmlIOFTPRead(void * context
, char * buffer
, int len
) {
2146 if ((buffer
== NULL
) || (len
< 0)) return(-1);
2147 return(xmlNanoFTPRead(context
, &buffer
[0], len
));
2152 * @context: the I/O context
2154 * Close an FTP I/O channel
2159 xmlIOFTPClose (void * context
) {
2160 return ( xmlNanoFTPClose(context
) );
2162 #endif /* LIBXML_FTP_ENABLED */
2166 * xmlRegisterInputCallbacks:
2167 * @matchFunc: the xmlInputMatchCallback
2168 * @openFunc: the xmlInputOpenCallback
2169 * @readFunc: the xmlInputReadCallback
2170 * @closeFunc: the xmlInputCloseCallback
2172 * Register a new set of I/O callback for handling parser input.
2174 * Returns the registered handler number or -1 in case of error
2177 xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc
,
2178 xmlInputOpenCallback openFunc
, xmlInputReadCallback readFunc
,
2179 xmlInputCloseCallback closeFunc
) {
2180 if (xmlInputCallbackNr
>= MAX_INPUT_CALLBACK
) {
2183 xmlInputCallbackTable
[xmlInputCallbackNr
].matchcallback
= matchFunc
;
2184 xmlInputCallbackTable
[xmlInputCallbackNr
].opencallback
= openFunc
;
2185 xmlInputCallbackTable
[xmlInputCallbackNr
].readcallback
= readFunc
;
2186 xmlInputCallbackTable
[xmlInputCallbackNr
].closecallback
= closeFunc
;
2187 xmlInputCallbackInitialized
= 1;
2188 return(xmlInputCallbackNr
++);
2191 #ifdef LIBXML_OUTPUT_ENABLED
2193 * xmlRegisterOutputCallbacks:
2194 * @matchFunc: the xmlOutputMatchCallback
2195 * @openFunc: the xmlOutputOpenCallback
2196 * @writeFunc: the xmlOutputWriteCallback
2197 * @closeFunc: the xmlOutputCloseCallback
2199 * Register a new set of I/O callback for handling output.
2201 * Returns the registered handler number or -1 in case of error
2204 xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc
,
2205 xmlOutputOpenCallback openFunc
, xmlOutputWriteCallback writeFunc
,
2206 xmlOutputCloseCallback closeFunc
) {
2207 if (xmlOutputCallbackNr
>= MAX_OUTPUT_CALLBACK
) {
2210 xmlOutputCallbackTable
[xmlOutputCallbackNr
].matchcallback
= matchFunc
;
2211 xmlOutputCallbackTable
[xmlOutputCallbackNr
].opencallback
= openFunc
;
2212 xmlOutputCallbackTable
[xmlOutputCallbackNr
].writecallback
= writeFunc
;
2213 xmlOutputCallbackTable
[xmlOutputCallbackNr
].closecallback
= closeFunc
;
2214 xmlOutputCallbackInitialized
= 1;
2215 return(xmlOutputCallbackNr
++);
2217 #endif /* LIBXML_OUTPUT_ENABLED */
2220 * xmlRegisterDefaultInputCallbacks:
2222 * Registers the default compiled-in I/O handlers.
2225 xmlRegisterDefaultInputCallbacks(void) {
2226 if (xmlInputCallbackInitialized
)
2229 xmlRegisterInputCallbacks(xmlFileMatch
, xmlFileOpen
,
2230 xmlFileRead
, xmlFileClose
);
2232 xmlRegisterInputCallbacks(xmlGzfileMatch
, xmlGzfileOpen
,
2233 xmlGzfileRead
, xmlGzfileClose
);
2234 #endif /* HAVE_ZLIB_H */
2235 #ifdef LIBXML_LZMA_ENABLED
2236 xmlRegisterInputCallbacks(xmlXzfileMatch
, xmlXzfileOpen
,
2237 xmlXzfileRead
, xmlXzfileClose
);
2238 #endif /* LIBXML_LZMA_ENABLED */
2240 #ifdef LIBXML_HTTP_ENABLED
2241 xmlRegisterInputCallbacks(xmlIOHTTPMatch
, xmlIOHTTPOpen
,
2242 xmlIOHTTPRead
, xmlIOHTTPClose
);
2243 #endif /* LIBXML_HTTP_ENABLED */
2245 #ifdef LIBXML_FTP_ENABLED
2246 xmlRegisterInputCallbacks(xmlIOFTPMatch
, xmlIOFTPOpen
,
2247 xmlIOFTPRead
, xmlIOFTPClose
);
2248 #endif /* LIBXML_FTP_ENABLED */
2249 xmlInputCallbackInitialized
= 1;
2252 #ifdef LIBXML_OUTPUT_ENABLED
2254 * xmlRegisterDefaultOutputCallbacks:
2256 * Registers the default compiled-in I/O handlers.
2259 xmlRegisterDefaultOutputCallbacks (void) {
2260 if (xmlOutputCallbackInitialized
)
2263 xmlRegisterOutputCallbacks(xmlFileMatch
, xmlFileOpenW
,
2264 xmlFileWrite
, xmlFileClose
);
2266 #ifdef LIBXML_HTTP_ENABLED
2267 xmlRegisterOutputCallbacks(xmlIOHTTPMatch
, xmlIOHTTPDfltOpenW
,
2268 xmlIOHTTPWrite
, xmlIOHTTPClosePut
);
2271 /*********************************
2272 No way a-priori to distinguish between gzipped files from
2273 uncompressed ones except opening if existing then closing
2274 and saving with same compression ratio ... a pain.
2277 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
2278 xmlGzfileWrite, xmlGzfileClose);
2282 #ifdef LIBXML_FTP_ENABLED
2283 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
2284 xmlIOFTPWrite, xmlIOFTPClose);
2286 **********************************/
2287 xmlOutputCallbackInitialized
= 1;
2290 #ifdef LIBXML_HTTP_ENABLED
2292 * xmlRegisterHTTPPostCallbacks:
2294 * By default, libxml submits HTTP output requests using the "PUT" method.
2295 * Calling this method changes the HTTP output method to use the "POST"
2300 xmlRegisterHTTPPostCallbacks( void ) {
2302 /* Register defaults if not done previously */
2304 if ( xmlOutputCallbackInitialized
== 0 )
2305 xmlRegisterDefaultOutputCallbacks( );
2307 xmlRegisterOutputCallbacks(xmlIOHTTPMatch
, xmlIOHTTPDfltOpenW
,
2308 xmlIOHTTPWrite
, xmlIOHTTPClosePost
);
2312 #endif /* LIBXML_OUTPUT_ENABLED */
2315 * xmlAllocParserInputBuffer:
2316 * @enc: the charset encoding if known
2318 * Create a buffered parser input for progressive parsing
2320 * Returns the new parser input or NULL
2322 xmlParserInputBufferPtr
2323 xmlAllocParserInputBuffer(xmlCharEncoding enc
) {
2324 xmlParserInputBufferPtr ret
;
2326 ret
= (xmlParserInputBufferPtr
) xmlMalloc(sizeof(xmlParserInputBuffer
));
2328 xmlIOErrMemory("creating input buffer");
2331 memset(ret
, 0, (size_t) sizeof(xmlParserInputBuffer
));
2332 ret
->buffer
= xmlBufCreateSize(2 * xmlDefaultBufferSize
);
2333 if (ret
->buffer
== NULL
) {
2337 xmlBufSetAllocationScheme(ret
->buffer
, XML_BUFFER_ALLOC_DOUBLEIT
);
2338 ret
->encoder
= xmlGetCharEncodingHandler(enc
);
2339 if (ret
->encoder
!= NULL
)
2340 ret
->raw
= xmlBufCreateSize(2 * xmlDefaultBufferSize
);
2343 ret
->readcallback
= NULL
;
2344 ret
->closecallback
= NULL
;
2345 ret
->context
= NULL
;
2346 ret
->compressed
= -1;
2347 ret
->rawconsumed
= 0;
2352 #ifdef LIBXML_OUTPUT_ENABLED
2354 * xmlAllocOutputBuffer:
2355 * @encoder: the encoding converter or NULL
2357 * Create a buffered parser output
2359 * Returns the new parser output or NULL
2362 xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder
) {
2363 xmlOutputBufferPtr ret
;
2365 ret
= (xmlOutputBufferPtr
) xmlMalloc(sizeof(xmlOutputBuffer
));
2367 xmlIOErrMemory("creating output buffer");
2370 memset(ret
, 0, (size_t) sizeof(xmlOutputBuffer
));
2371 ret
->buffer
= xmlBufCreate();
2372 if (ret
->buffer
== NULL
) {
2377 /* try to avoid a performance problem with Windows realloc() */
2378 if (xmlBufGetAllocationScheme(ret
->buffer
) == XML_BUFFER_ALLOC_EXACT
)
2379 xmlBufSetAllocationScheme(ret
->buffer
, XML_BUFFER_ALLOC_DOUBLEIT
);
2381 ret
->encoder
= encoder
;
2382 if (encoder
!= NULL
) {
2383 ret
->conv
= xmlBufCreateSize(4000);
2384 if (ret
->conv
== NULL
) {
2390 * This call is designed to initiate the encoder state
2392 xmlCharEncOutput(ret
, 1);
2395 ret
->writecallback
= NULL
;
2396 ret
->closecallback
= NULL
;
2397 ret
->context
= NULL
;
2404 * xmlAllocOutputBufferInternal:
2405 * @encoder: the encoding converter or NULL
2407 * Create a buffered parser output
2409 * Returns the new parser output or NULL
2412 xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder
) {
2413 xmlOutputBufferPtr ret
;
2415 ret
= (xmlOutputBufferPtr
) xmlMalloc(sizeof(xmlOutputBuffer
));
2417 xmlIOErrMemory("creating output buffer");
2420 memset(ret
, 0, (size_t) sizeof(xmlOutputBuffer
));
2421 ret
->buffer
= xmlBufCreate();
2422 if (ret
->buffer
== NULL
) {
2429 * For conversion buffers we use the special IO handling
2431 xmlBufSetAllocationScheme(ret
->buffer
, XML_BUFFER_ALLOC_IO
);
2433 ret
->encoder
= encoder
;
2434 if (encoder
!= NULL
) {
2435 ret
->conv
= xmlBufCreateSize(4000);
2436 if (ret
->conv
== NULL
) {
2442 * This call is designed to initiate the encoder state
2444 xmlCharEncOutput(ret
, 1);
2447 ret
->writecallback
= NULL
;
2448 ret
->closecallback
= NULL
;
2449 ret
->context
= NULL
;
2455 #endif /* LIBXML_OUTPUT_ENABLED */
2458 * xmlFreeParserInputBuffer:
2459 * @in: a buffered parser input
2461 * Free up the memory used by a buffered parser input
2464 xmlFreeParserInputBuffer(xmlParserInputBufferPtr in
) {
2465 if (in
== NULL
) return;
2468 xmlBufFree(in
->raw
);
2471 if (in
->encoder
!= NULL
) {
2472 xmlCharEncCloseFunc(in
->encoder
);
2474 if (in
->closecallback
!= NULL
) {
2475 in
->closecallback(in
->context
);
2477 if (in
->buffer
!= NULL
) {
2478 xmlBufFree(in
->buffer
);
2485 #ifdef LIBXML_OUTPUT_ENABLED
2487 * xmlOutputBufferClose:
2488 * @out: a buffered output
2490 * flushes and close the output I/O channel
2491 * and free up all the associated resources
2493 * Returns the number of byte written or -1 in case of error.
2496 xmlOutputBufferClose(xmlOutputBufferPtr out
)
2503 if (out
->writecallback
!= NULL
)
2504 xmlOutputBufferFlush(out
);
2505 if (out
->closecallback
!= NULL
) {
2506 err_rc
= out
->closecallback(out
->context
);
2508 written
= out
->written
;
2510 xmlBufFree(out
->conv
);
2513 if (out
->encoder
!= NULL
) {
2514 xmlCharEncCloseFunc(out
->encoder
);
2516 if (out
->buffer
!= NULL
) {
2517 xmlBufFree(out
->buffer
);
2524 return ((err_rc
== 0) ? written
: err_rc
);
2526 #endif /* LIBXML_OUTPUT_ENABLED */
2528 xmlParserInputBufferPtr
2529 __xmlParserInputBufferCreateFilename(const char *URI
, xmlCharEncoding enc
) {
2530 xmlParserInputBufferPtr ret
;
2532 void *context
= NULL
;
2534 if (xmlInputCallbackInitialized
== 0)
2535 xmlRegisterDefaultInputCallbacks();
2537 if (URI
== NULL
) return(NULL
);
2540 * Try to find one of the input accept method accepting that scheme
2541 * Go in reverse to give precedence to user defined handlers.
2543 if (context
== NULL
) {
2544 for (i
= xmlInputCallbackNr
- 1;i
>= 0;i
--) {
2545 if ((xmlInputCallbackTable
[i
].matchcallback
!= NULL
) &&
2546 (xmlInputCallbackTable
[i
].matchcallback(URI
) != 0)) {
2547 context
= xmlInputCallbackTable
[i
].opencallback(URI
);
2548 if (context
!= NULL
) {
2554 if (context
== NULL
) {
2559 * Allocate the Input buffer front-end.
2561 ret
= xmlAllocParserInputBuffer(enc
);
2563 ret
->context
= context
;
2564 ret
->readcallback
= xmlInputCallbackTable
[i
].readcallback
;
2565 ret
->closecallback
= xmlInputCallbackTable
[i
].closecallback
;
2567 if ((xmlInputCallbackTable
[i
].opencallback
== xmlGzfileOpen
) &&
2568 (strcmp(URI
, "-") != 0)) {
2569 #if defined(ZLIB_VERNUM) && ZLIB_VERNUM >= 0x1230
2570 ret
->compressed
= !gzdirect(context
);
2572 if (((z_stream
*)context
)->avail_in
> 4) {
2573 char *cptr
, buff4
[4];
2574 cptr
= (char *) ((z_stream
*)context
)->next_in
;
2575 if (gzread(context
, buff4
, 4) == 4) {
2576 if (strncmp(buff4
, cptr
, 4) == 0)
2577 ret
->compressed
= 0;
2579 ret
->compressed
= 1;
2586 #ifdef LIBXML_LZMA_ENABLED
2587 if ((xmlInputCallbackTable
[i
].opencallback
== xmlXzfileOpen
) &&
2588 (strcmp(URI
, "-") != 0)) {
2589 ret
->compressed
= __libxml2_xzcompressed(context
);
2594 xmlInputCallbackTable
[i
].closecallback (context
);
2600 * xmlParserInputBufferCreateFilename:
2601 * @URI: a C string containing the URI or filename
2602 * @enc: the charset encoding if known
2604 * Create a buffered parser input for the progressive parsing of a file
2605 * If filename is "-' then we use stdin as the input.
2606 * Automatic support for ZLIB/Compress compressed document is provided
2607 * by default if found at compile-time.
2608 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
2610 * Returns the new parser input or NULL
2612 xmlParserInputBufferPtr
2613 xmlParserInputBufferCreateFilename(const char *URI
, xmlCharEncoding enc
) {
2614 if ((xmlParserInputBufferCreateFilenameValue
)) {
2615 return xmlParserInputBufferCreateFilenameValue(URI
, enc
);
2617 return __xmlParserInputBufferCreateFilename(URI
, enc
);
2620 #ifdef LIBXML_OUTPUT_ENABLED
2622 __xmlOutputBufferCreateFilename(const char *URI
,
2623 xmlCharEncodingHandlerPtr encoder
,
2624 int compression ATTRIBUTE_UNUSED
) {
2625 xmlOutputBufferPtr ret
;
2628 void *context
= NULL
;
2629 char *unescaped
= NULL
;
2631 int is_file_uri
= 1;
2634 if (xmlOutputCallbackInitialized
== 0)
2635 xmlRegisterDefaultOutputCallbacks();
2637 if (URI
== NULL
) return(NULL
);
2639 puri
= xmlParseURI(URI
);
2642 if ((puri
->scheme
!= NULL
) &&
2643 (!xmlStrEqual(BAD_CAST puri
->scheme
, BAD_CAST
"file")))
2647 * try to limit the damages of the URI unescaping code.
2649 if ((puri
->scheme
== NULL
) ||
2650 (xmlStrEqual(BAD_CAST puri
->scheme
, BAD_CAST
"file")))
2651 unescaped
= xmlURIUnescapeString(URI
, 0, NULL
);
2656 * Try to find one of the output accept method accepting that scheme
2657 * Go in reverse to give precedence to user defined handlers.
2658 * try with an unescaped version of the URI
2660 if (unescaped
!= NULL
) {
2662 if ((compression
> 0) && (compression
<= 9) && (is_file_uri
== 1)) {
2663 context
= xmlGzfileOpenW(unescaped
, compression
);
2664 if (context
!= NULL
) {
2665 ret
= xmlAllocOutputBufferInternal(encoder
);
2667 ret
->context
= context
;
2668 ret
->writecallback
= xmlGzfileWrite
;
2669 ret
->closecallback
= xmlGzfileClose
;
2676 for (i
= xmlOutputCallbackNr
- 1;i
>= 0;i
--) {
2677 if ((xmlOutputCallbackTable
[i
].matchcallback
!= NULL
) &&
2678 (xmlOutputCallbackTable
[i
].matchcallback(unescaped
) != 0)) {
2679 #if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2680 /* Need to pass compression parameter into HTTP open calls */
2681 if (xmlOutputCallbackTable
[i
].matchcallback
== xmlIOHTTPMatch
)
2682 context
= xmlIOHTTPOpenW(unescaped
, compression
);
2685 context
= xmlOutputCallbackTable
[i
].opencallback(unescaped
);
2686 if (context
!= NULL
)
2694 * If this failed try with a non-escaped URI this may be a strange
2697 if (context
== NULL
) {
2699 if ((compression
> 0) && (compression
<= 9) && (is_file_uri
== 1)) {
2700 context
= xmlGzfileOpenW(URI
, compression
);
2701 if (context
!= NULL
) {
2702 ret
= xmlAllocOutputBufferInternal(encoder
);
2704 ret
->context
= context
;
2705 ret
->writecallback
= xmlGzfileWrite
;
2706 ret
->closecallback
= xmlGzfileClose
;
2712 for (i
= xmlOutputCallbackNr
- 1;i
>= 0;i
--) {
2713 if ((xmlOutputCallbackTable
[i
].matchcallback
!= NULL
) &&
2714 (xmlOutputCallbackTable
[i
].matchcallback(URI
) != 0)) {
2715 #if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2716 /* Need to pass compression parameter into HTTP open calls */
2717 if (xmlOutputCallbackTable
[i
].matchcallback
== xmlIOHTTPMatch
)
2718 context
= xmlIOHTTPOpenW(URI
, compression
);
2721 context
= xmlOutputCallbackTable
[i
].opencallback(URI
);
2722 if (context
!= NULL
)
2728 if (context
== NULL
) {
2733 * Allocate the Output buffer front-end.
2735 ret
= xmlAllocOutputBufferInternal(encoder
);
2737 ret
->context
= context
;
2738 ret
->writecallback
= xmlOutputCallbackTable
[i
].writecallback
;
2739 ret
->closecallback
= xmlOutputCallbackTable
[i
].closecallback
;
2745 * xmlOutputBufferCreateFilename:
2746 * @URI: a C string containing the URI or filename
2747 * @encoder: the encoding converter or NULL
2748 * @compression: the compression ration (0 none, 9 max).
2750 * Create a buffered output for the progressive saving of a file
2751 * If filename is "-' then we use stdout as the output.
2752 * Automatic support for ZLIB/Compress compressed document is provided
2753 * by default if found at compile-time.
2754 * TODO: currently if compression is set, the library only support
2755 * writing to a local file.
2757 * Returns the new output or NULL
2760 xmlOutputBufferCreateFilename(const char *URI
,
2761 xmlCharEncodingHandlerPtr encoder
,
2762 int compression ATTRIBUTE_UNUSED
) {
2763 if ((xmlOutputBufferCreateFilenameValue
)) {
2764 return xmlOutputBufferCreateFilenameValue(URI
, encoder
, compression
);
2766 return __xmlOutputBufferCreateFilename(URI
, encoder
, compression
);
2768 #endif /* LIBXML_OUTPUT_ENABLED */
2771 * xmlParserInputBufferCreateFile:
2773 * @enc: the charset encoding if known
2775 * Create a buffered parser input for the progressive parsing of a FILE *
2778 * Returns the new parser input or NULL
2780 xmlParserInputBufferPtr
2781 xmlParserInputBufferCreateFile(FILE *file
, xmlCharEncoding enc
) {
2782 xmlParserInputBufferPtr ret
;
2784 if (xmlInputCallbackInitialized
== 0)
2785 xmlRegisterDefaultInputCallbacks();
2787 if (file
== NULL
) return(NULL
);
2789 ret
= xmlAllocParserInputBuffer(enc
);
2791 ret
->context
= file
;
2792 ret
->readcallback
= xmlFileRead
;
2793 ret
->closecallback
= xmlFileFlush
;
2799 #ifdef LIBXML_OUTPUT_ENABLED
2801 * xmlOutputBufferCreateFile:
2803 * @encoder: the encoding converter or NULL
2805 * Create a buffered output for the progressive saving to a FILE *
2808 * Returns the new parser output or NULL
2811 xmlOutputBufferCreateFile(FILE *file
, xmlCharEncodingHandlerPtr encoder
) {
2812 xmlOutputBufferPtr ret
;
2814 if (xmlOutputCallbackInitialized
== 0)
2815 xmlRegisterDefaultOutputCallbacks();
2817 if (file
== NULL
) return(NULL
);
2819 ret
= xmlAllocOutputBufferInternal(encoder
);
2821 ret
->context
= file
;
2822 ret
->writecallback
= xmlFileWrite
;
2823 ret
->closecallback
= xmlFileFlush
;
2830 * xmlOutputBufferCreateBuffer:
2831 * @buffer: a xmlBufferPtr
2832 * @encoder: the encoding converter or NULL
2834 * Create a buffered output for the progressive saving to a xmlBuffer
2836 * Returns the new parser output or NULL
2839 xmlOutputBufferCreateBuffer(xmlBufferPtr buffer
,
2840 xmlCharEncodingHandlerPtr encoder
) {
2841 xmlOutputBufferPtr ret
;
2843 if (buffer
== NULL
) return(NULL
);
2845 ret
= xmlOutputBufferCreateIO((xmlOutputWriteCallback
)
2847 (xmlOutputCloseCallback
)
2848 NULL
, (void *) buffer
, encoder
);
2854 * xmlOutputBufferGetContent:
2855 * @out: an xmlOutputBufferPtr
2857 * Gives a pointer to the data currently held in the output buffer
2859 * Returns a pointer to the data or NULL in case of error
2862 xmlOutputBufferGetContent(xmlOutputBufferPtr out
) {
2863 if ((out
== NULL
) || (out
->buffer
== NULL
))
2866 return(xmlBufContent(out
->buffer
));
2870 * xmlOutputBufferGetSize:
2871 * @out: an xmlOutputBufferPtr
2873 * Gives the length of the data currently held in the output buffer
2875 * Returns 0 in case or error or no data is held, the size otherwise
2878 xmlOutputBufferGetSize(xmlOutputBufferPtr out
) {
2879 if ((out
== NULL
) || (out
->buffer
== NULL
))
2882 return(xmlBufUse(out
->buffer
));
2886 #endif /* LIBXML_OUTPUT_ENABLED */
2889 * xmlParserInputBufferCreateFd:
2890 * @fd: a file descriptor number
2891 * @enc: the charset encoding if known
2893 * Create a buffered parser input for the progressive parsing for the input
2894 * from a file descriptor
2896 * Returns the new parser input or NULL
2898 xmlParserInputBufferPtr
2899 xmlParserInputBufferCreateFd(int fd
, xmlCharEncoding enc
) {
2900 xmlParserInputBufferPtr ret
;
2902 if (fd
< 0) return(NULL
);
2904 ret
= xmlAllocParserInputBuffer(enc
);
2906 ret
->context
= (void *) (ptrdiff_t) fd
;
2907 ret
->readcallback
= xmlFdRead
;
2908 ret
->closecallback
= xmlFdClose
;
2915 * xmlParserInputBufferCreateMem:
2916 * @mem: the memory input
2917 * @size: the length of the memory block
2918 * @enc: the charset encoding if known
2920 * Create a buffered parser input for the progressive parsing for the input
2921 * from a memory area.
2923 * Returns the new parser input or NULL
2925 xmlParserInputBufferPtr
2926 xmlParserInputBufferCreateMem(const char *mem
, int size
, xmlCharEncoding enc
) {
2927 xmlParserInputBufferPtr ret
;
2930 if (size
< 0) return(NULL
);
2931 if (mem
== NULL
) return(NULL
);
2933 ret
= xmlAllocParserInputBuffer(enc
);
2935 ret
->context
= (void *) mem
;
2936 ret
->readcallback
= (xmlInputReadCallback
) xmlNop
;
2937 ret
->closecallback
= NULL
;
2938 errcode
= xmlBufAdd(ret
->buffer
, (const xmlChar
*) mem
, size
);
2949 * xmlParserInputBufferCreateStatic:
2950 * @mem: the memory input
2951 * @size: the length of the memory block
2952 * @enc: the charset encoding if known
2954 * Create a buffered parser input for the progressive parsing for the input
2955 * from an immutable memory area. This will not copy the memory area to
2956 * the buffer, but the memory is expected to be available until the end of
2957 * the parsing, this is useful for example when using mmap'ed file.
2959 * Returns the new parser input or NULL
2961 xmlParserInputBufferPtr
2962 xmlParserInputBufferCreateStatic(const char *mem
, int size
,
2963 xmlCharEncoding enc
) {
2964 xmlParserInputBufferPtr ret
;
2966 if (size
< 0) return(NULL
);
2967 if (mem
== NULL
) return(NULL
);
2969 ret
= (xmlParserInputBufferPtr
) xmlMalloc(sizeof(xmlParserInputBuffer
));
2971 xmlIOErrMemory("creating input buffer");
2974 memset(ret
, 0, (size_t) sizeof(xmlParserInputBuffer
));
2975 ret
->buffer
= xmlBufCreateStatic((void *)mem
, (size_t) size
);
2976 if (ret
->buffer
== NULL
) {
2980 ret
->encoder
= xmlGetCharEncodingHandler(enc
);
2981 if (ret
->encoder
!= NULL
)
2982 ret
->raw
= xmlBufCreateSize(2 * xmlDefaultBufferSize
);
2985 ret
->compressed
= -1;
2986 ret
->context
= (void *) mem
;
2987 ret
->readcallback
= NULL
;
2988 ret
->closecallback
= NULL
;
2993 #ifdef LIBXML_OUTPUT_ENABLED
2995 * xmlOutputBufferCreateFd:
2996 * @fd: a file descriptor number
2997 * @encoder: the encoding converter or NULL
2999 * Create a buffered output for the progressive saving
3000 * to a file descriptor
3002 * Returns the new parser output or NULL
3005 xmlOutputBufferCreateFd(int fd
, xmlCharEncodingHandlerPtr encoder
) {
3006 xmlOutputBufferPtr ret
;
3008 if (fd
< 0) return(NULL
);
3010 ret
= xmlAllocOutputBufferInternal(encoder
);
3012 ret
->context
= (void *) (ptrdiff_t) fd
;
3013 ret
->writecallback
= xmlFdWrite
;
3014 ret
->closecallback
= NULL
;
3019 #endif /* LIBXML_OUTPUT_ENABLED */
3022 * xmlParserInputBufferCreateIO:
3023 * @ioread: an I/O read function
3024 * @ioclose: an I/O close function
3025 * @ioctx: an I/O handler
3026 * @enc: the charset encoding if known
3028 * Create a buffered parser input for the progressive parsing for the input
3029 * from an I/O handler
3031 * Returns the new parser input or NULL
3033 xmlParserInputBufferPtr
3034 xmlParserInputBufferCreateIO(xmlInputReadCallback ioread
,
3035 xmlInputCloseCallback ioclose
, void *ioctx
, xmlCharEncoding enc
) {
3036 xmlParserInputBufferPtr ret
;
3038 if (ioread
== NULL
) return(NULL
);
3040 ret
= xmlAllocParserInputBuffer(enc
);
3042 ret
->context
= (void *) ioctx
;
3043 ret
->readcallback
= ioread
;
3044 ret
->closecallback
= ioclose
;
3050 #ifdef LIBXML_OUTPUT_ENABLED
3052 * xmlOutputBufferCreateIO:
3053 * @iowrite: an I/O write function
3054 * @ioclose: an I/O close function
3055 * @ioctx: an I/O handler
3056 * @encoder: the charset encoding if known
3058 * Create a buffered output for the progressive saving
3061 * Returns the new parser output or NULL
3064 xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite
,
3065 xmlOutputCloseCallback ioclose
, void *ioctx
,
3066 xmlCharEncodingHandlerPtr encoder
) {
3067 xmlOutputBufferPtr ret
;
3069 if (iowrite
== NULL
) return(NULL
);
3071 ret
= xmlAllocOutputBufferInternal(encoder
);
3073 ret
->context
= (void *) ioctx
;
3074 ret
->writecallback
= iowrite
;
3075 ret
->closecallback
= ioclose
;
3080 #endif /* LIBXML_OUTPUT_ENABLED */
3083 * xmlParserInputBufferCreateFilenameDefault:
3084 * @func: function pointer to the new ParserInputBufferCreateFilenameFunc
3086 * Registers a callback for URI input file handling
3088 * Returns the old value of the registration function
3090 xmlParserInputBufferCreateFilenameFunc
3091 xmlParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func
)
3093 xmlParserInputBufferCreateFilenameFunc old
= xmlParserInputBufferCreateFilenameValue
;
3095 old
= __xmlParserInputBufferCreateFilename
;
3098 xmlParserInputBufferCreateFilenameValue
= func
;
3103 * xmlOutputBufferCreateFilenameDefault:
3104 * @func: function pointer to the new OutputBufferCreateFilenameFunc
3106 * Registers a callback for URI output file handling
3108 * Returns the old value of the registration function
3110 xmlOutputBufferCreateFilenameFunc
3111 xmlOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func
)
3113 xmlOutputBufferCreateFilenameFunc old
= xmlOutputBufferCreateFilenameValue
;
3114 #ifdef LIBXML_OUTPUT_ENABLED
3116 old
= __xmlOutputBufferCreateFilename
;
3119 xmlOutputBufferCreateFilenameValue
= func
;
3124 * xmlParserInputBufferPush:
3125 * @in: a buffered parser input
3126 * @len: the size in bytes of the array.
3127 * @buf: an char array
3129 * Push the content of the arry in the input buffer
3130 * This routine handle the I18N transcoding to internal UTF-8
3131 * This is used when operating the parser in progressive (push) mode.
3133 * Returns the number of chars read and stored in the buffer, or -1
3137 xmlParserInputBufferPush(xmlParserInputBufferPtr in
,
3138 int len
, const char *buf
) {
3142 if (len
< 0) return(0);
3143 if ((in
== NULL
) || (in
->error
)) return(-1);
3144 if (in
->encoder
!= NULL
) {
3148 * Store the data in the incoming raw buffer
3150 if (in
->raw
== NULL
) {
3151 in
->raw
= xmlBufCreate();
3153 ret
= xmlBufAdd(in
->raw
, (const xmlChar
*) buf
, len
);
3158 * convert as much as possible to the parser reading buffer.
3160 use
= xmlBufUse(in
->raw
);
3161 nbchars
= xmlCharEncInput(in
, 1);
3163 xmlIOErr(XML_IO_ENCODER
, NULL
);
3164 in
->error
= XML_IO_ENCODER
;
3167 in
->rawconsumed
+= (use
- xmlBufUse(in
->raw
));
3170 ret
= xmlBufAdd(in
->buffer
, (xmlChar
*) buf
, nbchars
);
3175 xmlGenericError(xmlGenericErrorContext
,
3176 "I/O: pushed %d chars, buffer %d/%d\n",
3177 nbchars
, xmlBufUse(in
->buffer
), xmlBufLength(in
->buffer
));
3185 * When reading from an Input channel indicated end of file or error
3186 * don't reread from it again.
3189 endOfInput (void * context ATTRIBUTE_UNUSED
,
3190 char * buffer ATTRIBUTE_UNUSED
,
3191 int len ATTRIBUTE_UNUSED
) {
3196 * xmlParserInputBufferGrow:
3197 * @in: a buffered parser input
3198 * @len: indicative value of the amount of chars to read
3200 * Grow up the content of the input buffer, the old data are preserved
3201 * This routine handle the I18N transcoding to internal UTF-8
3202 * This routine is used when operating the parser in normal (pull) mode
3204 * TODO: one should be able to remove one extra copy by copying directly
3205 * onto in->buffer or in->raw
3207 * Returns the number of chars read and stored in the buffer, or -1
3211 xmlParserInputBufferGrow(xmlParserInputBufferPtr in
, int len
) {
3212 char *buffer
= NULL
;
3216 if ((in
== NULL
) || (in
->error
)) return(-1);
3217 if ((len
<= MINLEN
) && (len
!= 4))
3220 if (xmlBufAvail(in
->buffer
) <= 0) {
3221 xmlIOErr(XML_IO_BUFFER_FULL
, NULL
);
3222 in
->error
= XML_IO_BUFFER_FULL
;
3226 if (xmlBufGrow(in
->buffer
, len
+ 1) < 0) {
3227 xmlIOErrMemory("growing input buffer");
3228 in
->error
= XML_ERR_NO_MEMORY
;
3231 buffer
= (char *)xmlBufEnd(in
->buffer
);
3234 * Call the read method for this I/O type.
3236 if (in
->readcallback
!= NULL
) {
3237 res
= in
->readcallback(in
->context
, &buffer
[0], len
);
3239 in
->readcallback
= endOfInput
;
3241 xmlIOErr(XML_IO_NO_INPUT
, NULL
);
3242 in
->error
= XML_IO_NO_INPUT
;
3250 * try to establish compressed status of input if not done already
3252 if (in
->compressed
== -1) {
3253 #ifdef LIBXML_LZMA_ENABLED
3254 if (in
->readcallback
== xmlXzfileRead
)
3255 in
->compressed
= __libxml2_xzcompressed(in
->context
);
3260 if (in
->encoder
!= NULL
) {
3264 * Store the data in the incoming raw buffer
3266 if (in
->raw
== NULL
) {
3267 in
->raw
= xmlBufCreate();
3269 res
= xmlBufAdd(in
->raw
, (const xmlChar
*) buffer
, len
);
3274 * convert as much as possible to the parser reading buffer.
3276 use
= xmlBufUse(in
->raw
);
3277 nbchars
= xmlCharEncInput(in
, 1);
3279 xmlIOErr(XML_IO_ENCODER
, NULL
);
3280 in
->error
= XML_IO_ENCODER
;
3283 in
->rawconsumed
+= (use
- xmlBufUse(in
->raw
));
3286 xmlBufAddLen(in
->buffer
, nbchars
);
3289 xmlGenericError(xmlGenericErrorContext
,
3290 "I/O: read %d chars, buffer %d\n",
3291 nbchars
, xmlBufUse(in
->buffer
));
3297 * xmlParserInputBufferRead:
3298 * @in: a buffered parser input
3299 * @len: indicative value of the amount of chars to read
3301 * Refresh the content of the input buffer, the old data are considered
3303 * This routine handle the I18N transcoding to internal UTF-8
3305 * Returns the number of chars read and stored in the buffer, or -1
3309 xmlParserInputBufferRead(xmlParserInputBufferPtr in
, int len
) {
3310 if ((in
== NULL
) || (in
->error
)) return(-1);
3311 if (in
->readcallback
!= NULL
)
3312 return(xmlParserInputBufferGrow(in
, len
));
3313 else if (xmlBufGetAllocationScheme(in
->buffer
) == XML_BUFFER_ALLOC_IMMUTABLE
)
3319 #ifdef LIBXML_OUTPUT_ENABLED
3321 * xmlOutputBufferWrite:
3322 * @out: a buffered parser output
3323 * @len: the size in bytes of the array.
3324 * @buf: an char array
3326 * Write the content of the array in the output I/O buffer
3327 * This routine handle the I18N transcoding from internal UTF-8
3328 * The buffer is lossless, i.e. will store in case of partial
3329 * or delayed writes.
3331 * Returns the number of chars immediately written, or -1
3335 xmlOutputBufferWrite(xmlOutputBufferPtr out
, int len
, const char *buf
) {
3336 int nbchars
= 0; /* number of chars to output to I/O */
3337 int ret
; /* return from function call */
3338 int written
= 0; /* number of char written to I/O so far */
3339 int chunk
; /* number of byte curreent processed from buf */
3341 if ((out
== NULL
) || (out
->error
)) return(-1);
3342 if (len
< 0) return(0);
3343 if (out
->error
) return(-1);
3347 if (chunk
> 4 * MINLEN
)
3351 * first handle encoding stuff.
3353 if (out
->encoder
!= NULL
) {
3355 * Store the data in the incoming raw buffer
3357 if (out
->conv
== NULL
) {
3358 out
->conv
= xmlBufCreate();
3360 ret
= xmlBufAdd(out
->buffer
, (const xmlChar
*) buf
, chunk
);
3364 if ((xmlBufUse(out
->buffer
) < MINLEN
) && (chunk
== len
))
3368 * convert as much as possible to the parser reading buffer.
3370 ret
= xmlCharEncOutput(out
, 0);
3371 if ((ret
< 0) && (ret
!= -3)) {
3372 xmlIOErr(XML_IO_ENCODER
, NULL
);
3373 out
->error
= XML_IO_ENCODER
;
3376 nbchars
= xmlBufUse(out
->conv
);
3378 ret
= xmlBufAdd(out
->buffer
, (const xmlChar
*) buf
, chunk
);
3381 nbchars
= xmlBufUse(out
->buffer
);
3386 if ((nbchars
< MINLEN
) && (len
<= 0))
3389 if (out
->writecallback
) {
3391 * second write the stuff to the I/O channel
3393 if (out
->encoder
!= NULL
) {
3394 ret
= out
->writecallback(out
->context
,
3395 (const char *)xmlBufContent(out
->conv
), nbchars
);
3397 xmlBufShrink(out
->conv
, ret
);
3399 ret
= out
->writecallback(out
->context
,
3400 (const char *)xmlBufContent(out
->buffer
), nbchars
);
3402 xmlBufShrink(out
->buffer
, ret
);
3405 xmlIOErr(XML_IO_WRITE
, NULL
);
3406 out
->error
= XML_IO_WRITE
;
3409 out
->written
+= ret
;
3416 xmlGenericError(xmlGenericErrorContext
,
3417 "I/O: wrote %d chars\n", written
);
3424 * @out: a pointer to an array of bytes to store the result
3425 * @outlen: the length of @out
3426 * @in: a pointer to an array of unescaped UTF-8 bytes
3427 * @inlen: the length of @in
3429 * Take a block of UTF-8 chars in and escape them.
3430 * Returns 0 if success, or -1 otherwise
3431 * The value of @inlen after return is the number of octets consumed
3432 * if the return value is positive, else unpredictable.
3433 * The value of @outlen after return is the number of octets consumed.
3436 xmlEscapeContent(unsigned char* out
, int *outlen
,
3437 const xmlChar
* in
, int *inlen
) {
3438 unsigned char* outstart
= out
;
3439 const unsigned char* base
= in
;
3440 unsigned char* outend
= out
+ *outlen
;
3441 const unsigned char* inend
;
3443 inend
= in
+ (*inlen
);
3445 while ((in
< inend
) && (out
< outend
)) {
3447 if (outend
- out
< 4) break;
3452 } else if (*in
== '>') {
3453 if (outend
- out
< 4) break;
3458 } else if (*in
== '&') {
3459 if (outend
- out
< 5) break;
3465 } else if (*in
== '\r') {
3466 if (outend
- out
< 5) break;
3473 *out
++ = (unsigned char) *in
;
3477 *outlen
= out
- outstart
;
3483 * xmlOutputBufferWriteEscape:
3484 * @out: a buffered parser output
3485 * @str: a zero terminated UTF-8 string
3486 * @escaping: an optional escaping function (or NULL)
3488 * Write the content of the string in the output I/O buffer
3489 * This routine escapes the caracters and then handle the I18N
3490 * transcoding from internal UTF-8
3491 * The buffer is lossless, i.e. will store in case of partial
3492 * or delayed writes.
3494 * Returns the number of chars immediately written, or -1
3498 xmlOutputBufferWriteEscape(xmlOutputBufferPtr out
, const xmlChar
*str
,
3499 xmlCharEncodingOutputFunc escaping
) {
3500 int nbchars
= 0; /* number of chars to output to I/O */
3501 int ret
; /* return from function call */
3502 int written
= 0; /* number of char written to I/O so far */
3503 int oldwritten
=0;/* loop guard */
3504 int chunk
; /* number of byte currently processed from str */
3505 int len
; /* number of bytes in str */
3506 int cons
; /* byte from str consumed */
3508 if ((out
== NULL
) || (out
->error
) || (str
== NULL
) ||
3509 (out
->buffer
== NULL
) ||
3510 (xmlBufGetAllocationScheme(out
->buffer
) == XML_BUFFER_ALLOC_IMMUTABLE
))
3512 len
= strlen((const char *)str
);
3513 if (len
< 0) return(0);
3514 if (out
->error
) return(-1);
3515 if (escaping
== NULL
) escaping
= xmlEscapeContent
;
3518 oldwritten
= written
;
3521 * how many bytes to consume and how many bytes to store.
3524 chunk
= xmlBufAvail(out
->buffer
) - 1;
3527 * make sure we have enough room to save first, if this is
3528 * not the case force a flush, but make sure we stay in the loop
3531 if (xmlBufGrow(out
->buffer
, 100) < 0)
3538 * first handle encoding stuff.
3540 if (out
->encoder
!= NULL
) {
3542 * Store the data in the incoming raw buffer
3544 if (out
->conv
== NULL
) {
3545 out
->conv
= xmlBufCreate();
3547 ret
= escaping(xmlBufEnd(out
->buffer
) ,
3548 &chunk
, str
, &cons
);
3549 if ((ret
< 0) || (chunk
== 0)) /* chunk==0 => nothing done */
3551 xmlBufAddLen(out
->buffer
, chunk
);
3553 if ((xmlBufUse(out
->buffer
) < MINLEN
) && (cons
== len
))
3557 * convert as much as possible to the output buffer.
3559 ret
= xmlCharEncOutput(out
, 0);
3560 if ((ret
< 0) && (ret
!= -3)) {
3561 xmlIOErr(XML_IO_ENCODER
, NULL
);
3562 out
->error
= XML_IO_ENCODER
;
3565 nbchars
= xmlBufUse(out
->conv
);
3567 ret
= escaping(xmlBufEnd(out
->buffer
), &chunk
, str
, &cons
);
3568 if ((ret
< 0) || (chunk
== 0)) /* chunk==0 => nothing done */
3570 xmlBufAddLen(out
->buffer
, chunk
);
3571 nbchars
= xmlBufUse(out
->buffer
);
3576 if ((nbchars
< MINLEN
) && (len
<= 0))
3579 if (out
->writecallback
) {
3581 * second write the stuff to the I/O channel
3583 if (out
->encoder
!= NULL
) {
3584 ret
= out
->writecallback(out
->context
,
3585 (const char *)xmlBufContent(out
->conv
), nbchars
);
3587 xmlBufShrink(out
->conv
, ret
);
3589 ret
= out
->writecallback(out
->context
,
3590 (const char *)xmlBufContent(out
->buffer
), nbchars
);
3592 xmlBufShrink(out
->buffer
, ret
);
3595 xmlIOErr(XML_IO_WRITE
, NULL
);
3596 out
->error
= XML_IO_WRITE
;
3599 out
->written
+= ret
;
3600 } else if (xmlBufAvail(out
->buffer
) < MINLEN
) {
3601 xmlBufGrow(out
->buffer
, MINLEN
);
3604 } while ((len
> 0) && (oldwritten
!= written
));
3608 xmlGenericError(xmlGenericErrorContext
,
3609 "I/O: wrote %d chars\n", written
);
3615 * xmlOutputBufferWriteString:
3616 * @out: a buffered parser output
3617 * @str: a zero terminated C string
3619 * Write the content of the string in the output I/O buffer
3620 * This routine handle the I18N transcoding from internal UTF-8
3621 * The buffer is lossless, i.e. will store in case of partial
3622 * or delayed writes.
3624 * Returns the number of chars immediately written, or -1
3628 xmlOutputBufferWriteString(xmlOutputBufferPtr out
, const char *str
) {
3631 if ((out
== NULL
) || (out
->error
)) return(-1);
3637 return(xmlOutputBufferWrite(out
, len
, str
));
3642 * xmlOutputBufferFlush:
3643 * @out: a buffered output
3645 * flushes the output I/O channel
3647 * Returns the number of byte written or -1 in case of error.
3650 xmlOutputBufferFlush(xmlOutputBufferPtr out
) {
3651 int nbchars
= 0, ret
= 0;
3653 if ((out
== NULL
) || (out
->error
)) return(-1);
3655 * first handle encoding stuff.
3657 if ((out
->conv
!= NULL
) && (out
->encoder
!= NULL
)) {
3659 * convert as much as possible to the parser output buffer.
3662 nbchars
= xmlCharEncOutput(out
, 0);
3664 xmlIOErr(XML_IO_ENCODER
, NULL
);
3665 out
->error
= XML_IO_ENCODER
;
3672 * second flush the stuff to the I/O channel
3674 if ((out
->conv
!= NULL
) && (out
->encoder
!= NULL
) &&
3675 (out
->writecallback
!= NULL
)) {
3676 ret
= out
->writecallback(out
->context
,
3677 (const char *)xmlBufContent(out
->conv
),
3678 xmlBufUse(out
->conv
));
3680 xmlBufShrink(out
->conv
, ret
);
3681 } else if (out
->writecallback
!= NULL
) {
3682 ret
= out
->writecallback(out
->context
,
3683 (const char *)xmlBufContent(out
->buffer
),
3684 xmlBufUse(out
->buffer
));
3686 xmlBufShrink(out
->buffer
, ret
);
3689 xmlIOErr(XML_IO_FLUSH
, NULL
);
3690 out
->error
= XML_IO_FLUSH
;
3693 out
->written
+= ret
;
3696 xmlGenericError(xmlGenericErrorContext
,
3697 "I/O: flushed %d chars\n", ret
);
3701 #endif /* LIBXML_OUTPUT_ENABLED */
3704 * xmlParserGetDirectory:
3705 * @filename: the path to a file
3707 * lookup the directory for that file
3709 * Returns a new allocated string containing the directory, or NULL.
3712 xmlParserGetDirectory(const char *filename
) {
3717 #ifdef _WIN32_WCE /* easy way by now ... wince does not have dirs! */
3721 if (xmlInputCallbackInitialized
== 0)
3722 xmlRegisterDefaultInputCallbacks();
3724 if (filename
== NULL
) return(NULL
);
3726 #if defined(_WIN32) && !defined(__CYGWIN__)
3727 # define IS_XMLPGD_SEP(ch) ((ch=='/')||(ch=='\\'))
3729 # define IS_XMLPGD_SEP(ch) (ch=='/')
3732 strncpy(dir
, filename
, 1023);
3734 cur
= &dir
[strlen(dir
)];
3736 if (IS_XMLPGD_SEP(*cur
)) break;
3739 if (IS_XMLPGD_SEP(*cur
)) {
3740 if (cur
== dir
) dir
[1] = 0;
3742 ret
= xmlMemStrdup(dir
);
3744 if (getcwd(dir
, 1024) != NULL
) {
3746 ret
= xmlMemStrdup(dir
);
3750 #undef IS_XMLPGD_SEP
3753 /****************************************************************
3755 * External entities loading *
3757 ****************************************************************/
3760 * xmlCheckHTTPInput:
3761 * @ctxt: an XML parser context
3762 * @ret: an XML parser input
3764 * Check an input in case it was created from an HTTP stream, in that
3765 * case it will handle encoding and update of the base URL in case of
3766 * redirection. It also checks for HTTP errors in which case the input
3767 * is cleanly freed up and an appropriate error is raised in context
3769 * Returns the input or NULL in case of HTTP error.
3772 xmlCheckHTTPInput(xmlParserCtxtPtr ctxt
, xmlParserInputPtr ret
) {
3773 #ifdef LIBXML_HTTP_ENABLED
3774 if ((ret
!= NULL
) && (ret
->buf
!= NULL
) &&
3775 (ret
->buf
->readcallback
== xmlIOHTTPRead
) &&
3776 (ret
->buf
->context
!= NULL
)) {
3777 const char *encoding
;
3782 code
= xmlNanoHTTPReturnCode(ret
->buf
->context
);
3785 if (ret
->filename
!= NULL
)
3786 __xmlLoaderErr(ctxt
, "failed to load HTTP resource \"%s\"\n",
3787 (const char *) ret
->filename
);
3789 __xmlLoaderErr(ctxt
, "failed to load HTTP resource\n", NULL
);
3790 xmlFreeInputStream(ret
);
3794 mime
= xmlNanoHTTPMimeType(ret
->buf
->context
);
3795 if ((xmlStrstr(BAD_CAST mime
, BAD_CAST
"/xml")) ||
3796 (xmlStrstr(BAD_CAST mime
, BAD_CAST
"+xml"))) {
3797 encoding
= xmlNanoHTTPEncoding(ret
->buf
->context
);
3798 if (encoding
!= NULL
) {
3799 xmlCharEncodingHandlerPtr handler
;
3801 handler
= xmlFindCharEncodingHandler(encoding
);
3802 if (handler
!= NULL
) {
3803 xmlSwitchInputEncoding(ctxt
, ret
, handler
);
3805 __xmlErrEncoding(ctxt
, XML_ERR_UNKNOWN_ENCODING
,
3806 "Unknown encoding %s",
3807 BAD_CAST encoding
, NULL
);
3809 if (ret
->encoding
== NULL
)
3810 ret
->encoding
= xmlStrdup(BAD_CAST encoding
);
3813 } else if (xmlStrstr(BAD_CAST mime
, BAD_CAST
"html")) {
3816 redir
= xmlNanoHTTPRedir(ret
->buf
->context
);
3817 if (redir
!= NULL
) {
3818 if (ret
->filename
!= NULL
)
3819 xmlFree((xmlChar
*) ret
->filename
);
3820 if (ret
->directory
!= NULL
) {
3821 xmlFree((xmlChar
*) ret
->directory
);
3822 ret
->directory
= NULL
;
3825 (char *) xmlStrdup((const xmlChar
*) redir
);
3833 static int xmlNoNetExists(const char *URL
) {
3839 if (!xmlStrncasecmp(BAD_CAST URL
, BAD_CAST
"file://localhost/", 17))
3840 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
3845 else if (!xmlStrncasecmp(BAD_CAST URL
, BAD_CAST
"file:///", 8)) {
3846 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
3854 return xmlCheckFilename(path
);
3857 #ifdef LIBXML_CATALOG_ENABLED
3860 * xmlResolveResourceFromCatalog:
3861 * @URL: the URL for the entity to load
3862 * @ID: the System ID for the entity to load
3863 * @ctxt: the context in which the entity is called or NULL
3865 * Resolves the URL and ID against the appropriate catalog.
3866 * This function is used by xmlDefaultExternalEntityLoader and
3867 * xmlNoNetExternalEntityLoader.
3869 * Returns a new allocated URL, or NULL.
3872 xmlResolveResourceFromCatalog(const char *URL
, const char *ID
,
3873 xmlParserCtxtPtr ctxt
) {
3874 xmlChar
*resource
= NULL
;
3875 xmlCatalogAllow pref
;
3878 * If the resource doesn't exists as a file,
3879 * try to load it from the resource pointed in the catalogs
3881 pref
= xmlCatalogGetDefaults();
3883 if ((pref
!= XML_CATA_ALLOW_NONE
) && (!xmlNoNetExists(URL
))) {
3887 if ((ctxt
!= NULL
) && (ctxt
->catalogs
!= NULL
) &&
3888 ((pref
== XML_CATA_ALLOW_ALL
) ||
3889 (pref
== XML_CATA_ALLOW_DOCUMENT
))) {
3890 resource
= xmlCatalogLocalResolve(ctxt
->catalogs
,
3891 (const xmlChar
*)ID
,
3892 (const xmlChar
*)URL
);
3895 * Try a global lookup
3897 if ((resource
== NULL
) &&
3898 ((pref
== XML_CATA_ALLOW_ALL
) ||
3899 (pref
== XML_CATA_ALLOW_GLOBAL
))) {
3900 resource
= xmlCatalogResolve((const xmlChar
*)ID
,
3901 (const xmlChar
*)URL
);
3903 if ((resource
== NULL
) && (URL
!= NULL
))
3904 resource
= xmlStrdup((const xmlChar
*) URL
);
3907 * TODO: do an URI lookup on the reference
3909 if ((resource
!= NULL
) && (!xmlNoNetExists((const char *)resource
))) {
3910 xmlChar
*tmp
= NULL
;
3912 if ((ctxt
!= NULL
) && (ctxt
->catalogs
!= NULL
) &&
3913 ((pref
== XML_CATA_ALLOW_ALL
) ||
3914 (pref
== XML_CATA_ALLOW_DOCUMENT
))) {
3915 tmp
= xmlCatalogLocalResolveURI(ctxt
->catalogs
, resource
);
3917 if ((tmp
== NULL
) &&
3918 ((pref
== XML_CATA_ALLOW_ALL
) ||
3919 (pref
== XML_CATA_ALLOW_GLOBAL
))) {
3920 tmp
= xmlCatalogResolveURI(resource
);
3936 * xmlDefaultExternalEntityLoader:
3937 * @URL: the URL for the entity to load
3938 * @ID: the System ID for the entity to load
3939 * @ctxt: the context in which the entity is called or NULL
3941 * By default we don't load external entitites, yet.
3943 * Returns a new allocated xmlParserInputPtr, or NULL.
3945 static xmlParserInputPtr
3946 xmlDefaultExternalEntityLoader(const char *URL
, const char *ID
,
3947 xmlParserCtxtPtr ctxt
)
3949 xmlParserInputPtr ret
= NULL
;
3950 xmlChar
*resource
= NULL
;
3952 #ifdef DEBUG_EXTERNAL_ENTITIES
3953 xmlGenericError(xmlGenericErrorContext
,
3954 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL
);
3956 if ((ctxt
!= NULL
) && (ctxt
->options
& XML_PARSE_NONET
)) {
3957 int options
= ctxt
->options
;
3959 ctxt
->options
-= XML_PARSE_NONET
;
3960 ret
= xmlNoNetExternalEntityLoader(URL
, ID
, ctxt
);
3961 ctxt
->options
= options
;
3964 #ifdef LIBXML_CATALOG_ENABLED
3965 resource
= xmlResolveResourceFromCatalog(URL
, ID
, ctxt
);
3968 if (resource
== NULL
)
3969 resource
= (xmlChar
*) URL
;
3971 if (resource
== NULL
) {
3974 __xmlLoaderErr(ctxt
, "failed to load external entity \"%s\"\n", ID
);
3977 ret
= xmlNewInputFromFile(ctxt
, (const char *) resource
);
3978 if ((resource
!= NULL
) && (resource
!= (xmlChar
*) URL
))
3983 static xmlExternalEntityLoader xmlCurrentExternalEntityLoader
=
3984 xmlDefaultExternalEntityLoader
;
3987 * xmlSetExternalEntityLoader:
3988 * @f: the new entity resolver function
3990 * Changes the defaultexternal entity resolver function for the application
3993 xmlSetExternalEntityLoader(xmlExternalEntityLoader f
) {
3994 xmlCurrentExternalEntityLoader
= f
;
3998 * xmlGetExternalEntityLoader:
4000 * Get the default external entity resolver function for the application
4002 * Returns the xmlExternalEntityLoader function pointer
4004 xmlExternalEntityLoader
4005 xmlGetExternalEntityLoader(void) {
4006 return(xmlCurrentExternalEntityLoader
);
4010 * xmlLoadExternalEntity:
4011 * @URL: the URL for the entity to load
4012 * @ID: the Public ID for the entity to load
4013 * @ctxt: the context in which the entity is called or NULL
4015 * Load an external entity, note that the use of this function for
4016 * unparsed entities may generate problems
4018 * Returns the xmlParserInputPtr or NULL
4021 xmlLoadExternalEntity(const char *URL
, const char *ID
,
4022 xmlParserCtxtPtr ctxt
) {
4023 if ((URL
!= NULL
) && (xmlNoNetExists(URL
) == 0)) {
4024 char *canonicFilename
;
4025 xmlParserInputPtr ret
;
4027 canonicFilename
= (char *) xmlCanonicPath((const xmlChar
*) URL
);
4028 if (canonicFilename
== NULL
) {
4029 xmlIOErrMemory("building canonical path\n");
4033 ret
= xmlCurrentExternalEntityLoader(canonicFilename
, ID
, ctxt
);
4034 xmlFree(canonicFilename
);
4037 return(xmlCurrentExternalEntityLoader(URL
, ID
, ctxt
));
4040 /************************************************************************
4042 * Disabling Network access *
4044 ************************************************************************/
4047 * xmlNoNetExternalEntityLoader:
4048 * @URL: the URL for the entity to load
4049 * @ID: the System ID for the entity to load
4050 * @ctxt: the context in which the entity is called or NULL
4052 * A specific entity loader disabling network accesses, though still
4053 * allowing local catalog accesses for resolution.
4055 * Returns a new allocated xmlParserInputPtr, or NULL.
4058 xmlNoNetExternalEntityLoader(const char *URL
, const char *ID
,
4059 xmlParserCtxtPtr ctxt
) {
4060 xmlParserInputPtr input
= NULL
;
4061 xmlChar
*resource
= NULL
;
4063 #ifdef LIBXML_CATALOG_ENABLED
4064 resource
= xmlResolveResourceFromCatalog(URL
, ID
, ctxt
);
4067 if (resource
== NULL
)
4068 resource
= (xmlChar
*) URL
;
4070 if (resource
!= NULL
) {
4071 if ((!xmlStrncasecmp(BAD_CAST resource
, BAD_CAST
"ftp://", 6)) ||
4072 (!xmlStrncasecmp(BAD_CAST resource
, BAD_CAST
"http://", 7))) {
4073 xmlIOErr(XML_IO_NETWORK_ATTEMPT
, (const char *) resource
);
4074 if (resource
!= (xmlChar
*) URL
)
4079 input
= xmlDefaultExternalEntityLoader((const char *) resource
, ID
, ctxt
);
4080 if (resource
!= (xmlChar
*) URL
)
4085 #define bottom_xmlIO
4086 #include "elfgcchack.h"