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
39 #if defined(WIN32) || defined(_WIN32)
43 #if defined(_WIN32_WCE)
44 #include <winnls.h> /* for CP_UTF8 */
47 /* Figure a portable way to know if a file is a directory. */
50 /* MS C library seems to define stat and _stat. The definition
51 is identical. Still, mapping them to each other causes a warning. */
53 # define stat(x,y) _stat(x,y)
59 # if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
67 # define S_ISDIR(x) _S_ISDIR(x)
72 # define S_IFMT _S_IFMT
76 # define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
83 #include <libxml/xmlmemory.h>
84 #include <libxml/parser.h>
85 #include <libxml/parserInternals.h>
86 #include <libxml/xmlIO.h>
87 #include <libxml/uri.h>
88 #include <libxml/nanohttp.h>
89 #include <libxml/nanoftp.h>
90 #include <libxml/xmlerror.h>
91 #ifdef LIBXML_CATALOG_ENABLED
92 #include <libxml/catalog.h>
94 #include <libxml/globals.h>
96 /* #define VERBOSE_FAILURE */
97 /* #define DEBUG_EXTERNAL_ENTITIES */
98 /* #define DEBUG_INPUT */
107 * Input I/O callback sets
109 typedef struct _xmlInputCallback
{
110 xmlInputMatchCallback matchcallback
;
111 xmlInputOpenCallback opencallback
;
112 xmlInputReadCallback readcallback
;
113 xmlInputCloseCallback closecallback
;
116 #define MAX_INPUT_CALLBACK 15
118 static xmlInputCallback xmlInputCallbackTable
[MAX_INPUT_CALLBACK
];
119 static int xmlInputCallbackNr
= 0;
120 static int xmlInputCallbackInitialized
= 0;
122 #ifdef LIBXML_OUTPUT_ENABLED
124 * Output I/O callback sets
126 typedef struct _xmlOutputCallback
{
127 xmlOutputMatchCallback matchcallback
;
128 xmlOutputOpenCallback opencallback
;
129 xmlOutputWriteCallback writecallback
;
130 xmlOutputCloseCallback closecallback
;
133 #define MAX_OUTPUT_CALLBACK 15
135 static xmlOutputCallback xmlOutputCallbackTable
[MAX_OUTPUT_CALLBACK
];
136 static int xmlOutputCallbackNr
= 0;
137 static int xmlOutputCallbackInitialized
= 0;
140 xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder
);
141 #endif /* LIBXML_OUTPUT_ENABLED */
143 /************************************************************************
145 * Tree memory error handler *
147 ************************************************************************/
149 static const char *IOerr
[] = {
150 "Unknown IO error", /* UNKNOWN */
151 "Permission denied", /* EACCES */
152 "Resource temporarily unavailable",/* EAGAIN */
153 "Bad file descriptor", /* EBADF */
154 "Bad message", /* EBADMSG */
155 "Resource busy", /* EBUSY */
156 "Operation canceled", /* ECANCELED */
157 "No child processes", /* ECHILD */
158 "Resource deadlock avoided",/* EDEADLK */
159 "Domain error", /* EDOM */
160 "File exists", /* EEXIST */
161 "Bad address", /* EFAULT */
162 "File too large", /* EFBIG */
163 "Operation in progress", /* EINPROGRESS */
164 "Interrupted function call",/* EINTR */
165 "Invalid argument", /* EINVAL */
166 "Input/output error", /* EIO */
167 "Is a directory", /* EISDIR */
168 "Too many open files", /* EMFILE */
169 "Too many links", /* EMLINK */
170 "Inappropriate message buffer length",/* EMSGSIZE */
171 "Filename too long", /* ENAMETOOLONG */
172 "Too many open files in system",/* ENFILE */
173 "No such device", /* ENODEV */
174 "No such file or directory",/* ENOENT */
175 "Exec format error", /* ENOEXEC */
176 "No locks available", /* ENOLCK */
177 "Not enough space", /* ENOMEM */
178 "No space left on device", /* ENOSPC */
179 "Function not implemented", /* ENOSYS */
180 "Not a directory", /* ENOTDIR */
181 "Directory not empty", /* ENOTEMPTY */
182 "Not supported", /* ENOTSUP */
183 "Inappropriate I/O control operation",/* ENOTTY */
184 "No such device or address",/* ENXIO */
185 "Operation not permitted", /* EPERM */
186 "Broken pipe", /* EPIPE */
187 "Result too large", /* ERANGE */
188 "Read-only file system", /* EROFS */
189 "Invalid seek", /* ESPIPE */
190 "No such process", /* ESRCH */
191 "Operation timed out", /* ETIMEDOUT */
192 "Improper link", /* EXDEV */
193 "Attempt to load network entity %s", /* XML_IO_NETWORK_ATTEMPT */
194 "encoder error", /* XML_IO_ENCODER */
200 "not a socket", /* ENOTSOCK */
201 "already connected", /* EISCONN */
202 "connection refused", /* ECONNREFUSED */
203 "unreachable network", /* ENETUNREACH */
204 "adddress in use", /* EADDRINUSE */
205 "already in use", /* EALREADY */
206 "unknown address familly", /* EAFNOSUPPORT */
209 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
211 * __xmlIOWin32UTF8ToWChar:
212 * @u8String: uft-8 string
214 * Convert a string from utf-8 to wchar (WINDOWS ONLY!)
217 __xmlIOWin32UTF8ToWChar(const char *u8String
)
219 wchar_t *wString
= NULL
;
223 MultiByteToWideChar(CP_UTF8
, MB_ERR_INVALID_CHARS
, u8String
,
226 wString
= xmlMalloc(wLen
* sizeof(wchar_t));
228 if (MultiByteToWideChar
229 (CP_UTF8
, 0, u8String
, -1, wString
, wLen
) == 0) {
243 * @extra: extra informations
245 * Handle an out of memory condition
248 xmlIOErrMemory(const char *extra
)
250 __xmlSimpleError(XML_FROM_IO
, XML_ERR_NO_MEMORY
, NULL
, NULL
, extra
);
255 * @code: the error number
257 * @extra: extra informations
259 * Handle an I/O error
262 __xmlIOErr(int domain
, int code
, const char *extra
)
268 if (errno
== 0) code
= 0;
270 else if (errno
== EACCES
) code
= XML_IO_EACCES
;
273 else if (errno
== EAGAIN
) code
= XML_IO_EAGAIN
;
276 else if (errno
== EBADF
) code
= XML_IO_EBADF
;
279 else if (errno
== EBADMSG
) code
= XML_IO_EBADMSG
;
282 else if (errno
== EBUSY
) code
= XML_IO_EBUSY
;
285 else if (errno
== ECANCELED
) code
= XML_IO_ECANCELED
;
288 else if (errno
== ECHILD
) code
= XML_IO_ECHILD
;
291 else if (errno
== EDEADLK
) code
= XML_IO_EDEADLK
;
294 else if (errno
== EDOM
) code
= XML_IO_EDOM
;
297 else if (errno
== EEXIST
) code
= XML_IO_EEXIST
;
300 else if (errno
== EFAULT
) code
= XML_IO_EFAULT
;
303 else if (errno
== EFBIG
) code
= XML_IO_EFBIG
;
306 else if (errno
== EINPROGRESS
) code
= XML_IO_EINPROGRESS
;
309 else if (errno
== EINTR
) code
= XML_IO_EINTR
;
312 else if (errno
== EINVAL
) code
= XML_IO_EINVAL
;
315 else if (errno
== EIO
) code
= XML_IO_EIO
;
318 else if (errno
== EISDIR
) code
= XML_IO_EISDIR
;
321 else if (errno
== EMFILE
) code
= XML_IO_EMFILE
;
324 else if (errno
== EMLINK
) code
= XML_IO_EMLINK
;
327 else if (errno
== EMSGSIZE
) code
= XML_IO_EMSGSIZE
;
330 else if (errno
== ENAMETOOLONG
) code
= XML_IO_ENAMETOOLONG
;
333 else if (errno
== ENFILE
) code
= XML_IO_ENFILE
;
336 else if (errno
== ENODEV
) code
= XML_IO_ENODEV
;
339 else if (errno
== ENOENT
) code
= XML_IO_ENOENT
;
342 else if (errno
== ENOEXEC
) code
= XML_IO_ENOEXEC
;
345 else if (errno
== ENOLCK
) code
= XML_IO_ENOLCK
;
348 else if (errno
== ENOMEM
) code
= XML_IO_ENOMEM
;
351 else if (errno
== ENOSPC
) code
= XML_IO_ENOSPC
;
354 else if (errno
== ENOSYS
) code
= XML_IO_ENOSYS
;
357 else if (errno
== ENOTDIR
) code
= XML_IO_ENOTDIR
;
360 else if (errno
== ENOTEMPTY
) code
= XML_IO_ENOTEMPTY
;
363 else if (errno
== ENOTSUP
) code
= XML_IO_ENOTSUP
;
366 else if (errno
== ENOTTY
) code
= XML_IO_ENOTTY
;
369 else if (errno
== ENXIO
) code
= XML_IO_ENXIO
;
372 else if (errno
== EPERM
) code
= XML_IO_EPERM
;
375 else if (errno
== EPIPE
) code
= XML_IO_EPIPE
;
378 else if (errno
== ERANGE
) code
= XML_IO_ERANGE
;
381 else if (errno
== EROFS
) code
= XML_IO_EROFS
;
384 else if (errno
== ESPIPE
) code
= XML_IO_ESPIPE
;
387 else if (errno
== ESRCH
) code
= XML_IO_ESRCH
;
390 else if (errno
== ETIMEDOUT
) code
= XML_IO_ETIMEDOUT
;
393 else if (errno
== EXDEV
) code
= XML_IO_EXDEV
;
396 else if (errno
== ENOTSOCK
) code
= XML_IO_ENOTSOCK
;
399 else if (errno
== EISCONN
) code
= XML_IO_EISCONN
;
402 else if (errno
== ECONNREFUSED
) code
= XML_IO_ECONNREFUSED
;
405 else if (errno
== ETIMEDOUT
) code
= XML_IO_ETIMEDOUT
;
408 else if (errno
== ENETUNREACH
) code
= XML_IO_ENETUNREACH
;
411 else if (errno
== EADDRINUSE
) code
= XML_IO_EADDRINUSE
;
414 else if (errno
== EINPROGRESS
) code
= XML_IO_EINPROGRESS
;
417 else if (errno
== EALREADY
) code
= XML_IO_EALREADY
;
420 else if (errno
== EAFNOSUPPORT
) code
= XML_IO_EAFNOSUPPORT
;
422 else code
= XML_IO_UNKNOWN
;
423 #endif /* HAVE_ERRNO_H */
426 if (code
>= XML_IO_UNKNOWN
) idx
= code
- XML_IO_UNKNOWN
;
427 if (idx
>= (sizeof(IOerr
) / sizeof(IOerr
[0]))) idx
= 0;
429 __xmlSimpleError(domain
, code
, NULL
, IOerr
[idx
], extra
);
434 * @code: the error number
435 * @extra: extra informations
437 * Handle an I/O error
440 xmlIOErr(int code
, const char *extra
)
442 __xmlIOErr(XML_FROM_IO
, code
, extra
);
447 * @ctx: the parser context
448 * @extra: extra informations
450 * Handle a resource access error
453 __xmlLoaderErr(void *ctx
, const char *msg
, const char *filename
)
455 xmlParserCtxtPtr ctxt
= (xmlParserCtxtPtr
) ctx
;
456 xmlStructuredErrorFunc schannel
= NULL
;
457 xmlGenericErrorFunc channel
= NULL
;
459 xmlErrorLevel level
= XML_ERR_ERROR
;
461 if ((ctxt
!= NULL
) && (ctxt
->disableSAX
!= 0) &&
462 (ctxt
->instate
== XML_PARSER_EOF
))
464 if ((ctxt
!= NULL
) && (ctxt
->sax
!= NULL
)) {
465 if (ctxt
->validate
) {
466 channel
= ctxt
->sax
->error
;
467 level
= XML_ERR_ERROR
;
469 channel
= ctxt
->sax
->warning
;
470 level
= XML_ERR_WARNING
;
472 if (ctxt
->sax
->initialized
== XML_SAX2_MAGIC
)
473 schannel
= ctxt
->sax
->serror
;
474 data
= ctxt
->userData
;
476 __xmlRaiseError(schannel
, channel
, data
, ctxt
, NULL
, XML_FROM_IO
,
477 XML_IO_LOAD_ERROR
, level
, NULL
, 0,
478 filename
, NULL
, NULL
, 0, 0,
483 /************************************************************************
485 * Tree memory error handler *
487 ************************************************************************/
489 * xmlNormalizeWindowsPath:
490 * @path: the input file path
492 * This function is obsolete. Please see xmlURIFromPath in uri.c for
495 * Returns a canonicalized version of the path
498 xmlNormalizeWindowsPath(const xmlChar
*path
)
500 return xmlCanonicPath(path
);
504 * xmlCleanupInputCallbacks:
506 * clears the entire input callback table. this includes the
510 xmlCleanupInputCallbacks(void)
514 if (!xmlInputCallbackInitialized
)
517 for (i
= xmlInputCallbackNr
- 1; i
>= 0; i
--) {
518 xmlInputCallbackTable
[i
].matchcallback
= NULL
;
519 xmlInputCallbackTable
[i
].opencallback
= NULL
;
520 xmlInputCallbackTable
[i
].readcallback
= NULL
;
521 xmlInputCallbackTable
[i
].closecallback
= NULL
;
524 xmlInputCallbackNr
= 0;
525 xmlInputCallbackInitialized
= 0;
529 * xmlPopInputCallbacks:
531 * Clear the top input callback from the input stack. this includes the
534 * Returns the number of input callback registered or -1 in case of error.
537 xmlPopInputCallbacks(void)
539 if (!xmlInputCallbackInitialized
)
542 if (xmlInputCallbackNr
<= 0)
545 xmlInputCallbackNr
--;
546 xmlInputCallbackTable
[xmlInputCallbackNr
].matchcallback
= NULL
;
547 xmlInputCallbackTable
[xmlInputCallbackNr
].opencallback
= NULL
;
548 xmlInputCallbackTable
[xmlInputCallbackNr
].readcallback
= NULL
;
549 xmlInputCallbackTable
[xmlInputCallbackNr
].closecallback
= NULL
;
551 return(xmlInputCallbackNr
);
554 #ifdef LIBXML_OUTPUT_ENABLED
556 * xmlCleanupOutputCallbacks:
558 * clears the entire output callback table. this includes the
559 * compiled-in I/O callbacks.
562 xmlCleanupOutputCallbacks(void)
566 if (!xmlOutputCallbackInitialized
)
569 for (i
= xmlOutputCallbackNr
- 1; i
>= 0; i
--) {
570 xmlOutputCallbackTable
[i
].matchcallback
= NULL
;
571 xmlOutputCallbackTable
[i
].opencallback
= NULL
;
572 xmlOutputCallbackTable
[i
].writecallback
= NULL
;
573 xmlOutputCallbackTable
[i
].closecallback
= NULL
;
576 xmlOutputCallbackNr
= 0;
577 xmlOutputCallbackInitialized
= 0;
579 #endif /* LIBXML_OUTPUT_ENABLED */
581 /************************************************************************
583 * Standard I/O for file accesses *
585 ************************************************************************/
587 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
591 * @path: the path in utf-8 encoding
592 * @mode: type of access (0 - read, 1 - write)
594 * function opens the file specified by @path
598 xmlWrapOpenUtf8(const char *path
,int mode
)
603 wPath
= __xmlIOWin32UTF8ToWChar(path
);
606 fd
= _wfopen(wPath
, mode
? L
"wb" : L
"rb");
609 /* maybe path in native encoding */
611 fd
= fopen(path
, mode
? "wb" : "rb");
618 xmlWrapGzOpenUtf8(const char *path
, const char *mode
)
623 fd
= gzopen (path
, mode
);
627 wPath
= __xmlIOWin32UTF8ToWChar(path
);
630 int d
, m
= (strstr(mode
, "r") ? O_RDONLY
: O_RDWR
);
632 m
|= (strstr(mode
, "b") ? _O_BINARY
: 0);
634 d
= _wopen(wPath
, m
);
636 fd
= gzdopen(d
, mode
);
646 * @path: the path in utf-8 encoding
647 * @info: structure that stores results
649 * function obtains information about the file or directory
653 xmlWrapStatUtf8(const char *path
,struct stat
*info
)
659 wPath
= __xmlIOWin32UTF8ToWChar(path
);
662 retval
= _wstat(wPath
,info
);
665 /* maybe path in native encoding */
667 retval
= stat(path
,info
);
677 * @mode: type of access (0 - read, 1 - write)
679 * function opens the file specified by @path
683 xmlWrapOpenNative(const char *path
,int mode
)
685 return fopen(path
,mode
? "wb" : "rb");
691 * @info: structure that stores results
693 * function obtains information about the file or directory
697 xmlWrapStatNative(const char *path
,struct stat
*info
)
700 return stat(path
,info
);
706 typedef int (* xmlWrapStatFunc
) (const char *f
, struct stat
*s
);
707 static xmlWrapStatFunc xmlWrapStat
= xmlWrapStatNative
;
708 typedef FILE* (* xmlWrapOpenFunc
)(const char *f
,int mode
);
709 static xmlWrapOpenFunc xmlWrapOpen
= xmlWrapOpenNative
;
711 typedef gzFile (* xmlWrapGzOpenFunc
) (const char *f
, const char *mode
);
712 static xmlWrapGzOpenFunc xmlWrapGzOpen
= gzopen
;
715 * xmlInitPlatformSpecificIo:
717 * Initialize platform specific features.
720 xmlInitPlatformSpecificIo(void)
722 static int xmlPlatformIoInitialized
= 0;
725 if(xmlPlatformIoInitialized
)
728 osvi
.dwOSVersionInfoSize
= sizeof(osvi
);
730 if(GetVersionEx(&osvi
) && (osvi
.dwPlatformId
== VER_PLATFORM_WIN32_NT
)) {
731 xmlWrapStat
= xmlWrapStatUtf8
;
732 xmlWrapOpen
= xmlWrapOpenUtf8
;
734 xmlWrapGzOpen
= xmlWrapGzOpenUtf8
;
737 xmlWrapStat
= xmlWrapStatNative
;
738 xmlWrapOpen
= xmlWrapOpenNative
;
740 xmlWrapGzOpen
= gzopen
;
744 xmlPlatformIoInitialized
= 1;
752 * @path: the path to check
754 * function checks to see if @path is a valid source
755 * (file, socket...) for XML.
757 * if stat is not available on the target machine,
758 * returns 1. if stat fails, returns 0 (if calling
759 * stat on the filename fails, it can't be right).
760 * if stat succeeds and the file is a directory,
761 * returns 2. otherwise returns 1.
765 xmlCheckFilename (const char *path
)
768 struct stat stat_buffer
;
774 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
775 if (xmlWrapStat(path
, &stat_buffer
) == -1)
778 if (stat(path
, &stat_buffer
) == -1)
782 if (S_ISDIR(stat_buffer
.st_mode
))
785 #endif /* HAVE_STAT */
796 * @context: the I/O context
797 * @buffer: where to drop data
798 * @len: number of bytes to read
800 * Read @len bytes to @buffer from the I/O channel.
802 * Returns the number of bytes written
805 xmlFdRead (void * context
, char * buffer
, int len
) {
808 ret
= read((int) (long) context
, &buffer
[0], len
);
809 if (ret
< 0) xmlIOErr(0, "read()");
813 #ifdef LIBXML_OUTPUT_ENABLED
816 * @context: the I/O context
817 * @buffer: where to get data
818 * @len: number of bytes to write
820 * Write @len bytes from @buffer to the I/O channel.
822 * Returns the number of bytes written
825 xmlFdWrite (void * context
, const char * buffer
, int len
) {
829 ret
= write((int) (long) context
, &buffer
[0], len
);
830 if (ret
< 0) xmlIOErr(0, "write()");
834 #endif /* LIBXML_OUTPUT_ENABLED */
838 * @context: the I/O context
840 * Close an I/O channel
842 * Returns 0 in case of success and error code otherwise
845 xmlFdClose (void * context
) {
847 ret
= close((int) (long) context
);
848 if (ret
< 0) xmlIOErr(0, "close()");
854 * @filename: the URI for matching
858 * Returns 1 if matches, 0 otherwise
861 xmlFileMatch (const char *filename ATTRIBUTE_UNUSED
) {
867 * @filename: the URI for matching
869 * input from FILE *, supports compressed input
870 * if @filename is " " then the standard input is used
872 * Returns an I/O context or NULL in case of error
875 xmlFileOpen_real (const char *filename
) {
876 const char *path
= NULL
;
879 if (filename
== NULL
)
882 if (!strcmp(filename
, "-")) {
887 if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file://localhost/", 17)) {
888 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
889 path
= &filename
[17];
891 path
= &filename
[16];
893 } else if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file:///", 8)) {
894 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
899 } else if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file:/", 6)) {
900 /* lots of generators seems to lazy to read RFC 1738 */
901 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
911 if (!xmlCheckFilename(path
))
914 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
915 fd
= xmlWrapOpen(path
, 0);
917 fd
= fopen(path
, "r");
919 if (fd
== NULL
) xmlIOErr(0, path
);
925 * @filename: the URI for matching
927 * Wrapper around xmlFileOpen_real that try it with an unescaped
928 * version of @filename, if this fails fallback to @filename
930 * Returns a handler or NULL in case or failure
933 xmlFileOpen (const char *filename
) {
937 retval
= xmlFileOpen_real(filename
);
938 if (retval
== NULL
) {
939 unescaped
= xmlURIUnescapeString(filename
, 0, NULL
);
940 if (unescaped
!= NULL
) {
941 retval
= xmlFileOpen_real(unescaped
);
949 #ifdef LIBXML_OUTPUT_ENABLED
952 * @filename: the URI for matching
954 * output to from FILE *,
955 * if @filename is "-" then the standard output is used
957 * Returns an I/O context or NULL in case of error
960 xmlFileOpenW (const char *filename
) {
961 const char *path
= NULL
;
964 if (!strcmp(filename
, "-")) {
969 if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file://localhost/", 17))
970 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
971 path
= &filename
[17];
973 path
= &filename
[16];
975 else if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file:///", 8)) {
976 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
987 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
988 fd
= xmlWrapOpen(path
, 1);
990 fd
= fopen(path
, "wb");
993 if (fd
== NULL
) xmlIOErr(0, path
);
996 #endif /* LIBXML_OUTPUT_ENABLED */
1000 * @context: the I/O context
1001 * @buffer: where to drop data
1002 * @len: number of bytes to write
1004 * Read @len bytes to @buffer from the I/O channel.
1006 * Returns the number of bytes written or < 0 in case of failure
1009 xmlFileRead (void * context
, char * buffer
, int len
) {
1011 if ((context
== NULL
) || (buffer
== NULL
))
1013 ret
= fread(&buffer
[0], 1, len
, (FILE *) context
);
1014 if (ret
< 0) xmlIOErr(0, "fread()");
1018 #ifdef LIBXML_OUTPUT_ENABLED
1021 * @context: the I/O context
1022 * @buffer: where to drop data
1023 * @len: number of bytes to write
1025 * Write @len bytes from @buffer to the I/O channel.
1027 * Returns the number of bytes written
1030 xmlFileWrite (void * context
, const char * buffer
, int len
) {
1033 if ((context
== NULL
) || (buffer
== NULL
))
1035 items
= fwrite(&buffer
[0], len
, 1, (FILE *) context
);
1036 if ((items
== 0) && (ferror((FILE *) context
))) {
1037 xmlIOErr(0, "fwrite()");
1040 return(items
* len
);
1042 #endif /* LIBXML_OUTPUT_ENABLED */
1046 * @context: the I/O context
1048 * Close an I/O channel
1050 * Returns 0 or -1 in case of error
1053 xmlFileClose (void * context
) {
1057 if (context
== NULL
)
1059 fil
= (FILE *) context
;
1060 if ((fil
== stdout
) || (fil
== stderr
)) {
1063 xmlIOErr(0, "fflush()");
1068 ret
= ( fclose((FILE *) context
) == EOF
) ? -1 : 0;
1070 xmlIOErr(0, "fclose()");
1076 * @context: the I/O context
1078 * Flush an I/O channel
1081 xmlFileFlush (void * context
) {
1084 if (context
== NULL
)
1086 ret
= ( fflush((FILE *) context
) == EOF
) ? -1 : 0;
1088 xmlIOErr(0, "fflush()");
1092 #ifdef LIBXML_OUTPUT_ENABLED
1095 * @context: the xmlBuffer
1096 * @buffer: the data to write
1097 * @len: number of bytes to write
1099 * Write @len bytes from @buffer to the xml buffer
1101 * Returns the number of bytes written
1104 xmlBufferWrite (void * context
, const char * buffer
, int len
) {
1107 ret
= xmlBufferAdd((xmlBufferPtr
) context
, (const xmlChar
*) buffer
, len
);
1115 /************************************************************************
1117 * I/O for compressed file accesses *
1119 ************************************************************************/
1122 * @filename: the URI for matching
1124 * input from compressed file test
1126 * Returns 1 if matches, 0 otherwise
1129 xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED
) {
1134 * xmlGzfileOpen_real:
1135 * @filename: the URI for matching
1137 * input from compressed file open
1138 * if @filename is " " then the standard input is used
1140 * Returns an I/O context or NULL in case of error
1143 xmlGzfileOpen_real (const char *filename
) {
1144 const char *path
= NULL
;
1147 if (!strcmp(filename
, "-")) {
1148 fd
= gzdopen(dup(0), "rb");
1149 return((void *) fd
);
1152 if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file://localhost/", 17))
1153 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
1154 path
= &filename
[17];
1156 path
= &filename
[16];
1158 else if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file:///", 8)) {
1159 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
1160 path
= &filename
[8];
1162 path
= &filename
[7];
1169 if (!xmlCheckFilename(path
))
1172 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
1173 fd
= xmlWrapGzOpen(path
, "rb");
1175 fd
= gzopen(path
, "rb");
1177 return((void *) fd
);
1182 * @filename: the URI for matching
1184 * Wrapper around xmlGzfileOpen if the open fais, it will
1185 * try to unescape @filename
1188 xmlGzfileOpen (const char *filename
) {
1192 retval
= xmlGzfileOpen_real(filename
);
1193 if (retval
== NULL
) {
1194 unescaped
= xmlURIUnescapeString(filename
, 0, NULL
);
1195 if (unescaped
!= NULL
) {
1196 retval
= xmlGzfileOpen_real(unescaped
);
1203 #ifdef LIBXML_OUTPUT_ENABLED
1206 * @filename: the URI for matching
1207 * @compression: the compression factor (0 - 9 included)
1209 * input from compressed file open
1210 * if @filename is " " then the standard input is used
1212 * Returns an I/O context or NULL in case of error
1215 xmlGzfileOpenW (const char *filename
, int compression
) {
1216 const char *path
= NULL
;
1220 snprintf(mode
, sizeof(mode
), "wb%d", compression
);
1221 if (!strcmp(filename
, "-")) {
1222 fd
= gzdopen(dup(1), mode
);
1223 return((void *) fd
);
1226 if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file://localhost/", 17))
1227 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
1228 path
= &filename
[17];
1230 path
= &filename
[16];
1232 else if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"file:///", 8)) {
1233 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
1234 path
= &filename
[8];
1236 path
= &filename
[7];
1244 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
1245 fd
= xmlWrapGzOpen(path
, mode
);
1247 fd
= gzopen(path
, mode
);
1249 return((void *) fd
);
1251 #endif /* LIBXML_OUTPUT_ENABLED */
1255 * @context: the I/O context
1256 * @buffer: where to drop data
1257 * @len: number of bytes to write
1259 * Read @len bytes to @buffer from the compressed I/O channel.
1261 * Returns the number of bytes written
1264 xmlGzfileRead (void * context
, char * buffer
, int len
) {
1267 ret
= gzread((gzFile
) context
, &buffer
[0], len
);
1268 if (ret
< 0) xmlIOErr(0, "gzread()");
1272 #ifdef LIBXML_OUTPUT_ENABLED
1275 * @context: the I/O context
1276 * @buffer: where to drop data
1277 * @len: number of bytes to write
1279 * Write @len bytes from @buffer to the compressed I/O channel.
1281 * Returns the number of bytes written
1284 xmlGzfileWrite (void * context
, const char * buffer
, int len
) {
1287 ret
= gzwrite((gzFile
) context
, (char *) &buffer
[0], len
);
1288 if (ret
< 0) xmlIOErr(0, "gzwrite()");
1291 #endif /* LIBXML_OUTPUT_ENABLED */
1295 * @context: the I/O context
1297 * Close a compressed I/O channel
1300 xmlGzfileClose (void * context
) {
1303 ret
= (gzclose((gzFile
) context
) == Z_OK
) ? 0 : -1;
1304 if (ret
< 0) xmlIOErr(0, "gzclose()");
1307 #endif /* HAVE_ZLIB_H */
1309 #ifdef LIBXML_HTTP_ENABLED
1310 /************************************************************************
1312 * I/O for HTTP file accesses *
1314 ************************************************************************/
1316 #ifdef LIBXML_OUTPUT_ENABLED
1317 typedef struct xmlIOHTTPWriteCtxt_
1325 } xmlIOHTTPWriteCtxt
, *xmlIOHTTPWriteCtxtPtr
;
1329 #define DFLT_WBITS ( -15 )
1330 #define DFLT_MEM_LVL ( 8 )
1331 #define GZ_MAGIC1 ( 0x1f )
1332 #define GZ_MAGIC2 ( 0x8b )
1333 #define LXML_ZLIB_OS_CODE ( 0x03 )
1334 #define INIT_HTTP_BUFF_SIZE ( 32768 )
1335 #define DFLT_ZLIB_RATIO ( 5 )
1338 ** Data structure and functions to work with sending compressed data
1342 typedef struct xmlZMemBuff_
1347 unsigned char * zbuff
;
1350 } xmlZMemBuff
, *xmlZMemBuffPtr
;
1353 * append_reverse_ulong
1354 * @buff: Compressed memory buffer
1355 * @data: Unsigned long to append
1357 * Append a unsigned long in reverse byte order to the end of the
1361 append_reverse_ulong( xmlZMemBuff
* buff
, unsigned long data
) {
1369 ** This is plagiarized from putLong in gzio.c (zlib source) where
1370 ** the number "4" is hardcoded. If zlib is ever patched to
1371 ** support 64 bit file sizes, this code would need to be patched
1375 for ( idx
= 0; idx
< 4; idx
++ ) {
1376 *buff
->zctrl
.next_out
= ( data
& 0xff );
1378 buff
->zctrl
.next_out
++;
1387 * @buff: The memory buffer context to clear
1389 * Release all the resources associated with the compressed memory buffer.
1392 xmlFreeZMemBuff( xmlZMemBuffPtr buff
) {
1401 xmlFree( buff
->zbuff
);
1403 z_err
= deflateEnd( &buff
->zctrl
);
1404 if ( z_err
!= Z_OK
)
1405 xmlGenericError( xmlGenericErrorContext
,
1406 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
1409 deflateEnd( &buff
->zctrl
);
1418 *@compression: Compression value to use
1420 * Create a memory buffer to hold the compressed XML document. The
1421 * compressed document in memory will end up being identical to what
1422 * would be created if gzopen/gzwrite/gzclose were being used to
1423 * write the document to disk. The code for the header/trailer data to
1424 * the compression is plagiarized from the zlib source files.
1427 xmlCreateZMemBuff( int compression
) {
1431 xmlZMemBuffPtr buff
= NULL
;
1433 if ( ( compression
< 1 ) || ( compression
> 9 ) )
1436 /* Create the control and data areas */
1438 buff
= xmlMalloc( sizeof( xmlZMemBuff
) );
1439 if ( buff
== NULL
) {
1440 xmlIOErrMemory("creating buffer context");
1444 (void)memset( buff
, 0, sizeof( xmlZMemBuff
) );
1445 buff
->size
= INIT_HTTP_BUFF_SIZE
;
1446 buff
->zbuff
= xmlMalloc( buff
->size
);
1447 if ( buff
->zbuff
== NULL
) {
1448 xmlFreeZMemBuff( buff
);
1449 xmlIOErrMemory("creating buffer");
1453 z_err
= deflateInit2( &buff
->zctrl
, compression
, Z_DEFLATED
,
1454 DFLT_WBITS
, DFLT_MEM_LVL
, Z_DEFAULT_STRATEGY
);
1455 if ( z_err
!= Z_OK
) {
1457 xmlFreeZMemBuff( buff
);
1459 xmlStrPrintf(msg
, 500,
1460 (const xmlChar
*) "xmlCreateZMemBuff: %s %d\n",
1461 "Error initializing compression context. ZLIB error:",
1463 xmlIOErr(XML_IO_WRITE
, (const char *) msg
);
1467 /* Set the header data. The CRC will be needed for the trailer */
1468 buff
->crc
= crc32( 0L, NULL
, 0 );
1469 hdr_lgth
= snprintf( (char *)buff
->zbuff
, buff
->size
,
1470 "%c%c%c%c%c%c%c%c%c%c",
1471 GZ_MAGIC1
, GZ_MAGIC2
, Z_DEFLATED
,
1472 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE
);
1473 buff
->zctrl
.next_out
= buff
->zbuff
+ hdr_lgth
;
1474 buff
->zctrl
.avail_out
= buff
->size
- hdr_lgth
;
1481 * @buff: Buffer used to compress and consolidate data.
1482 * @ext_amt: Number of bytes to extend the buffer.
1484 * Extend the internal buffer used to store the compressed data by the
1487 * Returns 0 on success or -1 on failure to extend the buffer. On failure
1488 * the original buffer still exists at the original size.
1491 xmlZMemBuffExtend( xmlZMemBuffPtr buff
, size_t ext_amt
) {
1497 unsigned char * tmp_ptr
= NULL
;
1502 else if ( ext_amt
== 0 )
1505 cur_used
= buff
->zctrl
.next_out
- buff
->zbuff
;
1506 new_size
= buff
->size
+ ext_amt
;
1509 if ( cur_used
> new_size
)
1510 xmlGenericError( xmlGenericErrorContext
,
1511 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
1512 "Buffer overwrite detected during compressed memory",
1513 "buffer extension. Overflowed by",
1514 (cur_used
- new_size
) );
1517 tmp_ptr
= xmlRealloc( buff
->zbuff
, new_size
);
1518 if ( tmp_ptr
!= NULL
) {
1520 buff
->size
= new_size
;
1521 buff
->zbuff
= tmp_ptr
;
1522 buff
->zctrl
.next_out
= tmp_ptr
+ cur_used
;
1523 buff
->zctrl
.avail_out
= new_size
- cur_used
;
1527 xmlStrPrintf(msg
, 500,
1528 (const xmlChar
*) "xmlZMemBuffExtend: %s %lu bytes.\n",
1529 "Allocation failure extending output buffer to",
1531 xmlIOErr(XML_IO_WRITE
, (const char *) msg
);
1539 * @buff: Buffer used to compress and consolidate data
1540 * @src: Uncompressed source content to append to buffer
1541 * @len: Length of source data to append to buffer
1543 * Compress and append data to the internal buffer. The data buffer
1544 * will be expanded if needed to store the additional data.
1546 * Returns the number of bytes appended to the buffer or -1 on error.
1549 xmlZMemBuffAppend( xmlZMemBuffPtr buff
, const char * src
, int len
) {
1554 if ( ( buff
== NULL
) || ( src
== NULL
) )
1557 buff
->zctrl
.avail_in
= len
;
1558 buff
->zctrl
.next_in
= (unsigned char *)src
;
1559 while ( buff
->zctrl
.avail_in
> 0 ) {
1561 ** Extend the buffer prior to deflate call if a reasonable amount
1562 ** of output buffer space is not available.
1564 min_accept
= buff
->zctrl
.avail_in
/ DFLT_ZLIB_RATIO
;
1565 if ( buff
->zctrl
.avail_out
<= min_accept
) {
1566 if ( xmlZMemBuffExtend( buff
, buff
->size
) == -1 )
1570 z_err
= deflate( &buff
->zctrl
, Z_NO_FLUSH
);
1571 if ( z_err
!= Z_OK
) {
1573 xmlStrPrintf(msg
, 500,
1574 (const xmlChar
*) "xmlZMemBuffAppend: %s %d %s - %d",
1575 "Compression error while appending",
1576 len
, "bytes to buffer. ZLIB error", z_err
);
1577 xmlIOErr(XML_IO_WRITE
, (const char *) msg
);
1582 buff
->crc
= crc32( buff
->crc
, (unsigned char *)src
, len
);
1588 * xmlZMemBuffGetContent
1589 * @buff: Compressed memory content buffer
1590 * @data_ref: Pointer reference to point to compressed content
1592 * Flushes the compression buffers, appends gzip file trailers and
1593 * returns the compressed content and length of the compressed data.
1594 * NOTE: The gzip trailer code here is plagiarized from zlib source.
1596 * Returns the length of the compressed data or -1 on error.
1599 xmlZMemBuffGetContent( xmlZMemBuffPtr buff
, char ** data_ref
) {
1604 if ( ( buff
== NULL
) || ( data_ref
== NULL
) )
1607 /* Need to loop until compression output buffers are flushed */
1611 z_err
= deflate( &buff
->zctrl
, Z_FINISH
);
1612 if ( z_err
== Z_OK
) {
1613 /* In this case Z_OK means more buffer space needed */
1615 if ( xmlZMemBuffExtend( buff
, buff
->size
) == -1 )
1619 while ( z_err
== Z_OK
);
1621 /* If the compression state is not Z_STREAM_END, some error occurred */
1623 if ( z_err
== Z_STREAM_END
) {
1625 /* Need to append the gzip data trailer */
1627 if ( buff
->zctrl
.avail_out
< ( 2 * sizeof( unsigned long ) ) ) {
1628 if ( xmlZMemBuffExtend(buff
, (2 * sizeof(unsigned long))) == -1 )
1633 ** For whatever reason, the CRC and length data are pushed out
1634 ** in reverse byte order. So a memcpy can't be used here.
1637 append_reverse_ulong( buff
, buff
->crc
);
1638 append_reverse_ulong( buff
, buff
->zctrl
.total_in
);
1640 zlgth
= buff
->zctrl
.next_out
- buff
->zbuff
;
1641 *data_ref
= (char *)buff
->zbuff
;
1646 xmlStrPrintf(msg
, 500,
1647 (const xmlChar
*) "xmlZMemBuffGetContent: %s - %d\n",
1648 "Error flushing zlib buffers. Error code", z_err
);
1649 xmlIOErr(XML_IO_WRITE
, (const char *) msg
);
1654 #endif /* LIBXML_OUTPUT_ENABLED */
1655 #endif /* HAVE_ZLIB_H */
1657 #ifdef LIBXML_OUTPUT_ENABLED
1659 * xmlFreeHTTPWriteCtxt
1660 * @ctxt: Context to cleanup
1662 * Free allocated memory and reclaim system resources.
1667 xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt
)
1669 if ( ctxt
->uri
!= NULL
)
1670 xmlFree( ctxt
->uri
);
1672 if ( ctxt
->doc_buff
!= NULL
) {
1675 if ( ctxt
->compression
> 0 ) {
1676 xmlFreeZMemBuff( ctxt
->doc_buff
);
1681 xmlOutputBufferClose( ctxt
->doc_buff
);
1688 #endif /* LIBXML_OUTPUT_ENABLED */
1693 * @filename: the URI for matching
1695 * check if the URI matches an HTTP one
1697 * Returns 1 if matches, 0 otherwise
1700 xmlIOHTTPMatch (const char *filename
) {
1701 if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"http://", 7))
1708 * @filename: the URI for matching
1710 * open an HTTP I/O channel
1712 * Returns an I/O context or NULL in case of error
1715 xmlIOHTTPOpen (const char *filename
) {
1716 return(xmlNanoHTTPOpen(filename
, NULL
));
1719 #ifdef LIBXML_OUTPUT_ENABLED
1722 * @post_uri: The destination URI for the document
1723 * @compression: The compression desired for the document.
1725 * Open a temporary buffer to collect the document for a subsequent HTTP POST
1726 * request. Non-static as is called from the output buffer creation routine.
1728 * Returns an I/O context or NULL in case of error.
1732 xmlIOHTTPOpenW(const char *post_uri
, int compression
)
1735 xmlIOHTTPWriteCtxtPtr ctxt
= NULL
;
1737 if (post_uri
== NULL
)
1740 ctxt
= xmlMalloc(sizeof(xmlIOHTTPWriteCtxt
));
1742 xmlIOErrMemory("creating HTTP output context");
1746 (void) memset(ctxt
, 0, sizeof(xmlIOHTTPWriteCtxt
));
1748 ctxt
->uri
= (char *) xmlStrdup((const xmlChar
*)post_uri
);
1749 if (ctxt
->uri
== NULL
) {
1750 xmlIOErrMemory("copying URI");
1751 xmlFreeHTTPWriteCtxt(ctxt
);
1756 * ** Since the document length is required for an HTTP post,
1757 * ** need to put the document into a buffer. A memory buffer
1758 * ** is being used to avoid pushing the data to disk and back.
1762 if ((compression
> 0) && (compression
<= 9)) {
1764 ctxt
->compression
= compression
;
1765 ctxt
->doc_buff
= xmlCreateZMemBuff(compression
);
1769 /* Any character conversions should have been done before this */
1771 ctxt
->doc_buff
= xmlAllocOutputBufferInternal(NULL
);
1774 if (ctxt
->doc_buff
== NULL
) {
1775 xmlFreeHTTPWriteCtxt(ctxt
);
1781 #endif /* LIBXML_OUTPUT_ENABLED */
1783 #ifdef LIBXML_OUTPUT_ENABLED
1785 * xmlIOHTTPDfltOpenW
1786 * @post_uri: The destination URI for this document.
1788 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
1789 * HTTP post command. This function should generally not be used as
1790 * the open callback is short circuited in xmlOutputBufferCreateFile.
1792 * Returns a pointer to the new IO context.
1795 xmlIOHTTPDfltOpenW( const char * post_uri
) {
1796 return ( xmlIOHTTPOpenW( post_uri
, 0 ) );
1798 #endif /* LIBXML_OUTPUT_ENABLED */
1802 * @context: the I/O context
1803 * @buffer: where to drop data
1804 * @len: number of bytes to write
1806 * Read @len bytes to @buffer from the I/O channel.
1808 * Returns the number of bytes written
1811 xmlIOHTTPRead(void * context
, char * buffer
, int len
) {
1812 if ((buffer
== NULL
) || (len
< 0)) return(-1);
1813 return(xmlNanoHTTPRead(context
, &buffer
[0], len
));
1816 #ifdef LIBXML_OUTPUT_ENABLED
1819 * @context: previously opened writing context
1820 * @buffer: data to output to temporary buffer
1821 * @len: bytes to output
1823 * Collect data from memory buffer into a temporary file for later
1826 * Returns number of bytes written.
1830 xmlIOHTTPWrite( void * context
, const char * buffer
, int len
) {
1832 xmlIOHTTPWriteCtxtPtr ctxt
= context
;
1834 if ( ( ctxt
== NULL
) || ( ctxt
->doc_buff
== NULL
) || ( buffer
== NULL
) )
1839 /* Use gzwrite or fwrite as previously setup in the open call */
1842 if ( ctxt
->compression
> 0 )
1843 len
= xmlZMemBuffAppend( ctxt
->doc_buff
, buffer
, len
);
1847 len
= xmlOutputBufferWrite( ctxt
->doc_buff
, len
, buffer
);
1851 xmlStrPrintf(msg
, 500,
1852 (const xmlChar
*) "xmlIOHTTPWrite: %s\n%s '%s'.\n",
1853 "Error appending to internal buffer.",
1854 "Error sending document to URI",
1856 xmlIOErr(XML_IO_WRITE
, (const char *) msg
);
1862 #endif /* LIBXML_OUTPUT_ENABLED */
1867 * @context: the I/O context
1869 * Close an HTTP I/O channel
1874 xmlIOHTTPClose (void * context
) {
1875 xmlNanoHTTPClose(context
);
1879 #ifdef LIBXML_OUTPUT_ENABLED
1881 * xmlIOHTTCloseWrite
1882 * @context: The I/O context
1883 * @http_mthd: The HTTP method to be used when sending the data
1885 * Close the transmit HTTP I/O channel and actually send the data.
1888 xmlIOHTTPCloseWrite( void * context
, const char * http_mthd
) {
1892 int content_lgth
= 0;
1893 xmlIOHTTPWriteCtxtPtr ctxt
= context
;
1895 char * http_content
= NULL
;
1896 char * content_encoding
= NULL
;
1897 char * content_type
= (char *) "text/xml";
1898 void * http_ctxt
= NULL
;
1900 if ( ( ctxt
== NULL
) || ( http_mthd
== NULL
) )
1903 /* Retrieve the content from the appropriate buffer */
1907 if ( ctxt
->compression
> 0 ) {
1908 content_lgth
= xmlZMemBuffGetContent( ctxt
->doc_buff
, &http_content
);
1909 content_encoding
= (char *) "Content-Encoding: gzip";
1914 /* Pull the data out of the memory output buffer */
1916 xmlOutputBufferPtr dctxt
= ctxt
->doc_buff
;
1917 http_content
= (char *)dctxt
->buffer
->content
;
1918 content_lgth
= dctxt
->buffer
->use
;
1921 if ( http_content
== NULL
) {
1923 xmlStrPrintf(msg
, 500,
1924 (const xmlChar
*) "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
1925 "Error retrieving content.\nUnable to",
1926 http_mthd
, "data to URI", ctxt
->uri
);
1927 xmlIOErr(XML_IO_WRITE
, (const char *) msg
);
1932 http_ctxt
= xmlNanoHTTPMethod( ctxt
->uri
, http_mthd
, http_content
,
1933 &content_type
, content_encoding
,
1936 if ( http_ctxt
!= NULL
) {
1938 /* If testing/debugging - dump reply with request content */
1940 FILE * tst_file
= NULL
;
1941 char buffer
[ 4096 ];
1942 char * dump_name
= NULL
;
1945 xmlGenericError( xmlGenericErrorContext
,
1946 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
1947 http_mthd
, ctxt
->uri
,
1948 xmlNanoHTTPReturnCode( http_ctxt
) );
1951 ** Since either content or reply may be gzipped,
1952 ** dump them to separate files instead of the
1953 ** standard error context.
1956 dump_name
= tempnam( NULL
, "lxml" );
1957 if ( dump_name
!= NULL
) {
1958 (void)snprintf( buffer
, sizeof(buffer
), "%s.content", dump_name
);
1960 tst_file
= fopen( buffer
, "wb" );
1961 if ( tst_file
!= NULL
) {
1962 xmlGenericError( xmlGenericErrorContext
,
1963 "Transmitted content saved in file: %s\n", buffer
);
1965 fwrite( http_content
, sizeof( char ),
1966 content_lgth
, tst_file
);
1970 (void)snprintf( buffer
, sizeof(buffer
), "%s.reply", dump_name
);
1971 tst_file
= fopen( buffer
, "wb" );
1972 if ( tst_file
!= NULL
) {
1973 xmlGenericError( xmlGenericErrorContext
,
1974 "Reply content saved in file: %s\n", buffer
);
1977 while ( (avail
= xmlNanoHTTPRead( http_ctxt
,
1978 buffer
, sizeof( buffer
) )) > 0 ) {
1980 fwrite( buffer
, sizeof( char ), avail
, tst_file
);
1988 #endif /* DEBUG_HTTP */
1990 http_rtn
= xmlNanoHTTPReturnCode( http_ctxt
);
1991 if ( ( http_rtn
>= 200 ) && ( http_rtn
< 300 ) )
1995 xmlStrPrintf(msg
, 500,
1996 (const xmlChar
*) "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
1997 http_mthd
, content_lgth
,
1998 "bytes to URI", ctxt
->uri
,
1999 "failed. HTTP return code:", http_rtn
);
2000 xmlIOErr(XML_IO_WRITE
, (const char *) msg
);
2003 xmlNanoHTTPClose( http_ctxt
);
2004 xmlFree( content_type
);
2008 /* Final cleanups */
2010 xmlFreeHTTPWriteCtxt( ctxt
);
2012 return ( close_rc
);
2018 * @context: The I/O context
2020 * Close the transmit HTTP I/O channel and actually send data using a PUT
2024 xmlIOHTTPClosePut( void * ctxt
) {
2025 return ( xmlIOHTTPCloseWrite( ctxt
, "PUT" ) );
2030 * xmlIOHTTPClosePost
2032 * @context: The I/O context
2034 * Close the transmit HTTP I/O channel and actually send data using a POST
2038 xmlIOHTTPClosePost( void * ctxt
) {
2039 return ( xmlIOHTTPCloseWrite( ctxt
, "POST" ) );
2041 #endif /* LIBXML_OUTPUT_ENABLED */
2043 #endif /* LIBXML_HTTP_ENABLED */
2045 #ifdef LIBXML_FTP_ENABLED
2046 /************************************************************************
2048 * I/O for FTP file accesses *
2050 ************************************************************************/
2053 * @filename: the URI for matching
2055 * check if the URI matches an FTP one
2057 * Returns 1 if matches, 0 otherwise
2060 xmlIOFTPMatch (const char *filename
) {
2061 if (!xmlStrncasecmp(BAD_CAST filename
, BAD_CAST
"ftp://", 6))
2068 * @filename: the URI for matching
2070 * open an FTP I/O channel
2072 * Returns an I/O context or NULL in case of error
2075 xmlIOFTPOpen (const char *filename
) {
2076 return(xmlNanoFTPOpen(filename
));
2081 * @context: the I/O context
2082 * @buffer: where to drop data
2083 * @len: number of bytes to write
2085 * Read @len bytes to @buffer from the I/O channel.
2087 * Returns the number of bytes written
2090 xmlIOFTPRead(void * context
, char * buffer
, int len
) {
2091 if ((buffer
== NULL
) || (len
< 0)) return(-1);
2092 return(xmlNanoFTPRead(context
, &buffer
[0], len
));
2097 * @context: the I/O context
2099 * Close an FTP I/O channel
2104 xmlIOFTPClose (void * context
) {
2105 return ( xmlNanoFTPClose(context
) );
2107 #endif /* LIBXML_FTP_ENABLED */
2111 * xmlRegisterInputCallbacks:
2112 * @matchFunc: the xmlInputMatchCallback
2113 * @openFunc: the xmlInputOpenCallback
2114 * @readFunc: the xmlInputReadCallback
2115 * @closeFunc: the xmlInputCloseCallback
2117 * Register a new set of I/O callback for handling parser input.
2119 * Returns the registered handler number or -1 in case of error
2122 xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc
,
2123 xmlInputOpenCallback openFunc
, xmlInputReadCallback readFunc
,
2124 xmlInputCloseCallback closeFunc
) {
2125 if (xmlInputCallbackNr
>= MAX_INPUT_CALLBACK
) {
2128 xmlInputCallbackTable
[xmlInputCallbackNr
].matchcallback
= matchFunc
;
2129 xmlInputCallbackTable
[xmlInputCallbackNr
].opencallback
= openFunc
;
2130 xmlInputCallbackTable
[xmlInputCallbackNr
].readcallback
= readFunc
;
2131 xmlInputCallbackTable
[xmlInputCallbackNr
].closecallback
= closeFunc
;
2132 xmlInputCallbackInitialized
= 1;
2133 return(xmlInputCallbackNr
++);
2136 #ifdef LIBXML_OUTPUT_ENABLED
2138 * xmlRegisterOutputCallbacks:
2139 * @matchFunc: the xmlOutputMatchCallback
2140 * @openFunc: the xmlOutputOpenCallback
2141 * @writeFunc: the xmlOutputWriteCallback
2142 * @closeFunc: the xmlOutputCloseCallback
2144 * Register a new set of I/O callback for handling output.
2146 * Returns the registered handler number or -1 in case of error
2149 xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc
,
2150 xmlOutputOpenCallback openFunc
, xmlOutputWriteCallback writeFunc
,
2151 xmlOutputCloseCallback closeFunc
) {
2152 if (xmlOutputCallbackNr
>= MAX_OUTPUT_CALLBACK
) {
2155 xmlOutputCallbackTable
[xmlOutputCallbackNr
].matchcallback
= matchFunc
;
2156 xmlOutputCallbackTable
[xmlOutputCallbackNr
].opencallback
= openFunc
;
2157 xmlOutputCallbackTable
[xmlOutputCallbackNr
].writecallback
= writeFunc
;
2158 xmlOutputCallbackTable
[xmlOutputCallbackNr
].closecallback
= closeFunc
;
2159 xmlOutputCallbackInitialized
= 1;
2160 return(xmlOutputCallbackNr
++);
2162 #endif /* LIBXML_OUTPUT_ENABLED */
2165 * xmlRegisterDefaultInputCallbacks:
2167 * Registers the default compiled-in I/O handlers.
2170 xmlRegisterDefaultInputCallbacks(void) {
2171 if (xmlInputCallbackInitialized
)
2174 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
2175 xmlInitPlatformSpecificIo();
2178 xmlRegisterInputCallbacks(xmlFileMatch
, xmlFileOpen
,
2179 xmlFileRead
, xmlFileClose
);
2181 xmlRegisterInputCallbacks(xmlGzfileMatch
, xmlGzfileOpen
,
2182 xmlGzfileRead
, xmlGzfileClose
);
2183 #endif /* HAVE_ZLIB_H */
2185 #ifdef LIBXML_HTTP_ENABLED
2186 xmlRegisterInputCallbacks(xmlIOHTTPMatch
, xmlIOHTTPOpen
,
2187 xmlIOHTTPRead
, xmlIOHTTPClose
);
2188 #endif /* LIBXML_HTTP_ENABLED */
2190 #ifdef LIBXML_FTP_ENABLED
2191 xmlRegisterInputCallbacks(xmlIOFTPMatch
, xmlIOFTPOpen
,
2192 xmlIOFTPRead
, xmlIOFTPClose
);
2193 #endif /* LIBXML_FTP_ENABLED */
2194 xmlInputCallbackInitialized
= 1;
2197 #ifdef LIBXML_OUTPUT_ENABLED
2199 * xmlRegisterDefaultOutputCallbacks:
2201 * Registers the default compiled-in I/O handlers.
2204 xmlRegisterDefaultOutputCallbacks (void) {
2205 if (xmlOutputCallbackInitialized
)
2208 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
2209 xmlInitPlatformSpecificIo();
2212 xmlRegisterOutputCallbacks(xmlFileMatch
, xmlFileOpenW
,
2213 xmlFileWrite
, xmlFileClose
);
2215 #ifdef LIBXML_HTTP_ENABLED
2216 xmlRegisterOutputCallbacks(xmlIOHTTPMatch
, xmlIOHTTPDfltOpenW
,
2217 xmlIOHTTPWrite
, xmlIOHTTPClosePut
);
2220 /*********************************
2221 No way a-priori to distinguish between gzipped files from
2222 uncompressed ones except opening if existing then closing
2223 and saving with same compression ratio ... a pain.
2226 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
2227 xmlGzfileWrite, xmlGzfileClose);
2231 #ifdef LIBXML_FTP_ENABLED
2232 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
2233 xmlIOFTPWrite, xmlIOFTPClose);
2235 **********************************/
2236 xmlOutputCallbackInitialized
= 1;
2239 #ifdef LIBXML_HTTP_ENABLED
2241 * xmlRegisterHTTPPostCallbacks:
2243 * By default, libxml submits HTTP output requests using the "PUT" method.
2244 * Calling this method changes the HTTP output method to use the "POST"
2249 xmlRegisterHTTPPostCallbacks( void ) {
2251 /* Register defaults if not done previously */
2253 if ( xmlOutputCallbackInitialized
== 0 )
2254 xmlRegisterDefaultOutputCallbacks( );
2256 xmlRegisterOutputCallbacks(xmlIOHTTPMatch
, xmlIOHTTPDfltOpenW
,
2257 xmlIOHTTPWrite
, xmlIOHTTPClosePost
);
2261 #endif /* LIBXML_OUTPUT_ENABLED */
2264 * xmlAllocParserInputBuffer:
2265 * @enc: the charset encoding if known
2267 * Create a buffered parser input for progressive parsing
2269 * Returns the new parser input or NULL
2271 xmlParserInputBufferPtr
2272 xmlAllocParserInputBuffer(xmlCharEncoding enc
) {
2273 xmlParserInputBufferPtr ret
;
2275 ret
= (xmlParserInputBufferPtr
) xmlMalloc(sizeof(xmlParserInputBuffer
));
2277 xmlIOErrMemory("creating input buffer");
2280 memset(ret
, 0, (size_t) sizeof(xmlParserInputBuffer
));
2281 ret
->buffer
= xmlBufferCreateSize(2 * xmlDefaultBufferSize
);
2282 if (ret
->buffer
== NULL
) {
2286 ret
->buffer
->alloc
= XML_BUFFER_ALLOC_DOUBLEIT
;
2287 ret
->encoder
= xmlGetCharEncodingHandler(enc
);
2288 if (ret
->encoder
!= NULL
)
2289 ret
->raw
= xmlBufferCreateSize(2 * xmlDefaultBufferSize
);
2292 ret
->readcallback
= NULL
;
2293 ret
->closecallback
= NULL
;
2294 ret
->context
= NULL
;
2295 ret
->compressed
= -1;
2296 ret
->rawconsumed
= 0;
2301 #ifdef LIBXML_OUTPUT_ENABLED
2303 * xmlAllocOutputBuffer:
2304 * @encoder: the encoding converter or NULL
2306 * Create a buffered parser output
2308 * Returns the new parser output or NULL
2311 xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder
) {
2312 xmlOutputBufferPtr ret
;
2314 ret
= (xmlOutputBufferPtr
) xmlMalloc(sizeof(xmlOutputBuffer
));
2316 xmlIOErrMemory("creating output buffer");
2319 memset(ret
, 0, (size_t) sizeof(xmlOutputBuffer
));
2320 ret
->buffer
= xmlBufferCreate();
2321 if (ret
->buffer
== NULL
) {
2326 /* try to avoid a performance problem with Windows realloc() */
2327 if (ret
->buffer
->alloc
== XML_BUFFER_ALLOC_EXACT
)
2328 ret
->buffer
->alloc
= XML_BUFFER_ALLOC_DOUBLEIT
;
2330 ret
->encoder
= encoder
;
2331 if (encoder
!= NULL
) {
2332 ret
->conv
= xmlBufferCreateSize(4000);
2333 if (ret
->conv
== NULL
) {
2339 * This call is designed to initiate the encoder state
2341 xmlCharEncOutFunc(encoder
, ret
->conv
, NULL
);
2344 ret
->writecallback
= NULL
;
2345 ret
->closecallback
= NULL
;
2346 ret
->context
= NULL
;
2353 * xmlAllocOutputBufferInternal:
2354 * @encoder: the encoding converter or NULL
2356 * Create a buffered parser output
2358 * Returns the new parser output or NULL
2361 xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder
) {
2362 xmlOutputBufferPtr ret
;
2364 ret
= (xmlOutputBufferPtr
) xmlMalloc(sizeof(xmlOutputBuffer
));
2366 xmlIOErrMemory("creating output buffer");
2369 memset(ret
, 0, (size_t) sizeof(xmlOutputBuffer
));
2370 ret
->buffer
= xmlBufferCreate();
2371 if (ret
->buffer
== NULL
) {
2378 * For conversion buffers we use the special IO handling
2379 * We don't do that from the exported API to avoid confusing
2382 ret
->buffer
->alloc
= XML_BUFFER_ALLOC_IO
;
2383 ret
->buffer
->contentIO
= ret
->buffer
->content
;
2385 ret
->encoder
= encoder
;
2386 if (encoder
!= NULL
) {
2387 ret
->conv
= xmlBufferCreateSize(4000);
2388 if (ret
->conv
== NULL
) {
2394 * This call is designed to initiate the encoder state
2396 xmlCharEncOutFunc(encoder
, ret
->conv
, NULL
);
2399 ret
->writecallback
= NULL
;
2400 ret
->closecallback
= NULL
;
2401 ret
->context
= NULL
;
2407 #endif /* LIBXML_OUTPUT_ENABLED */
2410 * xmlFreeParserInputBuffer:
2411 * @in: a buffered parser input
2413 * Free up the memory used by a buffered parser input
2416 xmlFreeParserInputBuffer(xmlParserInputBufferPtr in
) {
2417 if (in
== NULL
) return;
2420 xmlBufferFree(in
->raw
);
2423 if (in
->encoder
!= NULL
) {
2424 xmlCharEncCloseFunc(in
->encoder
);
2426 if (in
->closecallback
!= NULL
) {
2427 in
->closecallback(in
->context
);
2429 if (in
->buffer
!= NULL
) {
2430 xmlBufferFree(in
->buffer
);
2437 #ifdef LIBXML_OUTPUT_ENABLED
2439 * xmlOutputBufferClose:
2440 * @out: a buffered output
2442 * flushes and close the output I/O channel
2443 * and free up all the associated resources
2445 * Returns the number of byte written or -1 in case of error.
2448 xmlOutputBufferClose(xmlOutputBufferPtr out
)
2455 if (out
->writecallback
!= NULL
)
2456 xmlOutputBufferFlush(out
);
2457 if (out
->closecallback
!= NULL
) {
2458 err_rc
= out
->closecallback(out
->context
);
2460 written
= out
->written
;
2462 xmlBufferFree(out
->conv
);
2465 if (out
->encoder
!= NULL
) {
2466 xmlCharEncCloseFunc(out
->encoder
);
2468 if (out
->buffer
!= NULL
) {
2469 xmlBufferFree(out
->buffer
);
2476 return ((err_rc
== 0) ? written
: err_rc
);
2478 #endif /* LIBXML_OUTPUT_ENABLED */
2480 xmlParserInputBufferPtr
2481 __xmlParserInputBufferCreateFilename(const char *URI
, xmlCharEncoding enc
) {
2482 xmlParserInputBufferPtr ret
;
2484 void *context
= NULL
;
2486 if (xmlInputCallbackInitialized
== 0)
2487 xmlRegisterDefaultInputCallbacks();
2489 if (URI
== NULL
) return(NULL
);
2492 * Try to find one of the input accept method accepting that scheme
2493 * Go in reverse to give precedence to user defined handlers.
2495 if (context
== NULL
) {
2496 for (i
= xmlInputCallbackNr
- 1;i
>= 0;i
--) {
2497 if ((xmlInputCallbackTable
[i
].matchcallback
!= NULL
) &&
2498 (xmlInputCallbackTable
[i
].matchcallback(URI
) != 0)) {
2499 context
= xmlInputCallbackTable
[i
].opencallback(URI
);
2500 if (context
!= NULL
) {
2506 if (context
== NULL
) {
2511 * Allocate the Input buffer front-end.
2513 ret
= xmlAllocParserInputBuffer(enc
);
2515 ret
->context
= context
;
2516 ret
->readcallback
= xmlInputCallbackTable
[i
].readcallback
;
2517 ret
->closecallback
= xmlInputCallbackTable
[i
].closecallback
;
2519 if ((xmlInputCallbackTable
[i
].opencallback
== xmlGzfileOpen
) &&
2520 (strcmp(URI
, "-") != 0)) {
2521 #if defined(ZLIB_VERNUM) && ZLIB_VERNUM >= 0x1230
2522 ret
->compressed
= !gzdirect(context
);
2524 if (((z_stream
*)context
)->avail_in
> 4) {
2525 char *cptr
, buff4
[4];
2526 cptr
= (char *) ((z_stream
*)context
)->next_in
;
2527 if (gzread(context
, buff4
, 4) == 4) {
2528 if (strncmp(buff4
, cptr
, 4) == 0)
2529 ret
->compressed
= 0;
2531 ret
->compressed
= 1;
2540 xmlInputCallbackTable
[i
].closecallback (context
);
2546 * xmlParserInputBufferCreateFilename:
2547 * @URI: a C string containing the URI or filename
2548 * @enc: the charset encoding if known
2550 * Create a buffered parser input for the progressive parsing of a file
2551 * If filename is "-' then we use stdin as the input.
2552 * Automatic support for ZLIB/Compress compressed document is provided
2553 * by default if found at compile-time.
2554 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
2556 * Returns the new parser input or NULL
2558 xmlParserInputBufferPtr
2559 xmlParserInputBufferCreateFilename(const char *URI
, xmlCharEncoding enc
) {
2560 if ((xmlParserInputBufferCreateFilenameValue
)) {
2561 return xmlParserInputBufferCreateFilenameValue(URI
, enc
);
2563 return __xmlParserInputBufferCreateFilename(URI
, enc
);
2566 #ifdef LIBXML_OUTPUT_ENABLED
2568 __xmlOutputBufferCreateFilename(const char *URI
,
2569 xmlCharEncodingHandlerPtr encoder
,
2570 int compression ATTRIBUTE_UNUSED
) {
2571 xmlOutputBufferPtr ret
;
2574 void *context
= NULL
;
2575 char *unescaped
= NULL
;
2577 int is_file_uri
= 1;
2580 if (xmlOutputCallbackInitialized
== 0)
2581 xmlRegisterDefaultOutputCallbacks();
2583 if (URI
== NULL
) return(NULL
);
2585 puri
= xmlParseURI(URI
);
2588 if ((puri
->scheme
!= NULL
) &&
2589 (!xmlStrEqual(BAD_CAST puri
->scheme
, BAD_CAST
"file")))
2593 * try to limit the damages of the URI unescaping code.
2595 if ((puri
->scheme
== NULL
) ||
2596 (xmlStrEqual(BAD_CAST puri
->scheme
, BAD_CAST
"file")))
2597 unescaped
= xmlURIUnescapeString(URI
, 0, NULL
);
2602 * Try to find one of the output accept method accepting that scheme
2603 * Go in reverse to give precedence to user defined handlers.
2604 * try with an unescaped version of the URI
2606 if (unescaped
!= NULL
) {
2608 if ((compression
> 0) && (compression
<= 9) && (is_file_uri
== 1)) {
2609 context
= xmlGzfileOpenW(unescaped
, compression
);
2610 if (context
!= NULL
) {
2611 ret
= xmlAllocOutputBufferInternal(encoder
);
2613 ret
->context
= context
;
2614 ret
->writecallback
= xmlGzfileWrite
;
2615 ret
->closecallback
= xmlGzfileClose
;
2622 for (i
= xmlOutputCallbackNr
- 1;i
>= 0;i
--) {
2623 if ((xmlOutputCallbackTable
[i
].matchcallback
!= NULL
) &&
2624 (xmlOutputCallbackTable
[i
].matchcallback(unescaped
) != 0)) {
2625 #if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2626 /* Need to pass compression parameter into HTTP open calls */
2627 if (xmlOutputCallbackTable
[i
].matchcallback
== xmlIOHTTPMatch
)
2628 context
= xmlIOHTTPOpenW(unescaped
, compression
);
2631 context
= xmlOutputCallbackTable
[i
].opencallback(unescaped
);
2632 if (context
!= NULL
)
2640 * If this failed try with a non-escaped URI this may be a strange
2643 if (context
== NULL
) {
2645 if ((compression
> 0) && (compression
<= 9) && (is_file_uri
== 1)) {
2646 context
= xmlGzfileOpenW(URI
, compression
);
2647 if (context
!= NULL
) {
2648 ret
= xmlAllocOutputBufferInternal(encoder
);
2650 ret
->context
= context
;
2651 ret
->writecallback
= xmlGzfileWrite
;
2652 ret
->closecallback
= xmlGzfileClose
;
2658 for (i
= xmlOutputCallbackNr
- 1;i
>= 0;i
--) {
2659 if ((xmlOutputCallbackTable
[i
].matchcallback
!= NULL
) &&
2660 (xmlOutputCallbackTable
[i
].matchcallback(URI
) != 0)) {
2661 #if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2662 /* Need to pass compression parameter into HTTP open calls */
2663 if (xmlOutputCallbackTable
[i
].matchcallback
== xmlIOHTTPMatch
)
2664 context
= xmlIOHTTPOpenW(URI
, compression
);
2667 context
= xmlOutputCallbackTable
[i
].opencallback(URI
);
2668 if (context
!= NULL
)
2674 if (context
== NULL
) {
2679 * Allocate the Output buffer front-end.
2681 ret
= xmlAllocOutputBufferInternal(encoder
);
2683 ret
->context
= context
;
2684 ret
->writecallback
= xmlOutputCallbackTable
[i
].writecallback
;
2685 ret
->closecallback
= xmlOutputCallbackTable
[i
].closecallback
;
2691 * xmlOutputBufferCreateFilename:
2692 * @URI: a C string containing the URI or filename
2693 * @encoder: the encoding converter or NULL
2694 * @compression: the compression ration (0 none, 9 max).
2696 * Create a buffered output for the progressive saving of a file
2697 * If filename is "-' then we use stdout as the output.
2698 * Automatic support for ZLIB/Compress compressed document is provided
2699 * by default if found at compile-time.
2700 * TODO: currently if compression is set, the library only support
2701 * writing to a local file.
2703 * Returns the new output or NULL
2706 xmlOutputBufferCreateFilename(const char *URI
,
2707 xmlCharEncodingHandlerPtr encoder
,
2708 int compression ATTRIBUTE_UNUSED
) {
2709 if ((xmlOutputBufferCreateFilenameValue
)) {
2710 return xmlOutputBufferCreateFilenameValue(URI
, encoder
, compression
);
2712 return __xmlOutputBufferCreateFilename(URI
, encoder
, compression
);
2714 #endif /* LIBXML_OUTPUT_ENABLED */
2717 * xmlParserInputBufferCreateFile:
2719 * @enc: the charset encoding if known
2721 * Create a buffered parser input for the progressive parsing of a FILE *
2724 * Returns the new parser input or NULL
2726 xmlParserInputBufferPtr
2727 xmlParserInputBufferCreateFile(FILE *file
, xmlCharEncoding enc
) {
2728 xmlParserInputBufferPtr ret
;
2730 if (xmlInputCallbackInitialized
== 0)
2731 xmlRegisterDefaultInputCallbacks();
2733 if (file
== NULL
) return(NULL
);
2735 ret
= xmlAllocParserInputBuffer(enc
);
2737 ret
->context
= file
;
2738 ret
->readcallback
= xmlFileRead
;
2739 ret
->closecallback
= xmlFileFlush
;
2745 #ifdef LIBXML_OUTPUT_ENABLED
2747 * xmlOutputBufferCreateFile:
2749 * @encoder: the encoding converter or NULL
2751 * Create a buffered output for the progressive saving to a FILE *
2754 * Returns the new parser output or NULL
2757 xmlOutputBufferCreateFile(FILE *file
, xmlCharEncodingHandlerPtr encoder
) {
2758 xmlOutputBufferPtr ret
;
2760 if (xmlOutputCallbackInitialized
== 0)
2761 xmlRegisterDefaultOutputCallbacks();
2763 if (file
== NULL
) return(NULL
);
2765 ret
= xmlAllocOutputBufferInternal(encoder
);
2767 ret
->context
= file
;
2768 ret
->writecallback
= xmlFileWrite
;
2769 ret
->closecallback
= xmlFileFlush
;
2776 * xmlOutputBufferCreateBuffer:
2777 * @buffer: a xmlBufferPtr
2778 * @encoder: the encoding converter or NULL
2780 * Create a buffered output for the progressive saving to a xmlBuffer
2782 * Returns the new parser output or NULL
2785 xmlOutputBufferCreateBuffer(xmlBufferPtr buffer
,
2786 xmlCharEncodingHandlerPtr encoder
) {
2787 xmlOutputBufferPtr ret
;
2789 if (buffer
== NULL
) return(NULL
);
2791 ret
= xmlOutputBufferCreateIO((xmlOutputWriteCallback
)
2793 (xmlOutputCloseCallback
)
2794 NULL
, (void *) buffer
, encoder
);
2799 #endif /* LIBXML_OUTPUT_ENABLED */
2802 * xmlParserInputBufferCreateFd:
2803 * @fd: a file descriptor number
2804 * @enc: the charset encoding if known
2806 * Create a buffered parser input for the progressive parsing for the input
2807 * from a file descriptor
2809 * Returns the new parser input or NULL
2811 xmlParserInputBufferPtr
2812 xmlParserInputBufferCreateFd(int fd
, xmlCharEncoding enc
) {
2813 xmlParserInputBufferPtr ret
;
2815 if (fd
< 0) return(NULL
);
2817 ret
= xmlAllocParserInputBuffer(enc
);
2819 ret
->context
= (void *) (long) fd
;
2820 ret
->readcallback
= xmlFdRead
;
2821 ret
->closecallback
= xmlFdClose
;
2828 * xmlParserInputBufferCreateMem:
2829 * @mem: the memory input
2830 * @size: the length of the memory block
2831 * @enc: the charset encoding if known
2833 * Create a buffered parser input for the progressive parsing for the input
2834 * from a memory area.
2836 * Returns the new parser input or NULL
2838 xmlParserInputBufferPtr
2839 xmlParserInputBufferCreateMem(const char *mem
, int size
, xmlCharEncoding enc
) {
2840 xmlParserInputBufferPtr ret
;
2843 if (size
<= 0) return(NULL
);
2844 if (mem
== NULL
) return(NULL
);
2846 ret
= xmlAllocParserInputBuffer(enc
);
2848 ret
->context
= (void *) mem
;
2849 ret
->readcallback
= (xmlInputReadCallback
) xmlNop
;
2850 ret
->closecallback
= NULL
;
2851 errcode
= xmlBufferAdd(ret
->buffer
, (const xmlChar
*) mem
, size
);
2862 * xmlParserInputBufferCreateStatic:
2863 * @mem: the memory input
2864 * @size: the length of the memory block
2865 * @enc: the charset encoding if known
2867 * Create a buffered parser input for the progressive parsing for the input
2868 * from an immutable memory area. This will not copy the memory area to
2869 * the buffer, but the memory is expected to be available until the end of
2870 * the parsing, this is useful for example when using mmap'ed file.
2872 * Returns the new parser input or NULL
2874 xmlParserInputBufferPtr
2875 xmlParserInputBufferCreateStatic(const char *mem
, int size
,
2876 xmlCharEncoding enc
) {
2877 xmlParserInputBufferPtr ret
;
2879 if (size
<= 0) return(NULL
);
2880 if (mem
== NULL
) return(NULL
);
2882 ret
= (xmlParserInputBufferPtr
) xmlMalloc(sizeof(xmlParserInputBuffer
));
2884 xmlIOErrMemory("creating input buffer");
2887 memset(ret
, 0, (size_t) sizeof(xmlParserInputBuffer
));
2888 ret
->buffer
= xmlBufferCreateStatic((void *)mem
, (size_t) size
);
2889 if (ret
->buffer
== NULL
) {
2893 ret
->encoder
= xmlGetCharEncodingHandler(enc
);
2894 if (ret
->encoder
!= NULL
)
2895 ret
->raw
= xmlBufferCreateSize(2 * xmlDefaultBufferSize
);
2898 ret
->compressed
= -1;
2899 ret
->context
= (void *) mem
;
2900 ret
->readcallback
= NULL
;
2901 ret
->closecallback
= NULL
;
2906 #ifdef LIBXML_OUTPUT_ENABLED
2908 * xmlOutputBufferCreateFd:
2909 * @fd: a file descriptor number
2910 * @encoder: the encoding converter or NULL
2912 * Create a buffered output for the progressive saving
2913 * to a file descriptor
2915 * Returns the new parser output or NULL
2918 xmlOutputBufferCreateFd(int fd
, xmlCharEncodingHandlerPtr encoder
) {
2919 xmlOutputBufferPtr ret
;
2921 if (fd
< 0) return(NULL
);
2923 ret
= xmlAllocOutputBufferInternal(encoder
);
2925 ret
->context
= (void *) (long) fd
;
2926 ret
->writecallback
= xmlFdWrite
;
2927 ret
->closecallback
= NULL
;
2932 #endif /* LIBXML_OUTPUT_ENABLED */
2935 * xmlParserInputBufferCreateIO:
2936 * @ioread: an I/O read function
2937 * @ioclose: an I/O close function
2938 * @ioctx: an I/O handler
2939 * @enc: the charset encoding if known
2941 * Create a buffered parser input for the progressive parsing for the input
2942 * from an I/O handler
2944 * Returns the new parser input or NULL
2946 xmlParserInputBufferPtr
2947 xmlParserInputBufferCreateIO(xmlInputReadCallback ioread
,
2948 xmlInputCloseCallback ioclose
, void *ioctx
, xmlCharEncoding enc
) {
2949 xmlParserInputBufferPtr ret
;
2951 if (ioread
== NULL
) return(NULL
);
2953 ret
= xmlAllocParserInputBuffer(enc
);
2955 ret
->context
= (void *) ioctx
;
2956 ret
->readcallback
= ioread
;
2957 ret
->closecallback
= ioclose
;
2963 #ifdef LIBXML_OUTPUT_ENABLED
2965 * xmlOutputBufferCreateIO:
2966 * @iowrite: an I/O write function
2967 * @ioclose: an I/O close function
2968 * @ioctx: an I/O handler
2969 * @encoder: the charset encoding if known
2971 * Create a buffered output for the progressive saving
2974 * Returns the new parser output or NULL
2977 xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite
,
2978 xmlOutputCloseCallback ioclose
, void *ioctx
,
2979 xmlCharEncodingHandlerPtr encoder
) {
2980 xmlOutputBufferPtr ret
;
2982 if (iowrite
== NULL
) return(NULL
);
2984 ret
= xmlAllocOutputBufferInternal(encoder
);
2986 ret
->context
= (void *) ioctx
;
2987 ret
->writecallback
= iowrite
;
2988 ret
->closecallback
= ioclose
;
2993 #endif /* LIBXML_OUTPUT_ENABLED */
2996 * xmlParserInputBufferCreateFilenameDefault:
2997 * @func: function pointer to the new ParserInputBufferCreateFilenameFunc
2999 * Registers a callback for URI input file handling
3001 * Returns the old value of the registration function
3003 xmlParserInputBufferCreateFilenameFunc
3004 xmlParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func
)
3006 xmlParserInputBufferCreateFilenameFunc old
= xmlParserInputBufferCreateFilenameValue
;
3008 old
= __xmlParserInputBufferCreateFilename
;
3011 xmlParserInputBufferCreateFilenameValue
= func
;
3016 * xmlOutputBufferCreateFilenameDefault:
3017 * @func: function pointer to the new OutputBufferCreateFilenameFunc
3019 * Registers a callback for URI output file handling
3021 * Returns the old value of the registration function
3023 xmlOutputBufferCreateFilenameFunc
3024 xmlOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func
)
3026 xmlOutputBufferCreateFilenameFunc old
= xmlOutputBufferCreateFilenameValue
;
3027 #ifdef LIBXML_OUTPUT_ENABLED
3029 old
= __xmlOutputBufferCreateFilename
;
3032 xmlOutputBufferCreateFilenameValue
= func
;
3037 * xmlParserInputBufferPush:
3038 * @in: a buffered parser input
3039 * @len: the size in bytes of the array.
3040 * @buf: an char array
3042 * Push the content of the arry in the input buffer
3043 * This routine handle the I18N transcoding to internal UTF-8
3044 * This is used when operating the parser in progressive (push) mode.
3046 * Returns the number of chars read and stored in the buffer, or -1
3050 xmlParserInputBufferPush(xmlParserInputBufferPtr in
,
3051 int len
, const char *buf
) {
3055 if (len
< 0) return(0);
3056 if ((in
== NULL
) || (in
->error
)) return(-1);
3057 if (in
->encoder
!= NULL
) {
3061 * Store the data in the incoming raw buffer
3063 if (in
->raw
== NULL
) {
3064 in
->raw
= xmlBufferCreate();
3066 ret
= xmlBufferAdd(in
->raw
, (const xmlChar
*) buf
, len
);
3071 * convert as much as possible to the parser reading buffer.
3074 nbchars
= xmlCharEncInFunc(in
->encoder
, in
->buffer
, in
->raw
);
3076 xmlIOErr(XML_IO_ENCODER
, NULL
);
3077 in
->error
= XML_IO_ENCODER
;
3080 in
->rawconsumed
+= (use
- in
->raw
->use
);
3083 ret
= xmlBufferAdd(in
->buffer
, (xmlChar
*) buf
, nbchars
);
3088 xmlGenericError(xmlGenericErrorContext
,
3089 "I/O: pushed %d chars, buffer %d/%d\n",
3090 nbchars
, in
->buffer
->use
, in
->buffer
->size
);
3098 * When reading from an Input channel indicated end of file or error
3099 * don't reread from it again.
3102 endOfInput (void * context ATTRIBUTE_UNUSED
,
3103 char * buffer ATTRIBUTE_UNUSED
,
3104 int len ATTRIBUTE_UNUSED
) {
3109 * xmlParserInputBufferGrow:
3110 * @in: a buffered parser input
3111 * @len: indicative value of the amount of chars to read
3113 * Grow up the content of the input buffer, the old data are preserved
3114 * This routine handle the I18N transcoding to internal UTF-8
3115 * This routine is used when operating the parser in normal (pull) mode
3117 * TODO: one should be able to remove one extra copy by copying directly
3118 * onto in->buffer or in->raw
3120 * Returns the number of chars read and stored in the buffer, or -1
3124 xmlParserInputBufferGrow(xmlParserInputBufferPtr in
, int len
) {
3125 char *buffer
= NULL
;
3129 unsigned int needSize
;
3131 if ((in
== NULL
) || (in
->error
)) return(-1);
3132 if ((len
<= MINLEN
) && (len
!= 4))
3135 buffree
= in
->buffer
->size
- in
->buffer
->use
;
3137 xmlIOErr(XML_IO_BUFFER_FULL
, NULL
);
3138 in
->error
= XML_IO_BUFFER_FULL
;
3142 needSize
= in
->buffer
->use
+ len
+ 1;
3143 if (needSize
> in
->buffer
->size
){
3144 if (!xmlBufferResize(in
->buffer
, needSize
)){
3145 xmlIOErrMemory("growing input buffer");
3146 in
->error
= XML_ERR_NO_MEMORY
;
3150 buffer
= (char *)&in
->buffer
->content
[in
->buffer
->use
];
3153 * Call the read method for this I/O type.
3155 if (in
->readcallback
!= NULL
) {
3156 res
= in
->readcallback(in
->context
, &buffer
[0], len
);
3158 in
->readcallback
= endOfInput
;
3160 xmlIOErr(XML_IO_NO_INPUT
, NULL
);
3161 in
->error
= XML_IO_NO_INPUT
;
3168 if (in
->encoder
!= NULL
) {
3172 * Store the data in the incoming raw buffer
3174 if (in
->raw
== NULL
) {
3175 in
->raw
= xmlBufferCreate();
3177 res
= xmlBufferAdd(in
->raw
, (const xmlChar
*) buffer
, len
);
3182 * convert as much as possible to the parser reading buffer.
3185 nbchars
= xmlCharEncInFunc(in
->encoder
, in
->buffer
, in
->raw
);
3187 xmlIOErr(XML_IO_ENCODER
, NULL
);
3188 in
->error
= XML_IO_ENCODER
;
3191 in
->rawconsumed
+= (use
- in
->raw
->use
);
3194 in
->buffer
->use
+= nbchars
;
3195 buffer
[nbchars
] = 0;
3198 xmlGenericError(xmlGenericErrorContext
,
3199 "I/O: read %d chars, buffer %d/%d\n",
3200 nbchars
, in
->buffer
->use
, in
->buffer
->size
);
3206 * xmlParserInputBufferRead:
3207 * @in: a buffered parser input
3208 * @len: indicative value of the amount of chars to read
3210 * Refresh the content of the input buffer, the old data are considered
3212 * This routine handle the I18N transcoding to internal UTF-8
3214 * Returns the number of chars read and stored in the buffer, or -1
3218 xmlParserInputBufferRead(xmlParserInputBufferPtr in
, int len
) {
3219 if ((in
== NULL
) || (in
->error
)) return(-1);
3220 if (in
->readcallback
!= NULL
)
3221 return(xmlParserInputBufferGrow(in
, len
));
3222 else if ((in
->buffer
!= NULL
) &&
3223 (in
->buffer
->alloc
== XML_BUFFER_ALLOC_IMMUTABLE
))
3229 #ifdef LIBXML_OUTPUT_ENABLED
3231 * xmlOutputBufferWrite:
3232 * @out: a buffered parser output
3233 * @len: the size in bytes of the array.
3234 * @buf: an char array
3236 * Write the content of the array in the output I/O buffer
3237 * This routine handle the I18N transcoding from internal UTF-8
3238 * The buffer is lossless, i.e. will store in case of partial
3239 * or delayed writes.
3241 * Returns the number of chars immediately written, or -1
3245 xmlOutputBufferWrite(xmlOutputBufferPtr out
, int len
, const char *buf
) {
3246 int nbchars
= 0; /* number of chars to output to I/O */
3247 int ret
; /* return from function call */
3248 int written
= 0; /* number of char written to I/O so far */
3249 int chunk
; /* number of byte curreent processed from buf */
3251 if ((out
== NULL
) || (out
->error
)) return(-1);
3252 if (len
< 0) return(0);
3253 if (out
->error
) return(-1);
3257 if (chunk
> 4 * MINLEN
)
3261 * first handle encoding stuff.
3263 if (out
->encoder
!= NULL
) {
3265 * Store the data in the incoming raw buffer
3267 if (out
->conv
== NULL
) {
3268 out
->conv
= xmlBufferCreate();
3270 ret
= xmlBufferAdd(out
->buffer
, (const xmlChar
*) buf
, chunk
);
3274 if ((out
->buffer
->use
< MINLEN
) && (chunk
== len
))
3278 * convert as much as possible to the parser reading buffer.
3280 ret
= xmlCharEncOutFunc(out
->encoder
, out
->conv
, out
->buffer
);
3281 if ((ret
< 0) && (ret
!= -3)) {
3282 xmlIOErr(XML_IO_ENCODER
, NULL
);
3283 out
->error
= XML_IO_ENCODER
;
3286 nbchars
= out
->conv
->use
;
3288 ret
= xmlBufferAdd(out
->buffer
, (const xmlChar
*) buf
, chunk
);
3291 nbchars
= out
->buffer
->use
;
3296 if ((nbchars
< MINLEN
) && (len
<= 0))
3299 if (out
->writecallback
) {
3301 * second write the stuff to the I/O channel
3303 if (out
->encoder
!= NULL
) {
3304 ret
= out
->writecallback(out
->context
,
3305 (const char *)out
->conv
->content
, nbchars
);
3307 xmlBufferShrink(out
->conv
, ret
);
3309 ret
= out
->writecallback(out
->context
,
3310 (const char *)out
->buffer
->content
, nbchars
);
3312 xmlBufferShrink(out
->buffer
, ret
);
3315 xmlIOErr(XML_IO_WRITE
, NULL
);
3316 out
->error
= XML_IO_WRITE
;
3319 out
->written
+= ret
;
3326 xmlGenericError(xmlGenericErrorContext
,
3327 "I/O: wrote %d chars\n", written
);
3334 * @out: a pointer to an array of bytes to store the result
3335 * @outlen: the length of @out
3336 * @in: a pointer to an array of unescaped UTF-8 bytes
3337 * @inlen: the length of @in
3339 * Take a block of UTF-8 chars in and escape them.
3340 * Returns 0 if success, or -1 otherwise
3341 * The value of @inlen after return is the number of octets consumed
3342 * if the return value is positive, else unpredictable.
3343 * The value of @outlen after return is the number of octets consumed.
3346 xmlEscapeContent(unsigned char* out
, int *outlen
,
3347 const xmlChar
* in
, int *inlen
) {
3348 unsigned char* outstart
= out
;
3349 const unsigned char* base
= in
;
3350 unsigned char* outend
= out
+ *outlen
;
3351 const unsigned char* inend
;
3353 inend
= in
+ (*inlen
);
3355 while ((in
< inend
) && (out
< outend
)) {
3357 if (outend
- out
< 4) break;
3362 } else if (*in
== '>') {
3363 if (outend
- out
< 4) break;
3368 } else if (*in
== '&') {
3369 if (outend
- out
< 5) break;
3375 } else if (*in
== '\r') {
3376 if (outend
- out
< 5) break;
3383 *out
++ = (unsigned char) *in
;
3387 *outlen
= out
- outstart
;
3393 * xmlOutputBufferWriteEscape:
3394 * @out: a buffered parser output
3395 * @str: a zero terminated UTF-8 string
3396 * @escaping: an optional escaping function (or NULL)
3398 * Write the content of the string in the output I/O buffer
3399 * This routine escapes the caracters and then handle the I18N
3400 * transcoding from internal UTF-8
3401 * The buffer is lossless, i.e. will store in case of partial
3402 * or delayed writes.
3404 * Returns the number of chars immediately written, or -1
3408 xmlOutputBufferWriteEscape(xmlOutputBufferPtr out
, const xmlChar
*str
,
3409 xmlCharEncodingOutputFunc escaping
) {
3410 int nbchars
= 0; /* number of chars to output to I/O */
3411 int ret
; /* return from function call */
3412 int written
= 0; /* number of char written to I/O so far */
3413 int oldwritten
=0;/* loop guard */
3414 int chunk
; /* number of byte currently processed from str */
3415 int len
; /* number of bytes in str */
3416 int cons
; /* byte from str consumed */
3418 if ((out
== NULL
) || (out
->error
) || (str
== NULL
) ||
3419 (out
->buffer
== NULL
) ||
3420 (out
->buffer
->alloc
== XML_BUFFER_ALLOC_IMMUTABLE
)) return(-1);
3421 len
= strlen((const char *)str
);
3422 if (len
< 0) return(0);
3423 if (out
->error
) return(-1);
3424 if (escaping
== NULL
) escaping
= xmlEscapeContent
;
3427 oldwritten
= written
;
3430 * how many bytes to consume and how many bytes to store.
3433 chunk
= (out
->buffer
->size
- out
->buffer
->use
) - 1;
3436 * make sure we have enough room to save first, if this is
3437 * not the case force a flush, but make sure we stay in the loop
3440 if (xmlBufferGrow(out
->buffer
, out
->buffer
->size
+ 100) < 0)
3447 * first handle encoding stuff.
3449 if (out
->encoder
!= NULL
) {
3451 * Store the data in the incoming raw buffer
3453 if (out
->conv
== NULL
) {
3454 out
->conv
= xmlBufferCreate();
3456 ret
= escaping(out
->buffer
->content
+ out
->buffer
->use
,
3457 &chunk
, str
, &cons
);
3458 if ((ret
< 0) || (chunk
== 0)) /* chunk==0 => nothing done */
3460 out
->buffer
->use
+= chunk
;
3461 out
->buffer
->content
[out
->buffer
->use
] = 0;
3463 if ((out
->buffer
->use
< MINLEN
) && (cons
== len
))
3467 * convert as much as possible to the output buffer.
3469 ret
= xmlCharEncOutFunc(out
->encoder
, out
->conv
, out
->buffer
);
3470 if ((ret
< 0) && (ret
!= -3)) {
3471 xmlIOErr(XML_IO_ENCODER
, NULL
);
3472 out
->error
= XML_IO_ENCODER
;
3475 nbchars
= out
->conv
->use
;
3477 ret
= escaping(out
->buffer
->content
+ out
->buffer
->use
,
3478 &chunk
, str
, &cons
);
3479 if ((ret
< 0) || (chunk
== 0)) /* chunk==0 => nothing done */
3481 out
->buffer
->use
+= chunk
;
3482 out
->buffer
->content
[out
->buffer
->use
] = 0;
3483 nbchars
= out
->buffer
->use
;
3488 if ((nbchars
< MINLEN
) && (len
<= 0))
3491 if (out
->writecallback
) {
3493 * second write the stuff to the I/O channel
3495 if (out
->encoder
!= NULL
) {
3496 ret
= out
->writecallback(out
->context
,
3497 (const char *)out
->conv
->content
, nbchars
);
3499 xmlBufferShrink(out
->conv
, ret
);
3501 ret
= out
->writecallback(out
->context
,
3502 (const char *)out
->buffer
->content
, nbchars
);
3504 xmlBufferShrink(out
->buffer
, ret
);
3507 xmlIOErr(XML_IO_WRITE
, NULL
);
3508 out
->error
= XML_IO_WRITE
;
3511 out
->written
+= ret
;
3512 } else if (out
->buffer
->size
- out
->buffer
->use
< MINLEN
) {
3513 xmlBufferResize(out
->buffer
, out
->buffer
->size
+ MINLEN
);
3516 } while ((len
> 0) && (oldwritten
!= written
));
3520 xmlGenericError(xmlGenericErrorContext
,
3521 "I/O: wrote %d chars\n", written
);
3527 * xmlOutputBufferWriteString:
3528 * @out: a buffered parser output
3529 * @str: a zero terminated C string
3531 * Write the content of the string in the output I/O buffer
3532 * This routine handle the I18N transcoding from internal UTF-8
3533 * The buffer is lossless, i.e. will store in case of partial
3534 * or delayed writes.
3536 * Returns the number of chars immediately written, or -1
3540 xmlOutputBufferWriteString(xmlOutputBufferPtr out
, const char *str
) {
3543 if ((out
== NULL
) || (out
->error
)) return(-1);
3549 return(xmlOutputBufferWrite(out
, len
, str
));
3554 * xmlOutputBufferFlush:
3555 * @out: a buffered output
3557 * flushes the output I/O channel
3559 * Returns the number of byte written or -1 in case of error.
3562 xmlOutputBufferFlush(xmlOutputBufferPtr out
) {
3563 int nbchars
= 0, ret
= 0;
3565 if ((out
== NULL
) || (out
->error
)) return(-1);
3567 * first handle encoding stuff.
3569 if ((out
->conv
!= NULL
) && (out
->encoder
!= NULL
)) {
3571 * convert as much as possible to the parser reading buffer.
3573 nbchars
= xmlCharEncOutFunc(out
->encoder
, out
->conv
, out
->buffer
);
3575 xmlIOErr(XML_IO_ENCODER
, NULL
);
3576 out
->error
= XML_IO_ENCODER
;
3582 * second flush the stuff to the I/O channel
3584 if ((out
->conv
!= NULL
) && (out
->encoder
!= NULL
) &&
3585 (out
->writecallback
!= NULL
)) {
3586 ret
= out
->writecallback(out
->context
,
3587 (const char *)out
->conv
->content
, out
->conv
->use
);
3589 xmlBufferShrink(out
->conv
, ret
);
3590 } else if (out
->writecallback
!= NULL
) {
3591 ret
= out
->writecallback(out
->context
,
3592 (const char *)out
->buffer
->content
, out
->buffer
->use
);
3594 xmlBufferShrink(out
->buffer
, ret
);
3597 xmlIOErr(XML_IO_FLUSH
, NULL
);
3598 out
->error
= XML_IO_FLUSH
;
3601 out
->written
+= ret
;
3604 xmlGenericError(xmlGenericErrorContext
,
3605 "I/O: flushed %d chars\n", ret
);
3609 #endif /* LIBXML_OUTPUT_ENABLED */
3612 * xmlParserGetDirectory:
3613 * @filename: the path to a file
3615 * lookup the directory for that file
3617 * Returns a new allocated string containing the directory, or NULL.
3620 xmlParserGetDirectory(const char *filename
) {
3625 #ifdef _WIN32_WCE /* easy way by now ... wince does not have dirs! */
3629 if (xmlInputCallbackInitialized
== 0)
3630 xmlRegisterDefaultInputCallbacks();
3632 if (filename
== NULL
) return(NULL
);
3634 #if defined(WIN32) && !defined(__CYGWIN__)
3635 # define IS_XMLPGD_SEP(ch) ((ch=='/')||(ch=='\\'))
3637 # define IS_XMLPGD_SEP(ch) (ch=='/')
3640 strncpy(dir
, filename
, 1023);
3642 cur
= &dir
[strlen(dir
)];
3644 if (IS_XMLPGD_SEP(*cur
)) break;
3647 if (IS_XMLPGD_SEP(*cur
)) {
3648 if (cur
== dir
) dir
[1] = 0;
3650 ret
= xmlMemStrdup(dir
);
3652 if (getcwd(dir
, 1024) != NULL
) {
3654 ret
= xmlMemStrdup(dir
);
3658 #undef IS_XMLPGD_SEP
3661 /****************************************************************
3663 * External entities loading *
3665 ****************************************************************/
3668 * xmlCheckHTTPInput:
3669 * @ctxt: an XML parser context
3670 * @ret: an XML parser input
3672 * Check an input in case it was created from an HTTP stream, in that
3673 * case it will handle encoding and update of the base URL in case of
3674 * redirection. It also checks for HTTP errors in which case the input
3675 * is cleanly freed up and an appropriate error is raised in context
3677 * Returns the input or NULL in case of HTTP error.
3680 xmlCheckHTTPInput(xmlParserCtxtPtr ctxt
, xmlParserInputPtr ret
) {
3681 #ifdef LIBXML_HTTP_ENABLED
3682 if ((ret
!= NULL
) && (ret
->buf
!= NULL
) &&
3683 (ret
->buf
->readcallback
== xmlIOHTTPRead
) &&
3684 (ret
->buf
->context
!= NULL
)) {
3685 const char *encoding
;
3690 code
= xmlNanoHTTPReturnCode(ret
->buf
->context
);
3693 if (ret
->filename
!= NULL
)
3694 __xmlLoaderErr(ctxt
, "failed to load HTTP resource \"%s\"\n",
3695 (const char *) ret
->filename
);
3697 __xmlLoaderErr(ctxt
, "failed to load HTTP resource\n", NULL
);
3698 xmlFreeInputStream(ret
);
3702 mime
= xmlNanoHTTPMimeType(ret
->buf
->context
);
3703 if ((xmlStrstr(BAD_CAST mime
, BAD_CAST
"/xml")) ||
3704 (xmlStrstr(BAD_CAST mime
, BAD_CAST
"+xml"))) {
3705 encoding
= xmlNanoHTTPEncoding(ret
->buf
->context
);
3706 if (encoding
!= NULL
) {
3707 xmlCharEncodingHandlerPtr handler
;
3709 handler
= xmlFindCharEncodingHandler(encoding
);
3710 if (handler
!= NULL
) {
3711 xmlSwitchInputEncoding(ctxt
, ret
, handler
);
3713 __xmlErrEncoding(ctxt
, XML_ERR_UNKNOWN_ENCODING
,
3714 "Unknown encoding %s",
3715 BAD_CAST encoding
, NULL
);
3717 if (ret
->encoding
== NULL
)
3718 ret
->encoding
= xmlStrdup(BAD_CAST encoding
);
3721 } else if (xmlStrstr(BAD_CAST mime
, BAD_CAST
"html")) {
3724 redir
= xmlNanoHTTPRedir(ret
->buf
->context
);
3725 if (redir
!= NULL
) {
3726 if (ret
->filename
!= NULL
)
3727 xmlFree((xmlChar
*) ret
->filename
);
3728 if (ret
->directory
!= NULL
) {
3729 xmlFree((xmlChar
*) ret
->directory
);
3730 ret
->directory
= NULL
;
3733 (char *) xmlStrdup((const xmlChar
*) redir
);
3741 static int xmlNoNetExists(const char *URL
) {
3747 if (!xmlStrncasecmp(BAD_CAST URL
, BAD_CAST
"file://localhost/", 17))
3748 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
3753 else if (!xmlStrncasecmp(BAD_CAST URL
, BAD_CAST
"file:///", 8)) {
3754 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
3762 return xmlCheckFilename(path
);
3765 #ifdef LIBXML_CATALOG_ENABLED
3768 * xmlResolveResourceFromCatalog:
3769 * @URL: the URL for the entity to load
3770 * @ID: the System ID for the entity to load
3771 * @ctxt: the context in which the entity is called or NULL
3773 * Resolves the URL and ID against the appropriate catalog.
3774 * This function is used by xmlDefaultExternalEntityLoader and
3775 * xmlNoNetExternalEntityLoader.
3777 * Returns a new allocated URL, or NULL.
3780 xmlResolveResourceFromCatalog(const char *URL
, const char *ID
,
3781 xmlParserCtxtPtr ctxt
) {
3782 xmlChar
*resource
= NULL
;
3783 xmlCatalogAllow pref
;
3786 * If the resource doesn't exists as a file,
3787 * try to load it from the resource pointed in the catalogs
3789 pref
= xmlCatalogGetDefaults();
3791 if ((pref
!= XML_CATA_ALLOW_NONE
) && (!xmlNoNetExists(URL
))) {
3795 if ((ctxt
!= NULL
) && (ctxt
->catalogs
!= NULL
) &&
3796 ((pref
== XML_CATA_ALLOW_ALL
) ||
3797 (pref
== XML_CATA_ALLOW_DOCUMENT
))) {
3798 resource
= xmlCatalogLocalResolve(ctxt
->catalogs
,
3799 (const xmlChar
*)ID
,
3800 (const xmlChar
*)URL
);
3803 * Try a global lookup
3805 if ((resource
== NULL
) &&
3806 ((pref
== XML_CATA_ALLOW_ALL
) ||
3807 (pref
== XML_CATA_ALLOW_GLOBAL
))) {
3808 resource
= xmlCatalogResolve((const xmlChar
*)ID
,
3809 (const xmlChar
*)URL
);
3811 if ((resource
== NULL
) && (URL
!= NULL
))
3812 resource
= xmlStrdup((const xmlChar
*) URL
);
3815 * TODO: do an URI lookup on the reference
3817 if ((resource
!= NULL
) && (!xmlNoNetExists((const char *)resource
))) {
3818 xmlChar
*tmp
= NULL
;
3820 if ((ctxt
!= NULL
) && (ctxt
->catalogs
!= NULL
) &&
3821 ((pref
== XML_CATA_ALLOW_ALL
) ||
3822 (pref
== XML_CATA_ALLOW_DOCUMENT
))) {
3823 tmp
= xmlCatalogLocalResolveURI(ctxt
->catalogs
, resource
);
3825 if ((tmp
== NULL
) &&
3826 ((pref
== XML_CATA_ALLOW_ALL
) ||
3827 (pref
== XML_CATA_ALLOW_GLOBAL
))) {
3828 tmp
= xmlCatalogResolveURI(resource
);
3844 * xmlDefaultExternalEntityLoader:
3845 * @URL: the URL for the entity to load
3846 * @ID: the System ID for the entity to load
3847 * @ctxt: the context in which the entity is called or NULL
3849 * By default we don't load external entitites, yet.
3851 * Returns a new allocated xmlParserInputPtr, or NULL.
3853 static xmlParserInputPtr
3854 xmlDefaultExternalEntityLoader(const char *URL
, const char *ID
,
3855 xmlParserCtxtPtr ctxt
)
3857 xmlParserInputPtr ret
= NULL
;
3858 xmlChar
*resource
= NULL
;
3860 #ifdef DEBUG_EXTERNAL_ENTITIES
3861 xmlGenericError(xmlGenericErrorContext
,
3862 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL
);
3864 if ((ctxt
!= NULL
) && (ctxt
->options
& XML_PARSE_NONET
)) {
3865 int options
= ctxt
->options
;
3867 ctxt
->options
-= XML_PARSE_NONET
;
3868 ret
= xmlNoNetExternalEntityLoader(URL
, ID
, ctxt
);
3869 ctxt
->options
= options
;
3872 #ifdef LIBXML_CATALOG_ENABLED
3873 resource
= xmlResolveResourceFromCatalog(URL
, ID
, ctxt
);
3876 if (resource
== NULL
)
3877 resource
= (xmlChar
*) URL
;
3879 if (resource
== NULL
) {
3882 __xmlLoaderErr(ctxt
, "failed to load external entity \"%s\"\n", ID
);
3885 ret
= xmlNewInputFromFile(ctxt
, (const char *) resource
);
3886 if ((resource
!= NULL
) && (resource
!= (xmlChar
*) URL
))
3891 static xmlExternalEntityLoader xmlCurrentExternalEntityLoader
=
3892 xmlDefaultExternalEntityLoader
;
3895 * xmlSetExternalEntityLoader:
3896 * @f: the new entity resolver function
3898 * Changes the defaultexternal entity resolver function for the application
3901 xmlSetExternalEntityLoader(xmlExternalEntityLoader f
) {
3902 xmlCurrentExternalEntityLoader
= f
;
3906 * xmlGetExternalEntityLoader:
3908 * Get the default external entity resolver function for the application
3910 * Returns the xmlExternalEntityLoader function pointer
3912 xmlExternalEntityLoader
3913 xmlGetExternalEntityLoader(void) {
3914 return(xmlCurrentExternalEntityLoader
);
3918 * xmlLoadExternalEntity:
3919 * @URL: the URL for the entity to load
3920 * @ID: the Public ID for the entity to load
3921 * @ctxt: the context in which the entity is called or NULL
3923 * Load an external entity, note that the use of this function for
3924 * unparsed entities may generate problems
3926 * Returns the xmlParserInputPtr or NULL
3929 xmlLoadExternalEntity(const char *URL
, const char *ID
,
3930 xmlParserCtxtPtr ctxt
) {
3931 if ((URL
!= NULL
) && (xmlNoNetExists(URL
) == 0)) {
3932 char *canonicFilename
;
3933 xmlParserInputPtr ret
;
3935 canonicFilename
= (char *) xmlCanonicPath((const xmlChar
*) URL
);
3936 if (canonicFilename
== NULL
) {
3937 xmlIOErrMemory("building canonical path\n");
3941 ret
= xmlCurrentExternalEntityLoader(canonicFilename
, ID
, ctxt
);
3942 xmlFree(canonicFilename
);
3945 return(xmlCurrentExternalEntityLoader(URL
, ID
, ctxt
));
3948 /************************************************************************
3950 * Disabling Network access *
3952 ************************************************************************/
3955 * xmlNoNetExternalEntityLoader:
3956 * @URL: the URL for the entity to load
3957 * @ID: the System ID for the entity to load
3958 * @ctxt: the context in which the entity is called or NULL
3960 * A specific entity loader disabling network accesses, though still
3961 * allowing local catalog accesses for resolution.
3963 * Returns a new allocated xmlParserInputPtr, or NULL.
3966 xmlNoNetExternalEntityLoader(const char *URL
, const char *ID
,
3967 xmlParserCtxtPtr ctxt
) {
3968 xmlParserInputPtr input
= NULL
;
3969 xmlChar
*resource
= NULL
;
3971 #ifdef LIBXML_CATALOG_ENABLED
3972 resource
= xmlResolveResourceFromCatalog(URL
, ID
, ctxt
);
3975 if (resource
== NULL
)
3976 resource
= (xmlChar
*) URL
;
3978 if (resource
!= NULL
) {
3979 if ((!xmlStrncasecmp(BAD_CAST resource
, BAD_CAST
"ftp://", 6)) ||
3980 (!xmlStrncasecmp(BAD_CAST resource
, BAD_CAST
"http://", 7))) {
3981 xmlIOErr(XML_IO_NETWORK_ATTEMPT
, (const char *) resource
);
3982 if (resource
!= (xmlChar
*) URL
)
3987 input
= xmlDefaultExternalEntityLoader((const char *) resource
, ID
, ctxt
);
3988 if (resource
!= (xmlChar
*) URL
)
3993 #define bottom_xmlIO
3994 #include "elfgcchack.h"