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 /* Figure a portable way to know if a file is a directory. */
42 /* MS C library seems to define stat and _stat. The definition
43 is identical. Still, mapping them to each other causes a warning. */
45 # define stat(x,y) _stat(x,y)
53 # define S_ISDIR(x) _S_ISDIR(x)
58 # define S_IFMT _S_IFMT
62 # define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
69 #include <libxml/xmlmemory.h>
70 #include <libxml/parser.h>
71 #include <libxml/parserInternals.h>
72 #include <libxml/xmlIO.h>
73 #include <libxml/uri.h>
74 #include <libxml/nanohttp.h>
75 #include <libxml/nanoftp.h>
76 #include <libxml/xmlerror.h>
77 #ifdef LIBXML_CATALOG_ENABLED
78 #include <libxml/catalog.h>
80 #include <libxml/globals.h>
82 /* #define VERBOSE_FAILURE */
83 /* #define DEBUG_EXTERNAL_ENTITIES */
84 /* #define DEBUG_INPUT */
93 * Input I/O callback sets
95 typedef struct _xmlInputCallback {
96 xmlInputMatchCallback matchcallback;
97 xmlInputOpenCallback opencallback;
98 xmlInputReadCallback readcallback;
99 xmlInputCloseCallback closecallback;
102 #define MAX_INPUT_CALLBACK 15
104 static xmlInputCallback xmlInputCallbackTable[MAX_INPUT_CALLBACK];
105 static int xmlInputCallbackNr = 0;
106 static int xmlInputCallbackInitialized = 0;
109 * Output I/O callback sets
111 typedef struct _xmlOutputCallback {
112 xmlOutputMatchCallback matchcallback;
113 xmlOutputOpenCallback opencallback;
114 xmlOutputWriteCallback writecallback;
115 xmlOutputCloseCallback closecallback;
118 #define MAX_OUTPUT_CALLBACK 15
120 static xmlOutputCallback xmlOutputCallbackTable[MAX_OUTPUT_CALLBACK];
121 static int xmlOutputCallbackNr = 0;
122 static int xmlOutputCallbackInitialized = 0;
126 * xmlNormalizeWindowsPath:
127 * @path: the input file path
129 * This function is obsolete. Please see xmlURIFromPath in uri.c for
132 * Returns a canonicalized version of the path
135 xmlNormalizeWindowsPath(const xmlChar *path)
137 return xmlCanonicPath(path);
141 * xmlCleanupInputCallbacks:
143 * clears the entire input callback table. this includes the
147 xmlCleanupInputCallbacks(void)
151 if (!xmlInputCallbackInitialized)
154 for (i = xmlInputCallbackNr - 1; i >= 0; i--) {
155 xmlInputCallbackTable[i].matchcallback = NULL;
156 xmlInputCallbackTable[i].opencallback = NULL;
157 xmlInputCallbackTable[i].readcallback = NULL;
158 xmlInputCallbackTable[i].closecallback = NULL;
160 xmlInputCallbackInitialized = 0;
162 xmlInputCallbackNr = 0;
163 xmlInputCallbackInitialized = 0;
167 * xmlCleanupOutputCallbacks:
169 * clears the entire output callback table. this includes the
170 * compiled-in I/O callbacks.
173 xmlCleanupOutputCallbacks(void)
177 if (!xmlOutputCallbackInitialized)
180 for (i = xmlOutputCallbackNr - 1; i >= 0; i--) {
181 xmlOutputCallbackTable[i].matchcallback = NULL;
182 xmlOutputCallbackTable[i].opencallback = NULL;
183 xmlOutputCallbackTable[i].writecallback = NULL;
184 xmlOutputCallbackTable[i].closecallback = NULL;
186 xmlOutputCallbackInitialized = 0;
188 xmlOutputCallbackNr = 0;
189 xmlOutputCallbackInitialized = 0;
192 /************************************************************************
194 * Standard I/O for file accesses *
196 ************************************************************************/
200 * @path: the path to check
202 * function checks to see if @path is a valid source
203 * (file, socket...) for XML.
205 * if stat is not available on the target machine,
206 * returns 1. if stat fails, returns 0 (if calling
207 * stat on the filename fails, it can't be right).
208 * if stat succeeds and the file is a directory,
209 * returns 2. otherwise returns 1.
213 xmlCheckFilename (const char *path)
216 struct stat stat_buffer;
218 if (stat(path, &stat_buffer) == -1)
222 if (S_ISDIR(stat_buffer.st_mode)) {
237 * @context: the I/O context
238 * @buffer: where to drop data
239 * @len: number of bytes to read
241 * Read @len bytes to @buffer from the I/O channel.
243 * Returns the number of bytes written
246 xmlFdRead (void * context, char * buffer, int len) {
247 return(read((int) (long) context, &buffer[0], len));
252 * @context: the I/O context
253 * @buffer: where to get data
254 * @len: number of bytes to write
256 * Write @len bytes from @buffer to the I/O channel.
258 * Returns the number of bytes written
261 xmlFdWrite (void * context, const char * buffer, int len) {
262 return(write((int) (long) context, &buffer[0], len));
267 * @context: the I/O context
269 * Close an I/O channel
271 * Returns 0 in case of success and error code otherwise
274 xmlFdClose (void * context) {
275 return ( close((int) (long) context) );
280 * @filename: the URI for matching
284 * Returns 1 if matches, 0 otherwise
287 xmlFileMatch (const char *filename ATTRIBUTE_UNUSED) {
293 * @filename: the URI for matching
295 * input from FILE *, supports compressed input
296 * if @filename is " " then the standard input is used
298 * Returns an I/O context or NULL in case of error
301 xmlFileOpen_real (const char *filename) {
302 const char *path = NULL;
305 if (!strcmp(filename, "-")) {
310 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
311 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
312 path = &filename[17];
314 path = &filename[16];
316 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
317 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
327 if (!xmlCheckFilename(path))
330 #if defined(WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
331 fd = fopen(path, "rb");
333 fd = fopen(path, "r");
340 * @filename: the URI for matching
342 * Wrapper around xmlFileOpen_real that try it with an unescaped
343 * version of @filename, if this fails fallback to @filename
345 * Returns a handler or NULL in case or failure
348 xmlFileOpen (const char *filename) {
351 unescaped = xmlURIUnescapeString(filename, 0, NULL);
352 if (unescaped != NULL) {
353 retval = xmlFileOpen_real(unescaped);
355 retval = xmlFileOpen_real(filename);
363 * @filename: the URI for matching
365 * output to from FILE *,
366 * if @filename is "-" then the standard output is used
368 * Returns an I/O context or NULL in case of error
371 xmlFileOpenW (const char *filename) {
372 const char *path = NULL;
375 if (!strcmp(filename, "-")) {
380 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
381 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
382 path = &filename[17];
384 path = &filename[16];
386 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
387 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
398 fd = fopen(path, "wb");
404 * @context: the I/O context
405 * @buffer: where to drop data
406 * @len: number of bytes to write
408 * Read @len bytes to @buffer from the I/O channel.
410 * Returns the number of bytes written
413 xmlFileRead (void * context, char * buffer, int len) {
414 return(fread(&buffer[0], 1, len, (FILE *) context));
419 * @context: the I/O context
420 * @buffer: where to drop data
421 * @len: number of bytes to write
423 * Write @len bytes from @buffer to the I/O channel.
425 * Returns the number of bytes written
428 xmlFileWrite (void * context, const char * buffer, int len) {
431 items = fwrite(&buffer[0], len, 1, (FILE *) context);
438 * @context: the I/O context
440 * Close an I/O channel
442 * Returns 0 or -1 in case of error
445 xmlFileClose (void * context) {
448 fil = (FILE *) context;
455 return ( ( fclose((FILE *) context) == EOF ) ? -1 : 0 );
460 * @context: the I/O context
462 * Flush an I/O channel
465 xmlFileFlush (void * context) {
466 return ( ( fflush((FILE *) context) == EOF ) ? -1 : 0 );
470 /************************************************************************
472 * I/O for compressed file accesses *
474 ************************************************************************/
477 * @filename: the URI for matching
479 * input from compressed file test
481 * Returns 1 if matches, 0 otherwise
484 xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
489 * xmlGzfileOpen_real:
490 * @filename: the URI for matching
492 * input from compressed file open
493 * if @filename is " " then the standard input is used
495 * Returns an I/O context or NULL in case of error
498 xmlGzfileOpen_real (const char *filename) {
499 const char *path = NULL;
502 if (!strcmp(filename, "-")) {
503 fd = gzdopen(dup(0), "rb");
507 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
508 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
509 path = &filename[17];
511 path = &filename[16];
513 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
514 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
524 if (!xmlCheckFilename(path))
527 fd = gzopen(path, "rb");
533 * @filename: the URI for matching
535 * Wrapper around xmlGzfileOpen if the open fais, it will
536 * try to unescape @filename
539 xmlGzfileOpen (const char *filename) {
543 retval = xmlGzfileOpen_real(filename);
544 if (retval == NULL) {
545 unescaped = xmlURIUnescapeString(filename, 0, NULL);
546 if (unescaped != NULL) {
547 retval = xmlGzfileOpen_real(unescaped);
556 * @filename: the URI for matching
557 * @compression: the compression factor (0 - 9 included)
559 * input from compressed file open
560 * if @filename is " " then the standard input is used
562 * Returns an I/O context or NULL in case of error
565 xmlGzfileOpenW (const char *filename, int compression) {
566 const char *path = NULL;
570 snprintf(mode, sizeof(mode), "wb%d", compression);
571 if (!strcmp(filename, "-")) {
572 fd = gzdopen(dup(1), mode);
576 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
577 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
578 path = &filename[17];
580 path = &filename[16];
582 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
583 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
594 fd = gzopen(path, mode);
600 * @context: the I/O context
601 * @buffer: where to drop data
602 * @len: number of bytes to write
604 * Read @len bytes to @buffer from the compressed I/O channel.
606 * Returns the number of bytes written
609 xmlGzfileRead (void * context, char * buffer, int len) {
610 return(gzread((gzFile) context, &buffer[0], len));
615 * @context: the I/O context
616 * @buffer: where to drop data
617 * @len: number of bytes to write
619 * Write @len bytes from @buffer to the compressed I/O channel.
621 * Returns the number of bytes written
624 xmlGzfileWrite (void * context, const char * buffer, int len) {
625 return(gzwrite((gzFile) context, (char *) &buffer[0], len));
630 * @context: the I/O context
632 * Close a compressed I/O channel
635 xmlGzfileClose (void * context) {
636 return ( ( gzclose((gzFile) context) == Z_OK ) ? 0 : -1 );
638 #endif /* HAVE_ZLIB_H */
640 #ifdef LIBXML_HTTP_ENABLED
641 /************************************************************************
643 * I/O for HTTP file accesses *
645 ************************************************************************/
647 typedef struct xmlIOHTTPWriteCtxt_
655 } xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr;
659 #define DFLT_WBITS ( -15 )
660 #define DFLT_MEM_LVL ( 8 )
661 #define GZ_MAGIC1 ( 0x1f )
662 #define GZ_MAGIC2 ( 0x8b )
663 #define LXML_ZLIB_OS_CODE ( 0x03 )
664 #define INIT_HTTP_BUFF_SIZE ( 32768 )
665 #define DFLT_ZLIB_RATIO ( 5 )
668 ** Data structure and functions to work with sending compressed data
672 typedef struct xmlZMemBuff_
677 unsigned char * zbuff;
680 } xmlZMemBuff, *xmlZMemBuffPtr;
683 * append_reverse_ulong
684 * @buff: Compressed memory buffer
685 * @data: Unsigned long to append
687 * Append a unsigned long in reverse byte order to the end of the
691 append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) {
699 ** This is plagiarized from putLong in gzio.c (zlib source) where
700 ** the number "4" is hardcoded. If zlib is ever patched to
701 ** support 64 bit file sizes, this code would need to be patched
705 for ( idx = 0; idx < 4; idx++ ) {
706 *buff->zctrl.next_out = ( data & 0xff );
708 buff->zctrl.next_out++;
717 * @buff: The memory buffer context to clear
719 * Release all the resources associated with the compressed memory buffer.
722 xmlFreeZMemBuff( xmlZMemBuffPtr buff ) {
731 xmlFree( buff->zbuff );
733 z_err = deflateEnd( &buff->zctrl );
735 xmlGenericError( xmlGenericErrorContext,
736 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
739 deflateEnd( &buff->zctrl );
748 *@compression: Compression value to use
750 * Create a memory buffer to hold the compressed XML document. The
751 * compressed document in memory will end up being identical to what
752 * would be created if gzopen/gzwrite/gzclose were being used to
753 * write the document to disk. The code for the header/trailer data to
754 * the compression is plagiarized from the zlib source files.
757 xmlCreateZMemBuff( int compression ) {
761 xmlZMemBuffPtr buff = NULL;
763 if ( ( compression < 1 ) || ( compression > 9 ) )
766 /* Create the control and data areas */
768 buff = xmlMalloc( sizeof( xmlZMemBuff ) );
769 if ( buff == NULL ) {
770 xmlGenericError( xmlGenericErrorContext,
771 "xmlCreateZMemBuff: %s\n",
772 "Failure allocating buffer context." );
776 (void)memset( buff, 0, sizeof( xmlZMemBuff ) );
777 buff->size = INIT_HTTP_BUFF_SIZE;
778 buff->zbuff = xmlMalloc( buff->size );
779 if ( buff->zbuff == NULL ) {
780 xmlFreeZMemBuff( buff );
781 xmlGenericError( xmlGenericErrorContext,
782 "xmlCreateZMemBuff: %s\n",
783 "Failure allocating data buffer." );
787 z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
788 DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
789 if ( z_err != Z_OK ) {
790 xmlFreeZMemBuff( buff );
792 xmlGenericError( xmlGenericErrorContext,
793 "xmlCreateZMemBuff: %s %d\n",
794 "Error initializing compression context. ZLIB error:",
799 /* Set the header data. The CRC will be needed for the trailer */
800 buff->crc = crc32( 0L, Z_NULL, 0 );
801 hdr_lgth = snprintf( (char *)buff->zbuff, buff->size,
802 "%c%c%c%c%c%c%c%c%c%c",
803 GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED,
804 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE );
805 buff->zctrl.next_out = buff->zbuff + hdr_lgth;
806 buff->zctrl.avail_out = buff->size - hdr_lgth;
813 * @buff: Buffer used to compress and consolidate data.
814 * @ext_amt: Number of bytes to extend the buffer.
816 * Extend the internal buffer used to store the compressed data by the
819 * Returns 0 on success or -1 on failure to extend the buffer. On failure
820 * the original buffer still exists at the original size.
823 xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) {
829 unsigned char * tmp_ptr = NULL;
834 else if ( ext_amt == 0 )
837 cur_used = buff->zctrl.next_out - buff->zbuff;
838 new_size = buff->size + ext_amt;
841 if ( cur_used > new_size )
842 xmlGenericError( xmlGenericErrorContext,
843 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
844 "Buffer overwrite detected during compressed memory",
845 "buffer extension. Overflowed by",
846 (cur_used - new_size ) );
849 tmp_ptr = xmlRealloc( buff->zbuff, new_size );
850 if ( tmp_ptr != NULL ) {
852 buff->size = new_size;
853 buff->zbuff = tmp_ptr;
854 buff->zctrl.next_out = tmp_ptr + cur_used;
855 buff->zctrl.avail_out = new_size - cur_used;
858 xmlGenericError( xmlGenericErrorContext,
859 "xmlZMemBuffExtend: %s %lu bytes.\n",
860 "Allocation failure extending output buffer to",
869 * @buff: Buffer used to compress and consolidate data
870 * @src: Uncompressed source content to append to buffer
871 * @len: Length of source data to append to buffer
873 * Compress and append data to the internal buffer. The data buffer
874 * will be expanded if needed to store the additional data.
876 * Returns the number of bytes appended to the buffer or -1 on error.
879 xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) {
884 if ( ( buff == NULL ) || ( src == NULL ) )
887 buff->zctrl.avail_in = len;
888 buff->zctrl.next_in = (unsigned char *)src;
889 while ( buff->zctrl.avail_in > 0 ) {
891 ** Extend the buffer prior to deflate call if a reasonable amount
892 ** of output buffer space is not available.
894 min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO;
895 if ( buff->zctrl.avail_out <= min_accept ) {
896 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
900 z_err = deflate( &buff->zctrl, Z_NO_FLUSH );
901 if ( z_err != Z_OK ) {
902 xmlGenericError( xmlGenericErrorContext,
903 "xmlZMemBuffAppend: %s %d %s - %d",
904 "Compression error while appending",
905 len, "bytes to buffer. ZLIB error", z_err );
910 buff->crc = crc32( buff->crc, (unsigned char *)src, len );
916 * xmlZMemBuffGetContent
917 * @buff: Compressed memory content buffer
918 * @data_ref: Pointer reference to point to compressed content
920 * Flushes the compression buffers, appends gzip file trailers and
921 * returns the compressed content and length of the compressed data.
922 * NOTE: The gzip trailer code here is plagiarized from zlib source.
924 * Returns the length of the compressed data or -1 on error.
927 xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) {
932 if ( ( buff == NULL ) || ( data_ref == NULL ) )
935 /* Need to loop until compression output buffers are flushed */
939 z_err = deflate( &buff->zctrl, Z_FINISH );
940 if ( z_err == Z_OK ) {
941 /* In this case Z_OK means more buffer space needed */
943 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
947 while ( z_err == Z_OK );
949 /* If the compression state is not Z_STREAM_END, some error occurred */
951 if ( z_err == Z_STREAM_END ) {
953 /* Need to append the gzip data trailer */
955 if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) {
956 if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 )
961 ** For whatever reason, the CRC and length data are pushed out
962 ** in reverse byte order. So a memcpy can't be used here.
965 append_reverse_ulong( buff, buff->crc );
966 append_reverse_ulong( buff, buff->zctrl.total_in );
968 zlgth = buff->zctrl.next_out - buff->zbuff;
969 *data_ref = (char *)buff->zbuff;
973 xmlGenericError( xmlGenericErrorContext,
974 "xmlZMemBuffGetContent: %s - %d\n",
975 "Error flushing zlib buffers. Error code", z_err );
979 #endif /* HAVE_ZLIB_H */
982 * xmlFreeHTTPWriteCtxt
983 * @ctxt: Context to cleanup
985 * Free allocated memory and reclaim system resources.
990 xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt )
992 if ( ctxt->uri != NULL )
993 xmlFree( ctxt->uri );
995 if ( ctxt->doc_buff != NULL ) {
998 if ( ctxt->compression > 0 ) {
999 xmlFreeZMemBuff( ctxt->doc_buff );
1004 xmlOutputBufferClose( ctxt->doc_buff );
1015 * @filename: the URI for matching
1017 * check if the URI matches an HTTP one
1019 * Returns 1 if matches, 0 otherwise
1022 xmlIOHTTPMatch (const char *filename) {
1023 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "http://", 7))
1030 * @filename: the URI for matching
1032 * open an HTTP I/O channel
1034 * Returns an I/O context or NULL in case of error
1037 xmlIOHTTPOpen (const char *filename) {
1038 return(xmlNanoHTTPOpen(filename, NULL));
1043 * @post_uri: The destination URI for the document
1044 * @compression: The compression desired for the document.
1046 * Open a temporary buffer to collect the document for a subsequent HTTP POST
1047 * request. Non-static as is called from the output buffer creation routine.
1049 * Returns an I/O context or NULL in case of error.
1053 xmlIOHTTPOpenW(const char *post_uri, int compression)
1056 xmlIOHTTPWriteCtxtPtr ctxt = NULL;
1058 if (post_uri == NULL)
1061 ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt));
1063 xmlGenericError(xmlGenericErrorContext,
1064 "xmlIOHTTPOpenW: Failed to create output HTTP context.\n");
1068 (void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt));
1070 ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri);
1071 if (ctxt->uri == NULL) {
1072 xmlGenericError(xmlGenericErrorContext,
1073 "xmlIOHTTPOpenW: Failed to duplicate destination URI.\n");
1074 xmlFreeHTTPWriteCtxt(ctxt);
1079 * ** Since the document length is required for an HTTP post,
1080 * ** need to put the document into a buffer. A memory buffer
1081 * ** is being used to avoid pushing the data to disk and back.
1085 if ((compression > 0) && (compression <= 9)) {
1087 ctxt->compression = compression;
1088 ctxt->doc_buff = xmlCreateZMemBuff(compression);
1092 /* Any character conversions should have been done before this */
1094 ctxt->doc_buff = xmlAllocOutputBuffer(NULL);
1097 if (ctxt->doc_buff == NULL) {
1098 xmlFreeHTTPWriteCtxt(ctxt);
1106 * xmlIOHTTPDfltOpenW
1107 * @post_uri: The destination URI for this document.
1109 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
1110 * HTTP post command. This function should generally not be used as
1111 * the open callback is short circuited in xmlOutputBufferCreateFile.
1113 * Returns a pointer to the new IO context.
1116 xmlIOHTTPDfltOpenW( const char * post_uri ) {
1117 return ( xmlIOHTTPOpenW( post_uri, 0 ) );
1122 * @context: the I/O context
1123 * @buffer: where to drop data
1124 * @len: number of bytes to write
1126 * Read @len bytes to @buffer from the I/O channel.
1128 * Returns the number of bytes written
1131 xmlIOHTTPRead(void * context, char * buffer, int len) {
1132 return(xmlNanoHTTPRead(context, &buffer[0], len));
1137 * @context: previously opened writing context
1138 * @buffer: data to output to temporary buffer
1139 * @len: bytes to output
1141 * Collect data from memory buffer into a temporary file for later
1144 * Returns number of bytes written.
1148 xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
1150 xmlIOHTTPWriteCtxtPtr ctxt = context;
1152 if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
1157 /* Use gzwrite or fwrite as previously setup in the open call */
1160 if ( ctxt->compression > 0 )
1161 len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len );
1165 len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
1168 xmlGenericError( xmlGenericErrorContext,
1169 "xmlIOHTTPWrite: %s\n%s '%s'.\n",
1170 "Error appending to internal buffer.",
1171 "Error sending document to URI",
1182 * @context: the I/O context
1184 * Close an HTTP I/O channel
1189 xmlIOHTTPClose (void * context) {
1190 xmlNanoHTTPClose(context);
1195 * xmlIOHTTCloseWrite
1196 * @context: The I/O context
1197 * @http_mthd: The HTTP method to be used when sending the data
1199 * Close the transmit HTTP I/O channel and actually send the data.
1202 xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
1206 int content_lgth = 0;
1207 xmlIOHTTPWriteCtxtPtr ctxt = context;
1209 char * http_content = NULL;
1210 char * content_encoding = NULL;
1211 char * content_type = (char *) "text/xml";
1212 void * http_ctxt = NULL;
1214 if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
1217 /* Retrieve the content from the appropriate buffer */
1221 if ( ctxt->compression > 0 ) {
1222 content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
1223 content_encoding = (char *) "Content-Encoding: gzip";
1228 /* Pull the data out of the memory output buffer */
1230 xmlOutputBufferPtr dctxt = ctxt->doc_buff;
1231 http_content = (char *)dctxt->buffer->content;
1232 content_lgth = dctxt->buffer->use;
1235 if ( http_content == NULL ) {
1236 xmlGenericError( xmlGenericErrorContext,
1237 "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
1238 "Error retrieving content.\nUnable to",
1239 http_mthd, "data to URI", ctxt->uri );
1244 http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
1245 &content_type, content_encoding,
1248 if ( http_ctxt != NULL ) {
1250 /* If testing/debugging - dump reply with request content */
1252 FILE * tst_file = NULL;
1253 char buffer[ 4096 ];
1254 char * dump_name = NULL;
1257 xmlGenericError( xmlGenericErrorContext,
1258 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
1259 http_mthd, ctxt->uri,
1260 xmlNanoHTTPReturnCode( http_ctxt ) );
1263 ** Since either content or reply may be gzipped,
1264 ** dump them to separate files instead of the
1265 ** standard error context.
1268 dump_name = tempnam( NULL, "lxml" );
1269 if ( dump_name != NULL ) {
1270 (void)snprintf( buffer, sizeof(buffer), "%s.content", dump_name );
1272 tst_file = fopen( buffer, "wb" );
1273 if ( tst_file != NULL ) {
1274 xmlGenericError( xmlGenericErrorContext,
1275 "Transmitted content saved in file: %s\n", buffer );
1277 fwrite( http_content, sizeof( char ),
1278 content_lgth, tst_file );
1282 (void)snprintf( buffer, sizeof(buffer), "%s.reply", dump_name );
1283 tst_file = fopen( buffer, "wb" );
1284 if ( tst_file != NULL ) {
1285 xmlGenericError( xmlGenericErrorContext,
1286 "Reply content saved in file: %s\n", buffer );
1289 while ( (avail = xmlNanoHTTPRead( http_ctxt,
1290 buffer, sizeof( buffer ) )) > 0 ) {
1292 fwrite( buffer, sizeof( char ), avail, tst_file );
1300 #endif /* DEBUG_HTTP */
1302 http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
1303 if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
1306 xmlGenericError( xmlGenericErrorContext,
1307 "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
1308 http_mthd, content_lgth,
1309 "bytes to URI", ctxt->uri,
1310 "failed. HTTP return code:", http_rtn );
1312 xmlNanoHTTPClose( http_ctxt );
1313 xmlFree( content_type );
1317 /* Final cleanups */
1319 xmlFreeHTTPWriteCtxt( ctxt );
1321 return ( close_rc );
1327 * @context: The I/O context
1329 * Close the transmit HTTP I/O channel and actually send data using a PUT
1333 xmlIOHTTPClosePut( void * ctxt ) {
1334 return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
1339 * xmlIOHTTPClosePost
1341 * @context: The I/O context
1343 * Close the transmit HTTP I/O channel and actually send data using a POST
1347 xmlIOHTTPClosePost( void * ctxt ) {
1348 return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
1351 #endif /* LIBXML_HTTP_ENABLED */
1353 #ifdef LIBXML_FTP_ENABLED
1354 /************************************************************************
1356 * I/O for FTP file accesses *
1358 ************************************************************************/
1361 * @filename: the URI for matching
1363 * check if the URI matches an FTP one
1365 * Returns 1 if matches, 0 otherwise
1368 xmlIOFTPMatch (const char *filename) {
1369 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "ftp://", 6))
1376 * @filename: the URI for matching
1378 * open an FTP I/O channel
1380 * Returns an I/O context or NULL in case of error
1383 xmlIOFTPOpen (const char *filename) {
1384 return(xmlNanoFTPOpen(filename));
1389 * @context: the I/O context
1390 * @buffer: where to drop data
1391 * @len: number of bytes to write
1393 * Read @len bytes to @buffer from the I/O channel.
1395 * Returns the number of bytes written
1398 xmlIOFTPRead(void * context, char * buffer, int len) {
1399 return(xmlNanoFTPRead(context, &buffer[0], len));
1404 * @context: the I/O context
1406 * Close an FTP I/O channel
1411 xmlIOFTPClose (void * context) {
1412 return ( xmlNanoFTPClose(context) );
1414 #endif /* LIBXML_FTP_ENABLED */
1418 * xmlRegisterInputCallbacks:
1419 * @matchFunc: the xmlInputMatchCallback
1420 * @openFunc: the xmlInputOpenCallback
1421 * @readFunc: the xmlInputReadCallback
1422 * @closeFunc: the xmlInputCloseCallback
1424 * Register a new set of I/O callback for handling parser input.
1426 * Returns the registered handler number or -1 in case of error
1429 xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
1430 xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
1431 xmlInputCloseCallback closeFunc) {
1432 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
1435 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
1436 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
1437 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
1438 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
1439 return(xmlInputCallbackNr++);
1443 * xmlRegisterOutputCallbacks:
1444 * @matchFunc: the xmlOutputMatchCallback
1445 * @openFunc: the xmlOutputOpenCallback
1446 * @writeFunc: the xmlOutputWriteCallback
1447 * @closeFunc: the xmlOutputCloseCallback
1449 * Register a new set of I/O callback for handling output.
1451 * Returns the registered handler number or -1 in case of error
1454 xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
1455 xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
1456 xmlOutputCloseCallback closeFunc) {
1457 if (xmlOutputCallbackNr >= MAX_INPUT_CALLBACK) {
1460 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
1461 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
1462 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
1463 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
1464 return(xmlOutputCallbackNr++);
1468 * xmlRegisterDefaultInputCallbacks:
1470 * Registers the default compiled-in I/O handlers.
1473 xmlRegisterDefaultInputCallbacks
1475 if (xmlInputCallbackInitialized)
1478 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
1479 xmlFileRead, xmlFileClose);
1481 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1482 xmlGzfileRead, xmlGzfileClose);
1483 #endif /* HAVE_ZLIB_H */
1485 #ifdef LIBXML_HTTP_ENABLED
1486 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
1487 xmlIOHTTPRead, xmlIOHTTPClose);
1488 #endif /* LIBXML_HTTP_ENABLED */
1490 #ifdef LIBXML_FTP_ENABLED
1491 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1492 xmlIOFTPRead, xmlIOFTPClose);
1493 #endif /* LIBXML_FTP_ENABLED */
1494 xmlInputCallbackInitialized = 1;
1498 * xmlRegisterDefaultOutputCallbacks:
1500 * Registers the default compiled-in I/O handlers.
1503 xmlRegisterDefaultOutputCallbacks
1505 if (xmlOutputCallbackInitialized)
1508 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
1509 xmlFileWrite, xmlFileClose);
1511 #ifdef LIBXML_HTTP_ENABLED
1512 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
1513 xmlIOHTTPWrite, xmlIOHTTPClosePut);
1516 /*********************************
1517 No way a-priori to distinguish between gzipped files from
1518 uncompressed ones except opening if existing then closing
1519 and saving with same compression ratio ... a pain.
1522 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1523 xmlGzfileWrite, xmlGzfileClose);
1527 #ifdef LIBXML_FTP_ENABLED
1528 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1529 xmlIOFTPWrite, xmlIOFTPClose);
1531 **********************************/
1532 xmlOutputCallbackInitialized = 1;
1535 #ifdef LIBXML_HTTP_ENABLED
1537 * xmlRegisterHTTPPostCallbacks:
1539 * By default, libxml submits HTTP output requests using the "PUT" method.
1540 * Calling this method changes the HTTP output method to use the "POST"
1545 xmlRegisterHTTPPostCallbacks( void ) {
1547 /* Register defaults if not done previously */
1549 if ( xmlOutputCallbackInitialized == 0 )
1550 xmlRegisterDefaultOutputCallbacks( );
1552 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
1553 xmlIOHTTPWrite, xmlIOHTTPClosePost);
1559 * xmlAllocParserInputBuffer:
1560 * @enc: the charset encoding if known
1562 * Create a buffered parser input for progressive parsing
1564 * Returns the new parser input or NULL
1566 xmlParserInputBufferPtr
1567 xmlAllocParserInputBuffer(xmlCharEncoding enc) {
1568 xmlParserInputBufferPtr ret;
1570 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
1572 xmlGenericError(xmlGenericErrorContext,
1573 "xmlAllocParserInputBuffer : out of memory!\n");
1576 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
1577 ret->buffer = xmlBufferCreate();
1578 if (ret->buffer == NULL) {
1582 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
1583 ret->encoder = xmlGetCharEncodingHandler(enc);
1584 if (ret->encoder != NULL)
1585 ret->raw = xmlBufferCreate();
1588 ret->readcallback = NULL;
1589 ret->closecallback = NULL;
1590 ret->context = NULL;
1596 * xmlAllocOutputBuffer:
1597 * @encoder: the encoding converter or NULL
1599 * Create a buffered parser output
1601 * Returns the new parser output or NULL
1604 xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
1605 xmlOutputBufferPtr ret;
1607 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
1609 xmlGenericError(xmlGenericErrorContext,
1610 "xmlAllocOutputBuffer : out of memory!\n");
1613 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
1614 ret->buffer = xmlBufferCreate();
1615 if (ret->buffer == NULL) {
1619 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
1620 ret->encoder = encoder;
1621 if (encoder != NULL) {
1622 ret->conv = xmlBufferCreateSize(4000);
1624 * This call is designed to initiate the encoder state
1626 xmlCharEncOutFunc(encoder, ret->conv, NULL);
1629 ret->writecallback = NULL;
1630 ret->closecallback = NULL;
1631 ret->context = NULL;
1638 * xmlFreeParserInputBuffer:
1639 * @in: a buffered parser input
1641 * Free up the memory used by a buffered parser input
1644 xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
1646 xmlBufferFree(in->raw);
1649 if (in->encoder != NULL) {
1650 xmlCharEncCloseFunc(in->encoder);
1652 if (in->closecallback != NULL) {
1653 in->closecallback(in->context);
1655 if (in->buffer != NULL) {
1656 xmlBufferFree(in->buffer);
1664 * xmlOutputBufferClose:
1665 * @out: a buffered output
1667 * flushes and close the output I/O channel
1668 * and free up all the associated resources
1670 * Returns the number of byte written or -1 in case of error.
1673 xmlOutputBufferClose(xmlOutputBufferPtr out) {
1679 if (out->writecallback != NULL)
1680 xmlOutputBufferFlush(out);
1681 if (out->closecallback != NULL) {
1682 err_rc = out->closecallback(out->context);
1684 written = out->written;
1686 xmlBufferFree(out->conv);
1689 if (out->encoder != NULL) {
1690 xmlCharEncCloseFunc(out->encoder);
1692 if (out->buffer != NULL) {
1693 xmlBufferFree(out->buffer);
1698 return( ( err_rc == 0 ) ? written : err_rc );
1702 * xmlParserInputBufferCreateFname:
1703 * @URI: a C string containing the URI or filename
1704 * @enc: the charset encoding if known
1706 * Returns the new parser input or NULL
1709 * xmlParserInputBufferCreateFilename:
1710 * @URI: a C string containing the URI or filename
1711 * @enc: the charset encoding if known
1713 * Create a buffered parser input for the progressive parsing of a file
1714 * If filename is "-' then we use stdin as the input.
1715 * Automatic support for ZLIB/Compress compressed document is provided
1716 * by default if found at compile-time.
1717 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
1719 * Returns the new parser input or NULL
1721 xmlParserInputBufferPtr
1722 xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
1723 xmlParserInputBufferPtr ret;
1725 void *context = NULL;
1727 if (xmlInputCallbackInitialized == 0)
1728 xmlRegisterDefaultInputCallbacks();
1730 if (URI == NULL) return(NULL);
1732 #ifdef LIBXML_CATALOG_ENABLED
1736 * Try to find one of the input accept method accepting that scheme
1737 * Go in reverse to give precedence to user defined handlers.
1739 if (context == NULL) {
1740 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
1741 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
1742 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
1743 context = xmlInputCallbackTable[i].opencallback(URI);
1744 if (context != NULL)
1749 if (context == NULL) {
1754 * Allocate the Input buffer front-end.
1756 ret = xmlAllocParserInputBuffer(enc);
1758 ret->context = context;
1759 ret->readcallback = xmlInputCallbackTable[i].readcallback;
1760 ret->closecallback = xmlInputCallbackTable[i].closecallback;
1766 * xmlOutputBufferCreateFilename:
1767 * @URI: a C string containing the URI or filename
1768 * @encoder: the encoding converter or NULL
1769 * @compression: the compression ration (0 none, 9 max).
1771 * Create a buffered output for the progressive saving of a file
1772 * If filename is "-' then we use stdout as the output.
1773 * Automatic support for ZLIB/Compress compressed document is provided
1774 * by default if found at compile-time.
1775 * TODO: currently if compression is set, the library only support
1776 * writing to a local file.
1778 * Returns the new output or NULL
1781 xmlOutputBufferCreateFilename(const char *URI,
1782 xmlCharEncodingHandlerPtr encoder,
1784 xmlOutputBufferPtr ret;
1786 void *context = NULL;
1789 int is_http_uri = 0; /* Can't change if HTTP disabled */
1791 if (xmlOutputCallbackInitialized == 0)
1792 xmlRegisterDefaultOutputCallbacks();
1794 if (URI == NULL) return(NULL);
1796 #ifdef LIBXML_HTTP_ENABLED
1797 /* Need to prevent HTTP URI's from falling into zlib short circuit */
1799 is_http_uri = xmlIOHTTPMatch( URI );
1804 * Try to find one of the output accept method accepting that scheme
1805 * Go in reverse to give precedence to user defined handlers.
1806 * try with an unescaped version of the URI
1808 unescaped = xmlURIUnescapeString(URI, 0, NULL);
1809 if (unescaped != NULL) {
1811 if ((compression > 0) && (compression <= 9) && (is_http_uri == 0)) {
1812 context = xmlGzfileOpenW(unescaped, compression);
1813 if (context != NULL) {
1814 ret = xmlAllocOutputBuffer(encoder);
1816 ret->context = context;
1817 ret->writecallback = xmlGzfileWrite;
1818 ret->closecallback = xmlGzfileClose;
1825 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
1826 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
1827 (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
1828 #if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
1829 /* Need to pass compression parameter into HTTP open calls */
1830 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
1831 context = xmlIOHTTPOpenW(unescaped, compression);
1834 context = xmlOutputCallbackTable[i].opencallback(unescaped);
1835 if (context != NULL)
1843 * If this failed try with a non-escaped URI this may be a strange
1846 if (context == NULL) {
1848 if ((compression > 0) && (compression <= 9) && (is_http_uri == 0)) {
1849 context = xmlGzfileOpenW(URI, compression);
1850 if (context != NULL) {
1851 ret = xmlAllocOutputBuffer(encoder);
1853 ret->context = context;
1854 ret->writecallback = xmlGzfileWrite;
1855 ret->closecallback = xmlGzfileClose;
1861 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
1862 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
1863 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
1864 #if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
1865 /* Need to pass compression parameter into HTTP open calls */
1866 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
1867 context = xmlIOHTTPOpenW(URI, compression);
1870 context = xmlOutputCallbackTable[i].opencallback(URI);
1871 if (context != NULL)
1877 if (context == NULL) {
1882 * Allocate the Output buffer front-end.
1884 ret = xmlAllocOutputBuffer(encoder);
1886 ret->context = context;
1887 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
1888 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
1894 * xmlParserInputBufferCreateFile:
1896 * @enc: the charset encoding if known
1898 * Create a buffered parser input for the progressive parsing of a FILE *
1901 * Returns the new parser input or NULL
1903 xmlParserInputBufferPtr
1904 xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
1905 xmlParserInputBufferPtr ret;
1907 if (xmlInputCallbackInitialized == 0)
1908 xmlRegisterDefaultInputCallbacks();
1910 if (file == NULL) return(NULL);
1912 ret = xmlAllocParserInputBuffer(enc);
1914 ret->context = file;
1915 ret->readcallback = xmlFileRead;
1916 ret->closecallback = xmlFileFlush;
1923 * xmlOutputBufferCreateFile:
1925 * @encoder: the encoding converter or NULL
1927 * Create a buffered output for the progressive saving to a FILE *
1930 * Returns the new parser output or NULL
1933 xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
1934 xmlOutputBufferPtr ret;
1936 if (xmlOutputCallbackInitialized == 0)
1937 xmlRegisterDefaultOutputCallbacks();
1939 if (file == NULL) return(NULL);
1941 ret = xmlAllocOutputBuffer(encoder);
1943 ret->context = file;
1944 ret->writecallback = xmlFileWrite;
1945 ret->closecallback = xmlFileFlush;
1952 * xmlParserInputBufferCreateFd:
1953 * @fd: a file descriptor number
1954 * @enc: the charset encoding if known
1956 * Create a buffered parser input for the progressive parsing for the input
1957 * from a file descriptor
1959 * Returns the new parser input or NULL
1961 xmlParserInputBufferPtr
1962 xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
1963 xmlParserInputBufferPtr ret;
1965 if (fd < 0) return(NULL);
1967 ret = xmlAllocParserInputBuffer(enc);
1969 ret->context = (void *) (long) fd;
1970 ret->readcallback = xmlFdRead;
1971 ret->closecallback = xmlFdClose;
1978 * xmlParserInputBufferCreateMem:
1979 * @mem: the memory input
1980 * @size: the length of the memory block
1981 * @enc: the charset encoding if known
1983 * Create a buffered parser input for the progressive parsing for the input
1984 * from a memory area.
1986 * Returns the new parser input or NULL
1988 xmlParserInputBufferPtr
1989 xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
1990 xmlParserInputBufferPtr ret;
1992 if (size <= 0) return(NULL);
1993 if (mem == NULL) return(NULL);
1995 ret = xmlAllocParserInputBuffer(enc);
1997 ret->context = (void *) mem;
1998 ret->readcallback = (xmlInputReadCallback) xmlNop;
1999 ret->closecallback = NULL;
2000 xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size);
2007 * xmlOutputBufferCreateFd:
2008 * @fd: a file descriptor number
2009 * @encoder: the encoding converter or NULL
2011 * Create a buffered output for the progressive saving
2012 * to a file descriptor
2014 * Returns the new parser output or NULL
2017 xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
2018 xmlOutputBufferPtr ret;
2020 if (fd < 0) return(NULL);
2022 ret = xmlAllocOutputBuffer(encoder);
2024 ret->context = (void *) (long) fd;
2025 ret->writecallback = xmlFdWrite;
2026 ret->closecallback = NULL;
2033 * xmlParserInputBufferCreateIO:
2034 * @ioread: an I/O read function
2035 * @ioclose: an I/O close function
2036 * @ioctx: an I/O handler
2037 * @enc: the charset encoding if known
2039 * Create a buffered parser input for the progressive parsing for the input
2040 * from an I/O handler
2042 * Returns the new parser input or NULL
2044 xmlParserInputBufferPtr
2045 xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
2046 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
2047 xmlParserInputBufferPtr ret;
2049 if (ioread == NULL) return(NULL);
2051 ret = xmlAllocParserInputBuffer(enc);
2053 ret->context = (void *) ioctx;
2054 ret->readcallback = ioread;
2055 ret->closecallback = ioclose;
2062 * xmlOutputBufferCreateIO:
2063 * @iowrite: an I/O write function
2064 * @ioclose: an I/O close function
2065 * @ioctx: an I/O handler
2066 * @encoder: the charset encoding if known
2068 * Create a buffered output for the progressive saving
2071 * Returns the new parser output or NULL
2074 xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
2075 xmlOutputCloseCallback ioclose, void *ioctx,
2076 xmlCharEncodingHandlerPtr encoder) {
2077 xmlOutputBufferPtr ret;
2079 if (iowrite == NULL) return(NULL);
2081 ret = xmlAllocOutputBuffer(encoder);
2083 ret->context = (void *) ioctx;
2084 ret->writecallback = iowrite;
2085 ret->closecallback = ioclose;
2092 * xmlParserInputBufferPush:
2093 * @in: a buffered parser input
2094 * @len: the size in bytes of the array.
2095 * @buf: an char array
2097 * Push the content of the arry in the input buffer
2098 * This routine handle the I18N transcoding to internal UTF-8
2099 * This is used when operating the parser in progressive (push) mode.
2101 * Returns the number of chars read and stored in the buffer, or -1
2105 xmlParserInputBufferPush(xmlParserInputBufferPtr in,
2106 int len, const char *buf) {
2109 if (len < 0) return(0);
2110 if (in->encoder != NULL) {
2112 * Store the data in the incoming raw buffer
2114 if (in->raw == NULL) {
2115 in->raw = xmlBufferCreate();
2117 xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
2120 * convert as much as possible to the parser reading buffer.
2122 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2124 xmlGenericError(xmlGenericErrorContext,
2125 "xmlParserInputBufferPush: encoder error\n");
2130 xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
2133 xmlGenericError(xmlGenericErrorContext,
2134 "I/O: pushed %d chars, buffer %d/%d\n",
2135 nbchars, in->buffer->use, in->buffer->size);
2143 * When reading from an Input channel indicated end of file or error
2144 * don't reread from it again.
2147 endOfInput (void * context ATTRIBUTE_UNUSED,
2148 char * buffer ATTRIBUTE_UNUSED,
2149 int len ATTRIBUTE_UNUSED) {
2154 * xmlParserInputBufferGrow:
2155 * @in: a buffered parser input
2156 * @len: indicative value of the amount of chars to read
2158 * Grow up the content of the input buffer, the old data are preserved
2159 * This routine handle the I18N transcoding to internal UTF-8
2160 * This routine is used when operating the parser in normal (pull) mode
2162 * TODO: one should be able to remove one extra copy by copying directly
2163 * onto in->buffer or in->raw
2165 * Returns the number of chars read and stored in the buffer, or -1
2169 xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
2170 char *buffer = NULL;
2174 unsigned int needSize;
2176 if ((len <= MINLEN) && (len != 4))
2178 buffree = in->buffer->size - in->buffer->use;
2180 xmlGenericError(xmlGenericErrorContext,
2181 "xmlParserInputBufferGrow : buffer full !\n");
2187 needSize = in->buffer->use + len + 1;
2188 if (needSize > in->buffer->size){
2189 if (!xmlBufferResize(in->buffer, needSize)){
2190 xmlGenericError(xmlGenericErrorContext,
2191 "xmlParserInputBufferGrow : out of memory!\n");
2195 buffer = (char *)&in->buffer->content[in->buffer->use];
2198 * Call the read method for this I/O type.
2200 if (in->readcallback != NULL) {
2201 res = in->readcallback(in->context, &buffer[0], len);
2203 in->readcallback = endOfInput;
2205 xmlGenericError(xmlGenericErrorContext,
2206 "xmlParserInputBufferGrow : no input !\n");
2213 if (in->encoder != NULL) {
2215 * Store the data in the incoming raw buffer
2217 if (in->raw == NULL) {
2218 in->raw = xmlBufferCreate();
2220 xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
2223 * convert as much as possible to the parser reading buffer.
2225 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2227 xmlGenericError(xmlGenericErrorContext,
2228 "xmlParserInputBufferGrow: encoder error\n");
2233 in->buffer->use += nbchars;
2234 buffer[nbchars] = 0;
2237 xmlGenericError(xmlGenericErrorContext,
2238 "I/O: read %d chars, buffer %d/%d\n",
2239 nbchars, in->buffer->use, in->buffer->size);
2245 * xmlParserInputBufferRead:
2246 * @in: a buffered parser input
2247 * @len: indicative value of the amount of chars to read
2249 * Refresh the content of the input buffer, the old data are considered
2251 * This routine handle the I18N transcoding to internal UTF-8
2253 * Returns the number of chars read and stored in the buffer, or -1
2257 xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
2258 /* xmlBufferEmpty(in->buffer); */
2259 if (in->readcallback != NULL)
2260 return(xmlParserInputBufferGrow(in, len));
2266 * xmlOutputBufferWrite:
2267 * @out: a buffered parser output
2268 * @len: the size in bytes of the array.
2269 * @buf: an char array
2271 * Write the content of the array in the output I/O buffer
2272 * This routine handle the I18N transcoding from internal UTF-8
2273 * The buffer is lossless, i.e. will store in case of partial
2274 * or delayed writes.
2276 * Returns the number of chars immediately written, or -1
2280 xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
2281 int nbchars = 0; /* number of chars to output to I/O */
2282 int ret; /* return from function call */
2283 int written = 0; /* number of char written to I/O so far */
2284 int chunk; /* number of byte curreent processed from buf */
2286 if (len < 0) return(0);
2290 if (chunk > 4 * MINLEN)
2294 * first handle encoding stuff.
2296 if (out->encoder != NULL) {
2298 * Store the data in the incoming raw buffer
2300 if (out->conv == NULL) {
2301 out->conv = xmlBufferCreate();
2303 xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2305 if ((out->buffer->use < MINLEN) && (chunk == len))
2309 * convert as much as possible to the parser reading buffer.
2311 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
2312 if ((ret < 0) && (ret != -3)) {
2313 xmlGenericError(xmlGenericErrorContext,
2314 "xmlOutputBufferWrite: encoder error\n");
2317 nbchars = out->conv->use;
2319 xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2320 nbchars = out->buffer->use;
2325 if ((nbchars < MINLEN) && (len <= 0))
2328 if (out->writecallback) {
2330 * second write the stuff to the I/O channel
2332 if (out->encoder != NULL) {
2333 ret = out->writecallback(out->context,
2334 (const char *)out->conv->content, nbchars);
2336 xmlBufferShrink(out->conv, ret);
2338 ret = out->writecallback(out->context,
2339 (const char *)out->buffer->content, nbchars);
2341 xmlBufferShrink(out->buffer, ret);
2344 xmlGenericError(xmlGenericErrorContext,
2345 "I/O: error %d writing %d bytes\n", ret, nbchars);
2348 out->written += ret;
2355 xmlGenericError(xmlGenericErrorContext,
2356 "I/O: wrote %d chars\n", written);
2362 * xmlOutputBufferWriteString:
2363 * @out: a buffered parser output
2364 * @str: a zero terminated C string
2366 * Write the content of the string in the output I/O buffer
2367 * This routine handle the I18N transcoding from internal UTF-8
2368 * The buffer is lossless, i.e. will store in case of partial
2369 * or delayed writes.
2371 * Returns the number of chars immediately written, or -1
2375 xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
2383 return(xmlOutputBufferWrite(out, len, str));
2388 * xmlOutputBufferFlush:
2389 * @out: a buffered output
2391 * flushes the output I/O channel
2393 * Returns the number of byte written or -1 in case of error.
2396 xmlOutputBufferFlush(xmlOutputBufferPtr out) {
2397 int nbchars = 0, ret = 0;
2400 * first handle encoding stuff.
2402 if ((out->conv != NULL) && (out->encoder != NULL)) {
2404 * convert as much as possible to the parser reading buffer.
2406 nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
2408 xmlGenericError(xmlGenericErrorContext,
2409 "xmlOutputBufferFlush: encoder error\n");
2415 * second flush the stuff to the I/O channel
2417 if ((out->conv != NULL) && (out->encoder != NULL) &&
2418 (out->writecallback != NULL)) {
2419 ret = out->writecallback(out->context,
2420 (const char *)out->conv->content, out->conv->use);
2422 xmlBufferShrink(out->conv, ret);
2423 } else if (out->writecallback != NULL) {
2424 ret = out->writecallback(out->context,
2425 (const char *)out->buffer->content, out->buffer->use);
2427 xmlBufferShrink(out->buffer, ret);
2430 xmlGenericError(xmlGenericErrorContext,
2431 "I/O: error %d flushing %d bytes\n", ret, nbchars);
2434 out->written += ret;
2437 xmlGenericError(xmlGenericErrorContext,
2438 "I/O: flushed %d chars\n", ret);
2444 * xmlParserGetDirectory:
2445 * @filename: the path to a file
2447 * lookup the directory for that file
2449 * Returns a new allocated string containing the directory, or NULL.
2452 xmlParserGetDirectory(const char *filename) {
2458 #ifdef _WIN32_WCE /* easy way by now ... wince does not have dirs! */
2462 if (xmlInputCallbackInitialized == 0)
2463 xmlRegisterDefaultInputCallbacks();
2465 if (filename == NULL) return(NULL);
2466 #if defined(WIN32) && !defined(__CYGWIN__)
2470 strncpy(dir, filename, 1023);
2472 cur = &dir[strlen(dir)];
2474 if (*cur == sep) break;
2478 if (cur == dir) dir[1] = 0;
2480 ret = xmlMemStrdup(dir);
2482 if (getcwd(dir, 1024) != NULL) {
2484 ret = xmlMemStrdup(dir);
2490 /****************************************************************
2492 * External entities loading *
2494 ****************************************************************/
2496 static int xmlSysIDExists(const char *URL) {
2505 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
2506 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
2511 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
2512 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
2519 ret = stat(path, &info);
2527 * xmlDefaultExternalEntityLoader:
2528 * @URL: the URL for the entity to load
2529 * @ID: the System ID for the entity to load
2530 * @ctxt: the context in which the entity is called or NULL
2532 * By default we don't load external entitites, yet.
2534 * Returns a new allocated xmlParserInputPtr, or NULL.
2538 xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
2539 xmlParserCtxtPtr ctxt) {
2540 xmlParserInputPtr ret = NULL;
2541 xmlChar *resource = NULL;
2542 #ifdef LIBXML_CATALOG_ENABLED
2543 xmlCatalogAllow pref;
2546 #ifdef DEBUG_EXTERNAL_ENTITIES
2547 xmlGenericError(xmlGenericErrorContext,
2548 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
2550 #ifdef LIBXML_CATALOG_ENABLED
2552 * If the resource doesn't exists as a file,
2553 * try to load it from the resource pointed in the catalogs
2555 pref = xmlCatalogGetDefaults();
2557 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlSysIDExists(URL))) {
2561 if ((ctxt->catalogs != NULL) &&
2562 ((pref == XML_CATA_ALLOW_ALL) ||
2563 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2564 resource = xmlCatalogLocalResolve(ctxt->catalogs,
2565 (const xmlChar *)ID,
2566 (const xmlChar *)URL);
2569 * Try a global lookup
2571 if ((resource == NULL) &&
2572 ((pref == XML_CATA_ALLOW_ALL) ||
2573 (pref == XML_CATA_ALLOW_GLOBAL))) {
2574 resource = xmlCatalogResolve((const xmlChar *)ID,
2575 (const xmlChar *)URL);
2577 if ((resource == NULL) && (URL != NULL))
2578 resource = xmlStrdup((const xmlChar *) URL);
2581 * TODO: do an URI lookup on the reference
2583 if ((resource != NULL) && (!xmlSysIDExists((const char *)resource))) {
2584 xmlChar *tmp = NULL;
2586 if ((ctxt->catalogs != NULL) &&
2587 ((pref == XML_CATA_ALLOW_ALL) ||
2588 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2589 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
2591 if ((tmp == NULL) &&
2592 ((pref == XML_CATA_ALLOW_ALL) ||
2593 (pref == XML_CATA_ALLOW_GLOBAL))) {
2594 tmp = xmlCatalogResolveURI(resource);
2605 if (resource == NULL)
2606 resource = (xmlChar *) URL;
2608 if (resource == NULL) {
2611 if ((ctxt->validate) && (ctxt->sax != NULL) &&
2612 (ctxt->sax->error != NULL))
2613 ctxt->sax->error(ctxt,
2614 "failed to load external entity \"%s\"\n", ID);
2615 else if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
2616 ctxt->sax->warning(ctxt,
2617 "failed to load external entity \"%s\"\n", ID);
2620 ret = xmlNewInputFromFile(ctxt, (const char *)resource);
2622 if ((ctxt->validate) && (ctxt->sax != NULL) &&
2623 (ctxt->sax->error != NULL))
2624 ctxt->sax->error(ctxt,
2625 "failed to load external entity \"%s\"\n", resource);
2626 else if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
2627 ctxt->sax->warning(ctxt,
2628 "failed to load external entity \"%s\"\n", resource);
2630 if ((resource != NULL) && (resource != (xmlChar *) URL))
2635 static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
2636 xmlDefaultExternalEntityLoader;
2639 * xmlSetExternalEntityLoader:
2640 * @f: the new entity resolver function
2642 * Changes the defaultexternal entity resolver function for the application
2645 xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
2646 xmlCurrentExternalEntityLoader = f;
2650 * xmlGetExternalEntityLoader:
2652 * Get the default external entity resolver function for the application
2654 * Returns the xmlExternalEntityLoader function pointer
2656 xmlExternalEntityLoader
2657 xmlGetExternalEntityLoader(void) {
2658 return(xmlCurrentExternalEntityLoader);
2662 * xmlLoadExternalEntity:
2663 * @URL: the URL for the entity to load
2664 * @ID: the Public ID for the entity to load
2665 * @ctxt: the context in which the entity is called or NULL
2667 * Load an external entity, note that the use of this function for
2668 * unparsed entities may generate problems
2669 * TODO: a more generic External entity API must be designed
2671 * Returns the xmlParserInputPtr or NULL
2674 xmlLoadExternalEntity(const char *URL, const char *ID,
2675 xmlParserCtxtPtr ctxt) {
2676 if ((URL != NULL) && (xmlSysIDExists(URL) == 0)) {
2677 char *canonicFilename;
2678 xmlParserInputPtr ret;
2680 canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL);
2681 if (canonicFilename == NULL) {
2682 if (xmlDefaultSAXHandler.error != NULL) {
2683 xmlDefaultSAXHandler.error(NULL, "out of memory\n");
2688 ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt);
2689 xmlFree(canonicFilename);
2692 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
2695 /************************************************************************
2697 * Disabling Network access *
2699 ************************************************************************/
2701 #ifdef LIBXML_CATALOG_ENABLED
2703 xmlNoNetExists(const char *URL)
2713 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
2714 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
2719 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
2720 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
2727 ret = stat(path, &info);
2736 * xmlNoNetExternalEntityLoader:
2737 * @URL: the URL for the entity to load
2738 * @ID: the System ID for the entity to load
2739 * @ctxt: the context in which the entity is called or NULL
2741 * A specific entity loader disabling network accesses, though still
2742 * allowing local catalog accesses for resolution.
2744 * Returns a new allocated xmlParserInputPtr, or NULL.
2747 xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
2748 xmlParserCtxtPtr ctxt) {
2749 xmlParserInputPtr input = NULL;
2750 xmlChar *resource = NULL;
2752 #ifdef LIBXML_CATALOG_ENABLED
2753 xmlCatalogAllow pref;
2756 * If the resource doesn't exists as a file,
2757 * try to load it from the resource pointed in the catalogs
2759 pref = xmlCatalogGetDefaults();
2761 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
2765 if ((ctxt->catalogs != NULL) &&
2766 ((pref == XML_CATA_ALLOW_ALL) ||
2767 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2768 resource = xmlCatalogLocalResolve(ctxt->catalogs,
2769 (const xmlChar *)ID,
2770 (const xmlChar *)URL);
2773 * Try a global lookup
2775 if ((resource == NULL) &&
2776 ((pref == XML_CATA_ALLOW_ALL) ||
2777 (pref == XML_CATA_ALLOW_GLOBAL))) {
2778 resource = xmlCatalogResolve((const xmlChar *)ID,
2779 (const xmlChar *)URL);
2781 if ((resource == NULL) && (URL != NULL))
2782 resource = xmlStrdup((const xmlChar *) URL);
2785 * TODO: do an URI lookup on the reference
2787 if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
2788 xmlChar *tmp = NULL;
2790 if ((ctxt->catalogs != NULL) &&
2791 ((pref == XML_CATA_ALLOW_ALL) ||
2792 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2793 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
2795 if ((tmp == NULL) &&
2796 ((pref == XML_CATA_ALLOW_ALL) ||
2797 (pref == XML_CATA_ALLOW_GLOBAL))) {
2798 tmp = xmlCatalogResolveURI(resource);
2808 if (resource == NULL)
2809 resource = (xmlChar *) URL;
2811 if (resource != NULL) {
2812 if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
2813 (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
2814 xmlGenericError(xmlGenericErrorContext,
2815 "Attempt to load network entity %s \n", resource);
2817 if (resource != (xmlChar *) URL)
2822 input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
2823 if (resource != (xmlChar *) URL)