blob: c21a168e36c8fb1fdf429f6cbdff9451ae691117 [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];
247 else if (!strncmp(filename, "file:///", 8))
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000248 path = &filename[7];
Owen Taylor3473f882001-02-23 17:55:21 +0000249 else
250 path = filename;
251
252 if (path == NULL)
253 return(NULL);
254 if (!xmlCheckFilename(path))
255 return(NULL);
256
257#ifdef WIN32
258 fd = fopen(path, "rb");
259#else
260 fd = fopen(path, "r");
261#endif /* WIN32 */
262 return((void *) fd);
263}
264
265/**
266 * xmlFileOpenW:
267 * @filename: the URI for matching
268 *
269 * output to from FILE *,
270 * if @filename is "-" then the standard output is used
271 *
272 * Returns an I/O context or NULL in case of error
273 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000274static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000275xmlFileOpenW (const char *filename) {
276 const char *path = NULL;
277 FILE *fd;
278
279 if (!strcmp(filename, "-")) {
280 fd = stdout;
281 return((void *) fd);
282 }
283
284 if (!strncmp(filename, "file://localhost", 16))
285 path = &filename[16];
286 else if (!strncmp(filename, "file:///", 8))
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000287 path = &filename[7];
Owen Taylor3473f882001-02-23 17:55:21 +0000288 else
289 path = filename;
290
291 if (path == NULL)
292 return(NULL);
293
294 fd = fopen(path, "w");
295 return((void *) fd);
296}
297
298/**
299 * xmlFileRead:
300 * @context: the I/O context
301 * @buffer: where to drop data
302 * @len: number of bytes to write
303 *
304 * Read @len bytes to @buffer from the I/O channel.
305 *
306 * Returns the number of bytes written
307 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000308static int
Owen Taylor3473f882001-02-23 17:55:21 +0000309xmlFileRead (void * context, char * buffer, int len) {
310 return(fread(&buffer[0], 1, len, (FILE *) context));
311}
312
313/**
314 * xmlFileWrite:
315 * @context: the I/O context
316 * @buffer: where to drop data
317 * @len: number of bytes to write
318 *
319 * Write @len bytes from @buffer to the I/O channel.
320 *
321 * Returns the number of bytes written
322 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000323static int
Owen Taylor3473f882001-02-23 17:55:21 +0000324xmlFileWrite (void * context, const char * buffer, int len) {
325 return(fwrite(&buffer[0], 1, len, (FILE *) context));
326}
327
328/**
329 * xmlFileClose:
330 * @context: the I/O context
331 *
332 * Close an I/O channel
333 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000334static int
Owen Taylor3473f882001-02-23 17:55:21 +0000335xmlFileClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +0000336 return ( ( fclose((FILE *) context) == EOF ) ? -1 : 0 );
Owen Taylor3473f882001-02-23 17:55:21 +0000337}
338
339/**
340 * xmlFileFlush:
341 * @context: the I/O context
342 *
343 * Flush an I/O channel
344 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000345static int
Owen Taylor3473f882001-02-23 17:55:21 +0000346xmlFileFlush (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +0000347 return ( ( fflush((FILE *) context) == EOF ) ? -1 : 0 );
Owen Taylor3473f882001-02-23 17:55:21 +0000348}
349
350#ifdef HAVE_ZLIB_H
351/************************************************************************
352 * *
353 * I/O for compressed file accesses *
354 * *
355 ************************************************************************/
356/**
357 * xmlGzfileMatch:
358 * @filename: the URI for matching
359 *
360 * input from compressed file test
361 *
362 * Returns 1 if matches, 0 otherwise
363 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000364static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000365xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000366 return(1);
367}
368
369/**
370 * xmlGzfileOpen:
371 * @filename: the URI for matching
372 *
373 * input from compressed file open
374 * if @filename is " " then the standard input is used
375 *
376 * Returns an I/O context or NULL in case of error
377 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000378static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000379xmlGzfileOpen (const char *filename) {
380 const char *path = NULL;
381 gzFile fd;
382
383 if (!strcmp(filename, "-")) {
384 fd = gzdopen(fileno(stdin), "rb");
385 return((void *) fd);
386 }
387
388 if (!strncmp(filename, "file://localhost", 16))
389 path = &filename[16];
390 else if (!strncmp(filename, "file:///", 8))
391 path = &filename[7];
392 else
393 path = filename;
394
395 if (path == NULL)
396 return(NULL);
397 if (!xmlCheckFilename(path))
398 return(NULL);
399
400 fd = gzopen(path, "rb");
401 return((void *) fd);
402}
403
404/**
405 * xmlGzfileOpenW:
406 * @filename: the URI for matching
407 * @compression: the compression factor (0 - 9 included)
408 *
409 * input from compressed file open
410 * if @filename is " " then the standard input is used
411 *
412 * Returns an I/O context or NULL in case of error
413 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000414static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000415xmlGzfileOpenW (const char *filename, int compression) {
416 const char *path = NULL;
417 char mode[15];
418 gzFile fd;
419
420 sprintf(mode, "wb%d", compression);
421 if (!strcmp(filename, "-")) {
422 fd = gzdopen(1, mode);
423 return((void *) fd);
424 }
425
426 if (!strncmp(filename, "file://localhost", 16))
427 path = &filename[16];
428 else if (!strncmp(filename, "file:///", 8))
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000429 path = &filename[7];
Owen Taylor3473f882001-02-23 17:55:21 +0000430 else
431 path = filename;
432
433 if (path == NULL)
434 return(NULL);
435
436 fd = gzopen(path, mode);
437 return((void *) fd);
438}
439
440/**
441 * xmlGzfileRead:
442 * @context: the I/O context
443 * @buffer: where to drop data
444 * @len: number of bytes to write
445 *
446 * Read @len bytes to @buffer from the compressed I/O channel.
447 *
448 * Returns the number of bytes written
449 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000450static int
Owen Taylor3473f882001-02-23 17:55:21 +0000451xmlGzfileRead (void * context, char * buffer, int len) {
452 return(gzread((gzFile) context, &buffer[0], len));
453}
454
455/**
456 * xmlGzfileWrite:
457 * @context: the I/O context
458 * @buffer: where to drop data
459 * @len: number of bytes to write
460 *
461 * Write @len bytes from @buffer to the compressed I/O channel.
462 *
463 * Returns the number of bytes written
464 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000465static int
Owen Taylor3473f882001-02-23 17:55:21 +0000466xmlGzfileWrite (void * context, const char * buffer, int len) {
467 return(gzwrite((gzFile) context, (char *) &buffer[0], len));
468}
469
470/**
471 * xmlGzfileClose:
472 * @context: the I/O context
473 *
474 * Close a compressed I/O channel
475 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000476static int
Owen Taylor3473f882001-02-23 17:55:21 +0000477xmlGzfileClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +0000478 return ( ( gzclose((gzFile) context) == Z_OK ) ? 0 : -1 );
Owen Taylor3473f882001-02-23 17:55:21 +0000479}
480#endif /* HAVE_ZLIB_H */
481
482#ifdef LIBXML_HTTP_ENABLED
483/************************************************************************
484 * *
485 * I/O for HTTP file accesses *
486 * *
487 ************************************************************************/
Daniel Veillardf012a642001-07-23 19:10:52 +0000488
489typedef struct xmlIOHTTPWriteCtxt_
490{
491 int compression;
492
493 char * uri;
494
495 void * doc_buff;
496
497} xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr;
498
499#ifdef HAVE_ZLIB_H
500
501#define DFLT_WBITS ( -15 )
502#define DFLT_MEM_LVL ( 8 )
503#define GZ_MAGIC1 ( 0x1f )
504#define GZ_MAGIC2 ( 0x8b )
505#define LXML_ZLIB_OS_CODE ( 0x03 )
506#define INIT_HTTP_BUFF_SIZE ( 32768 )
507#define DFLT_ZLIB_RATIO ( 5 )
508
509/*
510** Data structure and functions to work with sending compressed data
511** via HTTP.
512*/
513
514typedef struct xmlZMemBuff_
515{
516 unsigned long size;
517 unsigned long crc;
518
519 unsigned char * zbuff;
520 z_stream zctrl;
521
522} xmlZMemBuff, *xmlZMemBuffPtr;
523
524/**
525 * append_reverse_ulong
526 * @buff: Compressed memory buffer
527 * @data: Unsigned long to append
528 *
529 * Append a unsigned long in reverse byte order to the end of the
530 * memory buffer.
531 */
532static void
533append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) {
534
535 int idx;
536
537 if ( buff == NULL )
538 return;
539
540 /*
541 ** This is plagiarized from putLong in gzio.c (zlib source) where
542 ** the number "4" is hardcoded. If zlib is ever patched to
543 ** support 64 bit file sizes, this code would need to be patched
544 ** as well.
545 */
546
547 for ( idx = 0; idx < 4; idx++ ) {
548 *buff->zctrl.next_out = ( data & 0xff );
549 data >>= 8;
550 buff->zctrl.next_out++;
551 }
552
553 return;
554}
555
556/**
557 *
558 * xmlFreeZMemBuff
559 * @buff: The memory buffer context to clear
560 *
561 * Release all the resources associated with the compressed memory buffer.
562 */
563static void
564xmlFreeZMemBuff( xmlZMemBuffPtr buff ) {
565
566 int z_err;
567
568 if ( buff == NULL )
569 return;
570
571 xmlFree( buff->zbuff );
572 z_err = deflateEnd( &buff->zctrl );
573#ifdef DEBUG_HTTP
574 if ( z_err != Z_OK )
575 xmlGenericError( xmlGenericErrorContext,
576 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
577 z_err );
578#endif
579
580 xmlFree( buff );
581 return;
582}
583
584/**
585 * xmlCreateZMemBuff
586 *@compression: Compression value to use
587 *
588 * Create a memory buffer to hold the compressed XML document. The
589 * compressed document in memory will end up being identical to what
590 * would be created if gzopen/gzwrite/gzclose were being used to
591 * write the document to disk. The code for the header/trailer data to
592 * the compression is plagiarized from the zlib source files.
593 */
594static void *
595xmlCreateZMemBuff( int compression ) {
596
597 int z_err;
598 int hdr_lgth;
599 xmlZMemBuffPtr buff = NULL;
600
601 if ( ( compression < 1 ) || ( compression > 9 ) )
602 return ( NULL );
603
604 /* Create the control and data areas */
605
606 buff = xmlMalloc( sizeof( xmlZMemBuff ) );
607 if ( buff == NULL ) {
608 xmlGenericError( xmlGenericErrorContext,
609 "xmlCreateZMemBuff: %s\n",
610 "Failure allocating buffer context." );
611 return ( NULL );
612 }
613
614 (void)memset( buff, 0, sizeof( xmlZMemBuff ) );
615 buff->size = INIT_HTTP_BUFF_SIZE;
616 buff->zbuff = xmlMalloc( buff->size );
617 if ( buff->zbuff == NULL ) {
618 xmlFreeZMemBuff( buff );
619 xmlGenericError( xmlGenericErrorContext,
620 "xmlCreateZMemBuff: %s\n",
621 "Failure allocating data buffer." );
622 return ( NULL );
623 }
624
625 z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
626 DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
627 if ( z_err != Z_OK ) {
628 xmlFreeZMemBuff( buff );
629 buff = NULL;
630 xmlGenericError( xmlGenericErrorContext,
631 "xmlCreateZMemBuff: %s %d\n",
632 "Error initializing compression context. ZLIB error:",
633 z_err );
634 return ( NULL );
635 }
636
637 /* Set the header data. The CRC will be needed for the trailer */
638
639 buff->crc = crc32( 0L, Z_NULL, 0 );
640 hdr_lgth = sprintf( (char *)buff->zbuff, "%c%c%c%c%c%c%c%c%c%c",
641 GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED,
642 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE );
643 buff->zctrl.next_out = buff->zbuff + hdr_lgth;
644 buff->zctrl.avail_out = buff->size - hdr_lgth;
645
646 return ( buff );
647}
648
649/**
650 * xmlZMemBuffExtend
651 * @buff: Buffer used to compress and consolidate data.
652 * @ext_amt: Number of bytes to extend the buffer.
653 *
654 * Extend the internal buffer used to store the compressed data by the
655 * specified amount.
656 *
657 * Returns 0 on success or -1 on failure to extend the buffer. On failure
658 * the original buffer still exists at the original size.
659 */
660static int
661xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) {
662
663 int rc = -1;
664 size_t new_size;
665 size_t cur_used;
666
667 unsigned char * tmp_ptr = NULL;
668
669 if ( buff == NULL )
670 return ( -1 );
671
672 else if ( ext_amt == 0 )
673 return ( 0 );
674
675 cur_used = buff->zctrl.next_out - buff->zbuff;
676 new_size = buff->size + ext_amt;
677
678#ifdef DEBUG_HTTP
679 if ( cur_used > new_size )
680 xmlGenericError( xmlGenericErrorContext,
681 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
682 "Buffer overwrite detected during compressed memory",
683 "buffer extension. Overflowed by",
684 (cur_used - new_size ) );
685#endif
686
687 tmp_ptr = xmlRealloc( buff->zbuff, new_size );
688 if ( tmp_ptr != NULL ) {
689 rc = 0;
690 buff->size = new_size;
691 buff->zbuff = tmp_ptr;
692 buff->zctrl.next_out = tmp_ptr + cur_used;
693 buff->zctrl.avail_out = new_size - cur_used;
694 }
695 else {
696 xmlGenericError( xmlGenericErrorContext,
697 "xmlZMemBuffExtend: %s %lu bytes.\n",
698 "Allocation failure extending output buffer to",
699 new_size );
700 }
701
702 return ( rc );
703}
704
705/**
706 * xmlZMemBuffAppend
707 * @buff: Buffer used to compress and consolidate data
708 * @src: Uncompressed source content to append to buffer
709 * @len: Length of source data to append to buffer
710 *
711 * Compress and append data to the internal buffer. The data buffer
712 * will be expanded if needed to store the additional data.
713 *
714 * Returns the number of bytes appended to the buffer or -1 on error.
715 */
716static int
717xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) {
718
719 int z_err;
720 size_t min_accept;
721
722 if ( ( buff == NULL ) || ( src == NULL ) )
723 return ( -1 );
724
725 buff->zctrl.avail_in = len;
726 buff->zctrl.next_in = (unsigned char *)src;
727 while ( buff->zctrl.avail_in > 0 ) {
728 /*
729 ** Extend the buffer prior to deflate call if a reasonable amount
730 ** of output buffer space is not available.
731 */
732 min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO;
733 if ( buff->zctrl.avail_out <= min_accept ) {
734 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
735 return ( -1 );
736 }
737
738 z_err = deflate( &buff->zctrl, Z_NO_FLUSH );
739 if ( z_err != Z_OK ) {
740 xmlGenericError( xmlGenericErrorContext,
741 "xmlZMemBuffAppend: %s %d %s - %d",
742 "Compression error while appending",
743 len, "bytes to buffer. ZLIB error", z_err );
744 return ( -1 );
745 }
746 }
747
748 buff->crc = crc32( buff->crc, (unsigned char *)src, len );
749
750 return ( len );
751}
752
753/**
754 * xmlZMemBuffGetContent
755 * @buff: Compressed memory content buffer
756 * @data_ref: Pointer reference to point to compressed content
757 *
758 * Flushes the compression buffers, appends gzip file trailers and
759 * returns the compressed content and length of the compressed data.
760 * NOTE: The gzip trailer code here is plagiarized from zlib source.
761 *
762 * Returns the length of the compressed data or -1 on error.
763 */
764static int
765xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) {
766
767 int zlgth = -1;
768 int z_err;
769
770 if ( ( buff == NULL ) || ( data_ref == NULL ) )
771 return ( -1 );
772
773 /* Need to loop until compression output buffers are flushed */
774
775 do
776 {
777 z_err = deflate( &buff->zctrl, Z_FINISH );
778 if ( z_err == Z_OK ) {
779 /* In this case Z_OK means more buffer space needed */
780
781 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
782 return ( -1 );
783 }
784 }
785 while ( z_err == Z_OK );
786
787 /* If the compression state is not Z_STREAM_END, some error occurred */
788
789 if ( z_err == Z_STREAM_END ) {
790
791 /* Need to append the gzip data trailer */
792
793 if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) {
794 if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 )
795 return ( -1 );
796 }
797
798 /*
799 ** For whatever reason, the CRC and length data are pushed out
800 ** in reverse byte order. So a memcpy can't be used here.
801 */
802
803 append_reverse_ulong( buff, buff->crc );
804 append_reverse_ulong( buff, buff->zctrl.total_in );
805
806 zlgth = buff->zctrl.next_out - buff->zbuff;
807 *data_ref = (char *)buff->zbuff;
808 }
809
810 else
811 xmlGenericError( xmlGenericErrorContext,
812 "xmlZMemBuffGetContent: %s - %d\n",
813 "Error flushing zlib buffers. Error code", z_err );
814
815 return ( zlgth );
816}
817#endif /* HAVE_ZLIB_H */
818
819/**
820 * xmlFreeHTTPWriteCtxt
821 * @ctxt: Context to cleanup
822 *
823 * Free allocated memory and reclaim system resources.
824 *
825 * No return value.
826 */
827static void
828xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt )
829{
830 if ( ctxt->uri != NULL )
831 free( ctxt->uri );
832
833 if ( ctxt->doc_buff != NULL ) {
834
835#ifdef HAVE_ZLIB_H
836 if ( ctxt->compression > 0 ) {
837 xmlFreeZMemBuff( ctxt->doc_buff );
838 }
839 else
840#endif
841 {
842 xmlOutputBufferClose( ctxt->doc_buff );
843 }
844 }
845
846 free( ctxt );
847 return;
848}
849
850
Owen Taylor3473f882001-02-23 17:55:21 +0000851/**
852 * xmlIOHTTPMatch:
853 * @filename: the URI for matching
854 *
855 * check if the URI matches an HTTP one
856 *
857 * Returns 1 if matches, 0 otherwise
858 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000859static int
Owen Taylor3473f882001-02-23 17:55:21 +0000860xmlIOHTTPMatch (const char *filename) {
861 if (!strncmp(filename, "http://", 7))
862 return(1);
863 return(0);
864}
865
866/**
867 * xmlIOHTTPOpen:
868 * @filename: the URI for matching
869 *
870 * open an HTTP I/O channel
871 *
872 * Returns an I/O context or NULL in case of error
873 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000874static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000875xmlIOHTTPOpen (const char *filename) {
876 return(xmlNanoHTTPOpen(filename, NULL));
877}
878
879/**
Daniel Veillardf012a642001-07-23 19:10:52 +0000880 * xmlIOHTTPOpenW
881 * @post_uri: The destination URI for the document
882 * @compression: The compression desired for the document.
883 *
884 * Open a temporary buffer to collect the document for a subsequent HTTP POST
885 * request. Non-static as is called from the output buffer creation routine.
886 *
887 * Returns an I/O context or NULL in case of error.
888 */
889
890void *
891xmlIOHTTPOpenW( const char * post_uri, int compression ) {
892
893 xmlIOHTTPWriteCtxtPtr ctxt = NULL;
894
895 if ( post_uri == NULL )
896 return ( NULL );
897
898 ctxt = xmlMalloc( sizeof( xmlIOHTTPWriteCtxt ) );
899 if ( ctxt == NULL ) {
900 xmlGenericError( xmlGenericErrorContext,
901 "xmlIOHTTPOpenW: Failed to create output HTTP context.\n" );
902 return ( NULL );
903 }
904
905 (void)memset( ctxt, 0, sizeof( xmlIOHTTPWriteCtxt ) );
906
907 ctxt->uri = strdup( post_uri );
908 if ( ctxt->uri == NULL ) {
909 xmlGenericError( xmlGenericErrorContext,
910 "xmlIOHTTPOpenW: Failed to duplicate destination URI.\n" );
911 xmlFreeHTTPWriteCtxt( ctxt );
912 return ( NULL );
913 }
914
915 /*
916 ** Since the document length is required for an HTTP post,
917 ** need to put the document into a buffer. A memory buffer
918 ** is being used to avoid pushing the data to disk and back.
919 */
920
921#ifdef HAVE_ZLIB_H
922 if ( ( compression > 0 ) && ( compression <= 9 ) ) {
923
924 ctxt->compression = compression;
925 ctxt->doc_buff = xmlCreateZMemBuff( compression );
926 }
927 else
928#endif
929 {
930 /* Any character conversions should have been done before this */
931
932 ctxt->doc_buff = xmlAllocOutputBuffer( NULL );
933 }
934
935 if ( ctxt->doc_buff == NULL ) {
936 xmlFreeHTTPWriteCtxt( ctxt );
937 ctxt = NULL;
938 }
939
940 return ( ctxt );
941}
942
943/**
944 * xmlIOHTTPDfltOpenW
945 * @post_uri: The destination URI for this document.
946 *
947 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
948 * HTTP post command. This function should generally not be used as
949 * the open callback is short circuited in xmlOutputBufferCreateFile.
950 *
951 * Returns a pointer to the new IO context.
952 */
953static void *
954xmlIOHTTPDfltOpenW( const char * post_uri ) {
955 return ( xmlIOHTTPOpenW( post_uri, 0 ) );
956}
957
958/**
Owen Taylor3473f882001-02-23 17:55:21 +0000959 * xmlIOHTTPRead:
960 * @context: the I/O context
961 * @buffer: where to drop data
962 * @len: number of bytes to write
963 *
964 * Read @len bytes to @buffer from the I/O channel.
965 *
966 * Returns the number of bytes written
967 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000968static int
Owen Taylor3473f882001-02-23 17:55:21 +0000969xmlIOHTTPRead(void * context, char * buffer, int len) {
970 return(xmlNanoHTTPRead(context, &buffer[0], len));
971}
972
973/**
Daniel Veillardf012a642001-07-23 19:10:52 +0000974 * xmlIOHTTPWrite
975 * @context: previously opened writing context
976 * @buffer: data to output to temporary buffer
977 * @len: bytes to output
978 *
979 * Collect data from memory buffer into a temporary file for later
980 * processing.
981 *
982 * Returns number of bytes written.
983 */
984
985static int
986xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
987
988 xmlIOHTTPWriteCtxtPtr ctxt = context;
989
990 if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
991 return ( -1 );
992
993 if ( len > 0 ) {
994
995 /* Use gzwrite or fwrite as previously setup in the open call */
996
997#ifdef HAVE_ZLIB_H
998 if ( ctxt->compression > 0 )
999 len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len );
1000
1001 else
1002#endif
1003 len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
1004
1005 if ( len < 0 ) {
1006 xmlGenericError( xmlGenericErrorContext,
1007 "xmlIOHTTPWrite: %s\n%s '%s'.\n",
1008 "Error appending to internal buffer.",
1009 "Error sending document to URI",
1010 ctxt->uri );
1011 }
1012 }
1013
1014 return ( len );
1015}
1016
1017
1018/**
Owen Taylor3473f882001-02-23 17:55:21 +00001019 * xmlIOHTTPClose:
1020 * @context: the I/O context
1021 *
1022 * Close an HTTP I/O channel
1023 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001024static int
Owen Taylor3473f882001-02-23 17:55:21 +00001025xmlIOHTTPClose (void * context) {
1026 xmlNanoHTTPClose(context);
Daniel Veillardf012a642001-07-23 19:10:52 +00001027 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001028}
Daniel Veillardf012a642001-07-23 19:10:52 +00001029
1030/**
1031 * xmlIOHTTCloseWrite
1032 * @context: The I/O context
1033 * @http_mthd: The HTTP method to be used when sending the data
1034 *
1035 * Close the transmit HTTP I/O channel and actually send the data.
1036 */
1037static int
1038xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
1039
1040 int close_rc = -1;
1041 int http_rtn = 0;
1042 int content_lgth = 0;
1043 xmlIOHTTPWriteCtxtPtr ctxt = context;
1044
1045 char * http_content = NULL;
1046 char * content_encoding = NULL;
1047 char * content_type = (char *) "text/xml";
1048 void * http_ctxt = NULL;
1049
1050 if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
1051 return ( -1 );
1052
1053 /* Retrieve the content from the appropriate buffer */
1054
1055#ifdef HAVE_ZLIB_H
1056
1057 if ( ctxt->compression > 0 ) {
1058 content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
1059 content_encoding = (char *) "Content-Encoding: gzip";
1060 }
1061 else
1062#endif
1063 {
1064 /* Pull the data out of the memory output buffer */
1065
1066 xmlOutputBufferPtr dctxt = ctxt->doc_buff;
1067 http_content = (char *)dctxt->buffer->content;
1068 content_lgth = dctxt->buffer->use;
1069 }
1070
1071 if ( http_content == NULL ) {
1072 xmlGenericError( xmlGenericErrorContext,
1073 "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
1074 "Error retrieving content.\nUnable to",
1075 http_mthd, "data to URI", ctxt->uri );
1076 }
1077
1078 else {
1079
1080 http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
1081 &content_type, content_encoding,
1082 content_lgth );
1083
1084 if ( http_ctxt != NULL ) {
1085#ifdef DEBUG_HTTP
1086 /* If testing/debugging - dump reply with request content */
1087
1088 FILE * tst_file = NULL;
1089 char buffer[ 4096 ];
1090 char * dump_name = NULL;
1091 int avail;
1092
1093 xmlGenericError( xmlGenericErrorContext,
1094 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
1095 http_mthd, ctxt->uri,
1096 xmlNanoHTTPReturnCode( http_ctxt ) );
1097
1098 /*
1099 ** Since either content or reply may be gzipped,
1100 ** dump them to separate files instead of the
1101 ** standard error context.
1102 */
1103
1104 dump_name = tempnam( NULL, "lxml" );
1105 if ( dump_name != NULL ) {
1106 (void)sprintf( buffer, "%s.content", dump_name );
1107
1108 tst_file = fopen( buffer, "w" );
1109 if ( tst_file != NULL ) {
1110 xmlGenericError( xmlGenericErrorContext,
1111 "Transmitted content saved in file: %s\n", buffer );
1112
1113 fwrite( http_content, sizeof( char ),
1114 content_lgth, tst_file );
1115 fclose( tst_file );
1116 }
1117
1118 (void)sprintf( buffer, "%s.reply", dump_name );
1119 tst_file = fopen( buffer, "w" );
1120 if ( tst_file != NULL ) {
1121 xmlGenericError( xmlGenericErrorContext,
1122 "Reply content saved in file: %s\n", buffer );
1123
1124
1125 while ( (avail = xmlNanoHTTPRead( http_ctxt,
1126 buffer, sizeof( buffer ) )) > 0 ) {
1127
1128 fwrite( buffer, sizeof( char ), avail, tst_file );
1129 }
1130
1131 fclose( tst_file );
1132 }
1133
1134 free( dump_name );
1135 }
1136#endif /* DEBUG_HTTP */
1137
1138 http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
1139 if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
1140 close_rc = 0;
1141 else
1142 xmlGenericError( xmlGenericErrorContext,
1143 "xmlIOHTTPClose: HTTP '%s' of %d %s\n'%s' %s %d\n",
1144 http_mthd, content_lgth,
1145 "bytes to URI", ctxt->uri,
1146 "failed. HTTP return code:", http_rtn );
1147
1148 xmlNanoHTTPClose( http_ctxt );
1149 xmlFree( content_type );
1150 }
1151 }
1152
1153 /* Final cleanups */
1154
1155 xmlFreeHTTPWriteCtxt( ctxt );
1156
1157 return ( close_rc );
1158}
1159
1160/**
1161 * xmlIOHTTPClosePut
1162 *
1163 * @context: The I/O context
1164 *
1165 * Close the transmit HTTP I/O channel and actually send data using a PUT
1166 * HTTP method.
1167 */
1168static int
1169xmlIOHTTPClosePut( void * ctxt ) {
1170 return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
1171}
1172
1173
1174/**
1175 * xmlIOHTTPClosePost
1176 *
1177 * @context: The I/O context
1178 *
1179 * Close the transmit HTTP I/O channel and actually send data using a POST
1180 * HTTP method.
1181 */
1182static int
1183xmlIOHTTPClosePost( void * ctxt ) {
1184 return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
1185}
1186
Owen Taylor3473f882001-02-23 17:55:21 +00001187#endif /* LIBXML_HTTP_ENABLED */
1188
1189#ifdef LIBXML_FTP_ENABLED
1190/************************************************************************
1191 * *
1192 * I/O for FTP file accesses *
1193 * *
1194 ************************************************************************/
1195/**
1196 * xmlIOFTPMatch:
1197 * @filename: the URI for matching
1198 *
1199 * check if the URI matches an FTP one
1200 *
1201 * Returns 1 if matches, 0 otherwise
1202 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001203static int
Owen Taylor3473f882001-02-23 17:55:21 +00001204xmlIOFTPMatch (const char *filename) {
1205 if (!strncmp(filename, "ftp://", 6))
1206 return(1);
1207 return(0);
1208}
1209
1210/**
1211 * xmlIOFTPOpen:
1212 * @filename: the URI for matching
1213 *
1214 * open an FTP I/O channel
1215 *
1216 * Returns an I/O context or NULL in case of error
1217 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001218static void *
Owen Taylor3473f882001-02-23 17:55:21 +00001219xmlIOFTPOpen (const char *filename) {
1220 return(xmlNanoFTPOpen(filename));
1221}
1222
1223/**
1224 * xmlIOFTPRead:
1225 * @context: the I/O context
1226 * @buffer: where to drop data
1227 * @len: number of bytes to write
1228 *
1229 * Read @len bytes to @buffer from the I/O channel.
1230 *
1231 * Returns the number of bytes written
1232 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001233static int
Owen Taylor3473f882001-02-23 17:55:21 +00001234xmlIOFTPRead(void * context, char * buffer, int len) {
1235 return(xmlNanoFTPRead(context, &buffer[0], len));
1236}
1237
1238/**
1239 * xmlIOFTPClose:
1240 * @context: the I/O context
1241 *
1242 * Close an FTP I/O channel
1243 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001244static int
Owen Taylor3473f882001-02-23 17:55:21 +00001245xmlIOFTPClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001246 return ( xmlNanoFTPClose(context) );
Owen Taylor3473f882001-02-23 17:55:21 +00001247}
1248#endif /* LIBXML_FTP_ENABLED */
1249
1250
1251/**
1252 * xmlRegisterInputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001253 * @matchFunc: the xmlInputMatchCallback
1254 * @openFunc: the xmlInputOpenCallback
1255 * @readFunc: the xmlInputReadCallback
1256 * @closeFunc: the xmlInputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001257 *
1258 * Register a new set of I/O callback for handling parser input.
1259 *
1260 * Returns the registered handler number or -1 in case of error
1261 */
1262int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001263xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
1264 xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
1265 xmlInputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001266 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
1267 return(-1);
1268 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001269 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
1270 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
1271 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
1272 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
Owen Taylor3473f882001-02-23 17:55:21 +00001273 return(xmlInputCallbackNr++);
1274}
1275
1276/**
1277 * xmlRegisterOutputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001278 * @matchFunc: the xmlOutputMatchCallback
1279 * @openFunc: the xmlOutputOpenCallback
1280 * @writeFunc: the xmlOutputWriteCallback
1281 * @closeFunc: the xmlOutputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001282 *
1283 * Register a new set of I/O callback for handling output.
1284 *
1285 * Returns the registered handler number or -1 in case of error
1286 */
1287int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001288xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
1289 xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
1290 xmlOutputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001291 if (xmlOutputCallbackNr >= MAX_INPUT_CALLBACK) {
1292 return(-1);
1293 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001294 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
1295 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
1296 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
1297 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
Owen Taylor3473f882001-02-23 17:55:21 +00001298 return(xmlOutputCallbackNr++);
1299}
1300
1301/**
1302 * xmlRegisterDefaultInputCallbacks:
1303 *
1304 * Registers the default compiled-in I/O handlers.
1305 */
1306void
1307#ifdef VMS
1308xmlRegisterDefInputCallbacks
1309#else
1310xmlRegisterDefaultInputCallbacks
1311#endif
1312(void) {
1313 if (xmlInputCallbackInitialized)
1314 return;
1315
1316 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
1317 xmlFileRead, xmlFileClose);
1318#ifdef HAVE_ZLIB_H
1319 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1320 xmlGzfileRead, xmlGzfileClose);
1321#endif /* HAVE_ZLIB_H */
1322
1323#ifdef LIBXML_HTTP_ENABLED
1324 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
1325 xmlIOHTTPRead, xmlIOHTTPClose);
1326#endif /* LIBXML_HTTP_ENABLED */
1327
1328#ifdef LIBXML_FTP_ENABLED
1329 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1330 xmlIOFTPRead, xmlIOFTPClose);
1331#endif /* LIBXML_FTP_ENABLED */
1332 xmlInputCallbackInitialized = 1;
1333}
1334
1335/**
1336 * xmlRegisterDefaultOutputCallbacks:
1337 *
1338 * Registers the default compiled-in I/O handlers.
1339 */
1340void
1341#ifdef VMS
1342xmlRegisterDefOutputCallbacks
1343#else
1344xmlRegisterDefaultOutputCallbacks
1345#endif
1346(void) {
1347 if (xmlOutputCallbackInitialized)
1348 return;
1349
1350 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
1351 xmlFileWrite, xmlFileClose);
Daniel Veillardf012a642001-07-23 19:10:52 +00001352
1353#ifdef LIBXML_HTTP_ENABLED
1354 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
1355 xmlIOHTTPWrite, xmlIOHTTPClosePut);
1356#endif
1357
Owen Taylor3473f882001-02-23 17:55:21 +00001358/*********************************
1359 No way a-priori to distinguish between gzipped files from
1360 uncompressed ones except opening if existing then closing
1361 and saving with same compression ratio ... a pain.
1362
1363#ifdef HAVE_ZLIB_H
1364 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1365 xmlGzfileWrite, xmlGzfileClose);
1366#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001367
1368 Nor FTP PUT ....
1369#ifdef LIBXML_FTP_ENABLED
1370 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1371 xmlIOFTPWrite, xmlIOFTPClose);
1372#endif
1373 **********************************/
1374 xmlOutputCallbackInitialized = 1;
1375}
1376
Daniel Veillardf012a642001-07-23 19:10:52 +00001377#ifdef LIBXML_HTTP_ENABLED
1378/**
1379 * xmlRegisterHTTPPostCallbacks
1380 *
1381 * By default, libxml submits HTTP output requests using the "PUT" method.
1382 * Calling this method changes the HTTP output method to use the "POST"
1383 * method instead.
1384 *
1385 */
1386void
1387xmlRegisterHTTPPostCallbacks( void ) {
1388
1389 /* Register defaults if not done previously */
1390
1391 if ( xmlOutputCallbackInitialized == 0 )
1392 xmlRegisterDefaultOutputCallbacks( );
1393
1394 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
1395 xmlIOHTTPWrite, xmlIOHTTPClosePost);
1396 return;
1397}
1398#endif
1399
Owen Taylor3473f882001-02-23 17:55:21 +00001400/**
1401 * xmlAllocParserInputBuffer:
1402 * @enc: the charset encoding if known
1403 *
1404 * Create a buffered parser input for progressive parsing
1405 *
1406 * Returns the new parser input or NULL
1407 */
1408xmlParserInputBufferPtr
1409xmlAllocParserInputBuffer(xmlCharEncoding enc) {
1410 xmlParserInputBufferPtr ret;
1411
1412 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
1413 if (ret == NULL) {
1414 xmlGenericError(xmlGenericErrorContext,
1415 "xmlAllocParserInputBuffer : out of memory!\n");
1416 return(NULL);
1417 }
1418 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
1419 ret->buffer = xmlBufferCreate();
1420 if (ret->buffer == NULL) {
1421 xmlFree(ret);
1422 return(NULL);
1423 }
1424 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
1425 ret->encoder = xmlGetCharEncodingHandler(enc);
1426 if (ret->encoder != NULL)
1427 ret->raw = xmlBufferCreate();
1428 else
1429 ret->raw = NULL;
1430 ret->readcallback = NULL;
1431 ret->closecallback = NULL;
1432 ret->context = NULL;
1433
1434 return(ret);
1435}
1436
1437/**
1438 * xmlAllocOutputBuffer:
1439 * @encoder: the encoding converter or NULL
1440 *
1441 * Create a buffered parser output
1442 *
1443 * Returns the new parser output or NULL
1444 */
1445xmlOutputBufferPtr
1446xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
1447 xmlOutputBufferPtr ret;
1448
1449 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
1450 if (ret == NULL) {
1451 xmlGenericError(xmlGenericErrorContext,
1452 "xmlAllocOutputBuffer : out of memory!\n");
1453 return(NULL);
1454 }
1455 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
1456 ret->buffer = xmlBufferCreate();
1457 if (ret->buffer == NULL) {
1458 xmlFree(ret);
1459 return(NULL);
1460 }
1461 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
1462 ret->encoder = encoder;
1463 if (encoder != NULL) {
1464 ret->conv = xmlBufferCreateSize(4000);
1465 /*
1466 * This call is designed to initiate the encoder state
1467 */
1468 xmlCharEncOutFunc(encoder, ret->conv, NULL);
1469 } else
1470 ret->conv = NULL;
1471 ret->writecallback = NULL;
1472 ret->closecallback = NULL;
1473 ret->context = NULL;
1474 ret->written = 0;
1475
1476 return(ret);
1477}
1478
1479/**
1480 * xmlFreeParserInputBuffer:
1481 * @in: a buffered parser input
1482 *
1483 * Free up the memory used by a buffered parser input
1484 */
1485void
1486xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
1487 if (in->raw) {
1488 xmlBufferFree(in->raw);
1489 in->raw = NULL;
1490 }
1491 if (in->encoder != NULL) {
1492 xmlCharEncCloseFunc(in->encoder);
1493 }
1494 if (in->closecallback != NULL) {
1495 in->closecallback(in->context);
1496 }
1497 if (in->buffer != NULL) {
1498 xmlBufferFree(in->buffer);
1499 in->buffer = NULL;
1500 }
1501
Owen Taylor3473f882001-02-23 17:55:21 +00001502 xmlFree(in);
1503}
1504
1505/**
1506 * xmlOutputBufferClose:
1507 * @out: a buffered output
1508 *
1509 * flushes and close the output I/O channel
1510 * and free up all the associated resources
1511 *
1512 * Returns the number of byte written or -1 in case of error.
1513 */
1514int
1515xmlOutputBufferClose(xmlOutputBufferPtr out) {
1516 int written;
Daniel Veillardf012a642001-07-23 19:10:52 +00001517 int err_rc = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001518
1519 if (out == NULL)
1520 return(-1);
1521 if (out->writecallback != NULL)
1522 xmlOutputBufferFlush(out);
1523 if (out->closecallback != NULL) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001524 err_rc = out->closecallback(out->context);
Owen Taylor3473f882001-02-23 17:55:21 +00001525 }
1526 written = out->written;
1527 if (out->conv) {
1528 xmlBufferFree(out->conv);
1529 out->conv = NULL;
1530 }
1531 if (out->encoder != NULL) {
1532 xmlCharEncCloseFunc(out->encoder);
1533 }
1534 if (out->buffer != NULL) {
1535 xmlBufferFree(out->buffer);
1536 out->buffer = NULL;
1537 }
1538
Owen Taylor3473f882001-02-23 17:55:21 +00001539 xmlFree(out);
Daniel Veillardf012a642001-07-23 19:10:52 +00001540 return( ( err_rc == 0 ) ? written : err_rc );
Owen Taylor3473f882001-02-23 17:55:21 +00001541}
1542
1543/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001544 * xmlParserInputBufferCreateFname:
1545 * @URI: a C string containing the URI or filename
1546 * @enc: the charset encoding if known
1547 *
1548 * VMS version of xmlParserInputBufferCreateFilename()
1549 *
1550 * Returns the new parser input or NULL
1551 */
1552/**
Owen Taylor3473f882001-02-23 17:55:21 +00001553 * xmlParserInputBufferCreateFilename:
1554 * @URI: a C string containing the URI or filename
1555 * @enc: the charset encoding if known
1556 *
1557 * Create a buffered parser input for the progressive parsing of a file
1558 * If filename is "-' then we use stdin as the input.
1559 * Automatic support for ZLIB/Compress compressed document is provided
1560 * by default if found at compile-time.
1561 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
1562 *
1563 * Returns the new parser input or NULL
1564 */
1565xmlParserInputBufferPtr
1566#ifdef VMS
1567xmlParserInputBufferCreateFname
1568#else
1569xmlParserInputBufferCreateFilename
1570#endif
1571(const char *URI, xmlCharEncoding enc) {
1572 xmlParserInputBufferPtr ret;
Daniel Veillard388236f2001-07-08 18:35:48 +00001573 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001574 void *context = NULL;
Daniel Veillard388236f2001-07-08 18:35:48 +00001575 char *unescaped;
Owen Taylor3473f882001-02-23 17:55:21 +00001576
1577 if (xmlInputCallbackInitialized == 0)
1578 xmlRegisterDefaultInputCallbacks();
1579
1580 if (URI == NULL) return(NULL);
1581
1582 /*
1583 * Try to find one of the input accept method accepting taht scheme
1584 * Go in reverse to give precedence to user defined handlers.
Daniel Veillard388236f2001-07-08 18:35:48 +00001585 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00001586 */
Daniel Veillard388236f2001-07-08 18:35:48 +00001587 unescaped = xmlURIUnescapeString(URI, 0, NULL);
1588 if (unescaped != NULL) {
1589 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
1590 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
1591 (xmlInputCallbackTable[i].matchcallback(unescaped) != 0)) {
1592 context = xmlInputCallbackTable[i].opencallback(unescaped);
1593 if (context != NULL)
1594 break;
1595 }
1596 }
1597 xmlFree(unescaped);
1598 }
1599
1600 /*
1601 * If this failed try with a non-escaped URI this may be a strange
1602 * filename
1603 */
1604 if (context == NULL) {
1605 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
1606 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
1607 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
1608 context = xmlInputCallbackTable[i].opencallback(URI);
1609 if (context != NULL)
1610 break;
1611 }
Owen Taylor3473f882001-02-23 17:55:21 +00001612 }
1613 }
1614 if (context == NULL) {
1615 return(NULL);
1616 }
1617
1618 /*
1619 * Allocate the Input buffer front-end.
1620 */
1621 ret = xmlAllocParserInputBuffer(enc);
1622 if (ret != NULL) {
1623 ret->context = context;
1624 ret->readcallback = xmlInputCallbackTable[i].readcallback;
1625 ret->closecallback = xmlInputCallbackTable[i].closecallback;
1626 }
1627 return(ret);
1628}
1629
1630/**
1631 * xmlOutputBufferCreateFilename:
1632 * @URI: a C string containing the URI or filename
1633 * @encoder: the encoding converter or NULL
1634 * @compression: the compression ration (0 none, 9 max).
1635 *
1636 * Create a buffered output for the progressive saving of a file
1637 * If filename is "-' then we use stdout as the output.
1638 * Automatic support for ZLIB/Compress compressed document is provided
1639 * by default if found at compile-time.
1640 * TODO: currently if compression is set, the library only support
1641 * writing to a local file.
1642 *
1643 * Returns the new output or NULL
1644 */
1645xmlOutputBufferPtr
1646xmlOutputBufferCreateFilename(const char *URI,
1647 xmlCharEncodingHandlerPtr encoder,
1648 int compression) {
1649 xmlOutputBufferPtr ret;
1650 int i;
1651 void *context = NULL;
1652
Daniel Veillardf012a642001-07-23 19:10:52 +00001653 int is_http_uri = 0; /* Can't change if HTTP disabled */
1654
Owen Taylor3473f882001-02-23 17:55:21 +00001655 if (xmlOutputCallbackInitialized == 0)
1656 xmlRegisterDefaultOutputCallbacks();
1657
1658 if (URI == NULL) return(NULL);
1659
Daniel Veillardf012a642001-07-23 19:10:52 +00001660#ifdef LIBXML_HTTP_ENABLED
1661 /* Need to prevent HTTP URI's from falling into zlib short circuit */
1662
1663 is_http_uri = xmlIOHTTPMatch( URI );
1664#endif
1665
Owen Taylor3473f882001-02-23 17:55:21 +00001666#ifdef HAVE_ZLIB_H
Daniel Veillardf012a642001-07-23 19:10:52 +00001667 if ((compression > 0) && (compression <= 9) && (is_http_uri == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00001668 context = xmlGzfileOpenW(URI, compression);
1669 if (context != NULL) {
1670 ret = xmlAllocOutputBuffer(encoder);
1671 if (ret != NULL) {
1672 ret->context = context;
1673 ret->writecallback = xmlGzfileWrite;
1674 ret->closecallback = xmlGzfileClose;
1675 }
1676 return(ret);
1677 }
1678 }
1679#endif
1680
1681 /*
Daniel Veillardf012a642001-07-23 19:10:52 +00001682 * Try to find one of the output accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00001683 * Go in reverse to give precedence to user defined handlers.
1684 */
1685 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
1686 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
1687 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001688
1689#if ( defined( LIBXML_HTTP_ENABLED ) && defined( HAVE_ZLIB_H ) )
1690 /* Need to pass compression parameter into HTTP open calls */
1691
1692 if ( xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch )
1693 context = xmlIOHTTPOpenW( URI, compression );
1694 else
1695#endif
1696 context = xmlOutputCallbackTable[i].opencallback(URI);
1697
Owen Taylor3473f882001-02-23 17:55:21 +00001698 if (context != NULL)
1699 break;
1700 }
1701 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001702
Owen Taylor3473f882001-02-23 17:55:21 +00001703 if (context == NULL) {
1704 return(NULL);
1705 }
1706
1707 /*
1708 * Allocate the Output buffer front-end.
1709 */
1710 ret = xmlAllocOutputBuffer(encoder);
1711 if (ret != NULL) {
1712 ret->context = context;
1713 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
1714 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
1715 }
1716 return(ret);
1717}
1718
1719/**
1720 * xmlParserInputBufferCreateFile:
1721 * @file: a FILE*
1722 * @enc: the charset encoding if known
1723 *
1724 * Create a buffered parser input for the progressive parsing of a FILE *
1725 * buffered C I/O
1726 *
1727 * Returns the new parser input or NULL
1728 */
1729xmlParserInputBufferPtr
1730xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
1731 xmlParserInputBufferPtr ret;
1732
1733 if (xmlInputCallbackInitialized == 0)
1734 xmlRegisterDefaultInputCallbacks();
1735
1736 if (file == NULL) return(NULL);
1737
1738 ret = xmlAllocParserInputBuffer(enc);
1739 if (ret != NULL) {
1740 ret->context = file;
1741 ret->readcallback = xmlFileRead;
1742 ret->closecallback = xmlFileFlush;
1743 }
1744
1745 return(ret);
1746}
1747
1748/**
1749 * xmlOutputBufferCreateFile:
1750 * @file: a FILE*
1751 * @encoder: the encoding converter or NULL
1752 *
1753 * Create a buffered output for the progressive saving to a FILE *
1754 * buffered C I/O
1755 *
1756 * Returns the new parser output or NULL
1757 */
1758xmlOutputBufferPtr
1759xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
1760 xmlOutputBufferPtr ret;
1761
1762 if (xmlOutputCallbackInitialized == 0)
1763 xmlRegisterDefaultOutputCallbacks();
1764
1765 if (file == NULL) return(NULL);
1766
1767 ret = xmlAllocOutputBuffer(encoder);
1768 if (ret != NULL) {
1769 ret->context = file;
1770 ret->writecallback = xmlFileWrite;
1771 ret->closecallback = xmlFileFlush;
1772 }
1773
1774 return(ret);
1775}
1776
1777/**
1778 * xmlParserInputBufferCreateFd:
1779 * @fd: a file descriptor number
1780 * @enc: the charset encoding if known
1781 *
1782 * Create a buffered parser input for the progressive parsing for the input
1783 * from a file descriptor
1784 *
1785 * Returns the new parser input or NULL
1786 */
1787xmlParserInputBufferPtr
1788xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
1789 xmlParserInputBufferPtr ret;
1790
1791 if (fd < 0) return(NULL);
1792
1793 ret = xmlAllocParserInputBuffer(enc);
1794 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00001795 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00001796 ret->readcallback = xmlFdRead;
1797 ret->closecallback = xmlFdClose;
1798 }
1799
1800 return(ret);
1801}
1802
1803/**
1804 * xmlParserInputBufferCreateMem:
1805 * @mem: the memory input
1806 * @size: the length of the memory block
1807 * @enc: the charset encoding if known
1808 *
1809 * Create a buffered parser input for the progressive parsing for the input
1810 * from a memory area.
1811 *
1812 * Returns the new parser input or NULL
1813 */
1814xmlParserInputBufferPtr
1815xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
1816 xmlParserInputBufferPtr ret;
1817
1818 if (size <= 0) return(NULL);
1819 if (mem == NULL) return(NULL);
1820
1821 ret = xmlAllocParserInputBuffer(enc);
1822 if (ret != NULL) {
1823 ret->context = (void *) mem;
1824 ret->readcallback = (xmlInputReadCallback) xmlNop;
1825 ret->closecallback = NULL;
1826 xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size);
1827 }
1828
1829 return(ret);
1830}
1831
1832/**
1833 * xmlOutputBufferCreateFd:
1834 * @fd: a file descriptor number
1835 * @encoder: the encoding converter or NULL
1836 *
1837 * Create a buffered output for the progressive saving
1838 * to a file descriptor
1839 *
1840 * Returns the new parser output or NULL
1841 */
1842xmlOutputBufferPtr
1843xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
1844 xmlOutputBufferPtr ret;
1845
1846 if (fd < 0) return(NULL);
1847
1848 ret = xmlAllocOutputBuffer(encoder);
1849 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00001850 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00001851 ret->writecallback = xmlFdWrite;
1852 ret->closecallback = xmlFdClose;
1853 }
1854
1855 return(ret);
1856}
1857
1858/**
1859 * xmlParserInputBufferCreateIO:
1860 * @ioread: an I/O read function
1861 * @ioclose: an I/O close function
1862 * @ioctx: an I/O handler
1863 * @enc: the charset encoding if known
1864 *
1865 * Create a buffered parser input for the progressive parsing for the input
1866 * from an I/O handler
1867 *
1868 * Returns the new parser input or NULL
1869 */
1870xmlParserInputBufferPtr
1871xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
1872 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
1873 xmlParserInputBufferPtr ret;
1874
1875 if (ioread == NULL) return(NULL);
1876
1877 ret = xmlAllocParserInputBuffer(enc);
1878 if (ret != NULL) {
1879 ret->context = (void *) ioctx;
1880 ret->readcallback = ioread;
1881 ret->closecallback = ioclose;
1882 }
1883
1884 return(ret);
1885}
1886
1887/**
1888 * xmlOutputBufferCreateIO:
1889 * @iowrite: an I/O write function
1890 * @ioclose: an I/O close function
1891 * @ioctx: an I/O handler
1892 * @enc: the charset encoding if known
1893 *
1894 * Create a buffered output for the progressive saving
1895 * to an I/O handler
1896 *
1897 * Returns the new parser output or NULL
1898 */
1899xmlOutputBufferPtr
1900xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
1901 xmlOutputCloseCallback ioclose, void *ioctx,
1902 xmlCharEncodingHandlerPtr encoder) {
1903 xmlOutputBufferPtr ret;
1904
1905 if (iowrite == NULL) return(NULL);
1906
1907 ret = xmlAllocOutputBuffer(encoder);
1908 if (ret != NULL) {
1909 ret->context = (void *) ioctx;
1910 ret->writecallback = iowrite;
1911 ret->closecallback = ioclose;
1912 }
1913
1914 return(ret);
1915}
1916
1917/**
1918 * xmlParserInputBufferPush:
1919 * @in: a buffered parser input
1920 * @len: the size in bytes of the array.
1921 * @buf: an char array
1922 *
1923 * Push the content of the arry in the input buffer
1924 * This routine handle the I18N transcoding to internal UTF-8
1925 * This is used when operating the parser in progressive (push) mode.
1926 *
1927 * Returns the number of chars read and stored in the buffer, or -1
1928 * in case of error.
1929 */
1930int
1931xmlParserInputBufferPush(xmlParserInputBufferPtr in,
1932 int len, const char *buf) {
1933 int nbchars = 0;
1934
1935 if (len < 0) return(0);
1936 if (in->encoder != NULL) {
1937 /*
1938 * Store the data in the incoming raw buffer
1939 */
1940 if (in->raw == NULL) {
1941 in->raw = xmlBufferCreate();
1942 }
1943 xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
1944
1945 /*
1946 * convert as much as possible to the parser reading buffer.
1947 */
1948 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
1949 if (nbchars < 0) {
1950 xmlGenericError(xmlGenericErrorContext,
1951 "xmlParserInputBufferPush: encoder error\n");
1952 return(-1);
1953 }
1954 } else {
1955 nbchars = len;
1956 xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
1957 }
1958#ifdef DEBUG_INPUT
1959 xmlGenericError(xmlGenericErrorContext,
1960 "I/O: pushed %d chars, buffer %d/%d\n",
1961 nbchars, in->buffer->use, in->buffer->size);
1962#endif
1963 return(nbchars);
1964}
1965
1966/**
1967 * xmlParserInputBufferGrow:
1968 * @in: a buffered parser input
1969 * @len: indicative value of the amount of chars to read
1970 *
1971 * Grow up the content of the input buffer, the old data are preserved
1972 * This routine handle the I18N transcoding to internal UTF-8
1973 * This routine is used when operating the parser in normal (pull) mode
1974 *
1975 * TODO: one should be able to remove one extra copy by copying directy
1976 * onto in->buffer or in->raw
1977 *
1978 * Returns the number of chars read and stored in the buffer, or -1
1979 * in case of error.
1980 */
1981int
1982xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
1983 char *buffer = NULL;
1984 int res = 0;
1985 int nbchars = 0;
1986 int buffree;
1987
1988 if ((len <= MINLEN) && (len != 4))
1989 len = MINLEN;
1990 buffree = in->buffer->size - in->buffer->use;
1991 if (buffree <= 0) {
1992 xmlGenericError(xmlGenericErrorContext,
1993 "xmlParserInputBufferGrow : buffer full !\n");
1994 return(0);
1995 }
1996 if (len > buffree)
1997 len = buffree;
1998
1999 buffer = (char *) xmlMalloc((len + 1) * sizeof(char));
2000 if (buffer == NULL) {
2001 xmlGenericError(xmlGenericErrorContext,
2002 "xmlParserInputBufferGrow : out of memory !\n");
2003 return(-1);
2004 }
2005
2006 /*
2007 * Call the read method for this I/O type.
2008 */
2009 if (in->readcallback != NULL) {
2010 res = in->readcallback(in->context, &buffer[0], len);
2011 } else {
2012 xmlGenericError(xmlGenericErrorContext,
2013 "xmlParserInputBufferGrow : no input !\n");
2014 xmlFree(buffer);
2015 return(-1);
2016 }
2017 if (res < 0) {
2018 perror ("read error");
2019 xmlFree(buffer);
2020 return(-1);
2021 }
2022 len = res;
2023 if (in->encoder != NULL) {
2024 /*
2025 * Store the data in the incoming raw buffer
2026 */
2027 if (in->raw == NULL) {
2028 in->raw = xmlBufferCreate();
2029 }
2030 xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
2031
2032 /*
2033 * convert as much as possible to the parser reading buffer.
2034 */
2035 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2036 if (nbchars < 0) {
2037 xmlGenericError(xmlGenericErrorContext,
2038 "xmlParserInputBufferGrow: encoder error\n");
2039 return(-1);
2040 }
2041 } else {
2042 nbchars = len;
2043 buffer[nbchars] = 0;
2044 xmlBufferAdd(in->buffer, (xmlChar *) buffer, nbchars);
2045 }
2046#ifdef DEBUG_INPUT
2047 xmlGenericError(xmlGenericErrorContext,
2048 "I/O: read %d chars, buffer %d/%d\n",
2049 nbchars, in->buffer->use, in->buffer->size);
2050#endif
2051 xmlFree(buffer);
2052 return(nbchars);
2053}
2054
2055/**
2056 * xmlParserInputBufferRead:
2057 * @in: a buffered parser input
2058 * @len: indicative value of the amount of chars to read
2059 *
2060 * Refresh the content of the input buffer, the old data are considered
2061 * consumed
2062 * This routine handle the I18N transcoding to internal UTF-8
2063 *
2064 * Returns the number of chars read and stored in the buffer, or -1
2065 * in case of error.
2066 */
2067int
2068xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
2069 /* xmlBufferEmpty(in->buffer); */
2070 if (in->readcallback != NULL)
2071 return(xmlParserInputBufferGrow(in, len));
2072 else
2073 return(-1);
2074}
2075
2076/**
2077 * xmlOutputBufferWrite:
2078 * @out: a buffered parser output
2079 * @len: the size in bytes of the array.
2080 * @buf: an char array
2081 *
2082 * Write the content of the array in the output I/O buffer
2083 * This routine handle the I18N transcoding from internal UTF-8
2084 * The buffer is lossless, i.e. will store in case of partial
2085 * or delayed writes.
2086 *
2087 * Returns the number of chars immediately written, or -1
2088 * in case of error.
2089 */
2090int
2091xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
2092 int nbchars = 0; /* number of chars to output to I/O */
2093 int ret; /* return from function call */
2094 int written = 0; /* number of char written to I/O so far */
2095 int chunk; /* number of byte curreent processed from buf */
2096
2097 if (len < 0) return(0);
2098
2099 do {
2100 chunk = len;
2101 if (chunk > 4 * MINLEN)
2102 chunk = 4 * MINLEN;
2103
2104 /*
2105 * first handle encoding stuff.
2106 */
2107 if (out->encoder != NULL) {
2108 /*
2109 * Store the data in the incoming raw buffer
2110 */
2111 if (out->conv == NULL) {
2112 out->conv = xmlBufferCreate();
2113 }
2114 xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2115
2116 if ((out->buffer->use < MINLEN) && (chunk == len))
2117 goto done;
2118
2119 /*
2120 * convert as much as possible to the parser reading buffer.
2121 */
2122 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
2123 if (ret < 0) {
2124 xmlGenericError(xmlGenericErrorContext,
2125 "xmlOutputBufferWrite: encoder error\n");
2126 return(-1);
2127 }
2128 nbchars = out->conv->use;
2129 } else {
2130 xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2131 nbchars = out->buffer->use;
2132 }
2133 buf += chunk;
2134 len -= chunk;
2135
2136 if ((nbchars < MINLEN) && (len <= 0))
2137 goto done;
2138
2139 if (out->writecallback) {
2140 /*
2141 * second write the stuff to the I/O channel
2142 */
2143 if (out->encoder != NULL) {
2144 ret = out->writecallback(out->context,
2145 (const char *)out->conv->content, nbchars);
2146 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002147 xmlBufferShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002148 } else {
2149 ret = out->writecallback(out->context,
2150 (const char *)out->buffer->content, nbchars);
2151 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002152 xmlBufferShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002153 }
2154 if (ret < 0) {
2155 xmlGenericError(xmlGenericErrorContext,
2156 "I/O: error %d writing %d bytes\n", ret, nbchars);
2157 return(ret);
2158 }
2159 out->written += ret;
2160 }
2161 written += nbchars;
2162 } while (len > 0);
2163
2164done:
2165#ifdef DEBUG_INPUT
2166 xmlGenericError(xmlGenericErrorContext,
2167 "I/O: wrote %d chars\n", written);
2168#endif
2169 return(written);
2170}
2171
2172/**
2173 * xmlOutputBufferWriteString:
2174 * @out: a buffered parser output
2175 * @str: a zero terminated C string
2176 *
2177 * Write the content of the string in the output I/O buffer
2178 * This routine handle the I18N transcoding from internal UTF-8
2179 * The buffer is lossless, i.e. will store in case of partial
2180 * or delayed writes.
2181 *
2182 * Returns the number of chars immediately written, or -1
2183 * in case of error.
2184 */
2185int
2186xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
2187 int len;
2188
2189 if (str == NULL)
2190 return(-1);
2191 len = strlen(str);
2192
2193 if (len > 0)
2194 return(xmlOutputBufferWrite(out, len, str));
2195 return(len);
2196}
2197
2198/**
2199 * xmlOutputBufferFlush:
2200 * @out: a buffered output
2201 *
2202 * flushes the output I/O channel
2203 *
2204 * Returns the number of byte written or -1 in case of error.
2205 */
2206int
2207xmlOutputBufferFlush(xmlOutputBufferPtr out) {
2208 int nbchars = 0, ret = 0;
2209
2210 /*
2211 * first handle encoding stuff.
2212 */
2213 if ((out->conv != NULL) && (out->encoder != NULL)) {
2214 /*
2215 * convert as much as possible to the parser reading buffer.
2216 */
2217 nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
2218 if (nbchars < 0) {
2219 xmlGenericError(xmlGenericErrorContext,
2220 "xmlOutputBufferWrite: encoder error\n");
2221 return(-1);
2222 }
2223 }
2224
2225 /*
2226 * second flush the stuff to the I/O channel
2227 */
2228 if ((out->conv != NULL) && (out->encoder != NULL) &&
2229 (out->writecallback != NULL)) {
2230 ret = out->writecallback(out->context,
2231 (const char *)out->conv->content, out->conv->use);
2232 if (ret >= 0)
2233 xmlBufferShrink(out->conv, ret);
2234 } else if (out->writecallback != NULL) {
2235 ret = out->writecallback(out->context,
2236 (const char *)out->buffer->content, out->buffer->use);
2237 if (ret >= 0)
2238 xmlBufferShrink(out->buffer, ret);
2239 }
2240 if (ret < 0) {
2241 xmlGenericError(xmlGenericErrorContext,
2242 "I/O: error %d flushing %d bytes\n", ret, nbchars);
2243 return(ret);
2244 }
2245 out->written += ret;
2246
2247#ifdef DEBUG_INPUT
2248 xmlGenericError(xmlGenericErrorContext,
2249 "I/O: flushed %d chars\n", ret);
2250#endif
2251 return(ret);
2252}
2253
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002254/**
Owen Taylor3473f882001-02-23 17:55:21 +00002255 * xmlParserGetDirectory:
2256 * @filename: the path to a file
2257 *
2258 * lookup the directory for that file
2259 *
2260 * Returns a new allocated string containing the directory, or NULL.
2261 */
2262char *
2263xmlParserGetDirectory(const char *filename) {
2264 char *ret = NULL;
2265 char dir[1024];
2266 char *cur;
2267 char sep = '/';
2268
2269 if (xmlInputCallbackInitialized == 0)
2270 xmlRegisterDefaultInputCallbacks();
2271
2272 if (filename == NULL) return(NULL);
2273#ifdef WIN32
2274 sep = '\\';
2275#endif
2276
2277 strncpy(dir, filename, 1023);
2278 dir[1023] = 0;
2279 cur = &dir[strlen(dir)];
2280 while (cur > dir) {
2281 if (*cur == sep) break;
2282 cur --;
2283 }
2284 if (*cur == sep) {
2285 if (cur == dir) dir[1] = 0;
2286 else *cur = 0;
2287 ret = xmlMemStrdup(dir);
2288 } else {
2289 if (getcwd(dir, 1024) != NULL) {
2290 dir[1023] = 0;
2291 ret = xmlMemStrdup(dir);
2292 }
2293 }
2294 return(ret);
2295}
2296
2297/****************************************************************
2298 * *
2299 * External entities loading *
2300 * *
2301 ****************************************************************/
2302
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002303/**
Owen Taylor3473f882001-02-23 17:55:21 +00002304 * xmlDefaultExternalEntityLoader:
2305 * @URL: the URL for the entity to load
2306 * @ID: the System ID for the entity to load
2307 * @ctxt: the context in which the entity is called or NULL
2308 *
2309 * By default we don't load external entitites, yet.
2310 *
2311 * Returns a new allocated xmlParserInputPtr, or NULL.
2312 */
2313static
2314xmlParserInputPtr
2315xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
2316 xmlParserCtxtPtr ctxt) {
2317 xmlParserInputPtr ret = NULL;
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002318 const xmlChar *resource = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002319
2320#ifdef DEBUG_EXTERNAL_ENTITIES
2321 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf012a642001-07-23 19:10:52 +00002322 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00002323#endif
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002324#ifdef LIBXML_CATALOG_ENABLED
2325 /*
2326 * Try to load it from the resource pointed in the catalog
2327 */
2328 if (ID != NULL)
2329 resource = xmlCatalogGetPublic((const xmlChar *)ID);
2330 if ((resource == NULL) && (URL != NULL))
2331 resource = xmlCatalogGetSystem((const xmlChar *)URL);
2332#endif
2333
2334 if (resource == NULL)
2335 resource = (const xmlChar *)URL;
2336
2337 if (resource == NULL) {
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002338 if ((ctxt->validate) && (ctxt->sax != NULL) &&
2339 (ctxt->sax->error != NULL))
2340 ctxt->sax->error(ctxt,
2341 "failed to load external entity \"%s\"\n", ID);
2342 else if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00002343 ctxt->sax->warning(ctxt,
2344 "failed to load external entity \"%s\"\n", ID);
2345 return(NULL);
2346 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002347 ret = xmlNewInputFromFile(ctxt, (const char *)resource);
Owen Taylor3473f882001-02-23 17:55:21 +00002348 if (ret == NULL) {
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002349 if ((ctxt->validate) && (ctxt->sax != NULL) &&
2350 (ctxt->sax->error != NULL))
2351 ctxt->sax->error(ctxt,
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002352 "failed to load external entity \"%s\"\n", resource);
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002353 else if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00002354 ctxt->sax->warning(ctxt,
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002355 "failed to load external entity \"%s\"\n", resource);
Owen Taylor3473f882001-02-23 17:55:21 +00002356 }
2357 return(ret);
2358}
2359
2360static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
2361 xmlDefaultExternalEntityLoader;
2362
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002363/**
Owen Taylor3473f882001-02-23 17:55:21 +00002364 * xmlSetExternalEntityLoader:
2365 * @f: the new entity resolver function
2366 *
2367 * Changes the defaultexternal entity resolver function for the application
2368 */
2369void
2370xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
2371 xmlCurrentExternalEntityLoader = f;
2372}
2373
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002374/**
Owen Taylor3473f882001-02-23 17:55:21 +00002375 * xmlGetExternalEntityLoader:
2376 *
2377 * Get the default external entity resolver function for the application
2378 *
2379 * Returns the xmlExternalEntityLoader function pointer
2380 */
2381xmlExternalEntityLoader
2382xmlGetExternalEntityLoader(void) {
2383 return(xmlCurrentExternalEntityLoader);
2384}
2385
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002386/**
Owen Taylor3473f882001-02-23 17:55:21 +00002387 * xmlLoadExternalEntity:
2388 * @URL: the URL for the entity to load
2389 * @ID: the System ID for the entity to load
2390 * @ctxt: the context in which the entity is called or NULL
2391 *
2392 * Load an external entity, note that the use of this function for
2393 * unparsed entities may generate problems
2394 * TODO: a more generic External entitiy API must be designed
2395 *
2396 * Returns the xmlParserInputPtr or NULL
2397 */
2398xmlParserInputPtr
2399xmlLoadExternalEntity(const char *URL, const char *ID,
2400 xmlParserCtxtPtr ctxt) {
2401 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
2402}
2403