blob: 86b4701531771e51a4b23ebd432599c43c3761b9 [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
2 * xmlIO.c : implementation of the I/O interfaces used by the parser
3 *
4 * See Copyright for the status of this software.
5 *
Daniel Veillard344cee72001-08-20 00:08:40 +00006 * daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +00007 *
8 * 14 Nov 2000 ht - for VMS, truncated name of long functions to under 32 char
9 */
10
Bjorn Reese70a9da52001-04-21 16:57:29 +000011#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000012
Owen Taylor3473f882001-02-23 17:55:21 +000013#include <string.h>
14#include <errno.h>
15
16#ifdef HAVE_SYS_TYPES_H
17#include <sys/types.h>
18#endif
19#ifdef HAVE_SYS_STAT_H
20#include <sys/stat.h>
21#endif
22#ifdef HAVE_FCNTL_H
23#include <fcntl.h>
24#endif
25#ifdef HAVE_UNISTD_H
26#include <unistd.h>
27#endif
28#ifdef HAVE_STDLIB_H
29#include <stdlib.h>
30#endif
31#ifdef HAVE_ZLIB_H
32#include <zlib.h>
33#endif
34
35/* Figure a portable way to know if a file is a directory. */
36#ifndef HAVE_STAT
37# ifdef HAVE__STAT
Daniel Veillard50f34372001-08-03 12:06:36 +000038 /* MS C library seems to define stat and _stat. The definition
39 is identical. Still, mapping them to each other causes a warning. */
40# ifndef _MSC_VER
41# define stat(x,y) _stat(x,y)
42# endif
Owen Taylor3473f882001-02-23 17:55:21 +000043# define HAVE_STAT
44# endif
45#endif
46#ifdef HAVE_STAT
47# ifndef S_ISDIR
48# ifdef _S_ISDIR
49# define S_ISDIR(x) _S_ISDIR(x)
50# else
51# ifdef S_IFDIR
52# ifndef S_IFMT
53# ifdef _S_IFMT
54# define S_IFMT _S_IFMT
55# endif
56# endif
57# ifdef S_IFMT
58# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
59# endif
60# endif
61# endif
62# endif
63#endif
64
65#include <libxml/xmlmemory.h>
66#include <libxml/parser.h>
67#include <libxml/parserInternals.h>
68#include <libxml/xmlIO.h>
Daniel Veillard388236f2001-07-08 18:35:48 +000069#include <libxml/uri.h>
Owen Taylor3473f882001-02-23 17:55:21 +000070#include <libxml/nanohttp.h>
71#include <libxml/nanoftp.h>
72#include <libxml/xmlerror.h>
Daniel Veillard7d6fd212001-05-10 15:34:11 +000073#ifdef LIBXML_CATALOG_ENABLED
74#include <libxml/catalog.h>
75#endif
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000076#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000077
78#ifdef VMS
79#define xmlRegisterDefaultInputCallbacks xmlRegisterDefInputCallbacks
80#define xmlRegisterDefaultOutputCallbacks xmlRegisterDefOutputCallbacks
81#endif
82
Daniel Veillardf012a642001-07-23 19:10:52 +000083/* #define VERBOSE_FAILURE */
Daniel Veillard1fd36d22001-07-04 22:54:28 +000084/* #define DEBUG_EXTERNAL_ENTITIES */
Owen Taylor3473f882001-02-23 17:55:21 +000085/* #define DEBUG_INPUT */
86
87#ifdef DEBUG_INPUT
88#define MINLEN 40
89#else
90#define MINLEN 4000
91#endif
92
93/*
94 * Input I/O callback sets
95 */
96typedef struct _xmlInputCallback {
97 xmlInputMatchCallback matchcallback;
98 xmlInputOpenCallback opencallback;
99 xmlInputReadCallback readcallback;
100 xmlInputCloseCallback closecallback;
101} xmlInputCallback;
102
103#define MAX_INPUT_CALLBACK 15
104
Daniel Veillard22090732001-07-16 00:06:07 +0000105static xmlInputCallback xmlInputCallbackTable[MAX_INPUT_CALLBACK];
106static int xmlInputCallbackNr = 0;
107static int xmlInputCallbackInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000108
109/*
110 * Output I/O callback sets
111 */
112typedef struct _xmlOutputCallback {
113 xmlOutputMatchCallback matchcallback;
114 xmlOutputOpenCallback opencallback;
115 xmlOutputWriteCallback writecallback;
116 xmlOutputCloseCallback closecallback;
117} xmlOutputCallback;
118
119#define MAX_OUTPUT_CALLBACK 15
120
Daniel Veillard22090732001-07-16 00:06:07 +0000121static xmlOutputCallback xmlOutputCallbackTable[MAX_OUTPUT_CALLBACK];
122static int xmlOutputCallbackNr = 0;
123static int xmlOutputCallbackInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000124
125/************************************************************************
126 * *
127 * Standard I/O for file accesses *
128 * *
129 ************************************************************************/
130
131/**
132 * xmlCheckFilename
133 * @path: the path to check
134 *
135 * function checks to see if @path is a valid source
136 * (file, socket...) for XML.
137 *
138 * if stat is not available on the target machine,
139 * returns 1. if stat fails, returns 0 (if calling
140 * stat on the filename fails, it can't be right).
141 * if stat succeeds and the file is a directory,
142 * sets errno to EISDIR and returns 0. otherwise
143 * returns 1.
144 */
145
146static int
147xmlCheckFilename (const char *path)
148{
149#ifdef HAVE_STAT
150#ifdef S_ISDIR
151 struct stat stat_buffer;
152
153 if (stat(path, &stat_buffer) == -1)
154 return 0;
155
156 if (S_ISDIR(stat_buffer.st_mode)) {
157 errno = EISDIR;
158 return 0;
159 }
160
161#endif
162#endif
163 return 1;
164}
165
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000166static int
Owen Taylor3473f882001-02-23 17:55:21 +0000167xmlNop(void) {
168 return(0);
169}
170
171/**
Owen Taylor3473f882001-02-23 17:55:21 +0000172 * xmlFdRead:
173 * @context: the I/O context
174 * @buffer: where to drop data
175 * @len: number of bytes to read
176 *
177 * Read @len bytes to @buffer from the I/O channel.
178 *
179 * Returns the number of bytes written
180 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000181static int
Owen Taylor3473f882001-02-23 17:55:21 +0000182xmlFdRead (void * context, char * buffer, int len) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +0000183 return(read((int) (long) context, &buffer[0], len));
Owen Taylor3473f882001-02-23 17:55:21 +0000184}
185
186/**
187 * xmlFdWrite:
188 * @context: the I/O context
189 * @buffer: where to get data
190 * @len: number of bytes to write
191 *
192 * Write @len bytes from @buffer to the I/O channel.
193 *
194 * Returns the number of bytes written
195 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000196static int
Owen Taylor3473f882001-02-23 17:55:21 +0000197xmlFdWrite (void * context, const char * buffer, int len) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +0000198 return(write((int) (long) context, &buffer[0], len));
Owen Taylor3473f882001-02-23 17:55:21 +0000199}
200
201/**
202 * xmlFdClose:
203 * @context: the I/O context
204 *
205 * Close an I/O channel
Daniel Veillardf012a642001-07-23 19:10:52 +0000206 *
207 * Returns 0 in case of success and error code otherwise
Owen Taylor3473f882001-02-23 17:55:21 +0000208 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000209static int
Owen Taylor3473f882001-02-23 17:55:21 +0000210xmlFdClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +0000211 return ( close((int) (long) context) );
Owen Taylor3473f882001-02-23 17:55:21 +0000212}
213
214/**
215 * xmlFileMatch:
216 * @filename: the URI for matching
217 *
218 * input from FILE *
219 *
220 * Returns 1 if matches, 0 otherwise
221 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000222static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000223xmlFileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000224 return(1);
225}
226
227/**
228 * xmlFileOpen:
229 * @filename: the URI for matching
230 *
231 * input from FILE *, supports compressed input
232 * if @filename is " " then the standard input is used
233 *
234 * Returns an I/O context or NULL in case of error
235 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000236static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000237xmlFileOpen (const char *filename) {
238 const char *path = NULL;
239 FILE *fd;
240
241 if (!strcmp(filename, "-")) {
242 fd = stdin;
243 return((void *) fd);
244 }
245
246 if (!strncmp(filename, "file://localhost", 16))
247 path = &filename[16];
Daniel Veillardfe703322001-08-14 12:18:09 +0000248 else if (!strncmp(filename, "file:///", 8)) {
249#ifdef _WIN32
250 path = &filename[8];
251#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000252 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000253#endif
254 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000255 path = filename;
256
257 if (path == NULL)
258 return(NULL);
259 if (!xmlCheckFilename(path))
260 return(NULL);
261
262#ifdef WIN32
263 fd = fopen(path, "rb");
264#else
265 fd = fopen(path, "r");
266#endif /* WIN32 */
267 return((void *) fd);
268}
269
270/**
271 * xmlFileOpenW:
272 * @filename: the URI for matching
273 *
274 * output to from FILE *,
275 * if @filename is "-" then the standard output is used
276 *
277 * Returns an I/O context or NULL in case of error
278 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000279static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000280xmlFileOpenW (const char *filename) {
281 const char *path = NULL;
282 FILE *fd;
283
284 if (!strcmp(filename, "-")) {
285 fd = stdout;
286 return((void *) fd);
287 }
288
289 if (!strncmp(filename, "file://localhost", 16))
290 path = &filename[16];
Daniel Veillardfe703322001-08-14 12:18:09 +0000291 else if (!strncmp(filename, "file:///", 8)) {
292#ifdef _WIN32
293 path = &filename[8];
294#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000295 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000296#endif
297 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000298 path = filename;
299
300 if (path == NULL)
301 return(NULL);
302
303 fd = fopen(path, "w");
304 return((void *) fd);
305}
306
307/**
308 * xmlFileRead:
309 * @context: the I/O context
310 * @buffer: where to drop data
311 * @len: number of bytes to write
312 *
313 * Read @len bytes to @buffer from the I/O channel.
314 *
315 * Returns the number of bytes written
316 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000317static int
Owen Taylor3473f882001-02-23 17:55:21 +0000318xmlFileRead (void * context, char * buffer, int len) {
319 return(fread(&buffer[0], 1, len, (FILE *) context));
320}
321
322/**
323 * xmlFileWrite:
324 * @context: the I/O context
325 * @buffer: where to drop data
326 * @len: number of bytes to write
327 *
328 * Write @len bytes from @buffer to the I/O channel.
329 *
330 * Returns the number of bytes written
331 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000332static int
Owen Taylor3473f882001-02-23 17:55:21 +0000333xmlFileWrite (void * context, const char * buffer, int len) {
334 return(fwrite(&buffer[0], 1, len, (FILE *) context));
335}
336
337/**
338 * xmlFileClose:
339 * @context: the I/O context
340 *
341 * Close an I/O channel
342 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000343static int
Owen Taylor3473f882001-02-23 17:55:21 +0000344xmlFileClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +0000345 return ( ( fclose((FILE *) context) == EOF ) ? -1 : 0 );
Owen Taylor3473f882001-02-23 17:55:21 +0000346}
347
348/**
349 * xmlFileFlush:
350 * @context: the I/O context
351 *
352 * Flush an I/O channel
353 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000354static int
Owen Taylor3473f882001-02-23 17:55:21 +0000355xmlFileFlush (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +0000356 return ( ( fflush((FILE *) context) == EOF ) ? -1 : 0 );
Owen Taylor3473f882001-02-23 17:55:21 +0000357}
358
359#ifdef HAVE_ZLIB_H
360/************************************************************************
361 * *
362 * I/O for compressed file accesses *
363 * *
364 ************************************************************************/
365/**
366 * xmlGzfileMatch:
367 * @filename: the URI for matching
368 *
369 * input from compressed file test
370 *
371 * Returns 1 if matches, 0 otherwise
372 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000373static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000374xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000375 return(1);
376}
377
378/**
379 * xmlGzfileOpen:
380 * @filename: the URI for matching
381 *
382 * input from compressed file open
383 * if @filename is " " then the standard input is used
384 *
385 * Returns an I/O context or NULL in case of error
386 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000387static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000388xmlGzfileOpen (const char *filename) {
389 const char *path = NULL;
390 gzFile fd;
391
392 if (!strcmp(filename, "-")) {
393 fd = gzdopen(fileno(stdin), "rb");
394 return((void *) fd);
395 }
396
397 if (!strncmp(filename, "file://localhost", 16))
398 path = &filename[16];
Daniel Veillardfe703322001-08-14 12:18:09 +0000399 else if (!strncmp(filename, "file:///", 8)) {
400#ifdef _WIN32
401 path = &filename[8];
402#else
Owen Taylor3473f882001-02-23 17:55:21 +0000403 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000404#endif
405 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000406 path = filename;
407
408 if (path == NULL)
409 return(NULL);
410 if (!xmlCheckFilename(path))
411 return(NULL);
412
413 fd = gzopen(path, "rb");
414 return((void *) fd);
415}
416
417/**
418 * xmlGzfileOpenW:
419 * @filename: the URI for matching
420 * @compression: the compression factor (0 - 9 included)
421 *
422 * input from compressed file open
423 * if @filename is " " then the standard input is used
424 *
425 * Returns an I/O context or NULL in case of error
426 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000427static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000428xmlGzfileOpenW (const char *filename, int compression) {
429 const char *path = NULL;
430 char mode[15];
431 gzFile fd;
432
433 sprintf(mode, "wb%d", compression);
434 if (!strcmp(filename, "-")) {
435 fd = gzdopen(1, mode);
436 return((void *) fd);
437 }
438
439 if (!strncmp(filename, "file://localhost", 16))
440 path = &filename[16];
Daniel Veillardfe703322001-08-14 12:18:09 +0000441 else if (!strncmp(filename, "file:///", 8)) {
442#ifdef _WIN32
443 path = &filename[8];
444#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000445 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000446#endif
447 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000448 path = filename;
449
450 if (path == NULL)
451 return(NULL);
452
453 fd = gzopen(path, mode);
454 return((void *) fd);
455}
456
457/**
458 * xmlGzfileRead:
459 * @context: the I/O context
460 * @buffer: where to drop data
461 * @len: number of bytes to write
462 *
463 * Read @len bytes to @buffer from the compressed I/O channel.
464 *
465 * Returns the number of bytes written
466 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000467static int
Owen Taylor3473f882001-02-23 17:55:21 +0000468xmlGzfileRead (void * context, char * buffer, int len) {
469 return(gzread((gzFile) context, &buffer[0], len));
470}
471
472/**
473 * xmlGzfileWrite:
474 * @context: the I/O context
475 * @buffer: where to drop data
476 * @len: number of bytes to write
477 *
478 * Write @len bytes from @buffer to the compressed I/O channel.
479 *
480 * Returns the number of bytes written
481 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000482static int
Owen Taylor3473f882001-02-23 17:55:21 +0000483xmlGzfileWrite (void * context, const char * buffer, int len) {
484 return(gzwrite((gzFile) context, (char *) &buffer[0], len));
485}
486
487/**
488 * xmlGzfileClose:
489 * @context: the I/O context
490 *
491 * Close a compressed I/O channel
492 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000493static int
Owen Taylor3473f882001-02-23 17:55:21 +0000494xmlGzfileClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +0000495 return ( ( gzclose((gzFile) context) == Z_OK ) ? 0 : -1 );
Owen Taylor3473f882001-02-23 17:55:21 +0000496}
497#endif /* HAVE_ZLIB_H */
498
499#ifdef LIBXML_HTTP_ENABLED
500/************************************************************************
501 * *
502 * I/O for HTTP file accesses *
503 * *
504 ************************************************************************/
Daniel Veillardf012a642001-07-23 19:10:52 +0000505
506typedef struct xmlIOHTTPWriteCtxt_
507{
508 int compression;
509
510 char * uri;
511
512 void * doc_buff;
513
514} xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr;
515
516#ifdef HAVE_ZLIB_H
517
518#define DFLT_WBITS ( -15 )
519#define DFLT_MEM_LVL ( 8 )
520#define GZ_MAGIC1 ( 0x1f )
521#define GZ_MAGIC2 ( 0x8b )
522#define LXML_ZLIB_OS_CODE ( 0x03 )
523#define INIT_HTTP_BUFF_SIZE ( 32768 )
524#define DFLT_ZLIB_RATIO ( 5 )
525
526/*
527** Data structure and functions to work with sending compressed data
528** via HTTP.
529*/
530
531typedef struct xmlZMemBuff_
532{
533 unsigned long size;
534 unsigned long crc;
535
536 unsigned char * zbuff;
537 z_stream zctrl;
538
539} xmlZMemBuff, *xmlZMemBuffPtr;
540
541/**
542 * append_reverse_ulong
543 * @buff: Compressed memory buffer
544 * @data: Unsigned long to append
545 *
546 * Append a unsigned long in reverse byte order to the end of the
547 * memory buffer.
548 */
549static void
550append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) {
551
552 int idx;
553
554 if ( buff == NULL )
555 return;
556
557 /*
558 ** This is plagiarized from putLong in gzio.c (zlib source) where
559 ** the number "4" is hardcoded. If zlib is ever patched to
560 ** support 64 bit file sizes, this code would need to be patched
561 ** as well.
562 */
563
564 for ( idx = 0; idx < 4; idx++ ) {
565 *buff->zctrl.next_out = ( data & 0xff );
566 data >>= 8;
567 buff->zctrl.next_out++;
568 }
569
570 return;
571}
572
573/**
574 *
575 * xmlFreeZMemBuff
576 * @buff: The memory buffer context to clear
577 *
578 * Release all the resources associated with the compressed memory buffer.
579 */
580static void
581xmlFreeZMemBuff( xmlZMemBuffPtr buff ) {
582
583 int z_err;
584
585 if ( buff == NULL )
586 return;
587
588 xmlFree( buff->zbuff );
589 z_err = deflateEnd( &buff->zctrl );
590#ifdef DEBUG_HTTP
591 if ( z_err != Z_OK )
592 xmlGenericError( xmlGenericErrorContext,
593 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
594 z_err );
595#endif
596
597 xmlFree( buff );
598 return;
599}
600
601/**
602 * xmlCreateZMemBuff
603 *@compression: Compression value to use
604 *
605 * Create a memory buffer to hold the compressed XML document. The
606 * compressed document in memory will end up being identical to what
607 * would be created if gzopen/gzwrite/gzclose were being used to
608 * write the document to disk. The code for the header/trailer data to
609 * the compression is plagiarized from the zlib source files.
610 */
611static void *
612xmlCreateZMemBuff( int compression ) {
613
614 int z_err;
615 int hdr_lgth;
616 xmlZMemBuffPtr buff = NULL;
617
618 if ( ( compression < 1 ) || ( compression > 9 ) )
619 return ( NULL );
620
621 /* Create the control and data areas */
622
623 buff = xmlMalloc( sizeof( xmlZMemBuff ) );
624 if ( buff == NULL ) {
625 xmlGenericError( xmlGenericErrorContext,
626 "xmlCreateZMemBuff: %s\n",
627 "Failure allocating buffer context." );
628 return ( NULL );
629 }
630
631 (void)memset( buff, 0, sizeof( xmlZMemBuff ) );
632 buff->size = INIT_HTTP_BUFF_SIZE;
633 buff->zbuff = xmlMalloc( buff->size );
634 if ( buff->zbuff == NULL ) {
635 xmlFreeZMemBuff( buff );
636 xmlGenericError( xmlGenericErrorContext,
637 "xmlCreateZMemBuff: %s\n",
638 "Failure allocating data buffer." );
639 return ( NULL );
640 }
641
642 z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
643 DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
644 if ( z_err != Z_OK ) {
645 xmlFreeZMemBuff( buff );
646 buff = NULL;
647 xmlGenericError( xmlGenericErrorContext,
648 "xmlCreateZMemBuff: %s %d\n",
649 "Error initializing compression context. ZLIB error:",
650 z_err );
651 return ( NULL );
652 }
653
654 /* Set the header data. The CRC will be needed for the trailer */
655
656 buff->crc = crc32( 0L, Z_NULL, 0 );
657 hdr_lgth = sprintf( (char *)buff->zbuff, "%c%c%c%c%c%c%c%c%c%c",
658 GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED,
659 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE );
660 buff->zctrl.next_out = buff->zbuff + hdr_lgth;
661 buff->zctrl.avail_out = buff->size - hdr_lgth;
662
663 return ( buff );
664}
665
666/**
667 * xmlZMemBuffExtend
668 * @buff: Buffer used to compress and consolidate data.
669 * @ext_amt: Number of bytes to extend the buffer.
670 *
671 * Extend the internal buffer used to store the compressed data by the
672 * specified amount.
673 *
674 * Returns 0 on success or -1 on failure to extend the buffer. On failure
675 * the original buffer still exists at the original size.
676 */
677static int
678xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) {
679
680 int rc = -1;
681 size_t new_size;
682 size_t cur_used;
683
684 unsigned char * tmp_ptr = NULL;
685
686 if ( buff == NULL )
687 return ( -1 );
688
689 else if ( ext_amt == 0 )
690 return ( 0 );
691
692 cur_used = buff->zctrl.next_out - buff->zbuff;
693 new_size = buff->size + ext_amt;
694
695#ifdef DEBUG_HTTP
696 if ( cur_used > new_size )
697 xmlGenericError( xmlGenericErrorContext,
698 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
699 "Buffer overwrite detected during compressed memory",
700 "buffer extension. Overflowed by",
701 (cur_used - new_size ) );
702#endif
703
704 tmp_ptr = xmlRealloc( buff->zbuff, new_size );
705 if ( tmp_ptr != NULL ) {
706 rc = 0;
707 buff->size = new_size;
708 buff->zbuff = tmp_ptr;
709 buff->zctrl.next_out = tmp_ptr + cur_used;
710 buff->zctrl.avail_out = new_size - cur_used;
711 }
712 else {
713 xmlGenericError( xmlGenericErrorContext,
714 "xmlZMemBuffExtend: %s %lu bytes.\n",
715 "Allocation failure extending output buffer to",
716 new_size );
717 }
718
719 return ( rc );
720}
721
722/**
723 * xmlZMemBuffAppend
724 * @buff: Buffer used to compress and consolidate data
725 * @src: Uncompressed source content to append to buffer
726 * @len: Length of source data to append to buffer
727 *
728 * Compress and append data to the internal buffer. The data buffer
729 * will be expanded if needed to store the additional data.
730 *
731 * Returns the number of bytes appended to the buffer or -1 on error.
732 */
733static int
734xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) {
735
736 int z_err;
737 size_t min_accept;
738
739 if ( ( buff == NULL ) || ( src == NULL ) )
740 return ( -1 );
741
742 buff->zctrl.avail_in = len;
743 buff->zctrl.next_in = (unsigned char *)src;
744 while ( buff->zctrl.avail_in > 0 ) {
745 /*
746 ** Extend the buffer prior to deflate call if a reasonable amount
747 ** of output buffer space is not available.
748 */
749 min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO;
750 if ( buff->zctrl.avail_out <= min_accept ) {
751 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
752 return ( -1 );
753 }
754
755 z_err = deflate( &buff->zctrl, Z_NO_FLUSH );
756 if ( z_err != Z_OK ) {
757 xmlGenericError( xmlGenericErrorContext,
758 "xmlZMemBuffAppend: %s %d %s - %d",
759 "Compression error while appending",
760 len, "bytes to buffer. ZLIB error", z_err );
761 return ( -1 );
762 }
763 }
764
765 buff->crc = crc32( buff->crc, (unsigned char *)src, len );
766
767 return ( len );
768}
769
770/**
771 * xmlZMemBuffGetContent
772 * @buff: Compressed memory content buffer
773 * @data_ref: Pointer reference to point to compressed content
774 *
775 * Flushes the compression buffers, appends gzip file trailers and
776 * returns the compressed content and length of the compressed data.
777 * NOTE: The gzip trailer code here is plagiarized from zlib source.
778 *
779 * Returns the length of the compressed data or -1 on error.
780 */
781static int
782xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) {
783
784 int zlgth = -1;
785 int z_err;
786
787 if ( ( buff == NULL ) || ( data_ref == NULL ) )
788 return ( -1 );
789
790 /* Need to loop until compression output buffers are flushed */
791
792 do
793 {
794 z_err = deflate( &buff->zctrl, Z_FINISH );
795 if ( z_err == Z_OK ) {
796 /* In this case Z_OK means more buffer space needed */
797
798 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
799 return ( -1 );
800 }
801 }
802 while ( z_err == Z_OK );
803
804 /* If the compression state is not Z_STREAM_END, some error occurred */
805
806 if ( z_err == Z_STREAM_END ) {
807
808 /* Need to append the gzip data trailer */
809
810 if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) {
811 if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 )
812 return ( -1 );
813 }
814
815 /*
816 ** For whatever reason, the CRC and length data are pushed out
817 ** in reverse byte order. So a memcpy can't be used here.
818 */
819
820 append_reverse_ulong( buff, buff->crc );
821 append_reverse_ulong( buff, buff->zctrl.total_in );
822
823 zlgth = buff->zctrl.next_out - buff->zbuff;
824 *data_ref = (char *)buff->zbuff;
825 }
826
827 else
828 xmlGenericError( xmlGenericErrorContext,
829 "xmlZMemBuffGetContent: %s - %d\n",
830 "Error flushing zlib buffers. Error code", z_err );
831
832 return ( zlgth );
833}
834#endif /* HAVE_ZLIB_H */
835
836/**
837 * xmlFreeHTTPWriteCtxt
838 * @ctxt: Context to cleanup
839 *
840 * Free allocated memory and reclaim system resources.
841 *
842 * No return value.
843 */
844static void
845xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt )
846{
847 if ( ctxt->uri != NULL )
848 free( ctxt->uri );
849
850 if ( ctxt->doc_buff != NULL ) {
851
852#ifdef HAVE_ZLIB_H
853 if ( ctxt->compression > 0 ) {
854 xmlFreeZMemBuff( ctxt->doc_buff );
855 }
856 else
857#endif
858 {
859 xmlOutputBufferClose( ctxt->doc_buff );
860 }
861 }
862
863 free( ctxt );
864 return;
865}
866
867
Owen Taylor3473f882001-02-23 17:55:21 +0000868/**
869 * xmlIOHTTPMatch:
870 * @filename: the URI for matching
871 *
872 * check if the URI matches an HTTP one
873 *
874 * Returns 1 if matches, 0 otherwise
875 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000876static int
Owen Taylor3473f882001-02-23 17:55:21 +0000877xmlIOHTTPMatch (const char *filename) {
878 if (!strncmp(filename, "http://", 7))
879 return(1);
880 return(0);
881}
882
883/**
884 * xmlIOHTTPOpen:
885 * @filename: the URI for matching
886 *
887 * open an HTTP I/O channel
888 *
889 * Returns an I/O context or NULL in case of error
890 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000891static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000892xmlIOHTTPOpen (const char *filename) {
893 return(xmlNanoHTTPOpen(filename, NULL));
894}
895
896/**
Daniel Veillardf012a642001-07-23 19:10:52 +0000897 * xmlIOHTTPOpenW
898 * @post_uri: The destination URI for the document
899 * @compression: The compression desired for the document.
900 *
901 * Open a temporary buffer to collect the document for a subsequent HTTP POST
902 * request. Non-static as is called from the output buffer creation routine.
903 *
904 * Returns an I/O context or NULL in case of error.
905 */
906
907void *
908xmlIOHTTPOpenW( const char * post_uri, int compression ) {
909
910 xmlIOHTTPWriteCtxtPtr ctxt = NULL;
911
912 if ( post_uri == NULL )
913 return ( NULL );
914
915 ctxt = xmlMalloc( sizeof( xmlIOHTTPWriteCtxt ) );
916 if ( ctxt == NULL ) {
917 xmlGenericError( xmlGenericErrorContext,
918 "xmlIOHTTPOpenW: Failed to create output HTTP context.\n" );
919 return ( NULL );
920 }
921
922 (void)memset( ctxt, 0, sizeof( xmlIOHTTPWriteCtxt ) );
923
924 ctxt->uri = strdup( post_uri );
925 if ( ctxt->uri == NULL ) {
926 xmlGenericError( xmlGenericErrorContext,
927 "xmlIOHTTPOpenW: Failed to duplicate destination URI.\n" );
928 xmlFreeHTTPWriteCtxt( ctxt );
929 return ( NULL );
930 }
931
932 /*
933 ** Since the document length is required for an HTTP post,
934 ** need to put the document into a buffer. A memory buffer
935 ** is being used to avoid pushing the data to disk and back.
936 */
937
938#ifdef HAVE_ZLIB_H
939 if ( ( compression > 0 ) && ( compression <= 9 ) ) {
940
941 ctxt->compression = compression;
942 ctxt->doc_buff = xmlCreateZMemBuff( compression );
943 }
944 else
945#endif
946 {
947 /* Any character conversions should have been done before this */
948
949 ctxt->doc_buff = xmlAllocOutputBuffer( NULL );
950 }
951
952 if ( ctxt->doc_buff == NULL ) {
953 xmlFreeHTTPWriteCtxt( ctxt );
954 ctxt = NULL;
955 }
956
957 return ( ctxt );
958}
959
960/**
961 * xmlIOHTTPDfltOpenW
962 * @post_uri: The destination URI for this document.
963 *
964 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
965 * HTTP post command. This function should generally not be used as
966 * the open callback is short circuited in xmlOutputBufferCreateFile.
967 *
968 * Returns a pointer to the new IO context.
969 */
970static void *
971xmlIOHTTPDfltOpenW( const char * post_uri ) {
972 return ( xmlIOHTTPOpenW( post_uri, 0 ) );
973}
974
975/**
Owen Taylor3473f882001-02-23 17:55:21 +0000976 * xmlIOHTTPRead:
977 * @context: the I/O context
978 * @buffer: where to drop data
979 * @len: number of bytes to write
980 *
981 * Read @len bytes to @buffer from the I/O channel.
982 *
983 * Returns the number of bytes written
984 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000985static int
Owen Taylor3473f882001-02-23 17:55:21 +0000986xmlIOHTTPRead(void * context, char * buffer, int len) {
987 return(xmlNanoHTTPRead(context, &buffer[0], len));
988}
989
990/**
Daniel Veillardf012a642001-07-23 19:10:52 +0000991 * xmlIOHTTPWrite
992 * @context: previously opened writing context
993 * @buffer: data to output to temporary buffer
994 * @len: bytes to output
995 *
996 * Collect data from memory buffer into a temporary file for later
997 * processing.
998 *
999 * Returns number of bytes written.
1000 */
1001
1002static int
1003xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
1004
1005 xmlIOHTTPWriteCtxtPtr ctxt = context;
1006
1007 if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
1008 return ( -1 );
1009
1010 if ( len > 0 ) {
1011
1012 /* Use gzwrite or fwrite as previously setup in the open call */
1013
1014#ifdef HAVE_ZLIB_H
1015 if ( ctxt->compression > 0 )
1016 len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len );
1017
1018 else
1019#endif
1020 len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
1021
1022 if ( len < 0 ) {
1023 xmlGenericError( xmlGenericErrorContext,
1024 "xmlIOHTTPWrite: %s\n%s '%s'.\n",
1025 "Error appending to internal buffer.",
1026 "Error sending document to URI",
1027 ctxt->uri );
1028 }
1029 }
1030
1031 return ( len );
1032}
1033
1034
1035/**
Owen Taylor3473f882001-02-23 17:55:21 +00001036 * xmlIOHTTPClose:
1037 * @context: the I/O context
1038 *
1039 * Close an HTTP I/O channel
1040 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001041static int
Owen Taylor3473f882001-02-23 17:55:21 +00001042xmlIOHTTPClose (void * context) {
1043 xmlNanoHTTPClose(context);
Daniel Veillardf012a642001-07-23 19:10:52 +00001044 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001045}
Daniel Veillardf012a642001-07-23 19:10:52 +00001046
1047/**
1048 * xmlIOHTTCloseWrite
1049 * @context: The I/O context
1050 * @http_mthd: The HTTP method to be used when sending the data
1051 *
1052 * Close the transmit HTTP I/O channel and actually send the data.
1053 */
1054static int
1055xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
1056
1057 int close_rc = -1;
1058 int http_rtn = 0;
1059 int content_lgth = 0;
1060 xmlIOHTTPWriteCtxtPtr ctxt = context;
1061
1062 char * http_content = NULL;
1063 char * content_encoding = NULL;
1064 char * content_type = (char *) "text/xml";
1065 void * http_ctxt = NULL;
1066
1067 if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
1068 return ( -1 );
1069
1070 /* Retrieve the content from the appropriate buffer */
1071
1072#ifdef HAVE_ZLIB_H
1073
1074 if ( ctxt->compression > 0 ) {
1075 content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
1076 content_encoding = (char *) "Content-Encoding: gzip";
1077 }
1078 else
1079#endif
1080 {
1081 /* Pull the data out of the memory output buffer */
1082
1083 xmlOutputBufferPtr dctxt = ctxt->doc_buff;
1084 http_content = (char *)dctxt->buffer->content;
1085 content_lgth = dctxt->buffer->use;
1086 }
1087
1088 if ( http_content == NULL ) {
1089 xmlGenericError( xmlGenericErrorContext,
1090 "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
1091 "Error retrieving content.\nUnable to",
1092 http_mthd, "data to URI", ctxt->uri );
1093 }
1094
1095 else {
1096
1097 http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
1098 &content_type, content_encoding,
1099 content_lgth );
1100
1101 if ( http_ctxt != NULL ) {
1102#ifdef DEBUG_HTTP
1103 /* If testing/debugging - dump reply with request content */
1104
1105 FILE * tst_file = NULL;
1106 char buffer[ 4096 ];
1107 char * dump_name = NULL;
1108 int avail;
1109
1110 xmlGenericError( xmlGenericErrorContext,
1111 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
1112 http_mthd, ctxt->uri,
1113 xmlNanoHTTPReturnCode( http_ctxt ) );
1114
1115 /*
1116 ** Since either content or reply may be gzipped,
1117 ** dump them to separate files instead of the
1118 ** standard error context.
1119 */
1120
1121 dump_name = tempnam( NULL, "lxml" );
1122 if ( dump_name != NULL ) {
1123 (void)sprintf( buffer, "%s.content", dump_name );
1124
1125 tst_file = fopen( buffer, "w" );
1126 if ( tst_file != NULL ) {
1127 xmlGenericError( xmlGenericErrorContext,
1128 "Transmitted content saved in file: %s\n", buffer );
1129
1130 fwrite( http_content, sizeof( char ),
1131 content_lgth, tst_file );
1132 fclose( tst_file );
1133 }
1134
1135 (void)sprintf( buffer, "%s.reply", dump_name );
1136 tst_file = fopen( buffer, "w" );
1137 if ( tst_file != NULL ) {
1138 xmlGenericError( xmlGenericErrorContext,
1139 "Reply content saved in file: %s\n", buffer );
1140
1141
1142 while ( (avail = xmlNanoHTTPRead( http_ctxt,
1143 buffer, sizeof( buffer ) )) > 0 ) {
1144
1145 fwrite( buffer, sizeof( char ), avail, tst_file );
1146 }
1147
1148 fclose( tst_file );
1149 }
1150
1151 free( dump_name );
1152 }
1153#endif /* DEBUG_HTTP */
1154
1155 http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
1156 if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
1157 close_rc = 0;
1158 else
1159 xmlGenericError( xmlGenericErrorContext,
1160 "xmlIOHTTPClose: HTTP '%s' of %d %s\n'%s' %s %d\n",
1161 http_mthd, content_lgth,
1162 "bytes to URI", ctxt->uri,
1163 "failed. HTTP return code:", http_rtn );
1164
1165 xmlNanoHTTPClose( http_ctxt );
1166 xmlFree( content_type );
1167 }
1168 }
1169
1170 /* Final cleanups */
1171
1172 xmlFreeHTTPWriteCtxt( ctxt );
1173
1174 return ( close_rc );
1175}
1176
1177/**
1178 * xmlIOHTTPClosePut
1179 *
1180 * @context: The I/O context
1181 *
1182 * Close the transmit HTTP I/O channel and actually send data using a PUT
1183 * HTTP method.
1184 */
1185static int
1186xmlIOHTTPClosePut( void * ctxt ) {
1187 return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
1188}
1189
1190
1191/**
1192 * xmlIOHTTPClosePost
1193 *
1194 * @context: The I/O context
1195 *
1196 * Close the transmit HTTP I/O channel and actually send data using a POST
1197 * HTTP method.
1198 */
1199static int
1200xmlIOHTTPClosePost( void * ctxt ) {
1201 return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
1202}
1203
Owen Taylor3473f882001-02-23 17:55:21 +00001204#endif /* LIBXML_HTTP_ENABLED */
1205
1206#ifdef LIBXML_FTP_ENABLED
1207/************************************************************************
1208 * *
1209 * I/O for FTP file accesses *
1210 * *
1211 ************************************************************************/
1212/**
1213 * xmlIOFTPMatch:
1214 * @filename: the URI for matching
1215 *
1216 * check if the URI matches an FTP one
1217 *
1218 * Returns 1 if matches, 0 otherwise
1219 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001220static int
Owen Taylor3473f882001-02-23 17:55:21 +00001221xmlIOFTPMatch (const char *filename) {
1222 if (!strncmp(filename, "ftp://", 6))
1223 return(1);
1224 return(0);
1225}
1226
1227/**
1228 * xmlIOFTPOpen:
1229 * @filename: the URI for matching
1230 *
1231 * open an FTP I/O channel
1232 *
1233 * Returns an I/O context or NULL in case of error
1234 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001235static void *
Owen Taylor3473f882001-02-23 17:55:21 +00001236xmlIOFTPOpen (const char *filename) {
1237 return(xmlNanoFTPOpen(filename));
1238}
1239
1240/**
1241 * xmlIOFTPRead:
1242 * @context: the I/O context
1243 * @buffer: where to drop data
1244 * @len: number of bytes to write
1245 *
1246 * Read @len bytes to @buffer from the I/O channel.
1247 *
1248 * Returns the number of bytes written
1249 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001250static int
Owen Taylor3473f882001-02-23 17:55:21 +00001251xmlIOFTPRead(void * context, char * buffer, int len) {
1252 return(xmlNanoFTPRead(context, &buffer[0], len));
1253}
1254
1255/**
1256 * xmlIOFTPClose:
1257 * @context: the I/O context
1258 *
1259 * Close an FTP I/O channel
1260 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001261static int
Owen Taylor3473f882001-02-23 17:55:21 +00001262xmlIOFTPClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001263 return ( xmlNanoFTPClose(context) );
Owen Taylor3473f882001-02-23 17:55:21 +00001264}
1265#endif /* LIBXML_FTP_ENABLED */
1266
1267
1268/**
1269 * xmlRegisterInputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001270 * @matchFunc: the xmlInputMatchCallback
1271 * @openFunc: the xmlInputOpenCallback
1272 * @readFunc: the xmlInputReadCallback
1273 * @closeFunc: the xmlInputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001274 *
1275 * Register a new set of I/O callback for handling parser input.
1276 *
1277 * Returns the registered handler number or -1 in case of error
1278 */
1279int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001280xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
1281 xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
1282 xmlInputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001283 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
1284 return(-1);
1285 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001286 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
1287 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
1288 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
1289 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
Owen Taylor3473f882001-02-23 17:55:21 +00001290 return(xmlInputCallbackNr++);
1291}
1292
1293/**
1294 * xmlRegisterOutputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001295 * @matchFunc: the xmlOutputMatchCallback
1296 * @openFunc: the xmlOutputOpenCallback
1297 * @writeFunc: the xmlOutputWriteCallback
1298 * @closeFunc: the xmlOutputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001299 *
1300 * Register a new set of I/O callback for handling output.
1301 *
1302 * Returns the registered handler number or -1 in case of error
1303 */
1304int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001305xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
1306 xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
1307 xmlOutputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001308 if (xmlOutputCallbackNr >= MAX_INPUT_CALLBACK) {
1309 return(-1);
1310 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001311 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
1312 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
1313 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
1314 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
Owen Taylor3473f882001-02-23 17:55:21 +00001315 return(xmlOutputCallbackNr++);
1316}
1317
1318/**
1319 * xmlRegisterDefaultInputCallbacks:
1320 *
1321 * Registers the default compiled-in I/O handlers.
1322 */
1323void
1324#ifdef VMS
1325xmlRegisterDefInputCallbacks
1326#else
1327xmlRegisterDefaultInputCallbacks
1328#endif
1329(void) {
1330 if (xmlInputCallbackInitialized)
1331 return;
1332
1333 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
1334 xmlFileRead, xmlFileClose);
1335#ifdef HAVE_ZLIB_H
1336 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1337 xmlGzfileRead, xmlGzfileClose);
1338#endif /* HAVE_ZLIB_H */
1339
1340#ifdef LIBXML_HTTP_ENABLED
1341 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
1342 xmlIOHTTPRead, xmlIOHTTPClose);
1343#endif /* LIBXML_HTTP_ENABLED */
1344
1345#ifdef LIBXML_FTP_ENABLED
1346 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1347 xmlIOFTPRead, xmlIOFTPClose);
1348#endif /* LIBXML_FTP_ENABLED */
1349 xmlInputCallbackInitialized = 1;
1350}
1351
1352/**
1353 * xmlRegisterDefaultOutputCallbacks:
1354 *
1355 * Registers the default compiled-in I/O handlers.
1356 */
1357void
1358#ifdef VMS
1359xmlRegisterDefOutputCallbacks
1360#else
1361xmlRegisterDefaultOutputCallbacks
1362#endif
1363(void) {
1364 if (xmlOutputCallbackInitialized)
1365 return;
1366
1367 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
1368 xmlFileWrite, xmlFileClose);
Daniel Veillardf012a642001-07-23 19:10:52 +00001369
1370#ifdef LIBXML_HTTP_ENABLED
1371 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
1372 xmlIOHTTPWrite, xmlIOHTTPClosePut);
1373#endif
1374
Owen Taylor3473f882001-02-23 17:55:21 +00001375/*********************************
1376 No way a-priori to distinguish between gzipped files from
1377 uncompressed ones except opening if existing then closing
1378 and saving with same compression ratio ... a pain.
1379
1380#ifdef HAVE_ZLIB_H
1381 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1382 xmlGzfileWrite, xmlGzfileClose);
1383#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001384
1385 Nor FTP PUT ....
1386#ifdef LIBXML_FTP_ENABLED
1387 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1388 xmlIOFTPWrite, xmlIOFTPClose);
1389#endif
1390 **********************************/
1391 xmlOutputCallbackInitialized = 1;
1392}
1393
Daniel Veillardf012a642001-07-23 19:10:52 +00001394#ifdef LIBXML_HTTP_ENABLED
1395/**
1396 * xmlRegisterHTTPPostCallbacks
1397 *
1398 * By default, libxml submits HTTP output requests using the "PUT" method.
1399 * Calling this method changes the HTTP output method to use the "POST"
1400 * method instead.
1401 *
1402 */
1403void
1404xmlRegisterHTTPPostCallbacks( void ) {
1405
1406 /* Register defaults if not done previously */
1407
1408 if ( xmlOutputCallbackInitialized == 0 )
1409 xmlRegisterDefaultOutputCallbacks( );
1410
1411 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
1412 xmlIOHTTPWrite, xmlIOHTTPClosePost);
1413 return;
1414}
1415#endif
1416
Owen Taylor3473f882001-02-23 17:55:21 +00001417/**
1418 * xmlAllocParserInputBuffer:
1419 * @enc: the charset encoding if known
1420 *
1421 * Create a buffered parser input for progressive parsing
1422 *
1423 * Returns the new parser input or NULL
1424 */
1425xmlParserInputBufferPtr
1426xmlAllocParserInputBuffer(xmlCharEncoding enc) {
1427 xmlParserInputBufferPtr ret;
1428
1429 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
1430 if (ret == NULL) {
1431 xmlGenericError(xmlGenericErrorContext,
1432 "xmlAllocParserInputBuffer : out of memory!\n");
1433 return(NULL);
1434 }
1435 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
1436 ret->buffer = xmlBufferCreate();
1437 if (ret->buffer == NULL) {
1438 xmlFree(ret);
1439 return(NULL);
1440 }
1441 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
1442 ret->encoder = xmlGetCharEncodingHandler(enc);
1443 if (ret->encoder != NULL)
1444 ret->raw = xmlBufferCreate();
1445 else
1446 ret->raw = NULL;
1447 ret->readcallback = NULL;
1448 ret->closecallback = NULL;
1449 ret->context = NULL;
1450
1451 return(ret);
1452}
1453
1454/**
1455 * xmlAllocOutputBuffer:
1456 * @encoder: the encoding converter or NULL
1457 *
1458 * Create a buffered parser output
1459 *
1460 * Returns the new parser output or NULL
1461 */
1462xmlOutputBufferPtr
1463xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
1464 xmlOutputBufferPtr ret;
1465
1466 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
1467 if (ret == NULL) {
1468 xmlGenericError(xmlGenericErrorContext,
1469 "xmlAllocOutputBuffer : out of memory!\n");
1470 return(NULL);
1471 }
1472 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
1473 ret->buffer = xmlBufferCreate();
1474 if (ret->buffer == NULL) {
1475 xmlFree(ret);
1476 return(NULL);
1477 }
1478 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
1479 ret->encoder = encoder;
1480 if (encoder != NULL) {
1481 ret->conv = xmlBufferCreateSize(4000);
1482 /*
1483 * This call is designed to initiate the encoder state
1484 */
1485 xmlCharEncOutFunc(encoder, ret->conv, NULL);
1486 } else
1487 ret->conv = NULL;
1488 ret->writecallback = NULL;
1489 ret->closecallback = NULL;
1490 ret->context = NULL;
1491 ret->written = 0;
1492
1493 return(ret);
1494}
1495
1496/**
1497 * xmlFreeParserInputBuffer:
1498 * @in: a buffered parser input
1499 *
1500 * Free up the memory used by a buffered parser input
1501 */
1502void
1503xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
1504 if (in->raw) {
1505 xmlBufferFree(in->raw);
1506 in->raw = NULL;
1507 }
1508 if (in->encoder != NULL) {
1509 xmlCharEncCloseFunc(in->encoder);
1510 }
1511 if (in->closecallback != NULL) {
1512 in->closecallback(in->context);
1513 }
1514 if (in->buffer != NULL) {
1515 xmlBufferFree(in->buffer);
1516 in->buffer = NULL;
1517 }
1518
Owen Taylor3473f882001-02-23 17:55:21 +00001519 xmlFree(in);
1520}
1521
1522/**
1523 * xmlOutputBufferClose:
1524 * @out: a buffered output
1525 *
1526 * flushes and close the output I/O channel
1527 * and free up all the associated resources
1528 *
1529 * Returns the number of byte written or -1 in case of error.
1530 */
1531int
1532xmlOutputBufferClose(xmlOutputBufferPtr out) {
1533 int written;
Daniel Veillardf012a642001-07-23 19:10:52 +00001534 int err_rc = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001535
1536 if (out == NULL)
1537 return(-1);
1538 if (out->writecallback != NULL)
1539 xmlOutputBufferFlush(out);
1540 if (out->closecallback != NULL) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001541 err_rc = out->closecallback(out->context);
Owen Taylor3473f882001-02-23 17:55:21 +00001542 }
1543 written = out->written;
1544 if (out->conv) {
1545 xmlBufferFree(out->conv);
1546 out->conv = NULL;
1547 }
1548 if (out->encoder != NULL) {
1549 xmlCharEncCloseFunc(out->encoder);
1550 }
1551 if (out->buffer != NULL) {
1552 xmlBufferFree(out->buffer);
1553 out->buffer = NULL;
1554 }
1555
Owen Taylor3473f882001-02-23 17:55:21 +00001556 xmlFree(out);
Daniel Veillardf012a642001-07-23 19:10:52 +00001557 return( ( err_rc == 0 ) ? written : err_rc );
Owen Taylor3473f882001-02-23 17:55:21 +00001558}
1559
1560/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001561 * xmlParserInputBufferCreateFname:
1562 * @URI: a C string containing the URI or filename
1563 * @enc: the charset encoding if known
1564 *
1565 * VMS version of xmlParserInputBufferCreateFilename()
1566 *
1567 * Returns the new parser input or NULL
1568 */
1569/**
Owen Taylor3473f882001-02-23 17:55:21 +00001570 * xmlParserInputBufferCreateFilename:
1571 * @URI: a C string containing the URI or filename
1572 * @enc: the charset encoding if known
1573 *
1574 * Create a buffered parser input for the progressive parsing of a file
1575 * If filename is "-' then we use stdin as the input.
1576 * Automatic support for ZLIB/Compress compressed document is provided
1577 * by default if found at compile-time.
1578 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
1579 *
1580 * Returns the new parser input or NULL
1581 */
1582xmlParserInputBufferPtr
1583#ifdef VMS
1584xmlParserInputBufferCreateFname
1585#else
1586xmlParserInputBufferCreateFilename
1587#endif
1588(const char *URI, xmlCharEncoding enc) {
1589 xmlParserInputBufferPtr ret;
Daniel Veillard388236f2001-07-08 18:35:48 +00001590 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001591 void *context = NULL;
Daniel Veillard388236f2001-07-08 18:35:48 +00001592 char *unescaped;
Owen Taylor3473f882001-02-23 17:55:21 +00001593
1594 if (xmlInputCallbackInitialized == 0)
1595 xmlRegisterDefaultInputCallbacks();
1596
1597 if (URI == NULL) return(NULL);
1598
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001599#ifdef LIBXML_CATALOG_ENABLED
1600#endif
1601
Owen Taylor3473f882001-02-23 17:55:21 +00001602 /*
1603 * Try to find one of the input accept method accepting taht scheme
1604 * Go in reverse to give precedence to user defined handlers.
Daniel Veillard388236f2001-07-08 18:35:48 +00001605 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00001606 */
Daniel Veillard388236f2001-07-08 18:35:48 +00001607 unescaped = xmlURIUnescapeString(URI, 0, NULL);
1608 if (unescaped != NULL) {
1609 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
1610 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
1611 (xmlInputCallbackTable[i].matchcallback(unescaped) != 0)) {
1612 context = xmlInputCallbackTable[i].opencallback(unescaped);
1613 if (context != NULL)
1614 break;
1615 }
1616 }
1617 xmlFree(unescaped);
1618 }
1619
1620 /*
1621 * If this failed try with a non-escaped URI this may be a strange
1622 * filename
1623 */
1624 if (context == NULL) {
1625 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
1626 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
1627 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
1628 context = xmlInputCallbackTable[i].opencallback(URI);
1629 if (context != NULL)
1630 break;
1631 }
Owen Taylor3473f882001-02-23 17:55:21 +00001632 }
1633 }
1634 if (context == NULL) {
1635 return(NULL);
1636 }
1637
1638 /*
1639 * Allocate the Input buffer front-end.
1640 */
1641 ret = xmlAllocParserInputBuffer(enc);
1642 if (ret != NULL) {
1643 ret->context = context;
1644 ret->readcallback = xmlInputCallbackTable[i].readcallback;
1645 ret->closecallback = xmlInputCallbackTable[i].closecallback;
1646 }
1647 return(ret);
1648}
1649
1650/**
1651 * xmlOutputBufferCreateFilename:
1652 * @URI: a C string containing the URI or filename
1653 * @encoder: the encoding converter or NULL
1654 * @compression: the compression ration (0 none, 9 max).
1655 *
1656 * Create a buffered output for the progressive saving of a file
1657 * If filename is "-' then we use stdout as the output.
1658 * Automatic support for ZLIB/Compress compressed document is provided
1659 * by default if found at compile-time.
1660 * TODO: currently if compression is set, the library only support
1661 * writing to a local file.
1662 *
1663 * Returns the new output or NULL
1664 */
1665xmlOutputBufferPtr
1666xmlOutputBufferCreateFilename(const char *URI,
1667 xmlCharEncodingHandlerPtr encoder,
1668 int compression) {
1669 xmlOutputBufferPtr ret;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001670 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001671 void *context = NULL;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001672 char *unescaped;
Owen Taylor3473f882001-02-23 17:55:21 +00001673
Daniel Veillardf012a642001-07-23 19:10:52 +00001674 int is_http_uri = 0; /* Can't change if HTTP disabled */
1675
Owen Taylor3473f882001-02-23 17:55:21 +00001676 if (xmlOutputCallbackInitialized == 0)
1677 xmlRegisterDefaultOutputCallbacks();
1678
1679 if (URI == NULL) return(NULL);
1680
Daniel Veillardf012a642001-07-23 19:10:52 +00001681#ifdef LIBXML_HTTP_ENABLED
1682 /* Need to prevent HTTP URI's from falling into zlib short circuit */
1683
1684 is_http_uri = xmlIOHTTPMatch( URI );
1685#endif
1686
Owen Taylor3473f882001-02-23 17:55:21 +00001687
1688 /*
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001689 * Try to find one of the output accept method accepting taht scheme
Owen Taylor3473f882001-02-23 17:55:21 +00001690 * Go in reverse to give precedence to user defined handlers.
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001691 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00001692 */
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001693 unescaped = xmlURIUnescapeString(URI, 0, NULL);
1694 if (unescaped != NULL) {
1695#ifdef HAVE_ZLIB_H
1696 if ((compression > 0) && (compression <= 9) && (is_http_uri == 0)) {
1697 context = xmlGzfileOpenW(unescaped, compression);
1698 if (context != NULL) {
1699 ret = xmlAllocOutputBuffer(encoder);
1700 if (ret != NULL) {
1701 ret->context = context;
1702 ret->writecallback = xmlGzfileWrite;
1703 ret->closecallback = xmlGzfileClose;
1704 }
1705 xmlFree(unescaped);
1706 return(ret);
1707 }
1708 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001709#endif
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001710 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
1711 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
1712 (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
1713#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
1714 /* Need to pass compression parameter into HTTP open calls */
1715 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
1716 context = xmlIOHTTPOpenW(unescaped, compression);
1717 else
1718#endif
1719 context = xmlOutputCallbackTable[i].opencallback(unescaped);
1720 if (context != NULL)
1721 break;
1722 }
1723 }
1724 xmlFree(unescaped);
1725 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001726
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001727 /*
1728 * If this failed try with a non-escaped URI this may be a strange
1729 * filename
1730 */
1731 if (context == NULL) {
1732#ifdef HAVE_ZLIB_H
1733 if ((compression > 0) && (compression <= 9) && (is_http_uri == 0)) {
1734 context = xmlGzfileOpenW(URI, compression);
1735 if (context != NULL) {
1736 ret = xmlAllocOutputBuffer(encoder);
1737 if (ret != NULL) {
1738 ret->context = context;
1739 ret->writecallback = xmlGzfileWrite;
1740 ret->closecallback = xmlGzfileClose;
1741 }
1742 return(ret);
1743 }
1744 }
1745#endif
1746 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
1747 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
1748 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
1749 context = xmlOutputCallbackTable[i].opencallback(URI);
1750#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
1751 /* Need to pass compression parameter into HTTP open calls */
1752 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
1753 context = xmlIOHTTPOpenW(URI, compression);
1754 else
1755#endif
1756 context = xmlOutputCallbackTable[i].opencallback(URI);
1757 if (context != NULL)
1758 break;
1759 }
Owen Taylor3473f882001-02-23 17:55:21 +00001760 }
1761 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001762
Owen Taylor3473f882001-02-23 17:55:21 +00001763 if (context == NULL) {
1764 return(NULL);
1765 }
1766
1767 /*
1768 * Allocate the Output buffer front-end.
1769 */
1770 ret = xmlAllocOutputBuffer(encoder);
1771 if (ret != NULL) {
1772 ret->context = context;
1773 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
1774 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
1775 }
1776 return(ret);
1777}
1778
1779/**
1780 * xmlParserInputBufferCreateFile:
1781 * @file: a FILE*
1782 * @enc: the charset encoding if known
1783 *
1784 * Create a buffered parser input for the progressive parsing of a FILE *
1785 * buffered C I/O
1786 *
1787 * Returns the new parser input or NULL
1788 */
1789xmlParserInputBufferPtr
1790xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
1791 xmlParserInputBufferPtr ret;
1792
1793 if (xmlInputCallbackInitialized == 0)
1794 xmlRegisterDefaultInputCallbacks();
1795
1796 if (file == NULL) return(NULL);
1797
1798 ret = xmlAllocParserInputBuffer(enc);
1799 if (ret != NULL) {
1800 ret->context = file;
1801 ret->readcallback = xmlFileRead;
1802 ret->closecallback = xmlFileFlush;
1803 }
1804
1805 return(ret);
1806}
1807
1808/**
1809 * xmlOutputBufferCreateFile:
1810 * @file: a FILE*
1811 * @encoder: the encoding converter or NULL
1812 *
1813 * Create a buffered output for the progressive saving to a FILE *
1814 * buffered C I/O
1815 *
1816 * Returns the new parser output or NULL
1817 */
1818xmlOutputBufferPtr
1819xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
1820 xmlOutputBufferPtr ret;
1821
1822 if (xmlOutputCallbackInitialized == 0)
1823 xmlRegisterDefaultOutputCallbacks();
1824
1825 if (file == NULL) return(NULL);
1826
1827 ret = xmlAllocOutputBuffer(encoder);
1828 if (ret != NULL) {
1829 ret->context = file;
1830 ret->writecallback = xmlFileWrite;
1831 ret->closecallback = xmlFileFlush;
1832 }
1833
1834 return(ret);
1835}
1836
1837/**
1838 * xmlParserInputBufferCreateFd:
1839 * @fd: a file descriptor number
1840 * @enc: the charset encoding if known
1841 *
1842 * Create a buffered parser input for the progressive parsing for the input
1843 * from a file descriptor
1844 *
1845 * Returns the new parser input or NULL
1846 */
1847xmlParserInputBufferPtr
1848xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
1849 xmlParserInputBufferPtr ret;
1850
1851 if (fd < 0) return(NULL);
1852
1853 ret = xmlAllocParserInputBuffer(enc);
1854 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00001855 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00001856 ret->readcallback = xmlFdRead;
1857 ret->closecallback = xmlFdClose;
1858 }
1859
1860 return(ret);
1861}
1862
1863/**
1864 * xmlParserInputBufferCreateMem:
1865 * @mem: the memory input
1866 * @size: the length of the memory block
1867 * @enc: the charset encoding if known
1868 *
1869 * Create a buffered parser input for the progressive parsing for the input
1870 * from a memory area.
1871 *
1872 * Returns the new parser input or NULL
1873 */
1874xmlParserInputBufferPtr
1875xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
1876 xmlParserInputBufferPtr ret;
1877
1878 if (size <= 0) return(NULL);
1879 if (mem == NULL) return(NULL);
1880
1881 ret = xmlAllocParserInputBuffer(enc);
1882 if (ret != NULL) {
1883 ret->context = (void *) mem;
1884 ret->readcallback = (xmlInputReadCallback) xmlNop;
1885 ret->closecallback = NULL;
1886 xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size);
1887 }
1888
1889 return(ret);
1890}
1891
1892/**
1893 * xmlOutputBufferCreateFd:
1894 * @fd: a file descriptor number
1895 * @encoder: the encoding converter or NULL
1896 *
1897 * Create a buffered output for the progressive saving
1898 * to a file descriptor
1899 *
1900 * Returns the new parser output or NULL
1901 */
1902xmlOutputBufferPtr
1903xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
1904 xmlOutputBufferPtr ret;
1905
1906 if (fd < 0) return(NULL);
1907
1908 ret = xmlAllocOutputBuffer(encoder);
1909 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00001910 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00001911 ret->writecallback = xmlFdWrite;
1912 ret->closecallback = xmlFdClose;
1913 }
1914
1915 return(ret);
1916}
1917
1918/**
1919 * xmlParserInputBufferCreateIO:
1920 * @ioread: an I/O read function
1921 * @ioclose: an I/O close function
1922 * @ioctx: an I/O handler
1923 * @enc: the charset encoding if known
1924 *
1925 * Create a buffered parser input for the progressive parsing for the input
1926 * from an I/O handler
1927 *
1928 * Returns the new parser input or NULL
1929 */
1930xmlParserInputBufferPtr
1931xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
1932 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
1933 xmlParserInputBufferPtr ret;
1934
1935 if (ioread == NULL) return(NULL);
1936
1937 ret = xmlAllocParserInputBuffer(enc);
1938 if (ret != NULL) {
1939 ret->context = (void *) ioctx;
1940 ret->readcallback = ioread;
1941 ret->closecallback = ioclose;
1942 }
1943
1944 return(ret);
1945}
1946
1947/**
1948 * xmlOutputBufferCreateIO:
1949 * @iowrite: an I/O write function
1950 * @ioclose: an I/O close function
1951 * @ioctx: an I/O handler
1952 * @enc: the charset encoding if known
1953 *
1954 * Create a buffered output for the progressive saving
1955 * to an I/O handler
1956 *
1957 * Returns the new parser output or NULL
1958 */
1959xmlOutputBufferPtr
1960xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
1961 xmlOutputCloseCallback ioclose, void *ioctx,
1962 xmlCharEncodingHandlerPtr encoder) {
1963 xmlOutputBufferPtr ret;
1964
1965 if (iowrite == NULL) return(NULL);
1966
1967 ret = xmlAllocOutputBuffer(encoder);
1968 if (ret != NULL) {
1969 ret->context = (void *) ioctx;
1970 ret->writecallback = iowrite;
1971 ret->closecallback = ioclose;
1972 }
1973
1974 return(ret);
1975}
1976
1977/**
1978 * xmlParserInputBufferPush:
1979 * @in: a buffered parser input
1980 * @len: the size in bytes of the array.
1981 * @buf: an char array
1982 *
1983 * Push the content of the arry in the input buffer
1984 * This routine handle the I18N transcoding to internal UTF-8
1985 * This is used when operating the parser in progressive (push) mode.
1986 *
1987 * Returns the number of chars read and stored in the buffer, or -1
1988 * in case of error.
1989 */
1990int
1991xmlParserInputBufferPush(xmlParserInputBufferPtr in,
1992 int len, const char *buf) {
1993 int nbchars = 0;
1994
1995 if (len < 0) return(0);
1996 if (in->encoder != NULL) {
1997 /*
1998 * Store the data in the incoming raw buffer
1999 */
2000 if (in->raw == NULL) {
2001 in->raw = xmlBufferCreate();
2002 }
2003 xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
2004
2005 /*
2006 * convert as much as possible to the parser reading buffer.
2007 */
2008 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2009 if (nbchars < 0) {
2010 xmlGenericError(xmlGenericErrorContext,
2011 "xmlParserInputBufferPush: encoder error\n");
2012 return(-1);
2013 }
2014 } else {
2015 nbchars = len;
2016 xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
2017 }
2018#ifdef DEBUG_INPUT
2019 xmlGenericError(xmlGenericErrorContext,
2020 "I/O: pushed %d chars, buffer %d/%d\n",
2021 nbchars, in->buffer->use, in->buffer->size);
2022#endif
2023 return(nbchars);
2024}
2025
2026/**
2027 * xmlParserInputBufferGrow:
2028 * @in: a buffered parser input
2029 * @len: indicative value of the amount of chars to read
2030 *
2031 * Grow up the content of the input buffer, the old data are preserved
2032 * This routine handle the I18N transcoding to internal UTF-8
2033 * This routine is used when operating the parser in normal (pull) mode
2034 *
2035 * TODO: one should be able to remove one extra copy by copying directy
2036 * onto in->buffer or in->raw
2037 *
2038 * Returns the number of chars read and stored in the buffer, or -1
2039 * in case of error.
2040 */
2041int
2042xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
2043 char *buffer = NULL;
2044 int res = 0;
2045 int nbchars = 0;
2046 int buffree;
2047
2048 if ((len <= MINLEN) && (len != 4))
2049 len = MINLEN;
2050 buffree = in->buffer->size - in->buffer->use;
2051 if (buffree <= 0) {
2052 xmlGenericError(xmlGenericErrorContext,
2053 "xmlParserInputBufferGrow : buffer full !\n");
2054 return(0);
2055 }
2056 if (len > buffree)
2057 len = buffree;
2058
2059 buffer = (char *) xmlMalloc((len + 1) * sizeof(char));
2060 if (buffer == NULL) {
2061 xmlGenericError(xmlGenericErrorContext,
2062 "xmlParserInputBufferGrow : out of memory !\n");
2063 return(-1);
2064 }
2065
2066 /*
2067 * Call the read method for this I/O type.
2068 */
2069 if (in->readcallback != NULL) {
2070 res = in->readcallback(in->context, &buffer[0], len);
2071 } else {
2072 xmlGenericError(xmlGenericErrorContext,
2073 "xmlParserInputBufferGrow : no input !\n");
2074 xmlFree(buffer);
2075 return(-1);
2076 }
2077 if (res < 0) {
2078 perror ("read error");
2079 xmlFree(buffer);
2080 return(-1);
2081 }
2082 len = res;
2083 if (in->encoder != NULL) {
2084 /*
2085 * Store the data in the incoming raw buffer
2086 */
2087 if (in->raw == NULL) {
2088 in->raw = xmlBufferCreate();
2089 }
2090 xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
2091
2092 /*
2093 * convert as much as possible to the parser reading buffer.
2094 */
2095 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2096 if (nbchars < 0) {
2097 xmlGenericError(xmlGenericErrorContext,
2098 "xmlParserInputBufferGrow: encoder error\n");
2099 return(-1);
2100 }
2101 } else {
2102 nbchars = len;
2103 buffer[nbchars] = 0;
2104 xmlBufferAdd(in->buffer, (xmlChar *) buffer, nbchars);
2105 }
2106#ifdef DEBUG_INPUT
2107 xmlGenericError(xmlGenericErrorContext,
2108 "I/O: read %d chars, buffer %d/%d\n",
2109 nbchars, in->buffer->use, in->buffer->size);
2110#endif
2111 xmlFree(buffer);
2112 return(nbchars);
2113}
2114
2115/**
2116 * xmlParserInputBufferRead:
2117 * @in: a buffered parser input
2118 * @len: indicative value of the amount of chars to read
2119 *
2120 * Refresh the content of the input buffer, the old data are considered
2121 * consumed
2122 * This routine handle the I18N transcoding to internal UTF-8
2123 *
2124 * Returns the number of chars read and stored in the buffer, or -1
2125 * in case of error.
2126 */
2127int
2128xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
2129 /* xmlBufferEmpty(in->buffer); */
2130 if (in->readcallback != NULL)
2131 return(xmlParserInputBufferGrow(in, len));
2132 else
2133 return(-1);
2134}
2135
2136/**
2137 * xmlOutputBufferWrite:
2138 * @out: a buffered parser output
2139 * @len: the size in bytes of the array.
2140 * @buf: an char array
2141 *
2142 * Write the content of the array in the output I/O buffer
2143 * This routine handle the I18N transcoding from internal UTF-8
2144 * The buffer is lossless, i.e. will store in case of partial
2145 * or delayed writes.
2146 *
2147 * Returns the number of chars immediately written, or -1
2148 * in case of error.
2149 */
2150int
2151xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
2152 int nbchars = 0; /* number of chars to output to I/O */
2153 int ret; /* return from function call */
2154 int written = 0; /* number of char written to I/O so far */
2155 int chunk; /* number of byte curreent processed from buf */
2156
2157 if (len < 0) return(0);
2158
2159 do {
2160 chunk = len;
2161 if (chunk > 4 * MINLEN)
2162 chunk = 4 * MINLEN;
2163
2164 /*
2165 * first handle encoding stuff.
2166 */
2167 if (out->encoder != NULL) {
2168 /*
2169 * Store the data in the incoming raw buffer
2170 */
2171 if (out->conv == NULL) {
2172 out->conv = xmlBufferCreate();
2173 }
2174 xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2175
2176 if ((out->buffer->use < MINLEN) && (chunk == len))
2177 goto done;
2178
2179 /*
2180 * convert as much as possible to the parser reading buffer.
2181 */
2182 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
2183 if (ret < 0) {
2184 xmlGenericError(xmlGenericErrorContext,
2185 "xmlOutputBufferWrite: encoder error\n");
2186 return(-1);
2187 }
2188 nbchars = out->conv->use;
2189 } else {
2190 xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2191 nbchars = out->buffer->use;
2192 }
2193 buf += chunk;
2194 len -= chunk;
2195
2196 if ((nbchars < MINLEN) && (len <= 0))
2197 goto done;
2198
2199 if (out->writecallback) {
2200 /*
2201 * second write the stuff to the I/O channel
2202 */
2203 if (out->encoder != NULL) {
2204 ret = out->writecallback(out->context,
2205 (const char *)out->conv->content, nbchars);
2206 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002207 xmlBufferShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002208 } else {
2209 ret = out->writecallback(out->context,
2210 (const char *)out->buffer->content, nbchars);
2211 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002212 xmlBufferShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002213 }
2214 if (ret < 0) {
2215 xmlGenericError(xmlGenericErrorContext,
2216 "I/O: error %d writing %d bytes\n", ret, nbchars);
2217 return(ret);
2218 }
2219 out->written += ret;
2220 }
2221 written += nbchars;
2222 } while (len > 0);
2223
2224done:
2225#ifdef DEBUG_INPUT
2226 xmlGenericError(xmlGenericErrorContext,
2227 "I/O: wrote %d chars\n", written);
2228#endif
2229 return(written);
2230}
2231
2232/**
2233 * xmlOutputBufferWriteString:
2234 * @out: a buffered parser output
2235 * @str: a zero terminated C string
2236 *
2237 * Write the content of the string in the output I/O buffer
2238 * This routine handle the I18N transcoding from internal UTF-8
2239 * The buffer is lossless, i.e. will store in case of partial
2240 * or delayed writes.
2241 *
2242 * Returns the number of chars immediately written, or -1
2243 * in case of error.
2244 */
2245int
2246xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
2247 int len;
2248
2249 if (str == NULL)
2250 return(-1);
2251 len = strlen(str);
2252
2253 if (len > 0)
2254 return(xmlOutputBufferWrite(out, len, str));
2255 return(len);
2256}
2257
2258/**
2259 * xmlOutputBufferFlush:
2260 * @out: a buffered output
2261 *
2262 * flushes the output I/O channel
2263 *
2264 * Returns the number of byte written or -1 in case of error.
2265 */
2266int
2267xmlOutputBufferFlush(xmlOutputBufferPtr out) {
2268 int nbchars = 0, ret = 0;
2269
2270 /*
2271 * first handle encoding stuff.
2272 */
2273 if ((out->conv != NULL) && (out->encoder != NULL)) {
2274 /*
2275 * convert as much as possible to the parser reading buffer.
2276 */
2277 nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
2278 if (nbchars < 0) {
2279 xmlGenericError(xmlGenericErrorContext,
2280 "xmlOutputBufferWrite: encoder error\n");
2281 return(-1);
2282 }
2283 }
2284
2285 /*
2286 * second flush the stuff to the I/O channel
2287 */
2288 if ((out->conv != NULL) && (out->encoder != NULL) &&
2289 (out->writecallback != NULL)) {
2290 ret = out->writecallback(out->context,
2291 (const char *)out->conv->content, out->conv->use);
2292 if (ret >= 0)
2293 xmlBufferShrink(out->conv, ret);
2294 } else if (out->writecallback != NULL) {
2295 ret = out->writecallback(out->context,
2296 (const char *)out->buffer->content, out->buffer->use);
2297 if (ret >= 0)
2298 xmlBufferShrink(out->buffer, ret);
2299 }
2300 if (ret < 0) {
2301 xmlGenericError(xmlGenericErrorContext,
2302 "I/O: error %d flushing %d bytes\n", ret, nbchars);
2303 return(ret);
2304 }
2305 out->written += ret;
2306
2307#ifdef DEBUG_INPUT
2308 xmlGenericError(xmlGenericErrorContext,
2309 "I/O: flushed %d chars\n", ret);
2310#endif
2311 return(ret);
2312}
2313
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002314/**
Owen Taylor3473f882001-02-23 17:55:21 +00002315 * xmlParserGetDirectory:
2316 * @filename: the path to a file
2317 *
2318 * lookup the directory for that file
2319 *
2320 * Returns a new allocated string containing the directory, or NULL.
2321 */
2322char *
2323xmlParserGetDirectory(const char *filename) {
2324 char *ret = NULL;
2325 char dir[1024];
2326 char *cur;
2327 char sep = '/';
2328
2329 if (xmlInputCallbackInitialized == 0)
2330 xmlRegisterDefaultInputCallbacks();
2331
2332 if (filename == NULL) return(NULL);
2333#ifdef WIN32
2334 sep = '\\';
2335#endif
2336
2337 strncpy(dir, filename, 1023);
2338 dir[1023] = 0;
2339 cur = &dir[strlen(dir)];
2340 while (cur > dir) {
2341 if (*cur == sep) break;
2342 cur --;
2343 }
2344 if (*cur == sep) {
2345 if (cur == dir) dir[1] = 0;
2346 else *cur = 0;
2347 ret = xmlMemStrdup(dir);
2348 } else {
2349 if (getcwd(dir, 1024) != NULL) {
2350 dir[1023] = 0;
2351 ret = xmlMemStrdup(dir);
2352 }
2353 }
2354 return(ret);
2355}
2356
2357/****************************************************************
2358 * *
2359 * External entities loading *
2360 * *
2361 ****************************************************************/
2362
Daniel Veillard6990bf32001-08-23 21:17:48 +00002363#ifdef LIBXML_CATALOG_ENABLED
2364static int xmlSysIDExists(const char *URL) {
2365#ifdef HAVE_STAT
2366 int ret;
2367 struct stat info;
2368 const char *path;
2369
2370 if (URL == NULL)
2371 return(0);
2372
2373 if (!strncmp(URL, "file://localhost", 16))
2374 path = &URL[16];
2375 else if (!strncmp(URL, "file:///", 8)) {
2376#ifdef _WIN32
2377 path = &URL[8];
2378#else
2379 path = &URL[7];
2380#endif
2381 } else
2382 path = URL;
2383 ret = stat(path, &info);
2384 if (ret == 0)
2385 return(1);
2386#endif
2387 return(0);
2388}
2389#endif
2390
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002391/**
Owen Taylor3473f882001-02-23 17:55:21 +00002392 * xmlDefaultExternalEntityLoader:
2393 * @URL: the URL for the entity to load
2394 * @ID: the System ID for the entity to load
2395 * @ctxt: the context in which the entity is called or NULL
2396 *
2397 * By default we don't load external entitites, yet.
2398 *
2399 * Returns a new allocated xmlParserInputPtr, or NULL.
2400 */
2401static
2402xmlParserInputPtr
2403xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
2404 xmlParserCtxtPtr ctxt) {
2405 xmlParserInputPtr ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002406 xmlChar *resource = NULL;
2407#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002408 xmlCatalogAllow pref;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002409#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002410
2411#ifdef DEBUG_EXTERNAL_ENTITIES
2412 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf012a642001-07-23 19:10:52 +00002413 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00002414#endif
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002415#ifdef LIBXML_CATALOG_ENABLED
2416 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002417 * If the resource doesn't exists as a file,
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002418 * try to load it from the resource pointed in the catalogs
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002419 */
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002420 pref = xmlCatalogGetDefaults();
2421
Daniel Veillard6990bf32001-08-23 21:17:48 +00002422 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlSysIDExists(URL))) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002423 /*
2424 * Do a local lookup
2425 */
2426 if ((ctxt->catalogs != NULL) &&
2427 ((pref == XML_CATA_ALLOW_ALL) ||
2428 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2429 resource = xmlCatalogLocalResolve(ctxt->catalogs,
2430 (const xmlChar *)ID,
2431 (const xmlChar *)URL);
2432 }
2433 /*
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002434 * Try a global lookup
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002435 */
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002436 if ((resource == NULL) &&
2437 ((pref == XML_CATA_ALLOW_ALL) ||
2438 (pref == XML_CATA_ALLOW_GLOBAL))) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002439 resource = xmlCatalogResolve((const xmlChar *)ID,
2440 (const xmlChar *)URL);
2441 }
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002442 if ((resource == NULL) && (URL != NULL))
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00002443 resource = xmlStrdup((const xmlChar *) URL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002444
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002445 /*
2446 * TODO: do an URI lookup on the reference
2447 */
Daniel Veillard6990bf32001-08-23 21:17:48 +00002448 if ((resource != NULL) && (!xmlSysIDExists((const char *)resource))) {
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002449 xmlChar *tmp = NULL;
2450
2451 if ((ctxt->catalogs != NULL) &&
2452 ((pref == XML_CATA_ALLOW_ALL) ||
2453 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2454 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
2455 }
2456 if ((tmp == NULL) &&
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00002457 ((pref == XML_CATA_ALLOW_ALL) ||
2458 (pref == XML_CATA_ALLOW_GLOBAL))) {
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002459 tmp = xmlCatalogResolveURI(resource);
2460 }
2461
2462 if (tmp != NULL) {
2463 xmlFree(resource);
2464 resource = tmp;
2465 }
2466 }
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002467 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002468#endif
2469
2470 if (resource == NULL)
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002471 resource = (xmlChar *) URL;
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002472
2473 if (resource == NULL) {
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002474 if ((ctxt->validate) && (ctxt->sax != NULL) &&
2475 (ctxt->sax->error != NULL))
2476 ctxt->sax->error(ctxt,
2477 "failed to load external entity \"%s\"\n", ID);
2478 else if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00002479 ctxt->sax->warning(ctxt,
2480 "failed to load external entity \"%s\"\n", ID);
2481 return(NULL);
2482 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002483 ret = xmlNewInputFromFile(ctxt, (const char *)resource);
Owen Taylor3473f882001-02-23 17:55:21 +00002484 if (ret == NULL) {
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002485 if ((ctxt->validate) && (ctxt->sax != NULL) &&
2486 (ctxt->sax->error != NULL))
2487 ctxt->sax->error(ctxt,
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002488 "failed to load external entity \"%s\"\n", resource);
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002489 else if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00002490 ctxt->sax->warning(ctxt,
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002491 "failed to load external entity \"%s\"\n", resource);
Owen Taylor3473f882001-02-23 17:55:21 +00002492 }
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002493 if ((resource != NULL) && (resource != (xmlChar *) URL))
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002494 xmlFree(resource);
Owen Taylor3473f882001-02-23 17:55:21 +00002495 return(ret);
2496}
2497
2498static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
2499 xmlDefaultExternalEntityLoader;
2500
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002501/**
Owen Taylor3473f882001-02-23 17:55:21 +00002502 * xmlSetExternalEntityLoader:
2503 * @f: the new entity resolver function
2504 *
2505 * Changes the defaultexternal entity resolver function for the application
2506 */
2507void
2508xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
2509 xmlCurrentExternalEntityLoader = f;
2510}
2511
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002512/**
Owen Taylor3473f882001-02-23 17:55:21 +00002513 * xmlGetExternalEntityLoader:
2514 *
2515 * Get the default external entity resolver function for the application
2516 *
2517 * Returns the xmlExternalEntityLoader function pointer
2518 */
2519xmlExternalEntityLoader
2520xmlGetExternalEntityLoader(void) {
2521 return(xmlCurrentExternalEntityLoader);
2522}
2523
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002524/**
Owen Taylor3473f882001-02-23 17:55:21 +00002525 * xmlLoadExternalEntity:
2526 * @URL: the URL for the entity to load
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00002527 * @ID: the Public ID for the entity to load
Owen Taylor3473f882001-02-23 17:55:21 +00002528 * @ctxt: the context in which the entity is called or NULL
2529 *
2530 * Load an external entity, note that the use of this function for
2531 * unparsed entities may generate problems
2532 * TODO: a more generic External entitiy API must be designed
2533 *
2534 * Returns the xmlParserInputPtr or NULL
2535 */
2536xmlParserInputPtr
2537xmlLoadExternalEntity(const char *URL, const char *ID,
2538 xmlParserCtxtPtr ctxt) {
2539 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
2540}
2541