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