blob: b78ccbe738bf5d0cec419bfe333e03863d7bdbb9 [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 Veillardf012a642001-07-23 19:10:52 +00006 * Daniel.Veillard@w3.org
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;
1666 int i;
1667 void *context = NULL;
1668
Daniel Veillardf012a642001-07-23 19:10:52 +00001669 int is_http_uri = 0; /* Can't change if HTTP disabled */
1670
Owen Taylor3473f882001-02-23 17:55:21 +00001671 if (xmlOutputCallbackInitialized == 0)
1672 xmlRegisterDefaultOutputCallbacks();
1673
1674 if (URI == NULL) return(NULL);
1675
Daniel Veillardf012a642001-07-23 19:10:52 +00001676#ifdef LIBXML_HTTP_ENABLED
1677 /* Need to prevent HTTP URI's from falling into zlib short circuit */
1678
1679 is_http_uri = xmlIOHTTPMatch( URI );
1680#endif
1681
Owen Taylor3473f882001-02-23 17:55:21 +00001682#ifdef HAVE_ZLIB_H
Daniel Veillardf012a642001-07-23 19:10:52 +00001683 if ((compression > 0) && (compression <= 9) && (is_http_uri == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001684 context = xmlGzfileOpenW(URI, compression);
1685 if (context != NULL) {
1686 ret = xmlAllocOutputBuffer(encoder);
1687 if (ret != NULL) {
1688 ret->context = context;
1689 ret->writecallback = xmlGzfileWrite;
1690 ret->closecallback = xmlGzfileClose;
1691 }
1692 return(ret);
1693 }
1694 }
1695#endif
1696
1697 /*
Daniel Veillardf012a642001-07-23 19:10:52 +00001698 * Try to find one of the output accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00001699 * Go in reverse to give precedence to user defined handlers.
1700 */
1701 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
1702 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
1703 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001704
1705#if ( defined( LIBXML_HTTP_ENABLED ) && defined( HAVE_ZLIB_H ) )
1706 /* Need to pass compression parameter into HTTP open calls */
1707
1708 if ( xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch )
1709 context = xmlIOHTTPOpenW( URI, compression );
1710 else
1711#endif
1712 context = xmlOutputCallbackTable[i].opencallback(URI);
1713
Owen Taylor3473f882001-02-23 17:55:21 +00001714 if (context != NULL)
1715 break;
1716 }
1717 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001718
Owen Taylor3473f882001-02-23 17:55:21 +00001719 if (context == NULL) {
1720 return(NULL);
1721 }
1722
1723 /*
1724 * Allocate the Output buffer front-end.
1725 */
1726 ret = xmlAllocOutputBuffer(encoder);
1727 if (ret != NULL) {
1728 ret->context = context;
1729 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
1730 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
1731 }
1732 return(ret);
1733}
1734
1735/**
1736 * xmlParserInputBufferCreateFile:
1737 * @file: a FILE*
1738 * @enc: the charset encoding if known
1739 *
1740 * Create a buffered parser input for the progressive parsing of a FILE *
1741 * buffered C I/O
1742 *
1743 * Returns the new parser input or NULL
1744 */
1745xmlParserInputBufferPtr
1746xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
1747 xmlParserInputBufferPtr ret;
1748
1749 if (xmlInputCallbackInitialized == 0)
1750 xmlRegisterDefaultInputCallbacks();
1751
1752 if (file == NULL) return(NULL);
1753
1754 ret = xmlAllocParserInputBuffer(enc);
1755 if (ret != NULL) {
1756 ret->context = file;
1757 ret->readcallback = xmlFileRead;
1758 ret->closecallback = xmlFileFlush;
1759 }
1760
1761 return(ret);
1762}
1763
1764/**
1765 * xmlOutputBufferCreateFile:
1766 * @file: a FILE*
1767 * @encoder: the encoding converter or NULL
1768 *
1769 * Create a buffered output for the progressive saving to a FILE *
1770 * buffered C I/O
1771 *
1772 * Returns the new parser output or NULL
1773 */
1774xmlOutputBufferPtr
1775xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
1776 xmlOutputBufferPtr ret;
1777
1778 if (xmlOutputCallbackInitialized == 0)
1779 xmlRegisterDefaultOutputCallbacks();
1780
1781 if (file == NULL) return(NULL);
1782
1783 ret = xmlAllocOutputBuffer(encoder);
1784 if (ret != NULL) {
1785 ret->context = file;
1786 ret->writecallback = xmlFileWrite;
1787 ret->closecallback = xmlFileFlush;
1788 }
1789
1790 return(ret);
1791}
1792
1793/**
1794 * xmlParserInputBufferCreateFd:
1795 * @fd: a file descriptor number
1796 * @enc: the charset encoding if known
1797 *
1798 * Create a buffered parser input for the progressive parsing for the input
1799 * from a file descriptor
1800 *
1801 * Returns the new parser input or NULL
1802 */
1803xmlParserInputBufferPtr
1804xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
1805 xmlParserInputBufferPtr ret;
1806
1807 if (fd < 0) return(NULL);
1808
1809 ret = xmlAllocParserInputBuffer(enc);
1810 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00001811 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00001812 ret->readcallback = xmlFdRead;
1813 ret->closecallback = xmlFdClose;
1814 }
1815
1816 return(ret);
1817}
1818
1819/**
1820 * xmlParserInputBufferCreateMem:
1821 * @mem: the memory input
1822 * @size: the length of the memory block
1823 * @enc: the charset encoding if known
1824 *
1825 * Create a buffered parser input for the progressive parsing for the input
1826 * from a memory area.
1827 *
1828 * Returns the new parser input or NULL
1829 */
1830xmlParserInputBufferPtr
1831xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
1832 xmlParserInputBufferPtr ret;
1833
1834 if (size <= 0) return(NULL);
1835 if (mem == NULL) return(NULL);
1836
1837 ret = xmlAllocParserInputBuffer(enc);
1838 if (ret != NULL) {
1839 ret->context = (void *) mem;
1840 ret->readcallback = (xmlInputReadCallback) xmlNop;
1841 ret->closecallback = NULL;
1842 xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size);
1843 }
1844
1845 return(ret);
1846}
1847
1848/**
1849 * xmlOutputBufferCreateFd:
1850 * @fd: a file descriptor number
1851 * @encoder: the encoding converter or NULL
1852 *
1853 * Create a buffered output for the progressive saving
1854 * to a file descriptor
1855 *
1856 * Returns the new parser output or NULL
1857 */
1858xmlOutputBufferPtr
1859xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
1860 xmlOutputBufferPtr ret;
1861
1862 if (fd < 0) return(NULL);
1863
1864 ret = xmlAllocOutputBuffer(encoder);
1865 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00001866 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00001867 ret->writecallback = xmlFdWrite;
1868 ret->closecallback = xmlFdClose;
1869 }
1870
1871 return(ret);
1872}
1873
1874/**
1875 * xmlParserInputBufferCreateIO:
1876 * @ioread: an I/O read function
1877 * @ioclose: an I/O close function
1878 * @ioctx: an I/O handler
1879 * @enc: the charset encoding if known
1880 *
1881 * Create a buffered parser input for the progressive parsing for the input
1882 * from an I/O handler
1883 *
1884 * Returns the new parser input or NULL
1885 */
1886xmlParserInputBufferPtr
1887xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
1888 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
1889 xmlParserInputBufferPtr ret;
1890
1891 if (ioread == NULL) return(NULL);
1892
1893 ret = xmlAllocParserInputBuffer(enc);
1894 if (ret != NULL) {
1895 ret->context = (void *) ioctx;
1896 ret->readcallback = ioread;
1897 ret->closecallback = ioclose;
1898 }
1899
1900 return(ret);
1901}
1902
1903/**
1904 * xmlOutputBufferCreateIO:
1905 * @iowrite: an I/O write function
1906 * @ioclose: an I/O close function
1907 * @ioctx: an I/O handler
1908 * @enc: the charset encoding if known
1909 *
1910 * Create a buffered output for the progressive saving
1911 * to an I/O handler
1912 *
1913 * Returns the new parser output or NULL
1914 */
1915xmlOutputBufferPtr
1916xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
1917 xmlOutputCloseCallback ioclose, void *ioctx,
1918 xmlCharEncodingHandlerPtr encoder) {
1919 xmlOutputBufferPtr ret;
1920
1921 if (iowrite == NULL) return(NULL);
1922
1923 ret = xmlAllocOutputBuffer(encoder);
1924 if (ret != NULL) {
1925 ret->context = (void *) ioctx;
1926 ret->writecallback = iowrite;
1927 ret->closecallback = ioclose;
1928 }
1929
1930 return(ret);
1931}
1932
1933/**
1934 * xmlParserInputBufferPush:
1935 * @in: a buffered parser input
1936 * @len: the size in bytes of the array.
1937 * @buf: an char array
1938 *
1939 * Push the content of the arry in the input buffer
1940 * This routine handle the I18N transcoding to internal UTF-8
1941 * This is used when operating the parser in progressive (push) mode.
1942 *
1943 * Returns the number of chars read and stored in the buffer, or -1
1944 * in case of error.
1945 */
1946int
1947xmlParserInputBufferPush(xmlParserInputBufferPtr in,
1948 int len, const char *buf) {
1949 int nbchars = 0;
1950
1951 if (len < 0) return(0);
1952 if (in->encoder != NULL) {
1953 /*
1954 * Store the data in the incoming raw buffer
1955 */
1956 if (in->raw == NULL) {
1957 in->raw = xmlBufferCreate();
1958 }
1959 xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
1960
1961 /*
1962 * convert as much as possible to the parser reading buffer.
1963 */
1964 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
1965 if (nbchars < 0) {
1966 xmlGenericError(xmlGenericErrorContext,
1967 "xmlParserInputBufferPush: encoder error\n");
1968 return(-1);
1969 }
1970 } else {
1971 nbchars = len;
1972 xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
1973 }
1974#ifdef DEBUG_INPUT
1975 xmlGenericError(xmlGenericErrorContext,
1976 "I/O: pushed %d chars, buffer %d/%d\n",
1977 nbchars, in->buffer->use, in->buffer->size);
1978#endif
1979 return(nbchars);
1980}
1981
1982/**
1983 * xmlParserInputBufferGrow:
1984 * @in: a buffered parser input
1985 * @len: indicative value of the amount of chars to read
1986 *
1987 * Grow up the content of the input buffer, the old data are preserved
1988 * This routine handle the I18N transcoding to internal UTF-8
1989 * This routine is used when operating the parser in normal (pull) mode
1990 *
1991 * TODO: one should be able to remove one extra copy by copying directy
1992 * onto in->buffer or in->raw
1993 *
1994 * Returns the number of chars read and stored in the buffer, or -1
1995 * in case of error.
1996 */
1997int
1998xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
1999 char *buffer = NULL;
2000 int res = 0;
2001 int nbchars = 0;
2002 int buffree;
2003
2004 if ((len <= MINLEN) && (len != 4))
2005 len = MINLEN;
2006 buffree = in->buffer->size - in->buffer->use;
2007 if (buffree <= 0) {
2008 xmlGenericError(xmlGenericErrorContext,
2009 "xmlParserInputBufferGrow : buffer full !\n");
2010 return(0);
2011 }
2012 if (len > buffree)
2013 len = buffree;
2014
2015 buffer = (char *) xmlMalloc((len + 1) * sizeof(char));
2016 if (buffer == NULL) {
2017 xmlGenericError(xmlGenericErrorContext,
2018 "xmlParserInputBufferGrow : out of memory !\n");
2019 return(-1);
2020 }
2021
2022 /*
2023 * Call the read method for this I/O type.
2024 */
2025 if (in->readcallback != NULL) {
2026 res = in->readcallback(in->context, &buffer[0], len);
2027 } else {
2028 xmlGenericError(xmlGenericErrorContext,
2029 "xmlParserInputBufferGrow : no input !\n");
2030 xmlFree(buffer);
2031 return(-1);
2032 }
2033 if (res < 0) {
2034 perror ("read error");
2035 xmlFree(buffer);
2036 return(-1);
2037 }
2038 len = res;
2039 if (in->encoder != NULL) {
2040 /*
2041 * Store the data in the incoming raw buffer
2042 */
2043 if (in->raw == NULL) {
2044 in->raw = xmlBufferCreate();
2045 }
2046 xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
2047
2048 /*
2049 * convert as much as possible to the parser reading buffer.
2050 */
2051 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2052 if (nbchars < 0) {
2053 xmlGenericError(xmlGenericErrorContext,
2054 "xmlParserInputBufferGrow: encoder error\n");
2055 return(-1);
2056 }
2057 } else {
2058 nbchars = len;
2059 buffer[nbchars] = 0;
2060 xmlBufferAdd(in->buffer, (xmlChar *) buffer, nbchars);
2061 }
2062#ifdef DEBUG_INPUT
2063 xmlGenericError(xmlGenericErrorContext,
2064 "I/O: read %d chars, buffer %d/%d\n",
2065 nbchars, in->buffer->use, in->buffer->size);
2066#endif
2067 xmlFree(buffer);
2068 return(nbchars);
2069}
2070
2071/**
2072 * xmlParserInputBufferRead:
2073 * @in: a buffered parser input
2074 * @len: indicative value of the amount of chars to read
2075 *
2076 * Refresh the content of the input buffer, the old data are considered
2077 * consumed
2078 * This routine handle the I18N transcoding to internal UTF-8
2079 *
2080 * Returns the number of chars read and stored in the buffer, or -1
2081 * in case of error.
2082 */
2083int
2084xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
2085 /* xmlBufferEmpty(in->buffer); */
2086 if (in->readcallback != NULL)
2087 return(xmlParserInputBufferGrow(in, len));
2088 else
2089 return(-1);
2090}
2091
2092/**
2093 * xmlOutputBufferWrite:
2094 * @out: a buffered parser output
2095 * @len: the size in bytes of the array.
2096 * @buf: an char array
2097 *
2098 * Write the content of the array in the output I/O buffer
2099 * This routine handle the I18N transcoding from internal UTF-8
2100 * The buffer is lossless, i.e. will store in case of partial
2101 * or delayed writes.
2102 *
2103 * Returns the number of chars immediately written, or -1
2104 * in case of error.
2105 */
2106int
2107xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
2108 int nbchars = 0; /* number of chars to output to I/O */
2109 int ret; /* return from function call */
2110 int written = 0; /* number of char written to I/O so far */
2111 int chunk; /* number of byte curreent processed from buf */
2112
2113 if (len < 0) return(0);
2114
2115 do {
2116 chunk = len;
2117 if (chunk > 4 * MINLEN)
2118 chunk = 4 * MINLEN;
2119
2120 /*
2121 * first handle encoding stuff.
2122 */
2123 if (out->encoder != NULL) {
2124 /*
2125 * Store the data in the incoming raw buffer
2126 */
2127 if (out->conv == NULL) {
2128 out->conv = xmlBufferCreate();
2129 }
2130 xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2131
2132 if ((out->buffer->use < MINLEN) && (chunk == len))
2133 goto done;
2134
2135 /*
2136 * convert as much as possible to the parser reading buffer.
2137 */
2138 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
2139 if (ret < 0) {
2140 xmlGenericError(xmlGenericErrorContext,
2141 "xmlOutputBufferWrite: encoder error\n");
2142 return(-1);
2143 }
2144 nbchars = out->conv->use;
2145 } else {
2146 xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2147 nbchars = out->buffer->use;
2148 }
2149 buf += chunk;
2150 len -= chunk;
2151
2152 if ((nbchars < MINLEN) && (len <= 0))
2153 goto done;
2154
2155 if (out->writecallback) {
2156 /*
2157 * second write the stuff to the I/O channel
2158 */
2159 if (out->encoder != NULL) {
2160 ret = out->writecallback(out->context,
2161 (const char *)out->conv->content, nbchars);
2162 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002163 xmlBufferShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002164 } else {
2165 ret = out->writecallback(out->context,
2166 (const char *)out->buffer->content, nbchars);
2167 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002168 xmlBufferShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002169 }
2170 if (ret < 0) {
2171 xmlGenericError(xmlGenericErrorContext,
2172 "I/O: error %d writing %d bytes\n", ret, nbchars);
2173 return(ret);
2174 }
2175 out->written += ret;
2176 }
2177 written += nbchars;
2178 } while (len > 0);
2179
2180done:
2181#ifdef DEBUG_INPUT
2182 xmlGenericError(xmlGenericErrorContext,
2183 "I/O: wrote %d chars\n", written);
2184#endif
2185 return(written);
2186}
2187
2188/**
2189 * xmlOutputBufferWriteString:
2190 * @out: a buffered parser output
2191 * @str: a zero terminated C string
2192 *
2193 * Write the content of the string in the output I/O buffer
2194 * This routine handle the I18N transcoding from internal UTF-8
2195 * The buffer is lossless, i.e. will store in case of partial
2196 * or delayed writes.
2197 *
2198 * Returns the number of chars immediately written, or -1
2199 * in case of error.
2200 */
2201int
2202xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
2203 int len;
2204
2205 if (str == NULL)
2206 return(-1);
2207 len = strlen(str);
2208
2209 if (len > 0)
2210 return(xmlOutputBufferWrite(out, len, str));
2211 return(len);
2212}
2213
2214/**
2215 * xmlOutputBufferFlush:
2216 * @out: a buffered output
2217 *
2218 * flushes the output I/O channel
2219 *
2220 * Returns the number of byte written or -1 in case of error.
2221 */
2222int
2223xmlOutputBufferFlush(xmlOutputBufferPtr out) {
2224 int nbchars = 0, ret = 0;
2225
2226 /*
2227 * first handle encoding stuff.
2228 */
2229 if ((out->conv != NULL) && (out->encoder != NULL)) {
2230 /*
2231 * convert as much as possible to the parser reading buffer.
2232 */
2233 nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
2234 if (nbchars < 0) {
2235 xmlGenericError(xmlGenericErrorContext,
2236 "xmlOutputBufferWrite: encoder error\n");
2237 return(-1);
2238 }
2239 }
2240
2241 /*
2242 * second flush the stuff to the I/O channel
2243 */
2244 if ((out->conv != NULL) && (out->encoder != NULL) &&
2245 (out->writecallback != NULL)) {
2246 ret = out->writecallback(out->context,
2247 (const char *)out->conv->content, out->conv->use);
2248 if (ret >= 0)
2249 xmlBufferShrink(out->conv, ret);
2250 } else if (out->writecallback != NULL) {
2251 ret = out->writecallback(out->context,
2252 (const char *)out->buffer->content, out->buffer->use);
2253 if (ret >= 0)
2254 xmlBufferShrink(out->buffer, ret);
2255 }
2256 if (ret < 0) {
2257 xmlGenericError(xmlGenericErrorContext,
2258 "I/O: error %d flushing %d bytes\n", ret, nbchars);
2259 return(ret);
2260 }
2261 out->written += ret;
2262
2263#ifdef DEBUG_INPUT
2264 xmlGenericError(xmlGenericErrorContext,
2265 "I/O: flushed %d chars\n", ret);
2266#endif
2267 return(ret);
2268}
2269
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002270/**
Owen Taylor3473f882001-02-23 17:55:21 +00002271 * xmlParserGetDirectory:
2272 * @filename: the path to a file
2273 *
2274 * lookup the directory for that file
2275 *
2276 * Returns a new allocated string containing the directory, or NULL.
2277 */
2278char *
2279xmlParserGetDirectory(const char *filename) {
2280 char *ret = NULL;
2281 char dir[1024];
2282 char *cur;
2283 char sep = '/';
2284
2285 if (xmlInputCallbackInitialized == 0)
2286 xmlRegisterDefaultInputCallbacks();
2287
2288 if (filename == NULL) return(NULL);
2289#ifdef WIN32
2290 sep = '\\';
2291#endif
2292
2293 strncpy(dir, filename, 1023);
2294 dir[1023] = 0;
2295 cur = &dir[strlen(dir)];
2296 while (cur > dir) {
2297 if (*cur == sep) break;
2298 cur --;
2299 }
2300 if (*cur == sep) {
2301 if (cur == dir) dir[1] = 0;
2302 else *cur = 0;
2303 ret = xmlMemStrdup(dir);
2304 } else {
2305 if (getcwd(dir, 1024) != NULL) {
2306 dir[1023] = 0;
2307 ret = xmlMemStrdup(dir);
2308 }
2309 }
2310 return(ret);
2311}
2312
2313/****************************************************************
2314 * *
2315 * External entities loading *
2316 * *
2317 ****************************************************************/
2318
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002319/**
Owen Taylor3473f882001-02-23 17:55:21 +00002320 * xmlDefaultExternalEntityLoader:
2321 * @URL: the URL for the entity to load
2322 * @ID: the System ID for the entity to load
2323 * @ctxt: the context in which the entity is called or NULL
2324 *
2325 * By default we don't load external entitites, yet.
2326 *
2327 * Returns a new allocated xmlParserInputPtr, or NULL.
2328 */
2329static
2330xmlParserInputPtr
2331xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
2332 xmlParserCtxtPtr ctxt) {
2333 xmlParserInputPtr ret = NULL;
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002334 const xmlChar *resource = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002335
2336#ifdef DEBUG_EXTERNAL_ENTITIES
2337 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf012a642001-07-23 19:10:52 +00002338 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00002339#endif
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002340#ifdef LIBXML_CATALOG_ENABLED
2341 /*
2342 * Try to load it from the resource pointed in the catalog
2343 */
2344 if (ID != NULL)
2345 resource = xmlCatalogGetPublic((const xmlChar *)ID);
2346 if ((resource == NULL) && (URL != NULL))
2347 resource = xmlCatalogGetSystem((const xmlChar *)URL);
2348#endif
2349
2350 if (resource == NULL)
2351 resource = (const xmlChar *)URL;
2352
2353 if (resource == NULL) {
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002354 if ((ctxt->validate) && (ctxt->sax != NULL) &&
2355 (ctxt->sax->error != NULL))
2356 ctxt->sax->error(ctxt,
2357 "failed to load external entity \"%s\"\n", ID);
2358 else if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00002359 ctxt->sax->warning(ctxt,
2360 "failed to load external entity \"%s\"\n", ID);
2361 return(NULL);
2362 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002363 ret = xmlNewInputFromFile(ctxt, (const char *)resource);
Owen Taylor3473f882001-02-23 17:55:21 +00002364 if (ret == NULL) {
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002365 if ((ctxt->validate) && (ctxt->sax != NULL) &&
2366 (ctxt->sax->error != NULL))
2367 ctxt->sax->error(ctxt,
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002368 "failed to load external entity \"%s\"\n", resource);
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002369 else if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00002370 ctxt->sax->warning(ctxt,
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002371 "failed to load external entity \"%s\"\n", resource);
Owen Taylor3473f882001-02-23 17:55:21 +00002372 }
2373 return(ret);
2374}
2375
2376static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
2377 xmlDefaultExternalEntityLoader;
2378
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002379/**
Owen Taylor3473f882001-02-23 17:55:21 +00002380 * xmlSetExternalEntityLoader:
2381 * @f: the new entity resolver function
2382 *
2383 * Changes the defaultexternal entity resolver function for the application
2384 */
2385void
2386xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
2387 xmlCurrentExternalEntityLoader = f;
2388}
2389
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002390/**
Owen Taylor3473f882001-02-23 17:55:21 +00002391 * xmlGetExternalEntityLoader:
2392 *
2393 * Get the default external entity resolver function for the application
2394 *
2395 * Returns the xmlExternalEntityLoader function pointer
2396 */
2397xmlExternalEntityLoader
2398xmlGetExternalEntityLoader(void) {
2399 return(xmlCurrentExternalEntityLoader);
2400}
2401
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002402/**
Owen Taylor3473f882001-02-23 17:55:21 +00002403 * xmlLoadExternalEntity:
2404 * @URL: the URL for the entity to load
2405 * @ID: the System ID for the entity to load
2406 * @ctxt: the context in which the entity is called or NULL
2407 *
2408 * Load an external entity, note that the use of this function for
2409 * unparsed entities may generate problems
2410 * TODO: a more generic External entitiy API must be designed
2411 *
2412 * Returns the xmlParserInputPtr or NULL
2413 */
2414xmlParserInputPtr
2415xmlLoadExternalEntity(const char *URL, const char *ID,
2416 xmlParserCtxtPtr ctxt) {
2417 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
2418}
2419