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