blob: b8be560b3098aa6ff1bf09387ebdd1ca4c26dd5f [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
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001598#ifdef LIBXML_CATALOG_ENABLED
1599#endif
1600
Owen Taylor3473f882001-02-23 17:55:21 +00001601 /*
1602 * Try to find one of the input accept method accepting taht scheme
1603 * Go in reverse to give precedence to user defined handlers.
Daniel Veillard388236f2001-07-08 18:35:48 +00001604 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00001605 */
Daniel Veillard388236f2001-07-08 18:35:48 +00001606 unescaped = xmlURIUnescapeString(URI, 0, NULL);
1607 if (unescaped != NULL) {
1608 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
1609 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
1610 (xmlInputCallbackTable[i].matchcallback(unescaped) != 0)) {
1611 context = xmlInputCallbackTable[i].opencallback(unescaped);
1612 if (context != NULL)
1613 break;
1614 }
1615 }
1616 xmlFree(unescaped);
1617 }
1618
1619 /*
1620 * If this failed try with a non-escaped URI this may be a strange
1621 * filename
1622 */
1623 if (context == NULL) {
1624 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
1625 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
1626 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
1627 context = xmlInputCallbackTable[i].opencallback(URI);
1628 if (context != NULL)
1629 break;
1630 }
Owen Taylor3473f882001-02-23 17:55:21 +00001631 }
1632 }
1633 if (context == NULL) {
1634 return(NULL);
1635 }
1636
1637 /*
1638 * Allocate the Input buffer front-end.
1639 */
1640 ret = xmlAllocParserInputBuffer(enc);
1641 if (ret != NULL) {
1642 ret->context = context;
1643 ret->readcallback = xmlInputCallbackTable[i].readcallback;
1644 ret->closecallback = xmlInputCallbackTable[i].closecallback;
1645 }
1646 return(ret);
1647}
1648
1649/**
1650 * xmlOutputBufferCreateFilename:
1651 * @URI: a C string containing the URI or filename
1652 * @encoder: the encoding converter or NULL
1653 * @compression: the compression ration (0 none, 9 max).
1654 *
1655 * Create a buffered output for the progressive saving of a file
1656 * If filename is "-' then we use stdout as the output.
1657 * Automatic support for ZLIB/Compress compressed document is provided
1658 * by default if found at compile-time.
1659 * TODO: currently if compression is set, the library only support
1660 * writing to a local file.
1661 *
1662 * Returns the new output or NULL
1663 */
1664xmlOutputBufferPtr
1665xmlOutputBufferCreateFilename(const char *URI,
1666 xmlCharEncodingHandlerPtr encoder,
1667 int compression) {
1668 xmlOutputBufferPtr ret;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001669 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001670 void *context = NULL;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001671 char *unescaped;
Owen Taylor3473f882001-02-23 17:55:21 +00001672
Daniel Veillardf012a642001-07-23 19:10:52 +00001673 int is_http_uri = 0; /* Can't change if HTTP disabled */
1674
Owen Taylor3473f882001-02-23 17:55:21 +00001675 if (xmlOutputCallbackInitialized == 0)
1676 xmlRegisterDefaultOutputCallbacks();
1677
1678 if (URI == NULL) return(NULL);
1679
Daniel Veillardf012a642001-07-23 19:10:52 +00001680#ifdef LIBXML_HTTP_ENABLED
1681 /* Need to prevent HTTP URI's from falling into zlib short circuit */
1682
1683 is_http_uri = xmlIOHTTPMatch( URI );
1684#endif
1685
Owen Taylor3473f882001-02-23 17:55:21 +00001686
1687 /*
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001688 * Try to find one of the output accept method accepting taht scheme
Owen Taylor3473f882001-02-23 17:55:21 +00001689 * Go in reverse to give precedence to user defined handlers.
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001690 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00001691 */
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001692 unescaped = xmlURIUnescapeString(URI, 0, NULL);
1693 if (unescaped != NULL) {
1694#ifdef HAVE_ZLIB_H
1695 if ((compression > 0) && (compression <= 9) && (is_http_uri == 0)) {
1696 context = xmlGzfileOpenW(unescaped, compression);
1697 if (context != NULL) {
1698 ret = xmlAllocOutputBuffer(encoder);
1699 if (ret != NULL) {
1700 ret->context = context;
1701 ret->writecallback = xmlGzfileWrite;
1702 ret->closecallback = xmlGzfileClose;
1703 }
1704 xmlFree(unescaped);
1705 return(ret);
1706 }
1707 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001708#endif
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001709 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
1710 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
1711 (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
1712#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
1713 /* Need to pass compression parameter into HTTP open calls */
1714 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
1715 context = xmlIOHTTPOpenW(unescaped, compression);
1716 else
1717#endif
1718 context = xmlOutputCallbackTable[i].opencallback(unescaped);
1719 if (context != NULL)
1720 break;
1721 }
1722 }
1723 xmlFree(unescaped);
1724 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001725
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001726 /*
1727 * If this failed try with a non-escaped URI this may be a strange
1728 * filename
1729 */
1730 if (context == NULL) {
1731#ifdef HAVE_ZLIB_H
1732 if ((compression > 0) && (compression <= 9) && (is_http_uri == 0)) {
1733 context = xmlGzfileOpenW(URI, compression);
1734 if (context != NULL) {
1735 ret = xmlAllocOutputBuffer(encoder);
1736 if (ret != NULL) {
1737 ret->context = context;
1738 ret->writecallback = xmlGzfileWrite;
1739 ret->closecallback = xmlGzfileClose;
1740 }
1741 return(ret);
1742 }
1743 }
1744#endif
1745 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
1746 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
1747 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
1748 context = xmlOutputCallbackTable[i].opencallback(URI);
1749#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
1750 /* Need to pass compression parameter into HTTP open calls */
1751 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
1752 context = xmlIOHTTPOpenW(URI, compression);
1753 else
1754#endif
1755 context = xmlOutputCallbackTable[i].opencallback(URI);
1756 if (context != NULL)
1757 break;
1758 }
Owen Taylor3473f882001-02-23 17:55:21 +00001759 }
1760 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001761
Owen Taylor3473f882001-02-23 17:55:21 +00001762 if (context == NULL) {
1763 return(NULL);
1764 }
1765
1766 /*
1767 * Allocate the Output buffer front-end.
1768 */
1769 ret = xmlAllocOutputBuffer(encoder);
1770 if (ret != NULL) {
1771 ret->context = context;
1772 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
1773 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
1774 }
1775 return(ret);
1776}
1777
1778/**
1779 * xmlParserInputBufferCreateFile:
1780 * @file: a FILE*
1781 * @enc: the charset encoding if known
1782 *
1783 * Create a buffered parser input for the progressive parsing of a FILE *
1784 * buffered C I/O
1785 *
1786 * Returns the new parser input or NULL
1787 */
1788xmlParserInputBufferPtr
1789xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
1790 xmlParserInputBufferPtr ret;
1791
1792 if (xmlInputCallbackInitialized == 0)
1793 xmlRegisterDefaultInputCallbacks();
1794
1795 if (file == NULL) return(NULL);
1796
1797 ret = xmlAllocParserInputBuffer(enc);
1798 if (ret != NULL) {
1799 ret->context = file;
1800 ret->readcallback = xmlFileRead;
1801 ret->closecallback = xmlFileFlush;
1802 }
1803
1804 return(ret);
1805}
1806
1807/**
1808 * xmlOutputBufferCreateFile:
1809 * @file: a FILE*
1810 * @encoder: the encoding converter or NULL
1811 *
1812 * Create a buffered output for the progressive saving to a FILE *
1813 * buffered C I/O
1814 *
1815 * Returns the new parser output or NULL
1816 */
1817xmlOutputBufferPtr
1818xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
1819 xmlOutputBufferPtr ret;
1820
1821 if (xmlOutputCallbackInitialized == 0)
1822 xmlRegisterDefaultOutputCallbacks();
1823
1824 if (file == NULL) return(NULL);
1825
1826 ret = xmlAllocOutputBuffer(encoder);
1827 if (ret != NULL) {
1828 ret->context = file;
1829 ret->writecallback = xmlFileWrite;
1830 ret->closecallback = xmlFileFlush;
1831 }
1832
1833 return(ret);
1834}
1835
1836/**
1837 * xmlParserInputBufferCreateFd:
1838 * @fd: a file descriptor number
1839 * @enc: the charset encoding if known
1840 *
1841 * Create a buffered parser input for the progressive parsing for the input
1842 * from a file descriptor
1843 *
1844 * Returns the new parser input or NULL
1845 */
1846xmlParserInputBufferPtr
1847xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
1848 xmlParserInputBufferPtr ret;
1849
1850 if (fd < 0) return(NULL);
1851
1852 ret = xmlAllocParserInputBuffer(enc);
1853 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00001854 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00001855 ret->readcallback = xmlFdRead;
1856 ret->closecallback = xmlFdClose;
1857 }
1858
1859 return(ret);
1860}
1861
1862/**
1863 * xmlParserInputBufferCreateMem:
1864 * @mem: the memory input
1865 * @size: the length of the memory block
1866 * @enc: the charset encoding if known
1867 *
1868 * Create a buffered parser input for the progressive parsing for the input
1869 * from a memory area.
1870 *
1871 * Returns the new parser input or NULL
1872 */
1873xmlParserInputBufferPtr
1874xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
1875 xmlParserInputBufferPtr ret;
1876
1877 if (size <= 0) return(NULL);
1878 if (mem == NULL) return(NULL);
1879
1880 ret = xmlAllocParserInputBuffer(enc);
1881 if (ret != NULL) {
1882 ret->context = (void *) mem;
1883 ret->readcallback = (xmlInputReadCallback) xmlNop;
1884 ret->closecallback = NULL;
1885 xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size);
1886 }
1887
1888 return(ret);
1889}
1890
1891/**
1892 * xmlOutputBufferCreateFd:
1893 * @fd: a file descriptor number
1894 * @encoder: the encoding converter or NULL
1895 *
1896 * Create a buffered output for the progressive saving
1897 * to a file descriptor
1898 *
1899 * Returns the new parser output or NULL
1900 */
1901xmlOutputBufferPtr
1902xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
1903 xmlOutputBufferPtr ret;
1904
1905 if (fd < 0) return(NULL);
1906
1907 ret = xmlAllocOutputBuffer(encoder);
1908 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00001909 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00001910 ret->writecallback = xmlFdWrite;
1911 ret->closecallback = xmlFdClose;
1912 }
1913
1914 return(ret);
1915}
1916
1917/**
1918 * xmlParserInputBufferCreateIO:
1919 * @ioread: an I/O read function
1920 * @ioclose: an I/O close function
1921 * @ioctx: an I/O handler
1922 * @enc: the charset encoding if known
1923 *
1924 * Create a buffered parser input for the progressive parsing for the input
1925 * from an I/O handler
1926 *
1927 * Returns the new parser input or NULL
1928 */
1929xmlParserInputBufferPtr
1930xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
1931 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
1932 xmlParserInputBufferPtr ret;
1933
1934 if (ioread == NULL) return(NULL);
1935
1936 ret = xmlAllocParserInputBuffer(enc);
1937 if (ret != NULL) {
1938 ret->context = (void *) ioctx;
1939 ret->readcallback = ioread;
1940 ret->closecallback = ioclose;
1941 }
1942
1943 return(ret);
1944}
1945
1946/**
1947 * xmlOutputBufferCreateIO:
1948 * @iowrite: an I/O write function
1949 * @ioclose: an I/O close function
1950 * @ioctx: an I/O handler
1951 * @enc: the charset encoding if known
1952 *
1953 * Create a buffered output for the progressive saving
1954 * to an I/O handler
1955 *
1956 * Returns the new parser output or NULL
1957 */
1958xmlOutputBufferPtr
1959xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
1960 xmlOutputCloseCallback ioclose, void *ioctx,
1961 xmlCharEncodingHandlerPtr encoder) {
1962 xmlOutputBufferPtr ret;
1963
1964 if (iowrite == NULL) return(NULL);
1965
1966 ret = xmlAllocOutputBuffer(encoder);
1967 if (ret != NULL) {
1968 ret->context = (void *) ioctx;
1969 ret->writecallback = iowrite;
1970 ret->closecallback = ioclose;
1971 }
1972
1973 return(ret);
1974}
1975
1976/**
1977 * xmlParserInputBufferPush:
1978 * @in: a buffered parser input
1979 * @len: the size in bytes of the array.
1980 * @buf: an char array
1981 *
1982 * Push the content of the arry in the input buffer
1983 * This routine handle the I18N transcoding to internal UTF-8
1984 * This is used when operating the parser in progressive (push) mode.
1985 *
1986 * Returns the number of chars read and stored in the buffer, or -1
1987 * in case of error.
1988 */
1989int
1990xmlParserInputBufferPush(xmlParserInputBufferPtr in,
1991 int len, const char *buf) {
1992 int nbchars = 0;
1993
1994 if (len < 0) return(0);
1995 if (in->encoder != NULL) {
1996 /*
1997 * Store the data in the incoming raw buffer
1998 */
1999 if (in->raw == NULL) {
2000 in->raw = xmlBufferCreate();
2001 }
2002 xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
2003
2004 /*
2005 * convert as much as possible to the parser reading buffer.
2006 */
2007 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2008 if (nbchars < 0) {
2009 xmlGenericError(xmlGenericErrorContext,
2010 "xmlParserInputBufferPush: encoder error\n");
2011 return(-1);
2012 }
2013 } else {
2014 nbchars = len;
2015 xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
2016 }
2017#ifdef DEBUG_INPUT
2018 xmlGenericError(xmlGenericErrorContext,
2019 "I/O: pushed %d chars, buffer %d/%d\n",
2020 nbchars, in->buffer->use, in->buffer->size);
2021#endif
2022 return(nbchars);
2023}
2024
2025/**
2026 * xmlParserInputBufferGrow:
2027 * @in: a buffered parser input
2028 * @len: indicative value of the amount of chars to read
2029 *
2030 * Grow up the content of the input buffer, the old data are preserved
2031 * This routine handle the I18N transcoding to internal UTF-8
2032 * This routine is used when operating the parser in normal (pull) mode
2033 *
2034 * TODO: one should be able to remove one extra copy by copying directy
2035 * onto in->buffer or in->raw
2036 *
2037 * Returns the number of chars read and stored in the buffer, or -1
2038 * in case of error.
2039 */
2040int
2041xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
2042 char *buffer = NULL;
2043 int res = 0;
2044 int nbchars = 0;
2045 int buffree;
2046
2047 if ((len <= MINLEN) && (len != 4))
2048 len = MINLEN;
2049 buffree = in->buffer->size - in->buffer->use;
2050 if (buffree <= 0) {
2051 xmlGenericError(xmlGenericErrorContext,
2052 "xmlParserInputBufferGrow : buffer full !\n");
2053 return(0);
2054 }
2055 if (len > buffree)
2056 len = buffree;
2057
2058 buffer = (char *) xmlMalloc((len + 1) * sizeof(char));
2059 if (buffer == NULL) {
2060 xmlGenericError(xmlGenericErrorContext,
2061 "xmlParserInputBufferGrow : out of memory !\n");
2062 return(-1);
2063 }
2064
2065 /*
2066 * Call the read method for this I/O type.
2067 */
2068 if (in->readcallback != NULL) {
2069 res = in->readcallback(in->context, &buffer[0], len);
2070 } else {
2071 xmlGenericError(xmlGenericErrorContext,
2072 "xmlParserInputBufferGrow : no input !\n");
2073 xmlFree(buffer);
2074 return(-1);
2075 }
2076 if (res < 0) {
2077 perror ("read error");
2078 xmlFree(buffer);
2079 return(-1);
2080 }
2081 len = res;
2082 if (in->encoder != NULL) {
2083 /*
2084 * Store the data in the incoming raw buffer
2085 */
2086 if (in->raw == NULL) {
2087 in->raw = xmlBufferCreate();
2088 }
2089 xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
2090
2091 /*
2092 * convert as much as possible to the parser reading buffer.
2093 */
2094 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2095 if (nbchars < 0) {
2096 xmlGenericError(xmlGenericErrorContext,
2097 "xmlParserInputBufferGrow: encoder error\n");
2098 return(-1);
2099 }
2100 } else {
2101 nbchars = len;
2102 buffer[nbchars] = 0;
2103 xmlBufferAdd(in->buffer, (xmlChar *) buffer, nbchars);
2104 }
2105#ifdef DEBUG_INPUT
2106 xmlGenericError(xmlGenericErrorContext,
2107 "I/O: read %d chars, buffer %d/%d\n",
2108 nbchars, in->buffer->use, in->buffer->size);
2109#endif
2110 xmlFree(buffer);
2111 return(nbchars);
2112}
2113
2114/**
2115 * xmlParserInputBufferRead:
2116 * @in: a buffered parser input
2117 * @len: indicative value of the amount of chars to read
2118 *
2119 * Refresh the content of the input buffer, the old data are considered
2120 * consumed
2121 * This routine handle the I18N transcoding to internal UTF-8
2122 *
2123 * Returns the number of chars read and stored in the buffer, or -1
2124 * in case of error.
2125 */
2126int
2127xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
2128 /* xmlBufferEmpty(in->buffer); */
2129 if (in->readcallback != NULL)
2130 return(xmlParserInputBufferGrow(in, len));
2131 else
2132 return(-1);
2133}
2134
2135/**
2136 * xmlOutputBufferWrite:
2137 * @out: a buffered parser output
2138 * @len: the size in bytes of the array.
2139 * @buf: an char array
2140 *
2141 * Write the content of the array in the output I/O buffer
2142 * This routine handle the I18N transcoding from internal UTF-8
2143 * The buffer is lossless, i.e. will store in case of partial
2144 * or delayed writes.
2145 *
2146 * Returns the number of chars immediately written, or -1
2147 * in case of error.
2148 */
2149int
2150xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
2151 int nbchars = 0; /* number of chars to output to I/O */
2152 int ret; /* return from function call */
2153 int written = 0; /* number of char written to I/O so far */
2154 int chunk; /* number of byte curreent processed from buf */
2155
2156 if (len < 0) return(0);
2157
2158 do {
2159 chunk = len;
2160 if (chunk > 4 * MINLEN)
2161 chunk = 4 * MINLEN;
2162
2163 /*
2164 * first handle encoding stuff.
2165 */
2166 if (out->encoder != NULL) {
2167 /*
2168 * Store the data in the incoming raw buffer
2169 */
2170 if (out->conv == NULL) {
2171 out->conv = xmlBufferCreate();
2172 }
2173 xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2174
2175 if ((out->buffer->use < MINLEN) && (chunk == len))
2176 goto done;
2177
2178 /*
2179 * convert as much as possible to the parser reading buffer.
2180 */
2181 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
2182 if (ret < 0) {
2183 xmlGenericError(xmlGenericErrorContext,
2184 "xmlOutputBufferWrite: encoder error\n");
2185 return(-1);
2186 }
2187 nbchars = out->conv->use;
2188 } else {
2189 xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2190 nbchars = out->buffer->use;
2191 }
2192 buf += chunk;
2193 len -= chunk;
2194
2195 if ((nbchars < MINLEN) && (len <= 0))
2196 goto done;
2197
2198 if (out->writecallback) {
2199 /*
2200 * second write the stuff to the I/O channel
2201 */
2202 if (out->encoder != NULL) {
2203 ret = out->writecallback(out->context,
2204 (const char *)out->conv->content, nbchars);
2205 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002206 xmlBufferShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002207 } else {
2208 ret = out->writecallback(out->context,
2209 (const char *)out->buffer->content, nbchars);
2210 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002211 xmlBufferShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002212 }
2213 if (ret < 0) {
2214 xmlGenericError(xmlGenericErrorContext,
2215 "I/O: error %d writing %d bytes\n", ret, nbchars);
2216 return(ret);
2217 }
2218 out->written += ret;
2219 }
2220 written += nbchars;
2221 } while (len > 0);
2222
2223done:
2224#ifdef DEBUG_INPUT
2225 xmlGenericError(xmlGenericErrorContext,
2226 "I/O: wrote %d chars\n", written);
2227#endif
2228 return(written);
2229}
2230
2231/**
2232 * xmlOutputBufferWriteString:
2233 * @out: a buffered parser output
2234 * @str: a zero terminated C string
2235 *
2236 * Write the content of the string in the output I/O buffer
2237 * This routine handle the I18N transcoding from internal UTF-8
2238 * The buffer is lossless, i.e. will store in case of partial
2239 * or delayed writes.
2240 *
2241 * Returns the number of chars immediately written, or -1
2242 * in case of error.
2243 */
2244int
2245xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
2246 int len;
2247
2248 if (str == NULL)
2249 return(-1);
2250 len = strlen(str);
2251
2252 if (len > 0)
2253 return(xmlOutputBufferWrite(out, len, str));
2254 return(len);
2255}
2256
2257/**
2258 * xmlOutputBufferFlush:
2259 * @out: a buffered output
2260 *
2261 * flushes the output I/O channel
2262 *
2263 * Returns the number of byte written or -1 in case of error.
2264 */
2265int
2266xmlOutputBufferFlush(xmlOutputBufferPtr out) {
2267 int nbchars = 0, ret = 0;
2268
2269 /*
2270 * first handle encoding stuff.
2271 */
2272 if ((out->conv != NULL) && (out->encoder != NULL)) {
2273 /*
2274 * convert as much as possible to the parser reading buffer.
2275 */
2276 nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
2277 if (nbchars < 0) {
2278 xmlGenericError(xmlGenericErrorContext,
2279 "xmlOutputBufferWrite: encoder error\n");
2280 return(-1);
2281 }
2282 }
2283
2284 /*
2285 * second flush the stuff to the I/O channel
2286 */
2287 if ((out->conv != NULL) && (out->encoder != NULL) &&
2288 (out->writecallback != NULL)) {
2289 ret = out->writecallback(out->context,
2290 (const char *)out->conv->content, out->conv->use);
2291 if (ret >= 0)
2292 xmlBufferShrink(out->conv, ret);
2293 } else if (out->writecallback != NULL) {
2294 ret = out->writecallback(out->context,
2295 (const char *)out->buffer->content, out->buffer->use);
2296 if (ret >= 0)
2297 xmlBufferShrink(out->buffer, ret);
2298 }
2299 if (ret < 0) {
2300 xmlGenericError(xmlGenericErrorContext,
2301 "I/O: error %d flushing %d bytes\n", ret, nbchars);
2302 return(ret);
2303 }
2304 out->written += ret;
2305
2306#ifdef DEBUG_INPUT
2307 xmlGenericError(xmlGenericErrorContext,
2308 "I/O: flushed %d chars\n", ret);
2309#endif
2310 return(ret);
2311}
2312
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002313/**
Owen Taylor3473f882001-02-23 17:55:21 +00002314 * xmlParserGetDirectory:
2315 * @filename: the path to a file
2316 *
2317 * lookup the directory for that file
2318 *
2319 * Returns a new allocated string containing the directory, or NULL.
2320 */
2321char *
2322xmlParserGetDirectory(const char *filename) {
2323 char *ret = NULL;
2324 char dir[1024];
2325 char *cur;
2326 char sep = '/';
2327
2328 if (xmlInputCallbackInitialized == 0)
2329 xmlRegisterDefaultInputCallbacks();
2330
2331 if (filename == NULL) return(NULL);
2332#ifdef WIN32
2333 sep = '\\';
2334#endif
2335
2336 strncpy(dir, filename, 1023);
2337 dir[1023] = 0;
2338 cur = &dir[strlen(dir)];
2339 while (cur > dir) {
2340 if (*cur == sep) break;
2341 cur --;
2342 }
2343 if (*cur == sep) {
2344 if (cur == dir) dir[1] = 0;
2345 else *cur = 0;
2346 ret = xmlMemStrdup(dir);
2347 } else {
2348 if (getcwd(dir, 1024) != NULL) {
2349 dir[1023] = 0;
2350 ret = xmlMemStrdup(dir);
2351 }
2352 }
2353 return(ret);
2354}
2355
2356/****************************************************************
2357 * *
2358 * External entities loading *
2359 * *
2360 ****************************************************************/
2361
Daniel Veillard6990bf32001-08-23 21:17:48 +00002362#ifdef LIBXML_CATALOG_ENABLED
2363static int xmlSysIDExists(const char *URL) {
2364#ifdef HAVE_STAT
2365 int ret;
2366 struct stat info;
2367 const char *path;
2368
2369 if (URL == NULL)
2370 return(0);
2371
2372 if (!strncmp(URL, "file://localhost", 16))
2373 path = &URL[16];
2374 else if (!strncmp(URL, "file:///", 8)) {
2375#ifdef _WIN32
2376 path = &URL[8];
2377#else
2378 path = &URL[7];
2379#endif
2380 } else
2381 path = URL;
2382 ret = stat(path, &info);
2383 if (ret == 0)
2384 return(1);
2385#endif
2386 return(0);
2387}
2388#endif
2389
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002390/**
Owen Taylor3473f882001-02-23 17:55:21 +00002391 * xmlDefaultExternalEntityLoader:
2392 * @URL: the URL for the entity to load
2393 * @ID: the System ID for the entity to load
2394 * @ctxt: the context in which the entity is called or NULL
2395 *
2396 * By default we don't load external entitites, yet.
2397 *
2398 * Returns a new allocated xmlParserInputPtr, or NULL.
2399 */
2400static
2401xmlParserInputPtr
2402xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
2403 xmlParserCtxtPtr ctxt) {
2404 xmlParserInputPtr ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002405 xmlChar *resource = NULL;
2406#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002407 xmlCatalogAllow pref;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002408#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002409
2410#ifdef DEBUG_EXTERNAL_ENTITIES
2411 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf012a642001-07-23 19:10:52 +00002412 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00002413#endif
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002414#ifdef LIBXML_CATALOG_ENABLED
2415 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002416 * If the resource doesn't exists as a file,
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002417 * try to load it from the resource pointed in the catalogs
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002418 */
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002419 pref = xmlCatalogGetDefaults();
2420
Daniel Veillard6990bf32001-08-23 21:17:48 +00002421 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlSysIDExists(URL))) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002422 /*
2423 * Do a local lookup
2424 */
2425 if ((ctxt->catalogs != NULL) &&
2426 ((pref == XML_CATA_ALLOW_ALL) ||
2427 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2428 resource = xmlCatalogLocalResolve(ctxt->catalogs,
2429 (const xmlChar *)ID,
2430 (const xmlChar *)URL);
2431 }
2432 /*
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002433 * Try a global lookup
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002434 */
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002435 if ((resource == NULL) &&
2436 ((pref == XML_CATA_ALLOW_ALL) ||
2437 (pref == XML_CATA_ALLOW_GLOBAL))) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002438 resource = xmlCatalogResolve((const xmlChar *)ID,
2439 (const xmlChar *)URL);
2440 }
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002441 if ((resource == NULL) && (URL != NULL))
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00002442 resource = xmlStrdup((const xmlChar *) URL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002443
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002444 /*
2445 * TODO: do an URI lookup on the reference
2446 */
Daniel Veillard6990bf32001-08-23 21:17:48 +00002447 if ((resource != NULL) && (!xmlSysIDExists((const char *)resource))) {
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002448 xmlChar *tmp = NULL;
2449
2450 if ((ctxt->catalogs != NULL) &&
2451 ((pref == XML_CATA_ALLOW_ALL) ||
2452 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2453 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
2454 }
2455 if ((tmp == NULL) &&
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00002456 ((pref == XML_CATA_ALLOW_ALL) ||
2457 (pref == XML_CATA_ALLOW_GLOBAL))) {
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002458 tmp = xmlCatalogResolveURI(resource);
2459 }
2460
2461 if (tmp != NULL) {
2462 xmlFree(resource);
2463 resource = tmp;
2464 }
2465 }
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002466 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002467#endif
2468
2469 if (resource == NULL)
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002470 resource = (xmlChar *) URL;
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002471
2472 if (resource == NULL) {
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002473 if ((ctxt->validate) && (ctxt->sax != NULL) &&
2474 (ctxt->sax->error != NULL))
2475 ctxt->sax->error(ctxt,
2476 "failed to load external entity \"%s\"\n", ID);
2477 else if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00002478 ctxt->sax->warning(ctxt,
2479 "failed to load external entity \"%s\"\n", ID);
2480 return(NULL);
2481 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002482 ret = xmlNewInputFromFile(ctxt, (const char *)resource);
Owen Taylor3473f882001-02-23 17:55:21 +00002483 if (ret == NULL) {
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002484 if ((ctxt->validate) && (ctxt->sax != NULL) &&
2485 (ctxt->sax->error != NULL))
2486 ctxt->sax->error(ctxt,
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002487 "failed to load external entity \"%s\"\n", resource);
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002488 else if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00002489 ctxt->sax->warning(ctxt,
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002490 "failed to load external entity \"%s\"\n", resource);
Owen Taylor3473f882001-02-23 17:55:21 +00002491 }
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002492 if ((resource != NULL) && (resource != (xmlChar *) URL))
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002493 xmlFree(resource);
Owen Taylor3473f882001-02-23 17:55:21 +00002494 return(ret);
2495}
2496
2497static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
2498 xmlDefaultExternalEntityLoader;
2499
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002500/**
Owen Taylor3473f882001-02-23 17:55:21 +00002501 * xmlSetExternalEntityLoader:
2502 * @f: the new entity resolver function
2503 *
2504 * Changes the defaultexternal entity resolver function for the application
2505 */
2506void
2507xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
2508 xmlCurrentExternalEntityLoader = f;
2509}
2510
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002511/**
Owen Taylor3473f882001-02-23 17:55:21 +00002512 * xmlGetExternalEntityLoader:
2513 *
2514 * Get the default external entity resolver function for the application
2515 *
2516 * Returns the xmlExternalEntityLoader function pointer
2517 */
2518xmlExternalEntityLoader
2519xmlGetExternalEntityLoader(void) {
2520 return(xmlCurrentExternalEntityLoader);
2521}
2522
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002523/**
Owen Taylor3473f882001-02-23 17:55:21 +00002524 * xmlLoadExternalEntity:
2525 * @URL: the URL for the entity to load
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00002526 * @ID: the Public ID for the entity to load
Owen Taylor3473f882001-02-23 17:55:21 +00002527 * @ctxt: the context in which the entity is called or NULL
2528 *
2529 * Load an external entity, note that the use of this function for
2530 * unparsed entities may generate problems
2531 * TODO: a more generic External entitiy API must be designed
2532 *
2533 * Returns the xmlParserInputPtr or NULL
2534 */
2535xmlParserInputPtr
2536xmlLoadExternalEntity(const char *URL, const char *ID,
2537 xmlParserCtxtPtr ctxt) {
2538 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
2539}
2540