2 * xmlIO.c : implementation of the I/O interfaces used by the parser
4 * See Copyright for the status of this software.
8 * 14 Nov 2000 ht - for VMS, truncated name of long functions to under 32 char
20 #ifdef HAVE_SYS_TYPES_H
21 #include <sys/types.h>
23 #ifdef HAVE_SYS_STAT_H
42 #if defined(WIN32) || defined(_WIN32)
46 #if defined(_WIN32_WCE)
47 #include <winnls.h> /* for CP_UTF8 */
50 /* Figure a portable way to know if a file is a directory. */
53 /* MS C library seems to define stat and _stat. The definition
54 is identical. Still, mapping them to each other causes a warning. */
56 # define stat(x,y) _stat(x,y)
62 # if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
70 # define S_ISDIR(x) _S_ISDIR(x)
75 # define S_IFMT _S_IFMT
79 # define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
86 #include <libxml/xmlmemory.h>
87 #include <libxml/parser.h>
88 #include <libxml/parserInternals.h>
89 #include <libxml/xmlIO.h>
90 #include <libxml/uri.h>
91 #include <libxml/nanohttp.h>
92 #include <libxml/nanoftp.h>
93 #include <libxml/xmlerror.h>
94 #ifdef LIBXML_CATALOG_ENABLED
95 #include <libxml/catalog.h>
97 #include <libxml/globals.h>
102 /* #define VERBOSE_FAILURE */
103 /* #define DEBUG_EXTERNAL_ENTITIES */
104 /* #define DEBUG_INPUT */
113 * Input I/O callback sets
115 typedef struct _xmlInputCallback
{
116 xmlInputMatchCallback matchcallback
;
117 xmlInputOpenCallback opencallback
;
118 xmlInputReadCallback readcallback
;
119 xmlInputCloseCallback closecallback
;
122 #define MAX_INPUT_CALLBACK 15
124 static xmlInputCallback xmlInputCallbackTable
[MAX_INPUT_CALLBACK
];
125 static int xmlInputCallbackNr
= 0;
126 static int xmlInputCallbackInitialized
= 0;
128 #ifdef LIBXML_OUTPUT_ENABLED
130 * Output I/O callback sets
132 typedef struct _xmlOutputCallback
{
133 xmlOutputMatchCallback matchcallback
;
134 xmlOutputOpenCallback opencallback
;
135 xmlOutputWriteCallback writecallback
;
136 xmlOutputCloseCallback closecallback
;
139 #define MAX_OUTPUT_CALLBACK 15
141 static xmlOutputCallback xmlOutputCallbackTable
[MAX_OUTPUT_CALLBACK
];
142 static int xmlOutputCallbackNr
= 0;
143 static int xmlOutputCallbackInitialized
= 0;
146 xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder
);
147 #endif /* LIBXML_OUTPUT_ENABLED */
149 /************************************************************************
151 * Tree memory error handler *
153 ************************************************************************/
155 static const char *IOerr
[] = {
156 "Unknown IO error", /* UNKNOWN */
157 "Permission denied", /* EACCES */
158 "Resource temporarily unavailable",/* EAGAIN */
159 "Bad file descriptor", /* EBADF */
160 "Bad message", /* EBADMSG */
161 "Resource busy", /* EBUSY */
162 "Operation canceled", /* ECANCELED */
163 "No child processes", /* ECHILD */
164 "Resource deadlock avoided",/* EDEADLK */
165 "Domain error", /* EDOM */
166 "File exists", /* EEXIST */
167 "Bad address", /* EFAULT */
168 "File too large", /* EFBIG */
169 "Operation in progress", /* EINPROGRESS */
170 "Interrupted function call",/* EINTR */
171 "Invalid argument", /* EINVAL */
172 "Input/output error", /* EIO */
173 "Is a directory", /* EISDIR */
174 "Too many open files", /* EMFILE */
175 "Too many links", /* EMLINK */
176 "Inappropriate message buffer length",/* EMSGSIZE */
177 "Filename too long", /* ENAMETOOLONG */
178 "Too many open files in system",/* ENFILE */
179 "No such device", /* ENODEV */
180 "No such file or directory",/* ENOENT */
181 "Exec format error", /* ENOEXEC */
182 "No locks available", /* ENOLCK */
183 "Not enough space", /* ENOMEM */
184 "No space left on device", /* ENOSPC */
185 "Function not implemented", /* ENOSYS */
186 "Not a directory", /* ENOTDIR */
187 "Directory not empty", /* ENOTEMPTY */
188 "Not supported", /* ENOTSUP */
189 "Inappropriate I/O control operation",/* ENOTTY */
190 "No such device or address",/* ENXIO */
191 "Operation not permitted", /* EPERM */
192 "Broken pipe", /* EPIPE */
193 "Result too large", /* ERANGE */
194 "Read-only file system", /* EROFS */
195 "Invalid seek", /* ESPIPE */
196 "No such process", /* ESRCH */
197 "Operation timed out", /* ETIMEDOUT */
198 "Improper link", /* EXDEV */
199 "Attempt to load network entity %s", /* XML_IO_NETWORK_ATTEMPT */
200 "encoder error", /* XML_IO_ENCODER */
206 "not a socket", /* ENOTSOCK */
207 "already connected", /* EISCONN */
208 "connection refused", /* ECONNREFUSED */
209 "unreachable network", /* ENETUNREACH */
210 "adddress in use", /* EADDRINUSE */
211 "already in use", /* EALREADY */
212 "unknown address familly", /* EAFNOSUPPORT */
215 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
217 * __xmlIOWin32UTF8ToWChar:
218 * @u8String: uft-8 string
220 * Convert a string from utf-8 to wchar (WINDOWS ONLY!)
223 __xmlIOWin32UTF8ToWChar(const char *u8String
)
225 wchar_t *wString
= NULL
;
229 MultiByteToWideChar(CP_UTF8
, MB_ERR_INVALID_CHARS
, u8String
,
232 wString
= xmlMalloc(wLen
* sizeof(wchar_t));
234 if (MultiByteToWideChar
235 (CP_UTF8
, 0, u8String
, -1, wString
, wLen
) == 0) {
249 * @extra: extra informations
251 * Handle an out of memory condition
254 xmlIOErrMemory(const char *extra
)
256 __xmlSimpleError(XML_FROM_IO
, XML_ERR_NO_MEMORY
, NULL
, NULL
, extra
);
261 * @code: the error number
263 * @extra: extra informations
265 * Handle an I/O error
268 __xmlIOErr(int domain
, int code
, const char *extra
)
274 if (errno
== 0) code
= 0;
276 else if (errno
== EACCES
) code
= XML_IO_EACCES
;
279 else if (errno
== EAGAIN
) code
= XML_IO_EAGAIN
;
282 else if (errno
== EBADF
) code
= XML_IO_EBADF
;
285 else if (errno
== EBADMSG
) code
= XML_IO_EBADMSG
;
288 else if (errno
== EBUSY
) code
= XML_IO_EBUSY
;
291 else if (errno
== ECANCELED
) code
= XML_IO_ECANCELED
;
294 else if (errno
== ECHILD
) code
= XML_IO_ECHILD
;
297 else if (errno
== EDEADLK
) code
= XML_IO_EDEADLK
;
300 else if (errno
== EDOM
) code
= XML_IO_EDOM
;
303 else if (errno
== EEXIST
) code
= XML_IO_EEXIST
;
306 else if (errno
== EFAULT
) code
= XML_IO_EFAULT
;
309 else if (errno
== EFBIG
) code
= XML_IO_EFBIG
;
312 else if (errno
== EINPROGRESS
) code
= XML_IO_EINPROGRESS
;
315 else if (errno
== EINTR
) code
= XML_IO_EINTR
;
318 else if (errno
== EINVAL
) code
= XML_IO_EINVAL
;
321 else if (errno
== EIO
) code
= XML_IO_EIO
;
324 else if (errno
== EISDIR
) code
= XML_IO_EISDIR
;
327 else if (errno
== EMFILE
) code
= XML_IO_EMFILE
;
330 else if (errno
== EMLINK
) code
= XML_IO_EMLINK
;
333 else if (errno
== EMSGSIZE
) code
= XML_IO_EMSGSIZE
;
336 else if (errno
== ENAMETOOLONG
) code
= XML_IO_ENAMETOOLONG
;
339 else if (errno
== ENFILE
) code
= XML_IO_ENFILE
;
342 else if (errno
== ENODEV
) code
= XML_IO_ENODEV
;
345 else if (errno
== ENOENT
) code
= XML_IO_ENOENT
;
348 else if (errno
== ENOEXEC
) code
= XML_IO_ENOEXEC
;
351 else if (errno
== ENOLCK
) code
= XML_IO_ENOLCK
;
354 else if (errno
== ENOMEM
) code
= XML_IO_ENOMEM
;
357 else if (errno
== ENOSPC
) code
= XML_IO_ENOSPC
;
360 else if (errno
== ENOSYS
) code
= XML_IO_ENOSYS
;
363 else if (errno
== ENOTDIR
) code
= XML_IO_ENOTDIR
;
366 else if (errno
== ENOTEMPTY
) code
= XML_IO_ENOTEMPTY
;
369 else if (errno
== ENOTSUP
) code
= XML_IO_ENOTSUP
;
372 else if (errno
== ENOTTY
) code
= XML_IO_ENOTTY
;
375 else if (errno
== ENXIO
) code
= XML_IO_ENXIO
;
378 else if (errno
== EPERM
) code
= XML_IO_EPERM
;
381 else if (errno
== EPIPE
) code
= XML_IO_EPIPE
;
384 else if (errno
== ERANGE
) code
= XML_IO_ERANGE
;
387 else if (errno
== EROFS
) code
= XML_IO_EROFS
;
390 else if (errno
== ESPIPE
) code
= XML_IO_ESPIPE
;
393 else if (errno
== ESRCH
) code
= XML_IO_ESRCH
;
396 else if (errno
== ETIMEDOUT
) code
= XML_IO_ETIMEDOUT
;
399 else if (errno
== EXDEV
) code
= XML_IO_EXDEV
;
402 else if (errno
== ENOTSOCK
) code
= XML_IO_ENOTSOCK
;
405 else if (errno
== EISCONN
) code
= XML_IO_EISCONN
;
408 else if (errno
== ECONNREFUSED
) code
= XML_IO_ECONNREFUSED
;
411 else if (errno
== ETIMEDOUT
) code
= XML_IO_ETIMEDOUT
;
414 else if (errno
== ENETUNREACH
) code
= XML_IO_ENETUNREACH
;
417 else if (errno
== EADDRINUSE
) code
= XML_IO_EADDRINUSE
;
420 else if (errno
== EINPROGRESS
) code
= XML_IO_EINPROGRESS
;
423 else if (errno
== EALREADY
) code
= XML_IO_EALREADY
;
426 else if (errno
== EAFNOSUPPORT
) code
= XML_IO_EAFNOSUPPORT
;
428 else code
= XML_IO_UNKNOWN
;
429 #endif /* HAVE_ERRNO_H */
432 if (code
>= XML_IO_UNKNOWN
) idx
= code
- XML_IO_UNKNOWN
;
433 if (idx
>= (sizeof(IOerr
) / sizeof(IOerr
[0]))) idx
= 0;
435 __xmlSimpleError(domain
, code
, NULL
, IOerr
[idx
], extra
);
440 * @code: the error number
441 * @extra: extra informations
443 * Handle an I/O error
446 xmlIOErr(int code
, const char *extra
)
448 __xmlIOErr(XML_FROM_IO
, code
, extra
);
453 * @ctx: the parser context
454 * @extra: extra informations
456 * Handle a resource access error
459 __xmlLoaderErr(void *ctx
, const char *msg
, const char *filename
)
461 xmlParserCtxtPtr ctxt
= (xmlParserCtxtPtr
) ctx
;
462 xmlStructuredErrorFunc schannel
= NULL
;
463 xmlGenericErrorFunc channel
= NULL
;
465 xmlErrorLevel level
= XML_ERR_ERROR
;
467 if ((ctxt
!= NULL
) && (ctxt
->disableSAX
!= 0) &&
468 (ctxt
->instate
== XML_PARSER_EOF
))
470 if ((ctxt
!= NULL
) && (ctxt
->sax
!= NULL
)) {
471 if (ctxt
->validate
) {
472 channel
= ctxt
->sax
->error
;
473 level
= XML_ERR_ERROR
;
475 channel
= ctxt
->sax
->warning
;
476 level
= XML_ERR_WARNING
;
478 if (ctxt
->sax
->initialized
== XML_SAX2_MAGIC
)
479 schannel
= ctxt
->sax
->serror
;
480 data
= ctxt
->userData
;
482 __xmlRaiseError(schannel
, channel
, data
, ctxt
, NULL
, XML_FROM_IO
,
483 XML_IO_LOAD_ERROR
, level
, NULL
, 0,
484 filename
, NULL
, NULL
, 0, 0,
489 /************************************************************************
491 * Tree memory error handler *
493 ************************************************************************/
495 * xmlNormalizeWindowsPath:
496 * @path: the input file path
498 * This function is obsolete. Please see xmlURIFromPath in uri.c for
501 * Returns a canonicalized version of the path
504 xmlNormalizeWindowsPath(const xmlChar
*path
)
506 return xmlCanonicPath(path
);
510 * xmlCleanupInputCallbacks:
512 * clears the entire input callback table. this includes the
516 xmlCleanupInputCallbacks(void)
520 if (!xmlInputCallbackInitialized
)
523 for (i
= xmlInputCallbackNr
- 1; i
>= 0; i
--) {
524 xmlInputCallbackTable
[i
].matchcallback
= NULL
;
525 xmlInputCallbackTable
[i
].opencallback
= NULL
;
526 xmlInputCallbackTable
[i
].readcallback
= NULL
;
527 xmlInputCallbackTable
[i
].closecallback
= NULL
;
530 xmlInputCallbackNr
= 0;
531 xmlInputCallbackInitialized
= 0;
535 * xmlPopInputCallbacks:
537 * Clear the top input callback from the input stack. this includes the
540 * Returns the number of input callback registered or -1 in case of error.
543 xmlPopInputCallbacks(void)
545 if (!xmlInputCallbackInitialized
)
548 if (xmlInputCallbackNr
<= 0)
551 xmlInputCallbackNr
--;
552 xmlInputCallbackTable
[xmlInputCallbackNr
].matchcallback
= NULL
;
553 xmlInputCallbackTable
[xmlInputCallbackNr
].opencallback
= NULL
;
554 xmlInputCallbackTable
[xmlInputCallbackNr
].readcallback
= NULL
;
555 xmlInputCallbackTable
[xmlInputCallbackNr
].closecallback
= NULL
;
557 return(xmlInputCallbackNr
);
560 #ifdef LIBXML_OUTPUT_ENABLED
562 * xmlCleanupOutputCallbacks:
564 * clears the entire output callback table. this includes the
565 * compiled-in I/O callbacks.
568 xmlCleanupOutputCallbacks(void)
572 if (!xmlOutputCallbackInitialized
)
575 for (i
= xmlOutputCallbackNr
- 1; i
>= 0; i
--) {
576 xmlOutputCallbackTable
[i
].matchcallback
= NULL
;
577 xmlOutputCallbackTable
[i
].opencallback
= NULL
;
578 xmlOutputCallbackTable
[i
].writecallback
= NULL
;
579 xmlOutputCallbackTable
[i
].closecallback
= NULL
;
582 xmlOutputCallbackNr
= 0;
583 xmlOutputCallbackInitialized
= 0;
585 #endif /* LIBXML_OUTPUT_ENABLED */
587 /************************************************************************
589 * Standard I/O for file accesses *
591 ************************************************************************/
593 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
597 * @path: the path in utf-8 encoding
598 * @mode: type of access (0 - read, 1 - write)
600 * function opens the file specified by @path
604 xmlWrapOpenUtf8(const char *path
,int mode
)
609 wPath
= __xmlIOWin32UTF8ToWChar(path
);
612 fd
= _wfopen(wPath
, mode
? L
"wb" : L
"rb");
615 /* maybe path in native encoding */
617 fd
= fopen(path
, mode
? "wb" : "rb");
624 xmlWrapGzOpenUtf8(const char *path
, const char *mode
)
629 fd
= gzopen (path
, mode
);
633 wPath
= __xmlIOWin32UTF8ToWChar(path
);
636 int d
, m
= (strstr(mode
, "r") ? O_RDONLY
: O_RDWR
);
638 m
|= (strstr(mode
, "b") ? _O_BINARY
: 0);
640 d
= _wopen(wPath
, m
);
642 fd
= gzdopen(d
, mode
);
652 * @path: the path in utf-8 encoding
653 * @info: structure that stores results
655 * function obtains information about the file or directory
659 xmlWrapStatUtf8(const char *path
,struct stat
*info
)
665 wPath
= __xmlIOWin32UTF8ToWChar(path
);
668 retval
= _wstat(wPath
,info
);
671 /* maybe path in native encoding */
673 retval
= stat(path
,info
);
683 * @mode: type of access (0 - read, 1 - write)
685 * function opens the file specified by @path
689 xmlWrapOpenNative(const char *path
,int mode
)
691 return fopen(path
,mode
? "wb" : "rb");
697 * @info: structure that stores results
699 * function obtains information about the file or directory
703 xmlWrapStatNative(const char *path
,struct stat
*info
)
706 return stat(path
,info
);
712 typedef int (* xmlWrapStatFunc
) (const char *f
, struct stat
*s
);
713 static xmlWrapStatFunc xmlWrapStat
= xmlWrapStatNative
;
714 typedef FILE* (* xmlWrapOpenFunc
)(const char *f
,int mode
);
715 static xmlWrapOpenFunc xmlWrapOpen
= xmlWrapOpenNative
;
717 typedef gzFile (* xmlWrapGzOpenFunc
) (const char *f
, const char *mode
);
718 static xmlWrapGzOpenFunc xmlWrapGzOpen
= gzopen
;
721 * xmlInitPlatformSpecificIo:
723 * Initialize platform specific features.
726 xmlInitPlatformSpecificIo(void)
728 static int xmlPlatformIoInitialized
= 0;
731 if(xmlPlatformIoInitialized
)
734 osvi
.dwOSVersionInfoSize
= sizeof(osvi
);
736 if(GetVersionEx(&osvi
) && (osvi
.dwPlatformId
== VER_PLATFORM_WIN32_NT
)) {
737 xmlWrapStat
= xmlWrapStatUtf8
;
738 xmlWrapOpen
= xmlWrapOpenUtf8
;
740 xmlWrapGzOpen
= xmlWrapGzOpenUtf8
;
743 xmlWrapStat
= xmlWrapStatNative
;
744 xmlWrapOpen
= xmlWrapOpenNative
;
746 xmlWrapGzOpen
= gzopen
;
750 xmlPlatformIoInitialized
= 1;
758 * @path: the path to check
760 * function checks to see if @path is a valid source
761 * (file, socket...) for XML.
763 * if stat is not available on the target machine,
764 * returns 1. if stat fails, returns 0 (if calling
765 * stat on the filename fails, it can't be right).
766 * if stat succeeds and the file is a directory,
767 * returns 2. otherwise returns 1.
771 xmlCheckFilename (const char *path
)
774 struct stat stat_buffer
;
780 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
782 * On Windows stat and wstat do not work with long pathname,
783 * which start with '\\?\'
785 if ((path
[0] == '\\') && (path
[1] == '\\') && (path
[2] == '?') &&
789 if (xmlWrapStat(path
, &stat_buffer
) == -1)
792 if (stat(path
, &stat_buffer
) == -1)
796 if (S_ISDIR(stat_buffer
.st_mode
))
799 #endif /* HAVE_STAT */
806 * No Operation function, does nothing, no input
817 * @context: the I/O context
818 * @buffer: where to drop data
819 * @len: number of bytes to read
821 * Read @len bytes to @buffer from the I/O channel.
823 * Returns the number of bytes written
826 xmlFdRead (void * context
, char * buffer
, int len
) {
829 ret
= read((int) (long) context
, &buffer
[0], len
);
830 if (ret
< 0) xmlIOErr(0, "read()");
834 #ifdef LIBXML_OUTPUT_ENABLED
837 * @context: the I/O context
838 * @buffer: where to get data
839 * @len: number of bytes to write
841 * Write @len bytes from @buffer to the I/O channel.
843 * Returns the number of bytes written
846 xmlFdWrite (void * context
, const char * buffer
, int len
) {
850 ret
= write((int) (long) context
, &buffer
[0], len
);
851 if (ret
< 0) xmlIOErr(0, "write()");
855 #endif /* LIBXML_OUTPUT_ENABLED */
859 * @context: the I/O context
861 * Close an I/O channel
863 * Returns 0 in case of success and error code otherwise
866 xmlFdClose (void * context
) {
868 ret
= close((int) (long) context
);
869 if (ret
< 0) xmlIOErr(0, "close()");
875 * @filename: the URI for matching
879 * Returns 1 if matches, 0 otherwise
882 xmlFileMatch (const char *filename ATTRIBUTE_UNUSED
) {
888 * @filename: the URI for matching
890 * input from FILE *, supports compressed input
891 * if @filename is " " then the standard input is used
893 * Returns an I/O context or NULL in case of error
896 xmlFileOpen_real (const char *filename
) {
897 const char *path
= filename
;
900 if (filename
== NULL
)
903 if (!strcmp(filename
, "-")) {
908 if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file://localhost/", 17)) {
909 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
910 path
= &filename
[17];
912 path
= &filename
[16];
914 } else if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file:///", 8)) {
915 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
920 } else if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file:/", 6)) {
921 /* lots of generators seems to lazy to read RFC 1738 */
922 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
929 if (!xmlCheckFilename(path
))
932 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
933 fd
= xmlWrapOpen(path
, 0);
935 fd
= fopen(path
, "r");
937 if (fd
== NULL
) xmlIOErr(0, path
);
943 * @filename: the URI for matching
945 * Wrapper around xmlFileOpen_real that try it with an unescaped
946 * version of @filename, if this fails fallback to @filename
948 * Returns a handler or NULL in case or failure
951 xmlFileOpen (const char *filename
) {
955 retval
= xmlFileOpen_real(filename
);
956 if (retval
== NULL
) {
957 unescaped
= xmlURIUnescapeString(filename
, 0, NULL
);
958 if (unescaped
!= NULL
) {
959 retval
= xmlFileOpen_real(unescaped
);
967 #ifdef LIBXML_OUTPUT_ENABLED
970 * @filename: the URI for matching
972 * output to from FILE *,
973 * if @filename is "-" then the standard output is used
975 * Returns an I/O context or NULL in case of error
978 xmlFileOpenW (const char *filename
) {
979 const char *path
= NULL
;
982 if (!strcmp(filename
, "-")) {
987 if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file://localhost/", 17))
988 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
989 path
= &filename
[17];
991 path
= &filename
[16];
993 else if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file:///", 8)) {
994 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
1005 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
1006 fd
= xmlWrapOpen(path
, 1);
1008 fd
= fopen(path
, "wb");
1011 if (fd
== NULL
) xmlIOErr(0, path
);
1012 return((void *) fd
);
1014 #endif /* LIBXML_OUTPUT_ENABLED */
1018 * @context: the I/O context
1019 * @buffer: where to drop data
1020 * @len: number of bytes to write
1022 * Read @len bytes to @buffer from the I/O channel.
1024 * Returns the number of bytes written or < 0 in case of failure
1027 xmlFileRead (void * context
, char * buffer
, int len
) {
1029 if ((context
== NULL
) || (buffer
== NULL
))
1031 ret
= fread(&buffer
[0], 1, len
, (FILE *) context
);
1032 if (ret
< 0) xmlIOErr(0, "fread()");
1036 #ifdef LIBXML_OUTPUT_ENABLED
1039 * @context: the I/O context
1040 * @buffer: where to drop data
1041 * @len: number of bytes to write
1043 * Write @len bytes from @buffer to the I/O channel.
1045 * Returns the number of bytes written
1048 xmlFileWrite (void * context
, const char * buffer
, int len
) {
1051 if ((context
== NULL
) || (buffer
== NULL
))
1053 items
= fwrite(&buffer
[0], len
, 1, (FILE *) context
);
1054 if ((items
== 0) && (ferror((FILE *) context
))) {
1055 xmlIOErr(0, "fwrite()");
1058 return(items
* len
);
1060 #endif /* LIBXML_OUTPUT_ENABLED */
1064 * @context: the I/O context
1066 * Close an I/O channel
1068 * Returns 0 or -1 in case of error
1071 xmlFileClose (void * context
) {
1075 if (context
== NULL
)
1077 fil
= (FILE *) context
;
1078 if ((fil
== stdout
) || (fil
== stderr
)) {
1081 xmlIOErr(0, "fflush()");
1086 ret
= ( fclose((FILE *) context
) == EOF
) ? -1 : 0;
1088 xmlIOErr(0, "fclose()");
1094 * @context: the I/O context
1096 * Flush an I/O channel
1099 xmlFileFlush (void * context
) {
1102 if (context
== NULL
)
1104 ret
= ( fflush((FILE *) context
) == EOF
) ? -1 : 0;
1106 xmlIOErr(0, "fflush()");
1110 #ifdef LIBXML_OUTPUT_ENABLED
1113 * @context: the xmlBuffer
1114 * @buffer: the data to write
1115 * @len: number of bytes to write
1117 * Write @len bytes from @buffer to the xml buffer
1119 * Returns the number of bytes written
1122 xmlBufferWrite (void * context
, const char * buffer
, int len
) {
1125 ret
= xmlBufferAdd((xmlBufferPtr
) context
, (const xmlChar
*) buffer
, len
);
1133 /************************************************************************
1135 * I/O for compressed file accesses *
1137 ************************************************************************/
1140 * @filename: the URI for matching
1142 * input from compressed file test
1144 * Returns 1 if matches, 0 otherwise
1147 xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED
) {
1152 * xmlGzfileOpen_real:
1153 * @filename: the URI for matching
1155 * input from compressed file open
1156 * if @filename is " " then the standard input is used
1158 * Returns an I/O context or NULL in case of error
1161 xmlGzfileOpen_real (const char *filename
) {
1162 const char *path
= NULL
;
1165 if (!strcmp(filename
, "-")) {
1166 int duped_fd
= dup(fileno(stdin
));
1167 fd
= gzdopen(duped_fd
, "rb");
1168 if (fd
== Z_NULL
&& duped_fd
>= 0) {
1169 close(duped_fd
); /* gzdOpen() does not close on failure */
1172 return((void *) fd
);
1175 if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file://localhost/", 17))
1176 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
1177 path
= &filename
[17];
1179 path
= &filename
[16];
1181 else if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file:///", 8)) {
1182 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
1183 path
= &filename
[8];
1185 path
= &filename
[7];
1192 if (!xmlCheckFilename(path
))
1195 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
1196 fd
= xmlWrapGzOpen(path
, "rb");
1198 fd
= gzopen(path
, "rb");
1200 return((void *) fd
);
1205 * @filename: the URI for matching
1207 * Wrapper around xmlGzfileOpen if the open fais, it will
1208 * try to unescape @filename
1211 xmlGzfileOpen (const char *filename
) {
1215 retval
= xmlGzfileOpen_real(filename
);
1216 if (retval
== NULL
) {
1217 unescaped
= xmlURIUnescapeString(filename
, 0, NULL
);
1218 if (unescaped
!= NULL
) {
1219 retval
= xmlGzfileOpen_real(unescaped
);
1226 #ifdef LIBXML_OUTPUT_ENABLED
1229 * @filename: the URI for matching
1230 * @compression: the compression factor (0 - 9 included)
1232 * input from compressed file open
1233 * if @filename is " " then the standard input is used
1235 * Returns an I/O context or NULL in case of error
1238 xmlGzfileOpenW (const char *filename
, int compression
) {
1239 const char *path
= NULL
;
1243 snprintf(mode
, sizeof(mode
), "wb%d", compression
);
1244 if (!strcmp(filename
, "-")) {
1245 int duped_fd
= dup(fileno(stdout
));
1246 fd
= gzdopen(duped_fd
, "rb");
1247 if (fd
== Z_NULL
&& duped_fd
>= 0) {
1248 close(duped_fd
); /* gzdOpen() does not close on failure */
1251 return((void *) fd
);
1254 if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file://localhost/", 17))
1255 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
1256 path
= &filename
[17];
1258 path
= &filename
[16];
1260 else if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file:///", 8)) {
1261 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
1262 path
= &filename
[8];
1264 path
= &filename
[7];
1272 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
1273 fd
= xmlWrapGzOpen(path
, mode
);
1275 fd
= gzopen(path
, mode
);
1277 return((void *) fd
);
1279 #endif /* LIBXML_OUTPUT_ENABLED */
1283 * @context: the I/O context
1284 * @buffer: where to drop data
1285 * @len: number of bytes to write
1287 * Read @len bytes to @buffer from the compressed I/O channel.
1289 * Returns the number of bytes written
1292 xmlGzfileRead (void * context
, char * buffer
, int len
) {
1295 ret
= gzread((gzFile
) context
, &buffer
[0], len
);
1296 if (ret
< 0) xmlIOErr(0, "gzread()");
1300 #ifdef LIBXML_OUTPUT_ENABLED
1303 * @context: the I/O context
1304 * @buffer: where to drop data
1305 * @len: number of bytes to write
1307 * Write @len bytes from @buffer to the compressed I/O channel.
1309 * Returns the number of bytes written
1312 xmlGzfileWrite (void * context
, const char * buffer
, int len
) {
1315 ret
= gzwrite((gzFile
) context
, (char *) &buffer
[0], len
);
1316 if (ret
< 0) xmlIOErr(0, "gzwrite()");
1319 #endif /* LIBXML_OUTPUT_ENABLED */
1323 * @context: the I/O context
1325 * Close a compressed I/O channel
1328 xmlGzfileClose (void * context
) {
1331 ret
= (gzclose((gzFile
) context
) == Z_OK
) ? 0 : -1;
1332 if (ret
< 0) xmlIOErr(0, "gzclose()");
1335 #endif /* HAVE_ZLIB_H */
1338 /************************************************************************
1340 * I/O for compressed file accesses *
1342 ************************************************************************/
1346 * @filename: the URI for matching
1348 * input from compressed file test
1350 * Returns 1 if matches, 0 otherwise
1353 xmlXzfileMatch (const char *filename ATTRIBUTE_UNUSED
) {
1358 * xmlXzFileOpen_real:
1359 * @filename: the URI for matching
1361 * input from compressed file open
1362 * if @filename is " " then the standard input is used
1364 * Returns an I/O context or NULL in case of error
1367 xmlXzfileOpen_real (const char *filename
) {
1368 const char *path
= NULL
;
1371 if (!strcmp(filename
, "-")) {
1372 fd
= __libxml2_xzdopen(dup(fileno(stdin
)), "rb");
1373 return((void *) fd
);
1376 if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file://localhost/", 17)) {
1377 path
= &filename
[16];
1378 } else if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file:///", 8)) {
1379 path
= &filename
[7];
1380 } else if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file:/", 6)) {
1381 /* lots of generators seems to lazy to read RFC 1738 */
1382 path
= &filename
[5];
1388 if (!xmlCheckFilename(path
))
1391 fd
= __libxml2_xzopen(path
, "rb");
1392 return((void *) fd
);
1397 * @filename: the URI for matching
1399 * Wrapper around xmlXzfileOpen_real that try it with an unescaped
1400 * version of @filename, if this fails fallback to @filename
1402 * Returns a handler or NULL in case or failure
1405 xmlXzfileOpen (const char *filename
) {
1409 retval
= xmlXzfileOpen_real(filename
);
1410 if (retval
== NULL
) {
1411 unescaped
= xmlURIUnescapeString(filename
, 0, NULL
);
1412 if (unescaped
!= NULL
) {
1413 retval
= xmlXzfileOpen_real(unescaped
);
1423 * @context: the I/O context
1424 * @buffer: where to drop data
1425 * @len: number of bytes to write
1427 * Read @len bytes to @buffer from the compressed I/O channel.
1429 * Returns the number of bytes written
1432 xmlXzfileRead (void * context
, char * buffer
, int len
) {
1435 ret
= __libxml2_xzread((xzFile
) context
, &buffer
[0], len
);
1436 if (ret
< 0) xmlIOErr(0, "xzread()");
1442 * @context: the I/O context
1444 * Close a compressed I/O channel
1447 xmlXzfileClose (void * context
) {
1450 ret
= (__libxml2_xzclose((xzFile
) context
) == LZMA_OK
) ? 0 : -1;
1451 if (ret
< 0) xmlIOErr(0, "xzclose()");
1454 #endif /* HAVE_LZMA_H */
1456 #ifdef LIBXML_HTTP_ENABLED
1457 /************************************************************************
1459 * I/O for HTTP file accesses *
1461 ************************************************************************/
1463 #ifdef LIBXML_OUTPUT_ENABLED
1464 typedef struct xmlIOHTTPWriteCtxt_
1472 } xmlIOHTTPWriteCtxt
, *xmlIOHTTPWriteCtxtPtr
;
1476 #define DFLT_WBITS ( -15 )
1477 #define DFLT_MEM_LVL ( 8 )
1478 #define GZ_MAGIC1 ( 0x1f )
1479 #define GZ_MAGIC2 ( 0x8b )
1480 #define LXML_ZLIB_OS_CODE ( 0x03 )
1481 #define INIT_HTTP_BUFF_SIZE ( 32768 )
1482 #define DFLT_ZLIB_RATIO ( 5 )
1485 ** Data structure and functions to work with sending compressed data
1489 typedef struct xmlZMemBuff_
1494 unsigned char * zbuff
;
1497 } xmlZMemBuff
, *xmlZMemBuffPtr
;
1500 * append_reverse_ulong
1501 * @buff: Compressed memory buffer
1502 * @data: Unsigned long to append
1504 * Append a unsigned long in reverse byte order to the end of the
1508 append_reverse_ulong( xmlZMemBuff
* buff
, unsigned long data
) {
1516 ** This is plagiarized from putLong in gzio.c (zlib source) where
1517 ** the number "4" is hardcoded. If zlib is ever patched to
1518 ** support 64 bit file sizes, this code would need to be patched
1522 for ( idx
= 0; idx
< 4; idx
++ ) {
1523 *buff
->zctrl
.next_out
= ( data
& 0xff );
1525 buff
->zctrl
.next_out
++;
1534 * @buff: The memory buffer context to clear
1536 * Release all the resources associated with the compressed memory buffer.
1539 xmlFreeZMemBuff( xmlZMemBuffPtr buff
) {
1548 xmlFree( buff
->zbuff
);
1550 z_err
= deflateEnd( &buff
->zctrl
);
1551 if ( z_err
!= Z_OK
)
1552 xmlGenericError( xmlGenericErrorContext
,
1553 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
1556 deflateEnd( &buff
->zctrl
);
1565 *@compression: Compression value to use
1567 * Create a memory buffer to hold the compressed XML document. The
1568 * compressed document in memory will end up being identical to what
1569 * would be created if gzopen/gzwrite/gzclose were being used to
1570 * write the document to disk. The code for the header/trailer data to
1571 * the compression is plagiarized from the zlib source files.
1574 xmlCreateZMemBuff( int compression
) {
1578 xmlZMemBuffPtr buff
= NULL
;
1580 if ( ( compression
< 1 ) || ( compression
> 9 ) )
1583 /* Create the control and data areas */
1585 buff
= xmlMalloc( sizeof( xmlZMemBuff
) );
1586 if ( buff
== NULL
) {
1587 xmlIOErrMemory("creating buffer context");
1591 (void)memset( buff
, 0, sizeof( xmlZMemBuff
) );
1592 buff
->size
= INIT_HTTP_BUFF_SIZE
;
1593 buff
->zbuff
= xmlMalloc( buff
->size
);
1594 if ( buff
->zbuff
== NULL
) {
1595 xmlFreeZMemBuff( buff
);
1596 xmlIOErrMemory("creating buffer");
1600 z_err
= deflateInit2( &buff
->zctrl
, compression
, Z_DEFLATED
,
1601 DFLT_WBITS
, DFLT_MEM_LVL
, Z_DEFAULT_STRATEGY
);
1602 if ( z_err
!= Z_OK
) {
1604 xmlFreeZMemBuff( buff
);
1606 xmlStrPrintf(msg
, 500,
1607 (const xmlChar
*) "xmlCreateZMemBuff: %s %d\n",
1608 "Error initializing compression context. ZLIB error:",
1610 xmlIOErr(XML_IO_WRITE
, (const char *) msg
);
1614 /* Set the header data. The CRC will be needed for the trailer */
1615 buff
->crc
= crc32( 0L, NULL
, 0 );
1616 hdr_lgth
= snprintf( (char *)buff
->zbuff
, buff
->size
,
1617 "%c%c%c%c%c%c%c%c%c%c",
1618 GZ_MAGIC1
, GZ_MAGIC2
, Z_DEFLATED
,
1619 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE
);
1620 buff
->zctrl
.next_out
= buff
->zbuff
+ hdr_lgth
;
1621 buff
->zctrl
.avail_out
= buff
->size
- hdr_lgth
;
1628 * @buff: Buffer used to compress and consolidate data.
1629 * @ext_amt: Number of bytes to extend the buffer.
1631 * Extend the internal buffer used to store the compressed data by the
1634 * Returns 0 on success or -1 on failure to extend the buffer. On failure
1635 * the original buffer still exists at the original size.
1638 xmlZMemBuffExtend( xmlZMemBuffPtr buff
, size_t ext_amt
) {
1644 unsigned char * tmp_ptr
= NULL
;
1649 else if ( ext_amt
== 0 )
1652 cur_used
= buff
->zctrl
.next_out
- buff
->zbuff
;
1653 new_size
= buff
->size
+ ext_amt
;
1656 if ( cur_used
> new_size
)
1657 xmlGenericError( xmlGenericErrorContext
,
1658 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
1659 "Buffer overwrite detected during compressed memory",
1660 "buffer extension. Overflowed by",
1661 (cur_used
- new_size
) );
1664 tmp_ptr
= xmlRealloc( buff
->zbuff
, new_size
);
1665 if ( tmp_ptr
!= NULL
) {
1667 buff
->size
= new_size
;
1668 buff
->zbuff
= tmp_ptr
;
1669 buff
->zctrl
.next_out
= tmp_ptr
+ cur_used
;
1670 buff
->zctrl
.avail_out
= new_size
- cur_used
;
1674 xmlStrPrintf(msg
, 500,
1675 (const xmlChar
*) "xmlZMemBuffExtend: %s %lu bytes.\n",
1676 "Allocation failure extending output buffer to",
1678 xmlIOErr(XML_IO_WRITE
, (const char *) msg
);
1686 * @buff: Buffer used to compress and consolidate data
1687 * @src: Uncompressed source content to append to buffer
1688 * @len: Length of source data to append to buffer
1690 * Compress and append data to the internal buffer. The data buffer
1691 * will be expanded if needed to store the additional data.
1693 * Returns the number of bytes appended to the buffer or -1 on error.
1696 xmlZMemBuffAppend( xmlZMemBuffPtr buff
, const char * src
, int len
) {
1701 if ( ( buff
== NULL
) || ( src
== NULL
) )
1704 buff
->zctrl
.avail_in
= len
;
1705 buff
->zctrl
.next_in
= (unsigned char *)src
;
1706 while ( buff
->zctrl
.avail_in
> 0 ) {
1708 ** Extend the buffer prior to deflate call if a reasonable amount
1709 ** of output buffer space is not available.
1711 min_accept
= buff
->zctrl
.avail_in
/ DFLT_ZLIB_RATIO
;
1712 if ( buff
->zctrl
.avail_out
<= min_accept
) {
1713 if ( xmlZMemBuffExtend( buff
, buff
->size
) == -1 )
1717 z_err
= deflate( &buff
->zctrl
, Z_NO_FLUSH
);
1718 if ( z_err
!= Z_OK
) {
1720 xmlStrPrintf(msg
, 500,
1721 (const xmlChar
*) "xmlZMemBuffAppend: %s %d %s - %d",
1722 "Compression error while appending",
1723 len
, "bytes to buffer. ZLIB error", z_err
);
1724 xmlIOErr(XML_IO_WRITE
, (const char *) msg
);
1729 buff
->crc
= crc32( buff
->crc
, (unsigned char *)src
, len
);
1735 * xmlZMemBuffGetContent
1736 * @buff: Compressed memory content buffer
1737 * @data_ref: Pointer reference to point to compressed content
1739 * Flushes the compression buffers, appends gzip file trailers and
1740 * returns the compressed content and length of the compressed data.
1741 * NOTE: The gzip trailer code here is plagiarized from zlib source.
1743 * Returns the length of the compressed data or -1 on error.
1746 xmlZMemBuffGetContent( xmlZMemBuffPtr buff
, char ** data_ref
) {
1751 if ( ( buff
== NULL
) || ( data_ref
== NULL
) )
1754 /* Need to loop until compression output buffers are flushed */
1758 z_err
= deflate( &buff
->zctrl
, Z_FINISH
);
1759 if ( z_err
== Z_OK
) {
1760 /* In this case Z_OK means more buffer space needed */
1762 if ( xmlZMemBuffExtend( buff
, buff
->size
) == -1 )
1766 while ( z_err
== Z_OK
);
1768 /* If the compression state is not Z_STREAM_END, some error occurred */
1770 if ( z_err
== Z_STREAM_END
) {
1772 /* Need to append the gzip data trailer */
1774 if ( buff
->zctrl
.avail_out
< ( 2 * sizeof( unsigned long ) ) ) {
1775 if ( xmlZMemBuffExtend(buff
, (2 * sizeof(unsigned long))) == -1 )
1780 ** For whatever reason, the CRC and length data are pushed out
1781 ** in reverse byte order. So a memcpy can't be used here.
1784 append_reverse_ulong( buff
, buff
->crc
);
1785 append_reverse_ulong( buff
, buff
->zctrl
.total_in
);
1787 zlgth
= buff
->zctrl
.next_out
- buff
->zbuff
;
1788 *data_ref
= (char *)buff
->zbuff
;
1793 xmlStrPrintf(msg
, 500,
1794 (const xmlChar
*) "xmlZMemBuffGetContent: %s - %d\n",
1795 "Error flushing zlib buffers. Error code", z_err
);
1796 xmlIOErr(XML_IO_WRITE
, (const char *) msg
);
1801 #endif /* LIBXML_OUTPUT_ENABLED */
1802 #endif /* HAVE_ZLIB_H */
1804 #ifdef LIBXML_OUTPUT_ENABLED
1806 * xmlFreeHTTPWriteCtxt
1807 * @ctxt: Context to cleanup
1809 * Free allocated memory and reclaim system resources.
1814 xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt
)
1816 if ( ctxt
->uri
!= NULL
)
1817 xmlFree( ctxt
->uri
);
1819 if ( ctxt
->doc_buff
!= NULL
) {
1822 if ( ctxt
->compression
> 0 ) {
1823 xmlFreeZMemBuff( ctxt
->doc_buff
);
1828 xmlOutputBufferClose( ctxt
->doc_buff
);
1835 #endif /* LIBXML_OUTPUT_ENABLED */
1840 * @filename: the URI for matching
1842 * check if the URI matches an HTTP one
1844 * Returns 1 if matches, 0 otherwise
1847 xmlIOHTTPMatch (const char *filename
) {
1848 if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"http://", 7))
1855 * @filename: the URI for matching
1857 * open an HTTP I/O channel
1859 * Returns an I/O context or NULL in case of error
1862 xmlIOHTTPOpen (const char *filename
) {
1863 return(xmlNanoHTTPOpen(filename
, NULL
));
1866 #ifdef LIBXML_OUTPUT_ENABLED
1869 * @post_uri: The destination URI for the document
1870 * @compression: The compression desired for the document.
1872 * Open a temporary buffer to collect the document for a subsequent HTTP POST
1873 * request. Non-static as is called from the output buffer creation routine.
1875 * Returns an I/O context or NULL in case of error.
1879 xmlIOHTTPOpenW(const char *post_uri
, int compression
)
1882 xmlIOHTTPWriteCtxtPtr ctxt
= NULL
;
1884 if (post_uri
== NULL
)
1887 ctxt
= xmlMalloc(sizeof(xmlIOHTTPWriteCtxt
));
1889 xmlIOErrMemory("creating HTTP output context");
1893 (void) memset(ctxt
, 0, sizeof(xmlIOHTTPWriteCtxt
));
1895 ctxt
->uri
= (char *) xmlStrdup((const xmlChar
*)post_uri
);
1896 if (ctxt
->uri
== NULL
) {
1897 xmlIOErrMemory("copying URI");
1898 xmlFreeHTTPWriteCtxt(ctxt
);
1903 * ** Since the document length is required for an HTTP post,
1904 * ** need to put the document into a buffer. A memory buffer
1905 * ** is being used to avoid pushing the data to disk and back.
1909 if ((compression
> 0) && (compression
<= 9)) {
1911 ctxt
->compression
= compression
;
1912 ctxt
->doc_buff
= xmlCreateZMemBuff(compression
);
1916 /* Any character conversions should have been done before this */
1918 ctxt
->doc_buff
= xmlAllocOutputBufferInternal(NULL
);
1921 if (ctxt
->doc_buff
== NULL
) {
1922 xmlFreeHTTPWriteCtxt(ctxt
);
1928 #endif /* LIBXML_OUTPUT_ENABLED */
1930 #ifdef LIBXML_OUTPUT_ENABLED
1932 * xmlIOHTTPDfltOpenW
1933 * @post_uri: The destination URI for this document.
1935 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
1936 * HTTP post command. This function should generally not be used as
1937 * the open callback is short circuited in xmlOutputBufferCreateFile.
1939 * Returns a pointer to the new IO context.
1942 xmlIOHTTPDfltOpenW( const char * post_uri
) {
1943 return ( xmlIOHTTPOpenW( post_uri
, 0 ) );
1945 #endif /* LIBXML_OUTPUT_ENABLED */
1949 * @context: the I/O context
1950 * @buffer: where to drop data
1951 * @len: number of bytes to write
1953 * Read @len bytes to @buffer from the I/O channel.
1955 * Returns the number of bytes written
1958 xmlIOHTTPRead(void * context
, char * buffer
, int len
) {
1959 if ((buffer
== NULL
) || (len
< 0)) return(-1);
1960 return(xmlNanoHTTPRead(context
, &buffer
[0], len
));
1963 #ifdef LIBXML_OUTPUT_ENABLED
1966 * @context: previously opened writing context
1967 * @buffer: data to output to temporary buffer
1968 * @len: bytes to output
1970 * Collect data from memory buffer into a temporary file for later
1973 * Returns number of bytes written.
1977 xmlIOHTTPWrite( void * context
, const char * buffer
, int len
) {
1979 xmlIOHTTPWriteCtxtPtr ctxt
= context
;
1981 if ( ( ctxt
== NULL
) || ( ctxt
->doc_buff
== NULL
) || ( buffer
== NULL
) )
1986 /* Use gzwrite or fwrite as previously setup in the open call */
1989 if ( ctxt
->compression
> 0 )
1990 len
= xmlZMemBuffAppend( ctxt
->doc_buff
, buffer
, len
);
1994 len
= xmlOutputBufferWrite( ctxt
->doc_buff
, len
, buffer
);
1998 xmlStrPrintf(msg
, 500,
1999 (const xmlChar
*) "xmlIOHTTPWrite: %s\n%s '%s'.\n",
2000 "Error appending to internal buffer.",
2001 "Error sending document to URI",
2003 xmlIOErr(XML_IO_WRITE
, (const char *) msg
);
2009 #endif /* LIBXML_OUTPUT_ENABLED */
2014 * @context: the I/O context
2016 * Close an HTTP I/O channel
2021 xmlIOHTTPClose (void * context
) {
2022 xmlNanoHTTPClose(context
);
2026 #ifdef LIBXML_OUTPUT_ENABLED
2028 * xmlIOHTTCloseWrite
2029 * @context: The I/O context
2030 * @http_mthd: The HTTP method to be used when sending the data
2032 * Close the transmit HTTP I/O channel and actually send the data.
2035 xmlIOHTTPCloseWrite( void * context
, const char * http_mthd
) {
2039 int content_lgth
= 0;
2040 xmlIOHTTPWriteCtxtPtr ctxt
= context
;
2042 char * http_content
= NULL
;
2043 char * content_encoding
= NULL
;
2044 char * content_type
= (char *) "text/xml";
2045 void * http_ctxt
= NULL
;
2047 if ( ( ctxt
== NULL
) || ( http_mthd
== NULL
) )
2050 /* Retrieve the content from the appropriate buffer */
2054 if ( ctxt
->compression
> 0 ) {
2055 content_lgth
= xmlZMemBuffGetContent( ctxt
->doc_buff
, &http_content
);
2056 content_encoding
= (char *) "Content-Encoding: gzip";
2061 /* Pull the data out of the memory output buffer */
2063 xmlOutputBufferPtr dctxt
= ctxt
->doc_buff
;
2064 http_content
= (char *) xmlBufContent(dctxt
->buffer
);
2065 content_lgth
= xmlBufUse(dctxt
->buffer
);
2068 if ( http_content
== NULL
) {
2070 xmlStrPrintf(msg
, 500,
2071 (const xmlChar
*) "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
2072 "Error retrieving content.\nUnable to",
2073 http_mthd
, "data to URI", ctxt
->uri
);
2074 xmlIOErr(XML_IO_WRITE
, (const char *) msg
);
2079 http_ctxt
= xmlNanoHTTPMethod( ctxt
->uri
, http_mthd
, http_content
,
2080 &content_type
, content_encoding
,
2083 if ( http_ctxt
!= NULL
) {
2085 /* If testing/debugging - dump reply with request content */
2087 FILE * tst_file
= NULL
;
2088 char buffer
[ 4096 ];
2089 char * dump_name
= NULL
;
2092 xmlGenericError( xmlGenericErrorContext
,
2093 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
2094 http_mthd
, ctxt
->uri
,
2095 xmlNanoHTTPReturnCode( http_ctxt
) );
2098 ** Since either content or reply may be gzipped,
2099 ** dump them to separate files instead of the
2100 ** standard error context.
2103 dump_name
= tempnam( NULL
, "lxml" );
2104 if ( dump_name
!= NULL
) {
2105 (void)snprintf( buffer
, sizeof(buffer
), "%s.content", dump_name
);
2107 tst_file
= fopen( buffer
, "wb" );
2108 if ( tst_file
!= NULL
) {
2109 xmlGenericError( xmlGenericErrorContext
,
2110 "Transmitted content saved in file: %s\n", buffer
);
2112 fwrite( http_content
, sizeof( char ),
2113 content_lgth
, tst_file
);
2117 (void)snprintf( buffer
, sizeof(buffer
), "%s.reply", dump_name
);
2118 tst_file
= fopen( buffer
, "wb" );
2119 if ( tst_file
!= NULL
) {
2120 xmlGenericError( xmlGenericErrorContext
,
2121 "Reply content saved in file: %s\n", buffer
);
2124 while ( (avail
= xmlNanoHTTPRead( http_ctxt
,
2125 buffer
, sizeof( buffer
) )) > 0 ) {
2127 fwrite( buffer
, sizeof( char ), avail
, tst_file
);
2135 #endif /* DEBUG_HTTP */
2137 http_rtn
= xmlNanoHTTPReturnCode( http_ctxt
);
2138 if ( ( http_rtn
>= 200 ) && ( http_rtn
< 300 ) )
2142 xmlStrPrintf(msg
, 500,
2143 (const xmlChar
*) "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
2144 http_mthd
, content_lgth
,
2145 "bytes to URI", ctxt
->uri
,
2146 "failed. HTTP return code:", http_rtn
);
2147 xmlIOErr(XML_IO_WRITE
, (const char *) msg
);
2150 xmlNanoHTTPClose( http_ctxt
);
2151 xmlFree( content_type
);
2155 /* Final cleanups */
2157 xmlFreeHTTPWriteCtxt( ctxt
);
2159 return ( close_rc
);
2165 * @context: The I/O context
2167 * Close the transmit HTTP I/O channel and actually send data using a PUT
2171 xmlIOHTTPClosePut( void * ctxt
) {
2172 return ( xmlIOHTTPCloseWrite( ctxt
, "PUT" ) );
2177 * xmlIOHTTPClosePost
2179 * @context: The I/O context
2181 * Close the transmit HTTP I/O channel and actually send data using a POST
2185 xmlIOHTTPClosePost( void * ctxt
) {
2186 return ( xmlIOHTTPCloseWrite( ctxt
, "POST" ) );
2188 #endif /* LIBXML_OUTPUT_ENABLED */
2190 #endif /* LIBXML_HTTP_ENABLED */
2192 #ifdef LIBXML_FTP_ENABLED
2193 /************************************************************************
2195 * I/O for FTP file accesses *
2197 ************************************************************************/
2200 * @filename: the URI for matching
2202 * check if the URI matches an FTP one
2204 * Returns 1 if matches, 0 otherwise
2207 xmlIOFTPMatch (const char *filename
) {
2208 if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"ftp://", 6))
2215 * @filename: the URI for matching
2217 * open an FTP I/O channel
2219 * Returns an I/O context or NULL in case of error
2222 xmlIOFTPOpen (const char *filename
) {
2223 return(xmlNanoFTPOpen(filename
));
2228 * @context: the I/O context
2229 * @buffer: where to drop data
2230 * @len: number of bytes to write
2232 * Read @len bytes to @buffer from the I/O channel.
2234 * Returns the number of bytes written
2237 xmlIOFTPRead(void * context
, char * buffer
, int len
) {
2238 if ((buffer
== NULL
) || (len
< 0)) return(-1);
2239 return(xmlNanoFTPRead(context
, &buffer
[0], len
));
2244 * @context: the I/O context
2246 * Close an FTP I/O channel
2251 xmlIOFTPClose (void * context
) {
2252 return ( xmlNanoFTPClose(context
) );
2254 #endif /* LIBXML_FTP_ENABLED */
2258 * xmlRegisterInputCallbacks:
2259 * @matchFunc: the xmlInputMatchCallback
2260 * @openFunc: the xmlInputOpenCallback
2261 * @readFunc: the xmlInputReadCallback
2262 * @closeFunc: the xmlInputCloseCallback
2264 * Register a new set of I/O callback for handling parser input.
2266 * Returns the registered handler number or -1 in case of error
2269 xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc
,
2270 xmlInputOpenCallback openFunc
, xmlInputReadCallback readFunc
,
2271 xmlInputCloseCallback closeFunc
) {
2272 if (xmlInputCallbackNr
>= MAX_INPUT_CALLBACK
) {
2275 xmlInputCallbackTable
[xmlInputCallbackNr
].matchcallback
= matchFunc
;
2276 xmlInputCallbackTable
[xmlInputCallbackNr
].opencallback
= openFunc
;
2277 xmlInputCallbackTable
[xmlInputCallbackNr
].readcallback
= readFunc
;
2278 xmlInputCallbackTable
[xmlInputCallbackNr
].closecallback
= closeFunc
;
2279 xmlInputCallbackInitialized
= 1;
2280 return(xmlInputCallbackNr
++);
2283 #ifdef LIBXML_OUTPUT_ENABLED
2285 * xmlRegisterOutputCallbacks:
2286 * @matchFunc: the xmlOutputMatchCallback
2287 * @openFunc: the xmlOutputOpenCallback
2288 * @writeFunc: the xmlOutputWriteCallback
2289 * @closeFunc: the xmlOutputCloseCallback
2291 * Register a new set of I/O callback for handling output.
2293 * Returns the registered handler number or -1 in case of error
2296 xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc
,
2297 xmlOutputOpenCallback openFunc
, xmlOutputWriteCallback writeFunc
,
2298 xmlOutputCloseCallback closeFunc
) {
2299 if (xmlOutputCallbackNr
>= MAX_OUTPUT_CALLBACK
) {
2302 xmlOutputCallbackTable
[xmlOutputCallbackNr
].matchcallback
= matchFunc
;
2303 xmlOutputCallbackTable
[xmlOutputCallbackNr
].opencallback
= openFunc
;
2304 xmlOutputCallbackTable
[xmlOutputCallbackNr
].writecallback
= writeFunc
;
2305 xmlOutputCallbackTable
[xmlOutputCallbackNr
].closecallback
= closeFunc
;
2306 xmlOutputCallbackInitialized
= 1;
2307 return(xmlOutputCallbackNr
++);
2309 #endif /* LIBXML_OUTPUT_ENABLED */
2312 * xmlRegisterDefaultInputCallbacks:
2314 * Registers the default compiled-in I/O handlers.
2317 xmlRegisterDefaultInputCallbacks(void) {
2318 if (xmlInputCallbackInitialized
)
2321 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
2322 xmlInitPlatformSpecificIo();
2325 xmlRegisterInputCallbacks(xmlFileMatch
, xmlFileOpen
,
2326 xmlFileRead
, xmlFileClose
);
2328 xmlRegisterInputCallbacks(xmlGzfileMatch
, xmlGzfileOpen
,
2329 xmlGzfileRead
, xmlGzfileClose
);
2330 #endif /* HAVE_ZLIB_H */
2332 xmlRegisterInputCallbacks(xmlXzfileMatch
, xmlXzfileOpen
,
2333 xmlXzfileRead
, xmlXzfileClose
);
2334 #endif /* HAVE_ZLIB_H */
2336 #ifdef LIBXML_HTTP_ENABLED
2337 xmlRegisterInputCallbacks(xmlIOHTTPMatch
, xmlIOHTTPOpen
,
2338 xmlIOHTTPRead
, xmlIOHTTPClose
);
2339 #endif /* LIBXML_HTTP_ENABLED */
2341 #ifdef LIBXML_FTP_ENABLED
2342 xmlRegisterInputCallbacks(xmlIOFTPMatch
, xmlIOFTPOpen
,
2343 xmlIOFTPRead
, xmlIOFTPClose
);
2344 #endif /* LIBXML_FTP_ENABLED */
2345 xmlInputCallbackInitialized
= 1;
2348 #ifdef LIBXML_OUTPUT_ENABLED
2350 * xmlRegisterDefaultOutputCallbacks:
2352 * Registers the default compiled-in I/O handlers.
2355 xmlRegisterDefaultOutputCallbacks (void) {
2356 if (xmlOutputCallbackInitialized
)
2359 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
2360 xmlInitPlatformSpecificIo();
2363 xmlRegisterOutputCallbacks(xmlFileMatch
, xmlFileOpenW
,
2364 xmlFileWrite
, xmlFileClose
);
2366 #ifdef LIBXML_HTTP_ENABLED
2367 xmlRegisterOutputCallbacks(xmlIOHTTPMatch
, xmlIOHTTPDfltOpenW
,
2368 xmlIOHTTPWrite
, xmlIOHTTPClosePut
);
2371 /*********************************
2372 No way a-priori to distinguish between gzipped files from
2373 uncompressed ones except opening if existing then closing
2374 and saving with same compression ratio ... a pain.
2377 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
2378 xmlGzfileWrite, xmlGzfileClose);
2382 #ifdef LIBXML_FTP_ENABLED
2383 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
2384 xmlIOFTPWrite, xmlIOFTPClose);
2386 **********************************/
2387 xmlOutputCallbackInitialized
= 1;
2390 #ifdef LIBXML_HTTP_ENABLED
2392 * xmlRegisterHTTPPostCallbacks:
2394 * By default, libxml submits HTTP output requests using the "PUT" method.
2395 * Calling this method changes the HTTP output method to use the "POST"
2400 xmlRegisterHTTPPostCallbacks( void ) {
2402 /* Register defaults if not done previously */
2404 if ( xmlOutputCallbackInitialized
== 0 )
2405 xmlRegisterDefaultOutputCallbacks( );
2407 xmlRegisterOutputCallbacks(xmlIOHTTPMatch
, xmlIOHTTPDfltOpenW
,
2408 xmlIOHTTPWrite
, xmlIOHTTPClosePost
);
2412 #endif /* LIBXML_OUTPUT_ENABLED */
2415 * xmlAllocParserInputBuffer:
2416 * @enc: the charset encoding if known
2418 * Create a buffered parser input for progressive parsing
2420 * Returns the new parser input or NULL
2422 xmlParserInputBufferPtr
2423 xmlAllocParserInputBuffer(xmlCharEncoding enc
) {
2424 xmlParserInputBufferPtr ret
;
2426 ret
= (xmlParserInputBufferPtr
) xmlMalloc(sizeof(xmlParserInputBuffer
));
2428 xmlIOErrMemory("creating input buffer");
2431 memset(ret
, 0, (size_t) sizeof(xmlParserInputBuffer
));
2432 ret
->buffer
= xmlBufCreateSize(2 * xmlDefaultBufferSize
);
2433 if (ret
->buffer
== NULL
) {
2437 xmlBufSetAllocationScheme(ret
->buffer
, XML_BUFFER_ALLOC_DOUBLEIT
);
2438 ret
->encoder
= xmlGetCharEncodingHandler(enc
);
2439 if (ret
->encoder
!= NULL
)
2440 ret
->raw
= xmlBufCreateSize(2 * xmlDefaultBufferSize
);
2443 ret
->readcallback
= NULL
;
2444 ret
->closecallback
= NULL
;
2445 ret
->context
= NULL
;
2446 ret
->compressed
= -1;
2447 ret
->rawconsumed
= 0;
2452 #ifdef LIBXML_OUTPUT_ENABLED
2454 * xmlAllocOutputBuffer:
2455 * @encoder: the encoding converter or NULL
2457 * Create a buffered parser output
2459 * Returns the new parser output or NULL
2462 xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder
) {
2463 xmlOutputBufferPtr ret
;
2465 ret
= (xmlOutputBufferPtr
) xmlMalloc(sizeof(xmlOutputBuffer
));
2467 xmlIOErrMemory("creating output buffer");
2470 memset(ret
, 0, (size_t) sizeof(xmlOutputBuffer
));
2471 ret
->buffer
= xmlBufCreate();
2472 if (ret
->buffer
== NULL
) {
2477 /* try to avoid a performance problem with Windows realloc() */
2478 if (xmlBufGetAllocationScheme(ret
->buffer
) == XML_BUFFER_ALLOC_EXACT
)
2479 xmlBufSetAllocationScheme(ret
->buffer
, XML_BUFFER_ALLOC_DOUBLEIT
);
2481 ret
->encoder
= encoder
;
2482 if (encoder
!= NULL
) {
2483 ret
->conv
= xmlBufCreateSize(4000);
2484 if (ret
->conv
== NULL
) {
2490 * This call is designed to initiate the encoder state
2492 xmlCharEncOutput(ret
, 1);
2495 ret
->writecallback
= NULL
;
2496 ret
->closecallback
= NULL
;
2497 ret
->context
= NULL
;
2504 * xmlAllocOutputBufferInternal:
2505 * @encoder: the encoding converter or NULL
2507 * Create a buffered parser output
2509 * Returns the new parser output or NULL
2512 xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder
) {
2513 xmlOutputBufferPtr ret
;
2515 ret
= (xmlOutputBufferPtr
) xmlMalloc(sizeof(xmlOutputBuffer
));
2517 xmlIOErrMemory("creating output buffer");
2520 memset(ret
, 0, (size_t) sizeof(xmlOutputBuffer
));
2521 ret
->buffer
= xmlBufCreate();
2522 if (ret
->buffer
== NULL
) {
2529 * For conversion buffers we use the special IO handling
2531 xmlBufSetAllocationScheme(ret
->buffer
, XML_BUFFER_ALLOC_IO
);
2533 ret
->encoder
= encoder
;
2534 if (encoder
!= NULL
) {
2535 ret
->conv
= xmlBufCreateSize(4000);
2536 if (ret
->conv
== NULL
) {
2542 * This call is designed to initiate the encoder state
2544 xmlCharEncOutput(ret
, 1);
2547 ret
->writecallback
= NULL
;
2548 ret
->closecallback
= NULL
;
2549 ret
->context
= NULL
;
2555 #endif /* LIBXML_OUTPUT_ENABLED */
2558 * xmlFreeParserInputBuffer:
2559 * @in: a buffered parser input
2561 * Free up the memory used by a buffered parser input
2564 xmlFreeParserInputBuffer(xmlParserInputBufferPtr in
) {
2565 if (in
== NULL
) return;
2568 xmlBufFree(in
->raw
);
2571 if (in
->encoder
!= NULL
) {
2572 xmlCharEncCloseFunc(in
->encoder
);
2574 if (in
->closecallback
!= NULL
) {
2575 in
->closecallback(in
->context
);
2577 if (in
->buffer
!= NULL
) {
2578 xmlBufFree(in
->buffer
);
2585 #ifdef LIBXML_OUTPUT_ENABLED
2587 * xmlOutputBufferClose:
2588 * @out: a buffered output
2590 * flushes and close the output I/O channel
2591 * and free up all the associated resources
2593 * Returns the number of byte written or -1 in case of error.
2596 xmlOutputBufferClose(xmlOutputBufferPtr out
)
2603 if (out
->writecallback
!= NULL
)
2604 xmlOutputBufferFlush(out
);
2605 if (out
->closecallback
!= NULL
) {
2606 err_rc
= out
->closecallback(out
->context
);
2608 written
= out
->written
;
2610 xmlBufFree(out
->conv
);
2613 if (out
->encoder
!= NULL
) {
2614 xmlCharEncCloseFunc(out
->encoder
);
2616 if (out
->buffer
!= NULL
) {
2617 xmlBufFree(out
->buffer
);
2624 return ((err_rc
== 0) ? written
: err_rc
);
2626 #endif /* LIBXML_OUTPUT_ENABLED */
2628 xmlParserInputBufferPtr
2629 __xmlParserInputBufferCreateFilename(const char *URI
, xmlCharEncoding enc
) {
2630 xmlParserInputBufferPtr ret
;
2632 void *context
= NULL
;
2634 if (xmlInputCallbackInitialized
== 0)
2635 xmlRegisterDefaultInputCallbacks();
2637 if (URI
== NULL
) return(NULL
);
2640 * Try to find one of the input accept method accepting that scheme
2641 * Go in reverse to give precedence to user defined handlers.
2643 if (context
== NULL
) {
2644 for (i
= xmlInputCallbackNr
- 1;i
>= 0;i
--) {
2645 if ((xmlInputCallbackTable
[i
].matchcallback
!= NULL
) &&
2646 (xmlInputCallbackTable
[i
].matchcallback(URI
) != 0)) {
2647 context
= xmlInputCallbackTable
[i
].opencallback(URI
);
2648 if (context
!= NULL
) {
2654 if (context
== NULL
) {
2659 * Allocate the Input buffer front-end.
2661 ret
= xmlAllocParserInputBuffer(enc
);
2663 ret
->context
= context
;
2664 ret
->readcallback
= xmlInputCallbackTable
[i
].readcallback
;
2665 ret
->closecallback
= xmlInputCallbackTable
[i
].closecallback
;
2667 if ((xmlInputCallbackTable
[i
].opencallback
== xmlGzfileOpen
) &&
2668 (strcmp(URI
, "-") != 0)) {
2669 #if defined(ZLIB_VERNUM) && ZLIB_VERNUM >= 0x1230
2670 ret
->compressed
= !gzdirect(context
);
2672 if (((z_stream
*)context
)->avail_in
> 4) {
2673 char *cptr
, buff4
[4];
2674 cptr
= (char *) ((z_stream
*)context
)->next_in
;
2675 if (gzread(context
, buff4
, 4) == 4) {
2676 if (strncmp(buff4
, cptr
, 4) == 0)
2677 ret
->compressed
= 0;
2679 ret
->compressed
= 1;
2687 if ((xmlInputCallbackTable
[i
].opencallback
== xmlXzfileOpen
) &&
2688 (strcmp(URI
, "-") != 0)) {
2689 ret
->compressed
= __libxml2_xzcompressed(context
);
2694 xmlInputCallbackTable
[i
].closecallback (context
);
2700 * xmlParserInputBufferCreateFilename:
2701 * @URI: a C string containing the URI or filename
2702 * @enc: the charset encoding if known
2704 * Create a buffered parser input for the progressive parsing of a file
2705 * If filename is "-' then we use stdin as the input.
2706 * Automatic support for ZLIB/Compress compressed document is provided
2707 * by default if found at compile-time.
2708 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
2710 * Returns the new parser input or NULL
2712 xmlParserInputBufferPtr
2713 xmlParserInputBufferCreateFilename(const char *URI
, xmlCharEncoding enc
) {
2714 if ((xmlParserInputBufferCreateFilenameValue
)) {
2715 return xmlParserInputBufferCreateFilenameValue(URI
, enc
);
2717 return __xmlParserInputBufferCreateFilename(URI
, enc
);
2720 #ifdef LIBXML_OUTPUT_ENABLED
2722 __xmlOutputBufferCreateFilename(const char *URI
,
2723 xmlCharEncodingHandlerPtr encoder
,
2724 int compression ATTRIBUTE_UNUSED
) {
2725 xmlOutputBufferPtr ret
;
2728 void *context
= NULL
;
2729 char *unescaped
= NULL
;
2731 int is_file_uri
= 1;
2734 if (xmlOutputCallbackInitialized
== 0)
2735 xmlRegisterDefaultOutputCallbacks();
2737 if (URI
== NULL
) return(NULL
);
2739 puri
= xmlParseURI(URI
);
2742 if ((puri
->scheme
!= NULL
) &&
2743 (!xmlStrEqual(BAD_CAST puri
->scheme
, BAD_CAST
"file")))
2747 * try to limit the damages of the URI unescaping code.
2749 if ((puri
->scheme
== NULL
) ||
2750 (xmlStrEqual(BAD_CAST puri
->scheme
, BAD_CAST
"file")))
2751 unescaped
= xmlURIUnescapeString(URI
, 0, NULL
);
2756 * Try to find one of the output accept method accepting that scheme
2757 * Go in reverse to give precedence to user defined handlers.
2758 * try with an unescaped version of the URI
2760 if (unescaped
!= NULL
) {
2762 if ((compression
> 0) && (compression
<= 9) && (is_file_uri
== 1)) {
2763 context
= xmlGzfileOpenW(unescaped
, compression
);
2764 if (context
!= NULL
) {
2765 ret
= xmlAllocOutputBufferInternal(encoder
);
2767 ret
->context
= context
;
2768 ret
->writecallback
= xmlGzfileWrite
;
2769 ret
->closecallback
= xmlGzfileClose
;
2776 for (i
= xmlOutputCallbackNr
- 1;i
>= 0;i
--) {
2777 if ((xmlOutputCallbackTable
[i
].matchcallback
!= NULL
) &&
2778 (xmlOutputCallbackTable
[i
].matchcallback(unescaped
) != 0)) {
2779 #if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2780 /* Need to pass compression parameter into HTTP open calls */
2781 if (xmlOutputCallbackTable
[i
].matchcallback
== xmlIOHTTPMatch
)
2782 context
= xmlIOHTTPOpenW(unescaped
, compression
);
2785 context
= xmlOutputCallbackTable
[i
].opencallback(unescaped
);
2786 if (context
!= NULL
)
2794 * If this failed try with a non-escaped URI this may be a strange
2797 if (context
== NULL
) {
2799 if ((compression
> 0) && (compression
<= 9) && (is_file_uri
== 1)) {
2800 context
= xmlGzfileOpenW(URI
, compression
);
2801 if (context
!= NULL
) {
2802 ret
= xmlAllocOutputBufferInternal(encoder
);
2804 ret
->context
= context
;
2805 ret
->writecallback
= xmlGzfileWrite
;
2806 ret
->closecallback
= xmlGzfileClose
;
2812 for (i
= xmlOutputCallbackNr
- 1;i
>= 0;i
--) {
2813 if ((xmlOutputCallbackTable
[i
].matchcallback
!= NULL
) &&
2814 (xmlOutputCallbackTable
[i
].matchcallback(URI
) != 0)) {
2815 #if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2816 /* Need to pass compression parameter into HTTP open calls */
2817 if (xmlOutputCallbackTable
[i
].matchcallback
== xmlIOHTTPMatch
)
2818 context
= xmlIOHTTPOpenW(URI
, compression
);
2821 context
= xmlOutputCallbackTable
[i
].opencallback(URI
);
2822 if (context
!= NULL
)
2828 if (context
== NULL
) {
2833 * Allocate the Output buffer front-end.
2835 ret
= xmlAllocOutputBufferInternal(encoder
);
2837 ret
->context
= context
;
2838 ret
->writecallback
= xmlOutputCallbackTable
[i
].writecallback
;
2839 ret
->closecallback
= xmlOutputCallbackTable
[i
].closecallback
;
2845 * xmlOutputBufferCreateFilename:
2846 * @URI: a C string containing the URI or filename
2847 * @encoder: the encoding converter or NULL
2848 * @compression: the compression ration (0 none, 9 max).
2850 * Create a buffered output for the progressive saving of a file
2851 * If filename is "-' then we use stdout as the output.
2852 * Automatic support for ZLIB/Compress compressed document is provided
2853 * by default if found at compile-time.
2854 * TODO: currently if compression is set, the library only support
2855 * writing to a local file.
2857 * Returns the new output or NULL
2860 xmlOutputBufferCreateFilename(const char *URI
,
2861 xmlCharEncodingHandlerPtr encoder
,
2862 int compression ATTRIBUTE_UNUSED
) {
2863 if ((xmlOutputBufferCreateFilenameValue
)) {
2864 return xmlOutputBufferCreateFilenameValue(URI
, encoder
, compression
);
2866 return __xmlOutputBufferCreateFilename(URI
, encoder
, compression
);
2868 #endif /* LIBXML_OUTPUT_ENABLED */
2871 * xmlParserInputBufferCreateFile:
2873 * @enc: the charset encoding if known
2875 * Create a buffered parser input for the progressive parsing of a FILE *
2878 * Returns the new parser input or NULL
2880 xmlParserInputBufferPtr
2881 xmlParserInputBufferCreateFile(FILE *file
, xmlCharEncoding enc
) {
2882 xmlParserInputBufferPtr ret
;
2884 if (xmlInputCallbackInitialized
== 0)
2885 xmlRegisterDefaultInputCallbacks();
2887 if (file
== NULL
) return(NULL
);
2889 ret
= xmlAllocParserInputBuffer(enc
);
2891 ret
->context
= file
;
2892 ret
->readcallback
= xmlFileRead
;
2893 ret
->closecallback
= xmlFileFlush
;
2899 #ifdef LIBXML_OUTPUT_ENABLED
2901 * xmlOutputBufferCreateFile:
2903 * @encoder: the encoding converter or NULL
2905 * Create a buffered output for the progressive saving to a FILE *
2908 * Returns the new parser output or NULL
2911 xmlOutputBufferCreateFile(FILE *file
, xmlCharEncodingHandlerPtr encoder
) {
2912 xmlOutputBufferPtr ret
;
2914 if (xmlOutputCallbackInitialized
== 0)
2915 xmlRegisterDefaultOutputCallbacks();
2917 if (file
== NULL
) return(NULL
);
2919 ret
= xmlAllocOutputBufferInternal(encoder
);
2921 ret
->context
= file
;
2922 ret
->writecallback
= xmlFileWrite
;
2923 ret
->closecallback
= xmlFileFlush
;
2930 * xmlOutputBufferCreateBuffer:
2931 * @buffer: a xmlBufferPtr
2932 * @encoder: the encoding converter or NULL
2934 * Create a buffered output for the progressive saving to a xmlBuffer
2936 * Returns the new parser output or NULL
2939 xmlOutputBufferCreateBuffer(xmlBufferPtr buffer
,
2940 xmlCharEncodingHandlerPtr encoder
) {
2941 xmlOutputBufferPtr ret
;
2943 if (buffer
== NULL
) return(NULL
);
2945 ret
= xmlOutputBufferCreateIO((xmlOutputWriteCallback
)
2947 (xmlOutputCloseCallback
)
2948 NULL
, (void *) buffer
, encoder
);
2954 * xmlOutputBufferGetContent:
2955 * @out: an xmlOutputBufferPtr
2957 * Gives a pointer to the data currently held in the output buffer
2959 * Returns a pointer to the data or NULL in case of error
2962 xmlOutputBufferGetContent(xmlOutputBufferPtr out
) {
2963 if ((out
== NULL
) || (out
->buffer
== NULL
))
2966 return(xmlBufContent(out
->buffer
));
2970 * xmlOutputBufferGetSize:
2971 * @out: an xmlOutputBufferPtr
2973 * Gives the length of the data currently held in the output buffer
2975 * Returns 0 in case or error or no data is held, the size otherwise
2978 xmlOutputBufferGetSize(xmlOutputBufferPtr out
) {
2979 if ((out
== NULL
) || (out
->buffer
== NULL
))
2982 return(xmlBufUse(out
->buffer
));
2986 #endif /* LIBXML_OUTPUT_ENABLED */
2989 * xmlParserInputBufferCreateFd:
2990 * @fd: a file descriptor number
2991 * @enc: the charset encoding if known
2993 * Create a buffered parser input for the progressive parsing for the input
2994 * from a file descriptor
2996 * Returns the new parser input or NULL
2998 xmlParserInputBufferPtr
2999 xmlParserInputBufferCreateFd(int fd
, xmlCharEncoding enc
) {
3000 xmlParserInputBufferPtr ret
;
3002 if (fd
< 0) return(NULL
);
3004 ret
= xmlAllocParserInputBuffer(enc
);
3006 ret
->context
= (void *) (long) fd
;
3007 ret
->readcallback
= xmlFdRead
;
3008 ret
->closecallback
= xmlFdClose
;
3015 * xmlParserInputBufferCreateMem:
3016 * @mem: the memory input
3017 * @size: the length of the memory block
3018 * @enc: the charset encoding if known
3020 * Create a buffered parser input for the progressive parsing for the input
3021 * from a memory area.
3023 * Returns the new parser input or NULL
3025 xmlParserInputBufferPtr
3026 xmlParserInputBufferCreateMem(const char *mem
, int size
, xmlCharEncoding enc
) {
3027 xmlParserInputBufferPtr ret
;
3030 if (size
<= 0) return(NULL
);
3031 if (mem
== NULL
) return(NULL
);
3033 ret
= xmlAllocParserInputBuffer(enc
);
3035 ret
->context
= (void *) mem
;
3036 ret
->readcallback
= (xmlInputReadCallback
) xmlNop
;
3037 ret
->closecallback
= NULL
;
3038 errcode
= xmlBufAdd(ret
->buffer
, (const xmlChar
*) mem
, size
);
3049 * xmlParserInputBufferCreateStatic:
3050 * @mem: the memory input
3051 * @size: the length of the memory block
3052 * @enc: the charset encoding if known
3054 * Create a buffered parser input for the progressive parsing for the input
3055 * from an immutable memory area. This will not copy the memory area to
3056 * the buffer, but the memory is expected to be available until the end of
3057 * the parsing, this is useful for example when using mmap'ed file.
3059 * Returns the new parser input or NULL
3061 xmlParserInputBufferPtr
3062 xmlParserInputBufferCreateStatic(const char *mem
, int size
,
3063 xmlCharEncoding enc
) {
3064 xmlParserInputBufferPtr ret
;
3066 if (size
<= 0) return(NULL
);
3067 if (mem
== NULL
) return(NULL
);
3069 ret
= (xmlParserInputBufferPtr
) xmlMalloc(sizeof(xmlParserInputBuffer
));
3071 xmlIOErrMemory("creating input buffer");
3074 memset(ret
, 0, (size_t) sizeof(xmlParserInputBuffer
));
3075 ret
->buffer
= xmlBufCreateStatic((void *)mem
, (size_t) size
);
3076 if (ret
->buffer
== NULL
) {
3080 ret
->encoder
= xmlGetCharEncodingHandler(enc
);
3081 if (ret
->encoder
!= NULL
)
3082 ret
->raw
= xmlBufCreateSize(2 * xmlDefaultBufferSize
);
3085 ret
->compressed
= -1;
3086 ret
->context
= (void *) mem
;
3087 ret
->readcallback
= NULL
;
3088 ret
->closecallback
= NULL
;
3093 #ifdef LIBXML_OUTPUT_ENABLED
3095 * xmlOutputBufferCreateFd:
3096 * @fd: a file descriptor number
3097 * @encoder: the encoding converter or NULL
3099 * Create a buffered output for the progressive saving
3100 * to a file descriptor
3102 * Returns the new parser output or NULL
3105 xmlOutputBufferCreateFd(int fd
, xmlCharEncodingHandlerPtr encoder
) {
3106 xmlOutputBufferPtr ret
;
3108 if (fd
< 0) return(NULL
);
3110 ret
= xmlAllocOutputBufferInternal(encoder
);
3112 ret
->context
= (void *) (long) fd
;
3113 ret
->writecallback
= xmlFdWrite
;
3114 ret
->closecallback
= NULL
;
3119 #endif /* LIBXML_OUTPUT_ENABLED */
3122 * xmlParserInputBufferCreateIO:
3123 * @ioread: an I/O read function
3124 * @ioclose: an I/O close function
3125 * @ioctx: an I/O handler
3126 * @enc: the charset encoding if known
3128 * Create a buffered parser input for the progressive parsing for the input
3129 * from an I/O handler
3131 * Returns the new parser input or NULL
3133 xmlParserInputBufferPtr
3134 xmlParserInputBufferCreateIO(xmlInputReadCallback ioread
,
3135 xmlInputCloseCallback ioclose
, void *ioctx
, xmlCharEncoding enc
) {
3136 xmlParserInputBufferPtr ret
;
3138 if (ioread
== NULL
) return(NULL
);
3140 ret
= xmlAllocParserInputBuffer(enc
);
3142 ret
->context
= (void *) ioctx
;
3143 ret
->readcallback
= ioread
;
3144 ret
->closecallback
= ioclose
;
3150 #ifdef LIBXML_OUTPUT_ENABLED
3152 * xmlOutputBufferCreateIO:
3153 * @iowrite: an I/O write function
3154 * @ioclose: an I/O close function
3155 * @ioctx: an I/O handler
3156 * @encoder: the charset encoding if known
3158 * Create a buffered output for the progressive saving
3161 * Returns the new parser output or NULL
3164 xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite
,
3165 xmlOutputCloseCallback ioclose
, void *ioctx
,
3166 xmlCharEncodingHandlerPtr encoder
) {
3167 xmlOutputBufferPtr ret
;
3169 if (iowrite
== NULL
) return(NULL
);
3171 ret
= xmlAllocOutputBufferInternal(encoder
);
3173 ret
->context
= (void *) ioctx
;
3174 ret
->writecallback
= iowrite
;
3175 ret
->closecallback
= ioclose
;
3180 #endif /* LIBXML_OUTPUT_ENABLED */
3183 * xmlParserInputBufferCreateFilenameDefault:
3184 * @func: function pointer to the new ParserInputBufferCreateFilenameFunc
3186 * Registers a callback for URI input file handling
3188 * Returns the old value of the registration function
3190 xmlParserInputBufferCreateFilenameFunc
3191 xmlParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func
)
3193 xmlParserInputBufferCreateFilenameFunc old
= xmlParserInputBufferCreateFilenameValue
;
3195 old
= __xmlParserInputBufferCreateFilename
;
3198 xmlParserInputBufferCreateFilenameValue
= func
;
3203 * xmlOutputBufferCreateFilenameDefault:
3204 * @func: function pointer to the new OutputBufferCreateFilenameFunc
3206 * Registers a callback for URI output file handling
3208 * Returns the old value of the registration function
3210 xmlOutputBufferCreateFilenameFunc
3211 xmlOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func
)
3213 xmlOutputBufferCreateFilenameFunc old
= xmlOutputBufferCreateFilenameValue
;
3214 #ifdef LIBXML_OUTPUT_ENABLED
3216 old
= __xmlOutputBufferCreateFilename
;
3219 xmlOutputBufferCreateFilenameValue
= func
;
3224 * xmlParserInputBufferPush:
3225 * @in: a buffered parser input
3226 * @len: the size in bytes of the array.
3227 * @buf: an char array
3229 * Push the content of the arry in the input buffer
3230 * This routine handle the I18N transcoding to internal UTF-8
3231 * This is used when operating the parser in progressive (push) mode.
3233 * Returns the number of chars read and stored in the buffer, or -1
3237 xmlParserInputBufferPush(xmlParserInputBufferPtr in
,
3238 int len
, const char *buf
) {
3242 if (len
< 0) return(0);
3243 if ((in
== NULL
) || (in
->error
)) return(-1);
3244 if (in
->encoder
!= NULL
) {
3248 * Store the data in the incoming raw buffer
3250 if (in
->raw
== NULL
) {
3251 in
->raw
= xmlBufCreate();
3253 ret
= xmlBufAdd(in
->raw
, (const xmlChar
*) buf
, len
);
3258 * convert as much as possible to the parser reading buffer.
3260 use
= xmlBufUse(in
->raw
);
3261 nbchars
= xmlCharEncInput(in
, 1);
3263 xmlIOErr(XML_IO_ENCODER
, NULL
);
3264 in
->error
= XML_IO_ENCODER
;
3267 in
->rawconsumed
+= (use
- xmlBufUse(in
->raw
));
3270 ret
= xmlBufAdd(in
->buffer
, (xmlChar
*) buf
, nbchars
);
3275 xmlGenericError(xmlGenericErrorContext
,
3276 "I/O: pushed %d chars, buffer %d/%d\n",
3277 nbchars
, xmlBufUse(in
->buffer
), xmlBufLength(in
->buffer
));
3285 * When reading from an Input channel indicated end of file or error
3286 * don't reread from it again.
3289 endOfInput (void * context ATTRIBUTE_UNUSED
,
3290 char * buffer ATTRIBUTE_UNUSED
,
3291 int len ATTRIBUTE_UNUSED
) {
3296 * xmlParserInputBufferGrow:
3297 * @in: a buffered parser input
3298 * @len: indicative value of the amount of chars to read
3300 * Grow up the content of the input buffer, the old data are preserved
3301 * This routine handle the I18N transcoding to internal UTF-8
3302 * This routine is used when operating the parser in normal (pull) mode
3304 * TODO: one should be able to remove one extra copy by copying directly
3305 * onto in->buffer or in->raw
3307 * Returns the number of chars read and stored in the buffer, or -1
3311 xmlParserInputBufferGrow(xmlParserInputBufferPtr in
, int len
) {
3312 char *buffer
= NULL
;
3316 if ((in
== NULL
) || (in
->error
)) return(-1);
3317 if ((len
<= MINLEN
) && (len
!= 4))
3320 if (xmlBufAvail(in
->buffer
) <= 0) {
3321 xmlIOErr(XML_IO_BUFFER_FULL
, NULL
);
3322 in
->error
= XML_IO_BUFFER_FULL
;
3326 if (xmlBufGrow(in
->buffer
, len
+ 1) < 0) {
3327 xmlIOErrMemory("growing input buffer");
3328 in
->error
= XML_ERR_NO_MEMORY
;
3331 buffer
= (char *)xmlBufEnd(in
->buffer
);
3334 * Call the read method for this I/O type.
3336 if (in
->readcallback
!= NULL
) {
3337 res
= in
->readcallback(in
->context
, &buffer
[0], len
);
3339 in
->readcallback
= endOfInput
;
3341 xmlIOErr(XML_IO_NO_INPUT
, NULL
);
3342 in
->error
= XML_IO_NO_INPUT
;
3350 * try to establish compressed status of input if not done already
3352 if (in
->compressed
== -1) {
3354 if (in
->readcallback
== xmlXzfileRead
)
3355 in
->compressed
= __libxml2_xzcompressed(in
->context
);
3360 if (in
->encoder
!= NULL
) {
3364 * Store the data in the incoming raw buffer
3366 if (in
->raw
== NULL
) {
3367 in
->raw
= xmlBufCreate();
3369 res
= xmlBufAdd(in
->raw
, (const xmlChar
*) buffer
, len
);
3374 * convert as much as possible to the parser reading buffer.
3376 use
= xmlBufUse(in
->raw
);
3377 nbchars
= xmlCharEncInput(in
, 1);
3379 xmlIOErr(XML_IO_ENCODER
, NULL
);
3380 in
->error
= XML_IO_ENCODER
;
3383 in
->rawconsumed
+= (use
- xmlBufUse(in
->raw
));
3386 xmlBufAddLen(in
->buffer
, nbchars
);
3389 xmlGenericError(xmlGenericErrorContext
,
3390 "I/O: read %d chars, buffer %d\n",
3391 nbchars
, xmlBufUse(in
->buffer
));
3397 * xmlParserInputBufferRead:
3398 * @in: a buffered parser input
3399 * @len: indicative value of the amount of chars to read
3401 * Refresh the content of the input buffer, the old data are considered
3403 * This routine handle the I18N transcoding to internal UTF-8
3405 * Returns the number of chars read and stored in the buffer, or -1
3409 xmlParserInputBufferRead(xmlParserInputBufferPtr in
, int len
) {
3410 if ((in
== NULL
) || (in
->error
)) return(-1);
3411 if (in
->readcallback
!= NULL
)
3412 return(xmlParserInputBufferGrow(in
, len
));
3413 else if (xmlBufGetAllocationScheme(in
->buffer
) == XML_BUFFER_ALLOC_IMMUTABLE
)
3419 #ifdef LIBXML_OUTPUT_ENABLED
3421 * xmlOutputBufferWrite:
3422 * @out: a buffered parser output
3423 * @len: the size in bytes of the array.
3424 * @buf: an char array
3426 * Write the content of the array in the output I/O buffer
3427 * This routine handle the I18N transcoding from internal UTF-8
3428 * The buffer is lossless, i.e. will store in case of partial
3429 * or delayed writes.
3431 * Returns the number of chars immediately written, or -1
3435 xmlOutputBufferWrite(xmlOutputBufferPtr out
, int len
, const char *buf
) {
3436 int nbchars
= 0; /* number of chars to output to I/O */
3437 int ret
; /* return from function call */
3438 int written
= 0; /* number of char written to I/O so far */
3439 int chunk
; /* number of byte curreent processed from buf */
3441 if ((out
== NULL
) || (out
->error
)) return(-1);
3442 if (len
< 0) return(0);
3443 if (out
->error
) return(-1);
3447 if (chunk
> 4 * MINLEN
)
3451 * first handle encoding stuff.
3453 if (out
->encoder
!= NULL
) {
3455 * Store the data in the incoming raw buffer
3457 if (out
->conv
== NULL
) {
3458 out
->conv
= xmlBufCreate();
3460 ret
= xmlBufAdd(out
->buffer
, (const xmlChar
*) buf
, chunk
);
3464 if ((xmlBufUse(out
->buffer
) < MINLEN
) && (chunk
== len
))
3468 * convert as much as possible to the parser reading buffer.
3470 ret
= xmlCharEncOutput(out
, 0);
3471 if ((ret
< 0) && (ret
!= -3)) {
3472 xmlIOErr(XML_IO_ENCODER
, NULL
);
3473 out
->error
= XML_IO_ENCODER
;
3476 nbchars
= xmlBufUse(out
->conv
);
3478 ret
= xmlBufAdd(out
->buffer
, (const xmlChar
*) buf
, chunk
);
3481 nbchars
= xmlBufUse(out
->buffer
);
3486 if ((nbchars
< MINLEN
) && (len
<= 0))
3489 if (out
->writecallback
) {
3491 * second write the stuff to the I/O channel
3493 if (out
->encoder
!= NULL
) {
3494 ret
= out
->writecallback(out
->context
,
3495 (const char *)xmlBufContent(out
->conv
), nbchars
);
3497 xmlBufShrink(out
->conv
, ret
);
3499 ret
= out
->writecallback(out
->context
,
3500 (const char *)xmlBufContent(out
->buffer
), nbchars
);
3502 xmlBufShrink(out
->buffer
, ret
);
3505 xmlIOErr(XML_IO_WRITE
, NULL
);
3506 out
->error
= XML_IO_WRITE
;
3509 out
->written
+= ret
;
3516 xmlGenericError(xmlGenericErrorContext
,
3517 "I/O: wrote %d chars\n", written
);
3524 * @out: a pointer to an array of bytes to store the result
3525 * @outlen: the length of @out
3526 * @in: a pointer to an array of unescaped UTF-8 bytes
3527 * @inlen: the length of @in
3529 * Take a block of UTF-8 chars in and escape them.
3530 * Returns 0 if success, or -1 otherwise
3531 * The value of @inlen after return is the number of octets consumed
3532 * if the return value is positive, else unpredictable.
3533 * The value of @outlen after return is the number of octets consumed.
3536 xmlEscapeContent(unsigned char* out
, int *outlen
,
3537 const xmlChar
* in
, int *inlen
) {
3538 unsigned char* outstart
= out
;
3539 const unsigned char* base
= in
;
3540 unsigned char* outend
= out
+ *outlen
;
3541 const unsigned char* inend
;
3543 inend
= in
+ (*inlen
);
3545 while ((in
< inend
) && (out
< outend
)) {
3547 if (outend
- out
< 4) break;
3552 } else if (*in
== '>') {
3553 if (outend
- out
< 4) break;
3558 } else if (*in
== '&') {
3559 if (outend
- out
< 5) break;
3565 } else if (*in
== '\r') {
3566 if (outend
- out
< 5) break;
3573 *out
++ = (unsigned char) *in
;
3577 *outlen
= out
- outstart
;
3583 * xmlOutputBufferWriteEscape:
3584 * @out: a buffered parser output
3585 * @str: a zero terminated UTF-8 string
3586 * @escaping: an optional escaping function (or NULL)
3588 * Write the content of the string in the output I/O buffer
3589 * This routine escapes the caracters and then handle the I18N
3590 * transcoding from internal UTF-8
3591 * The buffer is lossless, i.e. will store in case of partial
3592 * or delayed writes.
3594 * Returns the number of chars immediately written, or -1
3598 xmlOutputBufferWriteEscape(xmlOutputBufferPtr out
, const xmlChar
*str
,
3599 xmlCharEncodingOutputFunc escaping
) {
3600 int nbchars
= 0; /* number of chars to output to I/O */
3601 int ret
; /* return from function call */
3602 int written
= 0; /* number of char written to I/O so far */
3603 int oldwritten
=0;/* loop guard */
3604 int chunk
; /* number of byte currently processed from str */
3605 int len
; /* number of bytes in str */
3606 int cons
; /* byte from str consumed */
3608 if ((out
== NULL
) || (out
->error
) || (str
== NULL
) ||
3609 (out
->buffer
== NULL
) ||
3610 (xmlBufGetAllocationScheme(out
->buffer
) == XML_BUFFER_ALLOC_IMMUTABLE
))
3612 len
= strlen((const char *)str
);
3613 if (len
< 0) return(0);
3614 if (out
->error
) return(-1);
3615 if (escaping
== NULL
) escaping
= xmlEscapeContent
;
3618 oldwritten
= written
;
3621 * how many bytes to consume and how many bytes to store.
3624 chunk
= xmlBufAvail(out
->buffer
) - 1;
3627 * make sure we have enough room to save first, if this is
3628 * not the case force a flush, but make sure we stay in the loop
3631 if (xmlBufGrow(out
->buffer
, 100) < 0)
3638 * first handle encoding stuff.
3640 if (out
->encoder
!= NULL
) {
3642 * Store the data in the incoming raw buffer
3644 if (out
->conv
== NULL
) {
3645 out
->conv
= xmlBufCreate();
3647 ret
= escaping(xmlBufEnd(out
->buffer
) ,
3648 &chunk
, str
, &cons
);
3649 if ((ret
< 0) || (chunk
== 0)) /* chunk==0 => nothing done */
3651 xmlBufAddLen(out
->buffer
, chunk
);
3653 if ((xmlBufUse(out
->buffer
) < MINLEN
) && (cons
== len
))
3657 * convert as much as possible to the output buffer.
3659 ret
= xmlCharEncOutput(out
, 0);
3660 if ((ret
< 0) && (ret
!= -3)) {
3661 xmlIOErr(XML_IO_ENCODER
, NULL
);
3662 out
->error
= XML_IO_ENCODER
;
3665 nbchars
= xmlBufUse(out
->conv
);
3667 ret
= escaping(xmlBufEnd(out
->buffer
), &chunk
, str
, &cons
);
3668 if ((ret
< 0) || (chunk
== 0)) /* chunk==0 => nothing done */
3670 xmlBufAddLen(out
->buffer
, chunk
);
3671 nbchars
= xmlBufUse(out
->buffer
);
3676 if ((nbchars
< MINLEN
) && (len
<= 0))
3679 if (out
->writecallback
) {
3681 * second write the stuff to the I/O channel
3683 if (out
->encoder
!= NULL
) {
3684 ret
= out
->writecallback(out
->context
,
3685 (const char *)xmlBufContent(out
->conv
), nbchars
);
3687 xmlBufShrink(out
->conv
, ret
);
3689 ret
= out
->writecallback(out
->context
,
3690 (const char *)xmlBufContent(out
->buffer
), nbchars
);
3692 xmlBufShrink(out
->buffer
, ret
);
3695 xmlIOErr(XML_IO_WRITE
, NULL
);
3696 out
->error
= XML_IO_WRITE
;
3699 out
->written
+= ret
;
3700 } else if (xmlBufAvail(out
->buffer
) < MINLEN
) {
3701 xmlBufGrow(out
->buffer
, MINLEN
);
3704 } while ((len
> 0) && (oldwritten
!= written
));
3708 xmlGenericError(xmlGenericErrorContext
,
3709 "I/O: wrote %d chars\n", written
);
3715 * xmlOutputBufferWriteString:
3716 * @out: a buffered parser output
3717 * @str: a zero terminated C string
3719 * Write the content of the string in the output I/O buffer
3720 * This routine handle the I18N transcoding from internal UTF-8
3721 * The buffer is lossless, i.e. will store in case of partial
3722 * or delayed writes.
3724 * Returns the number of chars immediately written, or -1
3728 xmlOutputBufferWriteString(xmlOutputBufferPtr out
, const char *str
) {
3731 if ((out
== NULL
) || (out
->error
)) return(-1);
3737 return(xmlOutputBufferWrite(out
, len
, str
));
3742 * xmlOutputBufferFlush:
3743 * @out: a buffered output
3745 * flushes the output I/O channel
3747 * Returns the number of byte written or -1 in case of error.
3750 xmlOutputBufferFlush(xmlOutputBufferPtr out
) {
3751 int nbchars
= 0, ret
= 0;
3753 if ((out
== NULL
) || (out
->error
)) return(-1);
3755 * first handle encoding stuff.
3757 if ((out
->conv
!= NULL
) && (out
->encoder
!= NULL
)) {
3759 * convert as much as possible to the parser output buffer.
3762 nbchars
= xmlCharEncOutput(out
, 0);
3764 xmlIOErr(XML_IO_ENCODER
, NULL
);
3765 out
->error
= XML_IO_ENCODER
;
3772 * second flush the stuff to the I/O channel
3774 if ((out
->conv
!= NULL
) && (out
->encoder
!= NULL
) &&
3775 (out
->writecallback
!= NULL
)) {
3776 ret
= out
->writecallback(out
->context
,
3777 (const char *)xmlBufContent(out
->conv
),
3778 xmlBufUse(out
->conv
));
3780 xmlBufShrink(out
->conv
, ret
);
3781 } else if (out
->writecallback
!= NULL
) {
3782 ret
= out
->writecallback(out
->context
,
3783 (const char *)xmlBufContent(out
->buffer
),
3784 xmlBufUse(out
->buffer
));
3786 xmlBufShrink(out
->buffer
, ret
);
3789 xmlIOErr(XML_IO_FLUSH
, NULL
);
3790 out
->error
= XML_IO_FLUSH
;
3793 out
->written
+= ret
;
3796 xmlGenericError(xmlGenericErrorContext
,
3797 "I/O: flushed %d chars\n", ret
);
3801 #endif /* LIBXML_OUTPUT_ENABLED */
3804 * xmlParserGetDirectory:
3805 * @filename: the path to a file
3807 * lookup the directory for that file
3809 * Returns a new allocated string containing the directory, or NULL.
3812 xmlParserGetDirectory(const char *filename
) {
3817 #ifdef _WIN32_WCE /* easy way by now ... wince does not have dirs! */
3821 if (xmlInputCallbackInitialized
== 0)
3822 xmlRegisterDefaultInputCallbacks();
3824 if (filename
== NULL
) return(NULL
);
3826 #if defined(WIN32) && !defined(__CYGWIN__)
3827 # define IS_XMLPGD_SEP(ch) ((ch=='/')||(ch=='\\'))
3829 # define IS_XMLPGD_SEP(ch) (ch=='/')
3832 strncpy(dir
, filename
, 1023);
3834 cur
= &dir
[strlen(dir
)];
3836 if (IS_XMLPGD_SEP(*cur
)) break;
3839 if (IS_XMLPGD_SEP(*cur
)) {
3840 if (cur
== dir
) dir
[1] = 0;
3842 ret
= xmlMemStrdup(dir
);
3844 if (getcwd(dir
, 1024) != NULL
) {
3846 ret
= xmlMemStrdup(dir
);
3850 #undef IS_XMLPGD_SEP
3853 /****************************************************************
3855 * External entities loading *
3857 ****************************************************************/
3860 * xmlCheckHTTPInput:
3861 * @ctxt: an XML parser context
3862 * @ret: an XML parser input
3864 * Check an input in case it was created from an HTTP stream, in that
3865 * case it will handle encoding and update of the base URL in case of
3866 * redirection. It also checks for HTTP errors in which case the input
3867 * is cleanly freed up and an appropriate error is raised in context
3869 * Returns the input or NULL in case of HTTP error.
3872 xmlCheckHTTPInput(xmlParserCtxtPtr ctxt
, xmlParserInputPtr ret
) {
3873 #ifdef LIBXML_HTTP_ENABLED
3874 if ((ret
!= NULL
) && (ret
->buf
!= NULL
) &&
3875 (ret
->buf
->readcallback
== xmlIOHTTPRead
) &&
3876 (ret
->buf
->context
!= NULL
)) {
3877 const char *encoding
;
3882 code
= xmlNanoHTTPReturnCode(ret
->buf
->context
);
3885 if (ret
->filename
!= NULL
)
3886 __xmlLoaderErr(ctxt
, "failed to load HTTP resource \"%s\"\n",
3887 (const char *) ret
->filename
);
3889 __xmlLoaderErr(ctxt
, "failed to load HTTP resource\n", NULL
);
3890 xmlFreeInputStream(ret
);
3894 mime
= xmlNanoHTTPMimeType(ret
->buf
->context
);
3895 if ((xmlStrstr(BAD_CAST mime
, BAD_CAST
"/xml")) ||
3896 (xmlStrstr(BAD_CAST mime
, BAD_CAST
"+xml"))) {
3897 encoding
= xmlNanoHTTPEncoding(ret
->buf
->context
);
3898 if (encoding
!= NULL
) {
3899 xmlCharEncodingHandlerPtr handler
;
3901 handler
= xmlFindCharEncodingHandler(encoding
);
3902 if (handler
!= NULL
) {
3903 xmlSwitchInputEncoding(ctxt
, ret
, handler
);
3905 __xmlErrEncoding(ctxt
, XML_ERR_UNKNOWN_ENCODING
,
3906 "Unknown encoding %s",
3907 BAD_CAST encoding
, NULL
);
3909 if (ret
->encoding
== NULL
)
3910 ret
->encoding
= xmlStrdup(BAD_CAST encoding
);
3913 } else if (xmlStrstr(BAD_CAST mime
, BAD_CAST
"html")) {
3916 redir
= xmlNanoHTTPRedir(ret
->buf
->context
);
3917 if (redir
!= NULL
) {
3918 if (ret
->filename
!= NULL
)
3919 xmlFree((xmlChar
*) ret
->filename
);
3920 if (ret
->directory
!= NULL
) {
3921 xmlFree((xmlChar
*) ret
->directory
);
3922 ret
->directory
= NULL
;
3925 (char *) xmlStrdup((const xmlChar
*) redir
);
3933 static int xmlNoNetExists(const char *URL
) {
3939 if (!xmlStrncasecmp(BAD_CAST URL
, BAD_CAST
"file://localhost/", 17))
3940 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
3945 else if (!xmlStrncasecmp(BAD_CAST URL
, BAD_CAST
"file:///", 8)) {
3946 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
3954 return xmlCheckFilename(path
);
3957 #ifdef LIBXML_CATALOG_ENABLED
3960 * xmlResolveResourceFromCatalog:
3961 * @URL: the URL for the entity to load
3962 * @ID: the System ID for the entity to load
3963 * @ctxt: the context in which the entity is called or NULL
3965 * Resolves the URL and ID against the appropriate catalog.
3966 * This function is used by xmlDefaultExternalEntityLoader and
3967 * xmlNoNetExternalEntityLoader.
3969 * Returns a new allocated URL, or NULL.
3972 xmlResolveResourceFromCatalog(const char *URL
, const char *ID
,
3973 xmlParserCtxtPtr ctxt
) {
3974 xmlChar
*resource
= NULL
;
3975 xmlCatalogAllow pref
;
3978 * If the resource doesn't exists as a file,
3979 * try to load it from the resource pointed in the catalogs
3981 pref
= xmlCatalogGetDefaults();
3983 if ((pref
!= XML_CATA_ALLOW_NONE
) && (!xmlNoNetExists(URL
))) {
3987 if ((ctxt
!= NULL
) && (ctxt
->catalogs
!= NULL
) &&
3988 ((pref
== XML_CATA_ALLOW_ALL
) ||
3989 (pref
== XML_CATA_ALLOW_DOCUMENT
))) {
3990 resource
= xmlCatalogLocalResolve(ctxt
->catalogs
,
3991 (const xmlChar
*)ID
,
3992 (const xmlChar
*)URL
);
3995 * Try a global lookup
3997 if ((resource
== NULL
) &&
3998 ((pref
== XML_CATA_ALLOW_ALL
) ||
3999 (pref
== XML_CATA_ALLOW_GLOBAL
))) {
4000 resource
= xmlCatalogResolve((const xmlChar
*)ID
,
4001 (const xmlChar
*)URL
);
4003 if ((resource
== NULL
) && (URL
!= NULL
))
4004 resource
= xmlStrdup((const xmlChar
*) URL
);
4007 * TODO: do an URI lookup on the reference
4009 if ((resource
!= NULL
) && (!xmlNoNetExists((const char *)resource
))) {
4010 xmlChar
*tmp
= NULL
;
4012 if ((ctxt
!= NULL
) && (ctxt
->catalogs
!= NULL
) &&
4013 ((pref
== XML_CATA_ALLOW_ALL
) ||
4014 (pref
== XML_CATA_ALLOW_DOCUMENT
))) {
4015 tmp
= xmlCatalogLocalResolveURI(ctxt
->catalogs
, resource
);
4017 if ((tmp
== NULL
) &&
4018 ((pref
== XML_CATA_ALLOW_ALL
) ||
4019 (pref
== XML_CATA_ALLOW_GLOBAL
))) {
4020 tmp
= xmlCatalogResolveURI(resource
);
4036 * xmlDefaultExternalEntityLoader:
4037 * @URL: the URL for the entity to load
4038 * @ID: the System ID for the entity to load
4039 * @ctxt: the context in which the entity is called or NULL
4041 * By default we don't load external entitites, yet.
4043 * Returns a new allocated xmlParserInputPtr, or NULL.
4045 static xmlParserInputPtr
4046 xmlDefaultExternalEntityLoader(const char *URL
, const char *ID
,
4047 xmlParserCtxtPtr ctxt
)
4049 xmlParserInputPtr ret
= NULL
;
4050 xmlChar
*resource
= NULL
;
4052 #ifdef DEBUG_EXTERNAL_ENTITIES
4053 xmlGenericError(xmlGenericErrorContext
,
4054 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL
);
4056 if ((ctxt
!= NULL
) && (ctxt
->options
& XML_PARSE_NONET
)) {
4057 int options
= ctxt
->options
;
4059 ctxt
->options
-= XML_PARSE_NONET
;
4060 ret
= xmlNoNetExternalEntityLoader(URL
, ID
, ctxt
);
4061 ctxt
->options
= options
;
4064 #ifdef LIBXML_CATALOG_ENABLED
4065 resource
= xmlResolveResourceFromCatalog(URL
, ID
, ctxt
);
4068 if (resource
== NULL
)
4069 resource
= (xmlChar
*) URL
;
4071 if (resource
== NULL
) {
4074 __xmlLoaderErr(ctxt
, "failed to load external entity \"%s\"\n", ID
);
4077 ret
= xmlNewInputFromFile(ctxt
, (const char *) resource
);
4078 if ((resource
!= NULL
) && (resource
!= (xmlChar
*) URL
))
4083 static xmlExternalEntityLoader xmlCurrentExternalEntityLoader
=
4084 xmlDefaultExternalEntityLoader
;
4087 * xmlSetExternalEntityLoader:
4088 * @f: the new entity resolver function
4090 * Changes the defaultexternal entity resolver function for the application
4093 xmlSetExternalEntityLoader(xmlExternalEntityLoader f
) {
4094 xmlCurrentExternalEntityLoader
= f
;
4098 * xmlGetExternalEntityLoader:
4100 * Get the default external entity resolver function for the application
4102 * Returns the xmlExternalEntityLoader function pointer
4104 xmlExternalEntityLoader
4105 xmlGetExternalEntityLoader(void) {
4106 return(xmlCurrentExternalEntityLoader
);
4110 * xmlLoadExternalEntity:
4111 * @URL: the URL for the entity to load
4112 * @ID: the Public ID for the entity to load
4113 * @ctxt: the context in which the entity is called or NULL
4115 * Load an external entity, note that the use of this function for
4116 * unparsed entities may generate problems
4118 * Returns the xmlParserInputPtr or NULL
4121 xmlLoadExternalEntity(const char *URL
, const char *ID
,
4122 xmlParserCtxtPtr ctxt
) {
4123 if ((URL
!= NULL
) && (xmlNoNetExists(URL
) == 0)) {
4124 char *canonicFilename
;
4125 xmlParserInputPtr ret
;
4127 canonicFilename
= (char *) xmlCanonicPath((const xmlChar
*) URL
);
4128 if (canonicFilename
== NULL
) {
4129 xmlIOErrMemory("building canonical path\n");
4133 ret
= xmlCurrentExternalEntityLoader(canonicFilename
, ID
, ctxt
);
4134 xmlFree(canonicFilename
);
4137 return(xmlCurrentExternalEntityLoader(URL
, ID
, ctxt
));
4140 /************************************************************************
4142 * Disabling Network access *
4144 ************************************************************************/
4147 * xmlNoNetExternalEntityLoader:
4148 * @URL: the URL for the entity to load
4149 * @ID: the System ID for the entity to load
4150 * @ctxt: the context in which the entity is called or NULL
4152 * A specific entity loader disabling network accesses, though still
4153 * allowing local catalog accesses for resolution.
4155 * Returns a new allocated xmlParserInputPtr, or NULL.
4158 xmlNoNetExternalEntityLoader(const char *URL
, const char *ID
,
4159 xmlParserCtxtPtr ctxt
) {
4160 xmlParserInputPtr input
= NULL
;
4161 xmlChar
*resource
= NULL
;
4163 #ifdef LIBXML_CATALOG_ENABLED
4164 resource
= xmlResolveResourceFromCatalog(URL
, ID
, ctxt
);
4167 if (resource
== NULL
)
4168 resource
= (xmlChar
*) URL
;
4170 if (resource
!= NULL
) {
4171 if ((!xmlStrncasecmp(BAD_CAST resource
, BAD_CAST
"ftp://", 6)) ||
4172 (!xmlStrncasecmp(BAD_CAST resource
, BAD_CAST
"http://", 7))) {
4173 xmlIOErr(XML_IO_NETWORK_ATTEMPT
, (const char *) resource
);
4174 if (resource
!= (xmlChar
*) URL
)
4179 input
= xmlDefaultExternalEntityLoader((const char *) resource
, ID
, ctxt
);
4180 if (resource
!= (xmlChar
*) URL
)
4185 #define bottom_xmlIO
4186 #include "elfgcchack.h"