blob: b9b9ae619d4dc48cb8969efe29256733fab3d0c5 [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
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000139 for (i = xmlInputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000140 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
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000164 for (i = xmlOutputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000165 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 Veillarda9e65e82001-10-30 10:32:36 +0000395 FILE *fil;
396
397 fil = (FILE *) context;
398 if (fil == stdin)
399 return(0);
400 if (fil == stdout)
401 return(0);
Daniel Veillardcd337f02001-11-22 18:20:37 +0000402 if (fil == stderr)
403 return(0);
Daniel Veillardf012a642001-07-23 19:10:52 +0000404 return ( ( fclose((FILE *) context) == EOF ) ? -1 : 0 );
Owen Taylor3473f882001-02-23 17:55:21 +0000405}
406
407/**
408 * xmlFileFlush:
409 * @context: the I/O context
410 *
411 * Flush an I/O channel
412 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000413static int
Owen Taylor3473f882001-02-23 17:55:21 +0000414xmlFileFlush (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +0000415 return ( ( fflush((FILE *) context) == EOF ) ? -1 : 0 );
Owen Taylor3473f882001-02-23 17:55:21 +0000416}
417
418#ifdef HAVE_ZLIB_H
419/************************************************************************
420 * *
421 * I/O for compressed file accesses *
422 * *
423 ************************************************************************/
424/**
425 * xmlGzfileMatch:
426 * @filename: the URI for matching
427 *
428 * input from compressed file test
429 *
430 * Returns 1 if matches, 0 otherwise
431 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000432static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000433xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000434 return(1);
435}
436
437/**
438 * xmlGzfileOpen:
439 * @filename: the URI for matching
440 *
441 * input from compressed file open
442 * if @filename is " " then the standard input is used
443 *
444 * Returns an I/O context or NULL in case of error
445 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000446static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000447xmlGzfileOpen (const char *filename) {
448 const char *path = NULL;
449 gzFile fd;
450
451 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000452 fd = gzdopen(dup(0), "rb");
Owen Taylor3473f882001-02-23 17:55:21 +0000453 return((void *) fd);
454 }
455
456 if (!strncmp(filename, "file://localhost", 16))
457 path = &filename[16];
Daniel Veillardfe703322001-08-14 12:18:09 +0000458 else if (!strncmp(filename, "file:///", 8)) {
459#ifdef _WIN32
460 path = &filename[8];
461#else
Owen Taylor3473f882001-02-23 17:55:21 +0000462 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000463#endif
464 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000465 path = filename;
466
467 if (path == NULL)
468 return(NULL);
469 if (!xmlCheckFilename(path))
470 return(NULL);
471
472 fd = gzopen(path, "rb");
473 return((void *) fd);
474}
475
476/**
477 * xmlGzfileOpenW:
478 * @filename: the URI for matching
479 * @compression: the compression factor (0 - 9 included)
480 *
481 * input from compressed file open
482 * if @filename is " " then the standard input is used
483 *
484 * Returns an I/O context or NULL in case of error
485 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000486static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000487xmlGzfileOpenW (const char *filename, int compression) {
488 const char *path = NULL;
489 char mode[15];
490 gzFile fd;
491
492 sprintf(mode, "wb%d", compression);
493 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000494 fd = gzdopen(dup(1), mode);
Owen Taylor3473f882001-02-23 17:55:21 +0000495 return((void *) fd);
496 }
497
498 if (!strncmp(filename, "file://localhost", 16))
499 path = &filename[16];
Daniel Veillardfe703322001-08-14 12:18:09 +0000500 else if (!strncmp(filename, "file:///", 8)) {
501#ifdef _WIN32
502 path = &filename[8];
503#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000504 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000505#endif
506 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000507 path = filename;
508
509 if (path == NULL)
510 return(NULL);
511
512 fd = gzopen(path, mode);
513 return((void *) fd);
514}
515
516/**
517 * xmlGzfileRead:
518 * @context: the I/O context
519 * @buffer: where to drop data
520 * @len: number of bytes to write
521 *
522 * Read @len bytes to @buffer from the compressed I/O channel.
523 *
524 * Returns the number of bytes written
525 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000526static int
Owen Taylor3473f882001-02-23 17:55:21 +0000527xmlGzfileRead (void * context, char * buffer, int len) {
528 return(gzread((gzFile) context, &buffer[0], len));
529}
530
531/**
532 * xmlGzfileWrite:
533 * @context: the I/O context
534 * @buffer: where to drop data
535 * @len: number of bytes to write
536 *
537 * Write @len bytes from @buffer to the compressed I/O channel.
538 *
539 * Returns the number of bytes written
540 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000541static int
Owen Taylor3473f882001-02-23 17:55:21 +0000542xmlGzfileWrite (void * context, const char * buffer, int len) {
543 return(gzwrite((gzFile) context, (char *) &buffer[0], len));
544}
545
546/**
547 * xmlGzfileClose:
548 * @context: the I/O context
549 *
550 * Close a compressed I/O channel
551 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000552static int
Owen Taylor3473f882001-02-23 17:55:21 +0000553xmlGzfileClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +0000554 return ( ( gzclose((gzFile) context) == Z_OK ) ? 0 : -1 );
Owen Taylor3473f882001-02-23 17:55:21 +0000555}
556#endif /* HAVE_ZLIB_H */
557
558#ifdef LIBXML_HTTP_ENABLED
559/************************************************************************
560 * *
561 * I/O for HTTP file accesses *
562 * *
563 ************************************************************************/
Daniel Veillardf012a642001-07-23 19:10:52 +0000564
565typedef struct xmlIOHTTPWriteCtxt_
566{
567 int compression;
568
569 char * uri;
570
571 void * doc_buff;
572
573} xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr;
574
575#ifdef HAVE_ZLIB_H
576
577#define DFLT_WBITS ( -15 )
578#define DFLT_MEM_LVL ( 8 )
579#define GZ_MAGIC1 ( 0x1f )
580#define GZ_MAGIC2 ( 0x8b )
581#define LXML_ZLIB_OS_CODE ( 0x03 )
582#define INIT_HTTP_BUFF_SIZE ( 32768 )
583#define DFLT_ZLIB_RATIO ( 5 )
584
585/*
586** Data structure and functions to work with sending compressed data
587** via HTTP.
588*/
589
590typedef struct xmlZMemBuff_
591{
592 unsigned long size;
593 unsigned long crc;
594
595 unsigned char * zbuff;
596 z_stream zctrl;
597
598} xmlZMemBuff, *xmlZMemBuffPtr;
599
600/**
601 * append_reverse_ulong
602 * @buff: Compressed memory buffer
603 * @data: Unsigned long to append
604 *
605 * Append a unsigned long in reverse byte order to the end of the
606 * memory buffer.
607 */
608static void
609append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) {
610
611 int idx;
612
613 if ( buff == NULL )
614 return;
615
616 /*
617 ** This is plagiarized from putLong in gzio.c (zlib source) where
618 ** the number "4" is hardcoded. If zlib is ever patched to
619 ** support 64 bit file sizes, this code would need to be patched
620 ** as well.
621 */
622
623 for ( idx = 0; idx < 4; idx++ ) {
624 *buff->zctrl.next_out = ( data & 0xff );
625 data >>= 8;
626 buff->zctrl.next_out++;
627 }
628
629 return;
630}
631
632/**
633 *
634 * xmlFreeZMemBuff
635 * @buff: The memory buffer context to clear
636 *
637 * Release all the resources associated with the compressed memory buffer.
638 */
639static void
640xmlFreeZMemBuff( xmlZMemBuffPtr buff ) {
641
642 int z_err;
643
644 if ( buff == NULL )
645 return;
646
647 xmlFree( buff->zbuff );
648 z_err = deflateEnd( &buff->zctrl );
649#ifdef DEBUG_HTTP
650 if ( z_err != Z_OK )
651 xmlGenericError( xmlGenericErrorContext,
652 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
653 z_err );
654#endif
655
656 xmlFree( buff );
657 return;
658}
659
660/**
661 * xmlCreateZMemBuff
662 *@compression: Compression value to use
663 *
664 * Create a memory buffer to hold the compressed XML document. The
665 * compressed document in memory will end up being identical to what
666 * would be created if gzopen/gzwrite/gzclose were being used to
667 * write the document to disk. The code for the header/trailer data to
668 * the compression is plagiarized from the zlib source files.
669 */
670static void *
671xmlCreateZMemBuff( int compression ) {
672
673 int z_err;
674 int hdr_lgth;
675 xmlZMemBuffPtr buff = NULL;
676
677 if ( ( compression < 1 ) || ( compression > 9 ) )
678 return ( NULL );
679
680 /* Create the control and data areas */
681
682 buff = xmlMalloc( sizeof( xmlZMemBuff ) );
683 if ( buff == NULL ) {
684 xmlGenericError( xmlGenericErrorContext,
685 "xmlCreateZMemBuff: %s\n",
686 "Failure allocating buffer context." );
687 return ( NULL );
688 }
689
690 (void)memset( buff, 0, sizeof( xmlZMemBuff ) );
691 buff->size = INIT_HTTP_BUFF_SIZE;
692 buff->zbuff = xmlMalloc( buff->size );
693 if ( buff->zbuff == NULL ) {
694 xmlFreeZMemBuff( buff );
695 xmlGenericError( xmlGenericErrorContext,
696 "xmlCreateZMemBuff: %s\n",
697 "Failure allocating data buffer." );
698 return ( NULL );
699 }
700
701 z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
702 DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
703 if ( z_err != Z_OK ) {
704 xmlFreeZMemBuff( buff );
705 buff = NULL;
706 xmlGenericError( xmlGenericErrorContext,
707 "xmlCreateZMemBuff: %s %d\n",
708 "Error initializing compression context. ZLIB error:",
709 z_err );
710 return ( NULL );
711 }
712
713 /* Set the header data. The CRC will be needed for the trailer */
714
715 buff->crc = crc32( 0L, Z_NULL, 0 );
716 hdr_lgth = sprintf( (char *)buff->zbuff, "%c%c%c%c%c%c%c%c%c%c",
717 GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED,
718 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE );
719 buff->zctrl.next_out = buff->zbuff + hdr_lgth;
720 buff->zctrl.avail_out = buff->size - hdr_lgth;
721
722 return ( buff );
723}
724
725/**
726 * xmlZMemBuffExtend
727 * @buff: Buffer used to compress and consolidate data.
728 * @ext_amt: Number of bytes to extend the buffer.
729 *
730 * Extend the internal buffer used to store the compressed data by the
731 * specified amount.
732 *
733 * Returns 0 on success or -1 on failure to extend the buffer. On failure
734 * the original buffer still exists at the original size.
735 */
736static int
737xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) {
738
739 int rc = -1;
740 size_t new_size;
741 size_t cur_used;
742
743 unsigned char * tmp_ptr = NULL;
744
745 if ( buff == NULL )
746 return ( -1 );
747
748 else if ( ext_amt == 0 )
749 return ( 0 );
750
751 cur_used = buff->zctrl.next_out - buff->zbuff;
752 new_size = buff->size + ext_amt;
753
754#ifdef DEBUG_HTTP
755 if ( cur_used > new_size )
756 xmlGenericError( xmlGenericErrorContext,
757 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
758 "Buffer overwrite detected during compressed memory",
759 "buffer extension. Overflowed by",
760 (cur_used - new_size ) );
761#endif
762
763 tmp_ptr = xmlRealloc( buff->zbuff, new_size );
764 if ( tmp_ptr != NULL ) {
765 rc = 0;
766 buff->size = new_size;
767 buff->zbuff = tmp_ptr;
768 buff->zctrl.next_out = tmp_ptr + cur_used;
769 buff->zctrl.avail_out = new_size - cur_used;
770 }
771 else {
772 xmlGenericError( xmlGenericErrorContext,
773 "xmlZMemBuffExtend: %s %lu bytes.\n",
774 "Allocation failure extending output buffer to",
775 new_size );
776 }
777
778 return ( rc );
779}
780
781/**
782 * xmlZMemBuffAppend
783 * @buff: Buffer used to compress and consolidate data
784 * @src: Uncompressed source content to append to buffer
785 * @len: Length of source data to append to buffer
786 *
787 * Compress and append data to the internal buffer. The data buffer
788 * will be expanded if needed to store the additional data.
789 *
790 * Returns the number of bytes appended to the buffer or -1 on error.
791 */
792static int
793xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) {
794
795 int z_err;
796 size_t min_accept;
797
798 if ( ( buff == NULL ) || ( src == NULL ) )
799 return ( -1 );
800
801 buff->zctrl.avail_in = len;
802 buff->zctrl.next_in = (unsigned char *)src;
803 while ( buff->zctrl.avail_in > 0 ) {
804 /*
805 ** Extend the buffer prior to deflate call if a reasonable amount
806 ** of output buffer space is not available.
807 */
808 min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO;
809 if ( buff->zctrl.avail_out <= min_accept ) {
810 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
811 return ( -1 );
812 }
813
814 z_err = deflate( &buff->zctrl, Z_NO_FLUSH );
815 if ( z_err != Z_OK ) {
816 xmlGenericError( xmlGenericErrorContext,
817 "xmlZMemBuffAppend: %s %d %s - %d",
818 "Compression error while appending",
819 len, "bytes to buffer. ZLIB error", z_err );
820 return ( -1 );
821 }
822 }
823
824 buff->crc = crc32( buff->crc, (unsigned char *)src, len );
825
826 return ( len );
827}
828
829/**
830 * xmlZMemBuffGetContent
831 * @buff: Compressed memory content buffer
832 * @data_ref: Pointer reference to point to compressed content
833 *
834 * Flushes the compression buffers, appends gzip file trailers and
835 * returns the compressed content and length of the compressed data.
836 * NOTE: The gzip trailer code here is plagiarized from zlib source.
837 *
838 * Returns the length of the compressed data or -1 on error.
839 */
840static int
841xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) {
842
843 int zlgth = -1;
844 int z_err;
845
846 if ( ( buff == NULL ) || ( data_ref == NULL ) )
847 return ( -1 );
848
849 /* Need to loop until compression output buffers are flushed */
850
851 do
852 {
853 z_err = deflate( &buff->zctrl, Z_FINISH );
854 if ( z_err == Z_OK ) {
855 /* In this case Z_OK means more buffer space needed */
856
857 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
858 return ( -1 );
859 }
860 }
861 while ( z_err == Z_OK );
862
863 /* If the compression state is not Z_STREAM_END, some error occurred */
864
865 if ( z_err == Z_STREAM_END ) {
866
867 /* Need to append the gzip data trailer */
868
869 if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) {
870 if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 )
871 return ( -1 );
872 }
873
874 /*
875 ** For whatever reason, the CRC and length data are pushed out
876 ** in reverse byte order. So a memcpy can't be used here.
877 */
878
879 append_reverse_ulong( buff, buff->crc );
880 append_reverse_ulong( buff, buff->zctrl.total_in );
881
882 zlgth = buff->zctrl.next_out - buff->zbuff;
883 *data_ref = (char *)buff->zbuff;
884 }
885
886 else
887 xmlGenericError( xmlGenericErrorContext,
888 "xmlZMemBuffGetContent: %s - %d\n",
889 "Error flushing zlib buffers. Error code", z_err );
890
891 return ( zlgth );
892}
893#endif /* HAVE_ZLIB_H */
894
895/**
896 * xmlFreeHTTPWriteCtxt
897 * @ctxt: Context to cleanup
898 *
899 * Free allocated memory and reclaim system resources.
900 *
901 * No return value.
902 */
903static void
904xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt )
905{
906 if ( ctxt->uri != NULL )
907 free( ctxt->uri );
908
909 if ( ctxt->doc_buff != NULL ) {
910
911#ifdef HAVE_ZLIB_H
912 if ( ctxt->compression > 0 ) {
913 xmlFreeZMemBuff( ctxt->doc_buff );
914 }
915 else
916#endif
917 {
918 xmlOutputBufferClose( ctxt->doc_buff );
919 }
920 }
921
922 free( ctxt );
923 return;
924}
925
926
Owen Taylor3473f882001-02-23 17:55:21 +0000927/**
928 * xmlIOHTTPMatch:
929 * @filename: the URI for matching
930 *
931 * check if the URI matches an HTTP one
932 *
933 * Returns 1 if matches, 0 otherwise
934 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000935static int
Owen Taylor3473f882001-02-23 17:55:21 +0000936xmlIOHTTPMatch (const char *filename) {
937 if (!strncmp(filename, "http://", 7))
938 return(1);
939 return(0);
940}
941
942/**
943 * xmlIOHTTPOpen:
944 * @filename: the URI for matching
945 *
946 * open an HTTP I/O channel
947 *
948 * Returns an I/O context or NULL in case of error
949 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000950static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000951xmlIOHTTPOpen (const char *filename) {
952 return(xmlNanoHTTPOpen(filename, NULL));
953}
954
955/**
Daniel Veillardf012a642001-07-23 19:10:52 +0000956 * xmlIOHTTPOpenW
957 * @post_uri: The destination URI for the document
958 * @compression: The compression desired for the document.
959 *
960 * Open a temporary buffer to collect the document for a subsequent HTTP POST
961 * request. Non-static as is called from the output buffer creation routine.
962 *
963 * Returns an I/O context or NULL in case of error.
964 */
965
966void *
967xmlIOHTTPOpenW( const char * post_uri, int compression ) {
968
969 xmlIOHTTPWriteCtxtPtr ctxt = NULL;
970
971 if ( post_uri == NULL )
972 return ( NULL );
973
974 ctxt = xmlMalloc( sizeof( xmlIOHTTPWriteCtxt ) );
975 if ( ctxt == NULL ) {
976 xmlGenericError( xmlGenericErrorContext,
977 "xmlIOHTTPOpenW: Failed to create output HTTP context.\n" );
978 return ( NULL );
979 }
980
981 (void)memset( ctxt, 0, sizeof( xmlIOHTTPWriteCtxt ) );
982
983 ctxt->uri = strdup( post_uri );
984 if ( ctxt->uri == NULL ) {
985 xmlGenericError( xmlGenericErrorContext,
986 "xmlIOHTTPOpenW: Failed to duplicate destination URI.\n" );
987 xmlFreeHTTPWriteCtxt( ctxt );
988 return ( NULL );
989 }
990
991 /*
992 ** Since the document length is required for an HTTP post,
993 ** need to put the document into a buffer. A memory buffer
994 ** is being used to avoid pushing the data to disk and back.
995 */
996
997#ifdef HAVE_ZLIB_H
998 if ( ( compression > 0 ) && ( compression <= 9 ) ) {
999
1000 ctxt->compression = compression;
1001 ctxt->doc_buff = xmlCreateZMemBuff( compression );
1002 }
1003 else
1004#endif
1005 {
1006 /* Any character conversions should have been done before this */
1007
1008 ctxt->doc_buff = xmlAllocOutputBuffer( NULL );
1009 }
1010
1011 if ( ctxt->doc_buff == NULL ) {
1012 xmlFreeHTTPWriteCtxt( ctxt );
1013 ctxt = NULL;
1014 }
1015
1016 return ( ctxt );
1017}
1018
1019/**
1020 * xmlIOHTTPDfltOpenW
1021 * @post_uri: The destination URI for this document.
1022 *
1023 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
1024 * HTTP post command. This function should generally not be used as
1025 * the open callback is short circuited in xmlOutputBufferCreateFile.
1026 *
1027 * Returns a pointer to the new IO context.
1028 */
1029static void *
1030xmlIOHTTPDfltOpenW( const char * post_uri ) {
1031 return ( xmlIOHTTPOpenW( post_uri, 0 ) );
1032}
1033
1034/**
Owen Taylor3473f882001-02-23 17:55:21 +00001035 * xmlIOHTTPRead:
1036 * @context: the I/O context
1037 * @buffer: where to drop data
1038 * @len: number of bytes to write
1039 *
1040 * Read @len bytes to @buffer from the I/O channel.
1041 *
1042 * Returns the number of bytes written
1043 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001044static int
Owen Taylor3473f882001-02-23 17:55:21 +00001045xmlIOHTTPRead(void * context, char * buffer, int len) {
1046 return(xmlNanoHTTPRead(context, &buffer[0], len));
1047}
1048
1049/**
Daniel Veillardf012a642001-07-23 19:10:52 +00001050 * xmlIOHTTPWrite
1051 * @context: previously opened writing context
1052 * @buffer: data to output to temporary buffer
1053 * @len: bytes to output
1054 *
1055 * Collect data from memory buffer into a temporary file for later
1056 * processing.
1057 *
1058 * Returns number of bytes written.
1059 */
1060
1061static int
1062xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
1063
1064 xmlIOHTTPWriteCtxtPtr ctxt = context;
1065
1066 if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
1067 return ( -1 );
1068
1069 if ( len > 0 ) {
1070
1071 /* Use gzwrite or fwrite as previously setup in the open call */
1072
1073#ifdef HAVE_ZLIB_H
1074 if ( ctxt->compression > 0 )
1075 len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len );
1076
1077 else
1078#endif
1079 len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
1080
1081 if ( len < 0 ) {
1082 xmlGenericError( xmlGenericErrorContext,
1083 "xmlIOHTTPWrite: %s\n%s '%s'.\n",
1084 "Error appending to internal buffer.",
1085 "Error sending document to URI",
1086 ctxt->uri );
1087 }
1088 }
1089
1090 return ( len );
1091}
1092
1093
1094/**
Owen Taylor3473f882001-02-23 17:55:21 +00001095 * xmlIOHTTPClose:
1096 * @context: the I/O context
1097 *
1098 * Close an HTTP I/O channel
1099 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001100static int
Owen Taylor3473f882001-02-23 17:55:21 +00001101xmlIOHTTPClose (void * context) {
1102 xmlNanoHTTPClose(context);
Daniel Veillardf012a642001-07-23 19:10:52 +00001103 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001104}
Daniel Veillardf012a642001-07-23 19:10:52 +00001105
1106/**
1107 * xmlIOHTTCloseWrite
1108 * @context: The I/O context
1109 * @http_mthd: The HTTP method to be used when sending the data
1110 *
1111 * Close the transmit HTTP I/O channel and actually send the data.
1112 */
1113static int
1114xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
1115
1116 int close_rc = -1;
1117 int http_rtn = 0;
1118 int content_lgth = 0;
1119 xmlIOHTTPWriteCtxtPtr ctxt = context;
1120
1121 char * http_content = NULL;
1122 char * content_encoding = NULL;
1123 char * content_type = (char *) "text/xml";
1124 void * http_ctxt = NULL;
1125
1126 if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
1127 return ( -1 );
1128
1129 /* Retrieve the content from the appropriate buffer */
1130
1131#ifdef HAVE_ZLIB_H
1132
1133 if ( ctxt->compression > 0 ) {
1134 content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
1135 content_encoding = (char *) "Content-Encoding: gzip";
1136 }
1137 else
1138#endif
1139 {
1140 /* Pull the data out of the memory output buffer */
1141
1142 xmlOutputBufferPtr dctxt = ctxt->doc_buff;
1143 http_content = (char *)dctxt->buffer->content;
1144 content_lgth = dctxt->buffer->use;
1145 }
1146
1147 if ( http_content == NULL ) {
1148 xmlGenericError( xmlGenericErrorContext,
1149 "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
1150 "Error retrieving content.\nUnable to",
1151 http_mthd, "data to URI", ctxt->uri );
1152 }
1153
1154 else {
1155
1156 http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
1157 &content_type, content_encoding,
1158 content_lgth );
1159
1160 if ( http_ctxt != NULL ) {
1161#ifdef DEBUG_HTTP
1162 /* If testing/debugging - dump reply with request content */
1163
1164 FILE * tst_file = NULL;
1165 char buffer[ 4096 ];
1166 char * dump_name = NULL;
1167 int avail;
1168
1169 xmlGenericError( xmlGenericErrorContext,
1170 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
1171 http_mthd, ctxt->uri,
1172 xmlNanoHTTPReturnCode( http_ctxt ) );
1173
1174 /*
1175 ** Since either content or reply may be gzipped,
1176 ** dump them to separate files instead of the
1177 ** standard error context.
1178 */
1179
1180 dump_name = tempnam( NULL, "lxml" );
1181 if ( dump_name != NULL ) {
1182 (void)sprintf( buffer, "%s.content", dump_name );
1183
1184 tst_file = fopen( buffer, "w" );
1185 if ( tst_file != NULL ) {
1186 xmlGenericError( xmlGenericErrorContext,
1187 "Transmitted content saved in file: %s\n", buffer );
1188
1189 fwrite( http_content, sizeof( char ),
1190 content_lgth, tst_file );
1191 fclose( tst_file );
1192 }
1193
1194 (void)sprintf( buffer, "%s.reply", dump_name );
1195 tst_file = fopen( buffer, "w" );
1196 if ( tst_file != NULL ) {
1197 xmlGenericError( xmlGenericErrorContext,
1198 "Reply content saved in file: %s\n", buffer );
1199
1200
1201 while ( (avail = xmlNanoHTTPRead( http_ctxt,
1202 buffer, sizeof( buffer ) )) > 0 ) {
1203
1204 fwrite( buffer, sizeof( char ), avail, tst_file );
1205 }
1206
1207 fclose( tst_file );
1208 }
1209
1210 free( dump_name );
1211 }
1212#endif /* DEBUG_HTTP */
1213
1214 http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
1215 if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
1216 close_rc = 0;
1217 else
1218 xmlGenericError( xmlGenericErrorContext,
1219 "xmlIOHTTPClose: HTTP '%s' of %d %s\n'%s' %s %d\n",
1220 http_mthd, content_lgth,
1221 "bytes to URI", ctxt->uri,
1222 "failed. HTTP return code:", http_rtn );
1223
1224 xmlNanoHTTPClose( http_ctxt );
1225 xmlFree( content_type );
1226 }
1227 }
1228
1229 /* Final cleanups */
1230
1231 xmlFreeHTTPWriteCtxt( ctxt );
1232
1233 return ( close_rc );
1234}
1235
1236/**
1237 * xmlIOHTTPClosePut
1238 *
1239 * @context: The I/O context
1240 *
1241 * Close the transmit HTTP I/O channel and actually send data using a PUT
1242 * HTTP method.
1243 */
1244static int
1245xmlIOHTTPClosePut( void * ctxt ) {
1246 return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
1247}
1248
1249
1250/**
1251 * xmlIOHTTPClosePost
1252 *
1253 * @context: The I/O context
1254 *
1255 * Close the transmit HTTP I/O channel and actually send data using a POST
1256 * HTTP method.
1257 */
1258static int
1259xmlIOHTTPClosePost( void * ctxt ) {
1260 return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
1261}
1262
Owen Taylor3473f882001-02-23 17:55:21 +00001263#endif /* LIBXML_HTTP_ENABLED */
1264
1265#ifdef LIBXML_FTP_ENABLED
1266/************************************************************************
1267 * *
1268 * I/O for FTP file accesses *
1269 * *
1270 ************************************************************************/
1271/**
1272 * xmlIOFTPMatch:
1273 * @filename: the URI for matching
1274 *
1275 * check if the URI matches an FTP one
1276 *
1277 * Returns 1 if matches, 0 otherwise
1278 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001279static int
Owen Taylor3473f882001-02-23 17:55:21 +00001280xmlIOFTPMatch (const char *filename) {
1281 if (!strncmp(filename, "ftp://", 6))
1282 return(1);
1283 return(0);
1284}
1285
1286/**
1287 * xmlIOFTPOpen:
1288 * @filename: the URI for matching
1289 *
1290 * open an FTP I/O channel
1291 *
1292 * Returns an I/O context or NULL in case of error
1293 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001294static void *
Owen Taylor3473f882001-02-23 17:55:21 +00001295xmlIOFTPOpen (const char *filename) {
1296 return(xmlNanoFTPOpen(filename));
1297}
1298
1299/**
1300 * xmlIOFTPRead:
1301 * @context: the I/O context
1302 * @buffer: where to drop data
1303 * @len: number of bytes to write
1304 *
1305 * Read @len bytes to @buffer from the I/O channel.
1306 *
1307 * Returns the number of bytes written
1308 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001309static int
Owen Taylor3473f882001-02-23 17:55:21 +00001310xmlIOFTPRead(void * context, char * buffer, int len) {
1311 return(xmlNanoFTPRead(context, &buffer[0], len));
1312}
1313
1314/**
1315 * xmlIOFTPClose:
1316 * @context: the I/O context
1317 *
1318 * Close an FTP I/O channel
1319 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001320static int
Owen Taylor3473f882001-02-23 17:55:21 +00001321xmlIOFTPClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001322 return ( xmlNanoFTPClose(context) );
Owen Taylor3473f882001-02-23 17:55:21 +00001323}
1324#endif /* LIBXML_FTP_ENABLED */
1325
1326
1327/**
1328 * xmlRegisterInputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001329 * @matchFunc: the xmlInputMatchCallback
1330 * @openFunc: the xmlInputOpenCallback
1331 * @readFunc: the xmlInputReadCallback
1332 * @closeFunc: the xmlInputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001333 *
1334 * Register a new set of I/O callback for handling parser input.
1335 *
1336 * Returns the registered handler number or -1 in case of error
1337 */
1338int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001339xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
1340 xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
1341 xmlInputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001342 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
1343 return(-1);
1344 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001345 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
1346 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
1347 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
1348 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
Owen Taylor3473f882001-02-23 17:55:21 +00001349 return(xmlInputCallbackNr++);
1350}
1351
1352/**
1353 * xmlRegisterOutputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001354 * @matchFunc: the xmlOutputMatchCallback
1355 * @openFunc: the xmlOutputOpenCallback
1356 * @writeFunc: the xmlOutputWriteCallback
1357 * @closeFunc: the xmlOutputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001358 *
1359 * Register a new set of I/O callback for handling output.
1360 *
1361 * Returns the registered handler number or -1 in case of error
1362 */
1363int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001364xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
1365 xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
1366 xmlOutputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001367 if (xmlOutputCallbackNr >= MAX_INPUT_CALLBACK) {
1368 return(-1);
1369 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001370 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
1371 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
1372 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
1373 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
Owen Taylor3473f882001-02-23 17:55:21 +00001374 return(xmlOutputCallbackNr++);
1375}
1376
1377/**
1378 * xmlRegisterDefaultInputCallbacks:
1379 *
1380 * Registers the default compiled-in I/O handlers.
1381 */
1382void
1383#ifdef VMS
1384xmlRegisterDefInputCallbacks
1385#else
1386xmlRegisterDefaultInputCallbacks
1387#endif
1388(void) {
1389 if (xmlInputCallbackInitialized)
1390 return;
1391
1392 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
1393 xmlFileRead, xmlFileClose);
1394#ifdef HAVE_ZLIB_H
1395 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1396 xmlGzfileRead, xmlGzfileClose);
1397#endif /* HAVE_ZLIB_H */
1398
1399#ifdef LIBXML_HTTP_ENABLED
1400 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
1401 xmlIOHTTPRead, xmlIOHTTPClose);
1402#endif /* LIBXML_HTTP_ENABLED */
1403
1404#ifdef LIBXML_FTP_ENABLED
1405 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1406 xmlIOFTPRead, xmlIOFTPClose);
1407#endif /* LIBXML_FTP_ENABLED */
1408 xmlInputCallbackInitialized = 1;
1409}
1410
1411/**
1412 * xmlRegisterDefaultOutputCallbacks:
1413 *
1414 * Registers the default compiled-in I/O handlers.
1415 */
1416void
1417#ifdef VMS
1418xmlRegisterDefOutputCallbacks
1419#else
1420xmlRegisterDefaultOutputCallbacks
1421#endif
1422(void) {
1423 if (xmlOutputCallbackInitialized)
1424 return;
1425
1426 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
1427 xmlFileWrite, xmlFileClose);
Daniel Veillardf012a642001-07-23 19:10:52 +00001428
1429#ifdef LIBXML_HTTP_ENABLED
1430 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
1431 xmlIOHTTPWrite, xmlIOHTTPClosePut);
1432#endif
1433
Owen Taylor3473f882001-02-23 17:55:21 +00001434/*********************************
1435 No way a-priori to distinguish between gzipped files from
1436 uncompressed ones except opening if existing then closing
1437 and saving with same compression ratio ... a pain.
1438
1439#ifdef HAVE_ZLIB_H
1440 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1441 xmlGzfileWrite, xmlGzfileClose);
1442#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001443
1444 Nor FTP PUT ....
1445#ifdef LIBXML_FTP_ENABLED
1446 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1447 xmlIOFTPWrite, xmlIOFTPClose);
1448#endif
1449 **********************************/
1450 xmlOutputCallbackInitialized = 1;
1451}
1452
Daniel Veillardf012a642001-07-23 19:10:52 +00001453#ifdef LIBXML_HTTP_ENABLED
1454/**
1455 * xmlRegisterHTTPPostCallbacks
1456 *
1457 * By default, libxml submits HTTP output requests using the "PUT" method.
1458 * Calling this method changes the HTTP output method to use the "POST"
1459 * method instead.
1460 *
1461 */
1462void
1463xmlRegisterHTTPPostCallbacks( void ) {
1464
1465 /* Register defaults if not done previously */
1466
1467 if ( xmlOutputCallbackInitialized == 0 )
1468 xmlRegisterDefaultOutputCallbacks( );
1469
1470 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
1471 xmlIOHTTPWrite, xmlIOHTTPClosePost);
1472 return;
1473}
1474#endif
1475
Owen Taylor3473f882001-02-23 17:55:21 +00001476/**
1477 * xmlAllocParserInputBuffer:
1478 * @enc: the charset encoding if known
1479 *
1480 * Create a buffered parser input for progressive parsing
1481 *
1482 * Returns the new parser input or NULL
1483 */
1484xmlParserInputBufferPtr
1485xmlAllocParserInputBuffer(xmlCharEncoding enc) {
1486 xmlParserInputBufferPtr ret;
1487
1488 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
1489 if (ret == NULL) {
1490 xmlGenericError(xmlGenericErrorContext,
1491 "xmlAllocParserInputBuffer : out of memory!\n");
1492 return(NULL);
1493 }
1494 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
1495 ret->buffer = xmlBufferCreate();
1496 if (ret->buffer == NULL) {
1497 xmlFree(ret);
1498 return(NULL);
1499 }
1500 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
1501 ret->encoder = xmlGetCharEncodingHandler(enc);
1502 if (ret->encoder != NULL)
1503 ret->raw = xmlBufferCreate();
1504 else
1505 ret->raw = NULL;
1506 ret->readcallback = NULL;
1507 ret->closecallback = NULL;
1508 ret->context = NULL;
1509
1510 return(ret);
1511}
1512
1513/**
1514 * xmlAllocOutputBuffer:
1515 * @encoder: the encoding converter or NULL
1516 *
1517 * Create a buffered parser output
1518 *
1519 * Returns the new parser output or NULL
1520 */
1521xmlOutputBufferPtr
1522xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
1523 xmlOutputBufferPtr ret;
1524
1525 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
1526 if (ret == NULL) {
1527 xmlGenericError(xmlGenericErrorContext,
1528 "xmlAllocOutputBuffer : out of memory!\n");
1529 return(NULL);
1530 }
1531 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
1532 ret->buffer = xmlBufferCreate();
1533 if (ret->buffer == NULL) {
1534 xmlFree(ret);
1535 return(NULL);
1536 }
1537 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
1538 ret->encoder = encoder;
1539 if (encoder != NULL) {
1540 ret->conv = xmlBufferCreateSize(4000);
1541 /*
1542 * This call is designed to initiate the encoder state
1543 */
1544 xmlCharEncOutFunc(encoder, ret->conv, NULL);
1545 } else
1546 ret->conv = NULL;
1547 ret->writecallback = NULL;
1548 ret->closecallback = NULL;
1549 ret->context = NULL;
1550 ret->written = 0;
1551
1552 return(ret);
1553}
1554
1555/**
1556 * xmlFreeParserInputBuffer:
1557 * @in: a buffered parser input
1558 *
1559 * Free up the memory used by a buffered parser input
1560 */
1561void
1562xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
1563 if (in->raw) {
1564 xmlBufferFree(in->raw);
1565 in->raw = NULL;
1566 }
1567 if (in->encoder != NULL) {
1568 xmlCharEncCloseFunc(in->encoder);
1569 }
1570 if (in->closecallback != NULL) {
1571 in->closecallback(in->context);
1572 }
1573 if (in->buffer != NULL) {
1574 xmlBufferFree(in->buffer);
1575 in->buffer = NULL;
1576 }
1577
Owen Taylor3473f882001-02-23 17:55:21 +00001578 xmlFree(in);
1579}
1580
1581/**
1582 * xmlOutputBufferClose:
1583 * @out: a buffered output
1584 *
1585 * flushes and close the output I/O channel
1586 * and free up all the associated resources
1587 *
1588 * Returns the number of byte written or -1 in case of error.
1589 */
1590int
1591xmlOutputBufferClose(xmlOutputBufferPtr out) {
1592 int written;
Daniel Veillardf012a642001-07-23 19:10:52 +00001593 int err_rc = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001594
1595 if (out == NULL)
1596 return(-1);
1597 if (out->writecallback != NULL)
1598 xmlOutputBufferFlush(out);
1599 if (out->closecallback != NULL) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001600 err_rc = out->closecallback(out->context);
Owen Taylor3473f882001-02-23 17:55:21 +00001601 }
1602 written = out->written;
1603 if (out->conv) {
1604 xmlBufferFree(out->conv);
1605 out->conv = NULL;
1606 }
1607 if (out->encoder != NULL) {
1608 xmlCharEncCloseFunc(out->encoder);
1609 }
1610 if (out->buffer != NULL) {
1611 xmlBufferFree(out->buffer);
1612 out->buffer = NULL;
1613 }
1614
Owen Taylor3473f882001-02-23 17:55:21 +00001615 xmlFree(out);
Daniel Veillardf012a642001-07-23 19:10:52 +00001616 return( ( err_rc == 0 ) ? written : err_rc );
Owen Taylor3473f882001-02-23 17:55:21 +00001617}
1618
1619/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001620 * xmlParserInputBufferCreateFname:
1621 * @URI: a C string containing the URI or filename
1622 * @enc: the charset encoding if known
1623 *
1624 * VMS version of xmlParserInputBufferCreateFilename()
1625 *
1626 * Returns the new parser input or NULL
1627 */
1628/**
Owen Taylor3473f882001-02-23 17:55:21 +00001629 * xmlParserInputBufferCreateFilename:
1630 * @URI: a C string containing the URI or filename
1631 * @enc: the charset encoding if known
1632 *
1633 * Create a buffered parser input for the progressive parsing of a file
1634 * If filename is "-' then we use stdin as the input.
1635 * Automatic support for ZLIB/Compress compressed document is provided
1636 * by default if found at compile-time.
1637 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
1638 *
1639 * Returns the new parser input or NULL
1640 */
1641xmlParserInputBufferPtr
1642#ifdef VMS
1643xmlParserInputBufferCreateFname
1644#else
1645xmlParserInputBufferCreateFilename
1646#endif
1647(const char *URI, xmlCharEncoding enc) {
1648 xmlParserInputBufferPtr ret;
Daniel Veillard388236f2001-07-08 18:35:48 +00001649 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001650 void *context = NULL;
Daniel Veillard388236f2001-07-08 18:35:48 +00001651 char *unescaped;
Owen Taylor3473f882001-02-23 17:55:21 +00001652
1653 if (xmlInputCallbackInitialized == 0)
1654 xmlRegisterDefaultInputCallbacks();
1655
1656 if (URI == NULL) return(NULL);
1657
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001658#ifdef LIBXML_CATALOG_ENABLED
1659#endif
1660
Owen Taylor3473f882001-02-23 17:55:21 +00001661 /*
1662 * Try to find one of the input accept method accepting taht scheme
1663 * Go in reverse to give precedence to user defined handlers.
Daniel Veillard388236f2001-07-08 18:35:48 +00001664 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00001665 */
Daniel Veillard388236f2001-07-08 18:35:48 +00001666 unescaped = xmlURIUnescapeString(URI, 0, NULL);
1667 if (unescaped != NULL) {
1668 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
1669 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
1670 (xmlInputCallbackTable[i].matchcallback(unescaped) != 0)) {
1671 context = xmlInputCallbackTable[i].opencallback(unescaped);
1672 if (context != NULL)
1673 break;
1674 }
1675 }
1676 xmlFree(unescaped);
1677 }
1678
1679 /*
1680 * If this failed try with a non-escaped URI this may be a strange
1681 * filename
1682 */
1683 if (context == NULL) {
1684 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
1685 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
1686 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
1687 context = xmlInputCallbackTable[i].opencallback(URI);
1688 if (context != NULL)
1689 break;
1690 }
Owen Taylor3473f882001-02-23 17:55:21 +00001691 }
1692 }
1693 if (context == NULL) {
1694 return(NULL);
1695 }
1696
1697 /*
1698 * Allocate the Input buffer front-end.
1699 */
1700 ret = xmlAllocParserInputBuffer(enc);
1701 if (ret != NULL) {
1702 ret->context = context;
1703 ret->readcallback = xmlInputCallbackTable[i].readcallback;
1704 ret->closecallback = xmlInputCallbackTable[i].closecallback;
1705 }
1706 return(ret);
1707}
1708
1709/**
1710 * xmlOutputBufferCreateFilename:
1711 * @URI: a C string containing the URI or filename
1712 * @encoder: the encoding converter or NULL
1713 * @compression: the compression ration (0 none, 9 max).
1714 *
1715 * Create a buffered output for the progressive saving of a file
1716 * If filename is "-' then we use stdout as the output.
1717 * Automatic support for ZLIB/Compress compressed document is provided
1718 * by default if found at compile-time.
1719 * TODO: currently if compression is set, the library only support
1720 * writing to a local file.
1721 *
1722 * Returns the new output or NULL
1723 */
1724xmlOutputBufferPtr
1725xmlOutputBufferCreateFilename(const char *URI,
1726 xmlCharEncodingHandlerPtr encoder,
1727 int compression) {
1728 xmlOutputBufferPtr ret;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001729 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001730 void *context = NULL;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001731 char *unescaped;
Owen Taylor3473f882001-02-23 17:55:21 +00001732
Daniel Veillardf012a642001-07-23 19:10:52 +00001733 int is_http_uri = 0; /* Can't change if HTTP disabled */
1734
Owen Taylor3473f882001-02-23 17:55:21 +00001735 if (xmlOutputCallbackInitialized == 0)
1736 xmlRegisterDefaultOutputCallbacks();
1737
1738 if (URI == NULL) return(NULL);
1739
Daniel Veillardf012a642001-07-23 19:10:52 +00001740#ifdef LIBXML_HTTP_ENABLED
1741 /* Need to prevent HTTP URI's from falling into zlib short circuit */
1742
1743 is_http_uri = xmlIOHTTPMatch( URI );
1744#endif
1745
Owen Taylor3473f882001-02-23 17:55:21 +00001746
1747 /*
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001748 * Try to find one of the output accept method accepting taht scheme
Owen Taylor3473f882001-02-23 17:55:21 +00001749 * Go in reverse to give precedence to user defined handlers.
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001750 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00001751 */
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001752 unescaped = xmlURIUnescapeString(URI, 0, NULL);
1753 if (unescaped != NULL) {
1754#ifdef HAVE_ZLIB_H
1755 if ((compression > 0) && (compression <= 9) && (is_http_uri == 0)) {
1756 context = xmlGzfileOpenW(unescaped, compression);
1757 if (context != NULL) {
1758 ret = xmlAllocOutputBuffer(encoder);
1759 if (ret != NULL) {
1760 ret->context = context;
1761 ret->writecallback = xmlGzfileWrite;
1762 ret->closecallback = xmlGzfileClose;
1763 }
1764 xmlFree(unescaped);
1765 return(ret);
1766 }
1767 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001768#endif
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001769 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
1770 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
1771 (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
1772#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
1773 /* Need to pass compression parameter into HTTP open calls */
1774 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
1775 context = xmlIOHTTPOpenW(unescaped, compression);
1776 else
1777#endif
1778 context = xmlOutputCallbackTable[i].opencallback(unescaped);
1779 if (context != NULL)
1780 break;
1781 }
1782 }
1783 xmlFree(unescaped);
1784 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001785
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001786 /*
1787 * If this failed try with a non-escaped URI this may be a strange
1788 * filename
1789 */
1790 if (context == NULL) {
1791#ifdef HAVE_ZLIB_H
1792 if ((compression > 0) && (compression <= 9) && (is_http_uri == 0)) {
1793 context = xmlGzfileOpenW(URI, compression);
1794 if (context != NULL) {
1795 ret = xmlAllocOutputBuffer(encoder);
1796 if (ret != NULL) {
1797 ret->context = context;
1798 ret->writecallback = xmlGzfileWrite;
1799 ret->closecallback = xmlGzfileClose;
1800 }
1801 return(ret);
1802 }
1803 }
1804#endif
1805 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
1806 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
1807 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
1808 context = xmlOutputCallbackTable[i].opencallback(URI);
1809#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
1810 /* Need to pass compression parameter into HTTP open calls */
1811 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
1812 context = xmlIOHTTPOpenW(URI, compression);
1813 else
1814#endif
1815 context = xmlOutputCallbackTable[i].opencallback(URI);
1816 if (context != NULL)
1817 break;
1818 }
Owen Taylor3473f882001-02-23 17:55:21 +00001819 }
1820 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001821
Owen Taylor3473f882001-02-23 17:55:21 +00001822 if (context == NULL) {
1823 return(NULL);
1824 }
1825
1826 /*
1827 * Allocate the Output buffer front-end.
1828 */
1829 ret = xmlAllocOutputBuffer(encoder);
1830 if (ret != NULL) {
1831 ret->context = context;
1832 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
1833 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
1834 }
1835 return(ret);
1836}
1837
1838/**
1839 * xmlParserInputBufferCreateFile:
1840 * @file: a FILE*
1841 * @enc: the charset encoding if known
1842 *
1843 * Create a buffered parser input for the progressive parsing of a FILE *
1844 * buffered C I/O
1845 *
1846 * Returns the new parser input or NULL
1847 */
1848xmlParserInputBufferPtr
1849xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
1850 xmlParserInputBufferPtr ret;
1851
1852 if (xmlInputCallbackInitialized == 0)
1853 xmlRegisterDefaultInputCallbacks();
1854
1855 if (file == NULL) return(NULL);
1856
1857 ret = xmlAllocParserInputBuffer(enc);
1858 if (ret != NULL) {
1859 ret->context = file;
1860 ret->readcallback = xmlFileRead;
1861 ret->closecallback = xmlFileFlush;
1862 }
1863
1864 return(ret);
1865}
1866
1867/**
1868 * xmlOutputBufferCreateFile:
1869 * @file: a FILE*
1870 * @encoder: the encoding converter or NULL
1871 *
1872 * Create a buffered output for the progressive saving to a FILE *
1873 * buffered C I/O
1874 *
1875 * Returns the new parser output or NULL
1876 */
1877xmlOutputBufferPtr
1878xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
1879 xmlOutputBufferPtr ret;
1880
1881 if (xmlOutputCallbackInitialized == 0)
1882 xmlRegisterDefaultOutputCallbacks();
1883
1884 if (file == NULL) return(NULL);
1885
1886 ret = xmlAllocOutputBuffer(encoder);
1887 if (ret != NULL) {
1888 ret->context = file;
1889 ret->writecallback = xmlFileWrite;
1890 ret->closecallback = xmlFileFlush;
1891 }
1892
1893 return(ret);
1894}
1895
1896/**
1897 * xmlParserInputBufferCreateFd:
1898 * @fd: a file descriptor number
1899 * @enc: the charset encoding if known
1900 *
1901 * Create a buffered parser input for the progressive parsing for the input
1902 * from a file descriptor
1903 *
1904 * Returns the new parser input or NULL
1905 */
1906xmlParserInputBufferPtr
1907xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
1908 xmlParserInputBufferPtr ret;
1909
1910 if (fd < 0) return(NULL);
1911
1912 ret = xmlAllocParserInputBuffer(enc);
1913 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00001914 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00001915 ret->readcallback = xmlFdRead;
1916 ret->closecallback = xmlFdClose;
1917 }
1918
1919 return(ret);
1920}
1921
1922/**
1923 * xmlParserInputBufferCreateMem:
1924 * @mem: the memory input
1925 * @size: the length of the memory block
1926 * @enc: the charset encoding if known
1927 *
1928 * Create a buffered parser input for the progressive parsing for the input
1929 * from a memory area.
1930 *
1931 * Returns the new parser input or NULL
1932 */
1933xmlParserInputBufferPtr
1934xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
1935 xmlParserInputBufferPtr ret;
1936
1937 if (size <= 0) return(NULL);
1938 if (mem == NULL) return(NULL);
1939
1940 ret = xmlAllocParserInputBuffer(enc);
1941 if (ret != NULL) {
1942 ret->context = (void *) mem;
1943 ret->readcallback = (xmlInputReadCallback) xmlNop;
1944 ret->closecallback = NULL;
1945 xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size);
1946 }
1947
1948 return(ret);
1949}
1950
1951/**
1952 * xmlOutputBufferCreateFd:
1953 * @fd: a file descriptor number
1954 * @encoder: the encoding converter or NULL
1955 *
1956 * Create a buffered output for the progressive saving
1957 * to a file descriptor
1958 *
1959 * Returns the new parser output or NULL
1960 */
1961xmlOutputBufferPtr
1962xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
1963 xmlOutputBufferPtr ret;
1964
1965 if (fd < 0) return(NULL);
1966
1967 ret = xmlAllocOutputBuffer(encoder);
1968 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00001969 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00001970 ret->writecallback = xmlFdWrite;
1971 ret->closecallback = xmlFdClose;
1972 }
1973
1974 return(ret);
1975}
1976
1977/**
1978 * xmlParserInputBufferCreateIO:
1979 * @ioread: an I/O read function
1980 * @ioclose: an I/O close function
1981 * @ioctx: an I/O handler
1982 * @enc: the charset encoding if known
1983 *
1984 * Create a buffered parser input for the progressive parsing for the input
1985 * from an I/O handler
1986 *
1987 * Returns the new parser input or NULL
1988 */
1989xmlParserInputBufferPtr
1990xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
1991 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
1992 xmlParserInputBufferPtr ret;
1993
1994 if (ioread == NULL) return(NULL);
1995
1996 ret = xmlAllocParserInputBuffer(enc);
1997 if (ret != NULL) {
1998 ret->context = (void *) ioctx;
1999 ret->readcallback = ioread;
2000 ret->closecallback = ioclose;
2001 }
2002
2003 return(ret);
2004}
2005
2006/**
2007 * xmlOutputBufferCreateIO:
2008 * @iowrite: an I/O write function
2009 * @ioclose: an I/O close function
2010 * @ioctx: an I/O handler
2011 * @enc: the charset encoding if known
2012 *
2013 * Create a buffered output for the progressive saving
2014 * to an I/O handler
2015 *
2016 * Returns the new parser output or NULL
2017 */
2018xmlOutputBufferPtr
2019xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
2020 xmlOutputCloseCallback ioclose, void *ioctx,
2021 xmlCharEncodingHandlerPtr encoder) {
2022 xmlOutputBufferPtr ret;
2023
2024 if (iowrite == NULL) return(NULL);
2025
2026 ret = xmlAllocOutputBuffer(encoder);
2027 if (ret != NULL) {
2028 ret->context = (void *) ioctx;
2029 ret->writecallback = iowrite;
2030 ret->closecallback = ioclose;
2031 }
2032
2033 return(ret);
2034}
2035
2036/**
2037 * xmlParserInputBufferPush:
2038 * @in: a buffered parser input
2039 * @len: the size in bytes of the array.
2040 * @buf: an char array
2041 *
2042 * Push the content of the arry in the input buffer
2043 * This routine handle the I18N transcoding to internal UTF-8
2044 * This is used when operating the parser in progressive (push) mode.
2045 *
2046 * Returns the number of chars read and stored in the buffer, or -1
2047 * in case of error.
2048 */
2049int
2050xmlParserInputBufferPush(xmlParserInputBufferPtr in,
2051 int len, const char *buf) {
2052 int nbchars = 0;
2053
2054 if (len < 0) return(0);
2055 if (in->encoder != NULL) {
2056 /*
2057 * Store the data in the incoming raw buffer
2058 */
2059 if (in->raw == NULL) {
2060 in->raw = xmlBufferCreate();
2061 }
2062 xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
2063
2064 /*
2065 * convert as much as possible to the parser reading buffer.
2066 */
2067 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2068 if (nbchars < 0) {
2069 xmlGenericError(xmlGenericErrorContext,
2070 "xmlParserInputBufferPush: encoder error\n");
2071 return(-1);
2072 }
2073 } else {
2074 nbchars = len;
2075 xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
2076 }
2077#ifdef DEBUG_INPUT
2078 xmlGenericError(xmlGenericErrorContext,
2079 "I/O: pushed %d chars, buffer %d/%d\n",
2080 nbchars, in->buffer->use, in->buffer->size);
2081#endif
2082 return(nbchars);
2083}
2084
2085/**
2086 * xmlParserInputBufferGrow:
2087 * @in: a buffered parser input
2088 * @len: indicative value of the amount of chars to read
2089 *
2090 * Grow up the content of the input buffer, the old data are preserved
2091 * This routine handle the I18N transcoding to internal UTF-8
2092 * This routine is used when operating the parser in normal (pull) mode
2093 *
2094 * TODO: one should be able to remove one extra copy by copying directy
2095 * onto in->buffer or in->raw
2096 *
2097 * Returns the number of chars read and stored in the buffer, or -1
2098 * in case of error.
2099 */
2100int
2101xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
2102 char *buffer = NULL;
2103 int res = 0;
2104 int nbchars = 0;
2105 int buffree;
2106
2107 if ((len <= MINLEN) && (len != 4))
2108 len = MINLEN;
2109 buffree = in->buffer->size - in->buffer->use;
2110 if (buffree <= 0) {
2111 xmlGenericError(xmlGenericErrorContext,
2112 "xmlParserInputBufferGrow : buffer full !\n");
2113 return(0);
2114 }
2115 if (len > buffree)
2116 len = buffree;
2117
2118 buffer = (char *) xmlMalloc((len + 1) * sizeof(char));
2119 if (buffer == NULL) {
2120 xmlGenericError(xmlGenericErrorContext,
2121 "xmlParserInputBufferGrow : out of memory !\n");
2122 return(-1);
2123 }
2124
2125 /*
2126 * Call the read method for this I/O type.
2127 */
2128 if (in->readcallback != NULL) {
2129 res = in->readcallback(in->context, &buffer[0], len);
2130 } else {
2131 xmlGenericError(xmlGenericErrorContext,
2132 "xmlParserInputBufferGrow : no input !\n");
2133 xmlFree(buffer);
2134 return(-1);
2135 }
2136 if (res < 0) {
2137 perror ("read error");
2138 xmlFree(buffer);
2139 return(-1);
2140 }
2141 len = res;
2142 if (in->encoder != NULL) {
2143 /*
2144 * Store the data in the incoming raw buffer
2145 */
2146 if (in->raw == NULL) {
2147 in->raw = xmlBufferCreate();
2148 }
2149 xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
2150
2151 /*
2152 * convert as much as possible to the parser reading buffer.
2153 */
2154 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2155 if (nbchars < 0) {
2156 xmlGenericError(xmlGenericErrorContext,
2157 "xmlParserInputBufferGrow: encoder error\n");
2158 return(-1);
2159 }
2160 } else {
2161 nbchars = len;
2162 buffer[nbchars] = 0;
2163 xmlBufferAdd(in->buffer, (xmlChar *) buffer, nbchars);
2164 }
2165#ifdef DEBUG_INPUT
2166 xmlGenericError(xmlGenericErrorContext,
2167 "I/O: read %d chars, buffer %d/%d\n",
2168 nbchars, in->buffer->use, in->buffer->size);
2169#endif
2170 xmlFree(buffer);
2171 return(nbchars);
2172}
2173
2174/**
2175 * xmlParserInputBufferRead:
2176 * @in: a buffered parser input
2177 * @len: indicative value of the amount of chars to read
2178 *
2179 * Refresh the content of the input buffer, the old data are considered
2180 * consumed
2181 * This routine handle the I18N transcoding to internal UTF-8
2182 *
2183 * Returns the number of chars read and stored in the buffer, or -1
2184 * in case of error.
2185 */
2186int
2187xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
2188 /* xmlBufferEmpty(in->buffer); */
2189 if (in->readcallback != NULL)
2190 return(xmlParserInputBufferGrow(in, len));
2191 else
2192 return(-1);
2193}
2194
2195/**
2196 * xmlOutputBufferWrite:
2197 * @out: a buffered parser output
2198 * @len: the size in bytes of the array.
2199 * @buf: an char array
2200 *
2201 * Write the content of the array in the output I/O buffer
2202 * This routine handle the I18N transcoding from internal UTF-8
2203 * The buffer is lossless, i.e. will store in case of partial
2204 * or delayed writes.
2205 *
2206 * Returns the number of chars immediately written, or -1
2207 * in case of error.
2208 */
2209int
2210xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
2211 int nbchars = 0; /* number of chars to output to I/O */
2212 int ret; /* return from function call */
2213 int written = 0; /* number of char written to I/O so far */
2214 int chunk; /* number of byte curreent processed from buf */
2215
2216 if (len < 0) return(0);
2217
2218 do {
2219 chunk = len;
2220 if (chunk > 4 * MINLEN)
2221 chunk = 4 * MINLEN;
2222
2223 /*
2224 * first handle encoding stuff.
2225 */
2226 if (out->encoder != NULL) {
2227 /*
2228 * Store the data in the incoming raw buffer
2229 */
2230 if (out->conv == NULL) {
2231 out->conv = xmlBufferCreate();
2232 }
2233 xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2234
2235 if ((out->buffer->use < MINLEN) && (chunk == len))
2236 goto done;
2237
2238 /*
2239 * convert as much as possible to the parser reading buffer.
2240 */
2241 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
2242 if (ret < 0) {
2243 xmlGenericError(xmlGenericErrorContext,
2244 "xmlOutputBufferWrite: encoder error\n");
2245 return(-1);
2246 }
2247 nbchars = out->conv->use;
2248 } else {
2249 xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2250 nbchars = out->buffer->use;
2251 }
2252 buf += chunk;
2253 len -= chunk;
2254
2255 if ((nbchars < MINLEN) && (len <= 0))
2256 goto done;
2257
2258 if (out->writecallback) {
2259 /*
2260 * second write the stuff to the I/O channel
2261 */
2262 if (out->encoder != NULL) {
2263 ret = out->writecallback(out->context,
2264 (const char *)out->conv->content, nbchars);
2265 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002266 xmlBufferShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002267 } else {
2268 ret = out->writecallback(out->context,
2269 (const char *)out->buffer->content, nbchars);
2270 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002271 xmlBufferShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002272 }
2273 if (ret < 0) {
2274 xmlGenericError(xmlGenericErrorContext,
2275 "I/O: error %d writing %d bytes\n", ret, nbchars);
2276 return(ret);
2277 }
2278 out->written += ret;
2279 }
2280 written += nbchars;
2281 } while (len > 0);
2282
2283done:
2284#ifdef DEBUG_INPUT
2285 xmlGenericError(xmlGenericErrorContext,
2286 "I/O: wrote %d chars\n", written);
2287#endif
2288 return(written);
2289}
2290
2291/**
2292 * xmlOutputBufferWriteString:
2293 * @out: a buffered parser output
2294 * @str: a zero terminated C string
2295 *
2296 * Write the content of the string in the output I/O buffer
2297 * This routine handle the I18N transcoding from internal UTF-8
2298 * The buffer is lossless, i.e. will store in case of partial
2299 * or delayed writes.
2300 *
2301 * Returns the number of chars immediately written, or -1
2302 * in case of error.
2303 */
2304int
2305xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
2306 int len;
2307
2308 if (str == NULL)
2309 return(-1);
2310 len = strlen(str);
2311
2312 if (len > 0)
2313 return(xmlOutputBufferWrite(out, len, str));
2314 return(len);
2315}
2316
2317/**
2318 * xmlOutputBufferFlush:
2319 * @out: a buffered output
2320 *
2321 * flushes the output I/O channel
2322 *
2323 * Returns the number of byte written or -1 in case of error.
2324 */
2325int
2326xmlOutputBufferFlush(xmlOutputBufferPtr out) {
2327 int nbchars = 0, ret = 0;
2328
2329 /*
2330 * first handle encoding stuff.
2331 */
2332 if ((out->conv != NULL) && (out->encoder != NULL)) {
2333 /*
2334 * convert as much as possible to the parser reading buffer.
2335 */
2336 nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
2337 if (nbchars < 0) {
2338 xmlGenericError(xmlGenericErrorContext,
2339 "xmlOutputBufferWrite: encoder error\n");
2340 return(-1);
2341 }
2342 }
2343
2344 /*
2345 * second flush the stuff to the I/O channel
2346 */
2347 if ((out->conv != NULL) && (out->encoder != NULL) &&
2348 (out->writecallback != NULL)) {
2349 ret = out->writecallback(out->context,
2350 (const char *)out->conv->content, out->conv->use);
2351 if (ret >= 0)
2352 xmlBufferShrink(out->conv, ret);
2353 } else if (out->writecallback != NULL) {
2354 ret = out->writecallback(out->context,
2355 (const char *)out->buffer->content, out->buffer->use);
2356 if (ret >= 0)
2357 xmlBufferShrink(out->buffer, ret);
2358 }
2359 if (ret < 0) {
2360 xmlGenericError(xmlGenericErrorContext,
2361 "I/O: error %d flushing %d bytes\n", ret, nbchars);
2362 return(ret);
2363 }
2364 out->written += ret;
2365
2366#ifdef DEBUG_INPUT
2367 xmlGenericError(xmlGenericErrorContext,
2368 "I/O: flushed %d chars\n", ret);
2369#endif
2370 return(ret);
2371}
2372
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002373/**
Owen Taylor3473f882001-02-23 17:55:21 +00002374 * xmlParserGetDirectory:
2375 * @filename: the path to a file
2376 *
2377 * lookup the directory for that file
2378 *
2379 * Returns a new allocated string containing the directory, or NULL.
2380 */
2381char *
2382xmlParserGetDirectory(const char *filename) {
2383 char *ret = NULL;
2384 char dir[1024];
2385 char *cur;
2386 char sep = '/';
2387
2388 if (xmlInputCallbackInitialized == 0)
2389 xmlRegisterDefaultInputCallbacks();
2390
2391 if (filename == NULL) return(NULL);
2392#ifdef WIN32
2393 sep = '\\';
2394#endif
2395
2396 strncpy(dir, filename, 1023);
2397 dir[1023] = 0;
2398 cur = &dir[strlen(dir)];
2399 while (cur > dir) {
2400 if (*cur == sep) break;
2401 cur --;
2402 }
2403 if (*cur == sep) {
2404 if (cur == dir) dir[1] = 0;
2405 else *cur = 0;
2406 ret = xmlMemStrdup(dir);
2407 } else {
2408 if (getcwd(dir, 1024) != NULL) {
2409 dir[1023] = 0;
2410 ret = xmlMemStrdup(dir);
2411 }
2412 }
2413 return(ret);
2414}
2415
2416/****************************************************************
2417 * *
2418 * External entities loading *
2419 * *
2420 ****************************************************************/
2421
Daniel Veillard6990bf32001-08-23 21:17:48 +00002422#ifdef LIBXML_CATALOG_ENABLED
2423static int xmlSysIDExists(const char *URL) {
2424#ifdef HAVE_STAT
2425 int ret;
2426 struct stat info;
2427 const char *path;
2428
2429 if (URL == NULL)
2430 return(0);
2431
2432 if (!strncmp(URL, "file://localhost", 16))
2433 path = &URL[16];
2434 else if (!strncmp(URL, "file:///", 8)) {
2435#ifdef _WIN32
2436 path = &URL[8];
2437#else
2438 path = &URL[7];
2439#endif
2440 } else
2441 path = URL;
2442 ret = stat(path, &info);
2443 if (ret == 0)
2444 return(1);
2445#endif
2446 return(0);
2447}
2448#endif
2449
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002450/**
Owen Taylor3473f882001-02-23 17:55:21 +00002451 * xmlDefaultExternalEntityLoader:
2452 * @URL: the URL for the entity to load
2453 * @ID: the System ID for the entity to load
2454 * @ctxt: the context in which the entity is called or NULL
2455 *
2456 * By default we don't load external entitites, yet.
2457 *
2458 * Returns a new allocated xmlParserInputPtr, or NULL.
2459 */
2460static
2461xmlParserInputPtr
2462xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
2463 xmlParserCtxtPtr ctxt) {
2464 xmlParserInputPtr ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002465 xmlChar *resource = NULL;
2466#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002467 xmlCatalogAllow pref;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002468#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002469
2470#ifdef DEBUG_EXTERNAL_ENTITIES
2471 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf012a642001-07-23 19:10:52 +00002472 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00002473#endif
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002474#ifdef LIBXML_CATALOG_ENABLED
2475 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002476 * If the resource doesn't exists as a file,
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002477 * try to load it from the resource pointed in the catalogs
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002478 */
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002479 pref = xmlCatalogGetDefaults();
2480
Daniel Veillard6990bf32001-08-23 21:17:48 +00002481 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlSysIDExists(URL))) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002482 /*
2483 * Do a local lookup
2484 */
2485 if ((ctxt->catalogs != NULL) &&
2486 ((pref == XML_CATA_ALLOW_ALL) ||
2487 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2488 resource = xmlCatalogLocalResolve(ctxt->catalogs,
2489 (const xmlChar *)ID,
2490 (const xmlChar *)URL);
2491 }
2492 /*
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002493 * Try a global lookup
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002494 */
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002495 if ((resource == NULL) &&
2496 ((pref == XML_CATA_ALLOW_ALL) ||
2497 (pref == XML_CATA_ALLOW_GLOBAL))) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002498 resource = xmlCatalogResolve((const xmlChar *)ID,
2499 (const xmlChar *)URL);
2500 }
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002501 if ((resource == NULL) && (URL != NULL))
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00002502 resource = xmlStrdup((const xmlChar *) URL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002503
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002504 /*
2505 * TODO: do an URI lookup on the reference
2506 */
Daniel Veillard6990bf32001-08-23 21:17:48 +00002507 if ((resource != NULL) && (!xmlSysIDExists((const char *)resource))) {
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002508 xmlChar *tmp = NULL;
2509
2510 if ((ctxt->catalogs != NULL) &&
2511 ((pref == XML_CATA_ALLOW_ALL) ||
2512 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2513 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
2514 }
2515 if ((tmp == NULL) &&
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00002516 ((pref == XML_CATA_ALLOW_ALL) ||
2517 (pref == XML_CATA_ALLOW_GLOBAL))) {
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002518 tmp = xmlCatalogResolveURI(resource);
2519 }
2520
2521 if (tmp != NULL) {
2522 xmlFree(resource);
2523 resource = tmp;
2524 }
2525 }
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002526 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002527#endif
2528
2529 if (resource == NULL)
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002530 resource = (xmlChar *) URL;
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002531
2532 if (resource == NULL) {
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002533 if ((ctxt->validate) && (ctxt->sax != NULL) &&
2534 (ctxt->sax->error != NULL))
2535 ctxt->sax->error(ctxt,
2536 "failed to load external entity \"%s\"\n", ID);
2537 else if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00002538 ctxt->sax->warning(ctxt,
2539 "failed to load external entity \"%s\"\n", ID);
2540 return(NULL);
2541 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002542 ret = xmlNewInputFromFile(ctxt, (const char *)resource);
Owen Taylor3473f882001-02-23 17:55:21 +00002543 if (ret == NULL) {
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002544 if ((ctxt->validate) && (ctxt->sax != NULL) &&
2545 (ctxt->sax->error != NULL))
2546 ctxt->sax->error(ctxt,
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002547 "failed to load external entity \"%s\"\n", resource);
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002548 else if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00002549 ctxt->sax->warning(ctxt,
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002550 "failed to load external entity \"%s\"\n", resource);
Owen Taylor3473f882001-02-23 17:55:21 +00002551 }
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002552 if ((resource != NULL) && (resource != (xmlChar *) URL))
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002553 xmlFree(resource);
Owen Taylor3473f882001-02-23 17:55:21 +00002554 return(ret);
2555}
2556
2557static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
2558 xmlDefaultExternalEntityLoader;
2559
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002560/**
Owen Taylor3473f882001-02-23 17:55:21 +00002561 * xmlSetExternalEntityLoader:
2562 * @f: the new entity resolver function
2563 *
2564 * Changes the defaultexternal entity resolver function for the application
2565 */
2566void
2567xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
2568 xmlCurrentExternalEntityLoader = f;
2569}
2570
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002571/**
Owen Taylor3473f882001-02-23 17:55:21 +00002572 * xmlGetExternalEntityLoader:
2573 *
2574 * Get the default external entity resolver function for the application
2575 *
2576 * Returns the xmlExternalEntityLoader function pointer
2577 */
2578xmlExternalEntityLoader
2579xmlGetExternalEntityLoader(void) {
2580 return(xmlCurrentExternalEntityLoader);
2581}
2582
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002583/**
Owen Taylor3473f882001-02-23 17:55:21 +00002584 * xmlLoadExternalEntity:
2585 * @URL: the URL for the entity to load
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00002586 * @ID: the Public ID for the entity to load
Owen Taylor3473f882001-02-23 17:55:21 +00002587 * @ctxt: the context in which the entity is called or NULL
2588 *
2589 * Load an external entity, note that the use of this function for
2590 * unparsed entities may generate problems
2591 * TODO: a more generic External entitiy API must be designed
2592 *
2593 * Returns the xmlParserInputPtr or NULL
2594 */
2595xmlParserInputPtr
2596xmlLoadExternalEntity(const char *URL, const char *ID,
2597 xmlParserCtxtPtr ctxt) {
2598 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
2599}
2600
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00002601/************************************************************************
2602 * *
2603 * Disabling Network access *
2604 * *
2605 ************************************************************************/
2606
2607#ifdef LIBXML_CATALOG_ENABLED
2608static int
2609xmlNoNetExists(const char *URL)
2610{
2611#ifdef HAVE_STAT
2612 int ret;
2613 struct stat info;
2614 const char *path;
2615
2616 if (URL == NULL)
2617 return (0);
2618
2619 if (!xmlStrncmp(BAD_CAST URL, BAD_CAST "file://localhost", 16))
2620 path = &URL[16];
2621 else if (!xmlStrncmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
2622#ifdef _WIN32
2623 path = &URL[8];
2624#else
2625 path = &URL[7];
2626#endif
2627 } else
2628 path = URL;
2629 ret = stat(path, &info);
2630 if (ret == 0)
2631 return (1);
2632#endif
2633 return (0);
2634}
2635#endif
2636
2637/**
2638 * xmlNoNetExternalEntityLoader:
2639 * @URL: the URL for the entity to load
2640 * @ID: the System ID for the entity to load
2641 * @ctxt: the context in which the entity is called or NULL
2642 *
2643 * A specific entity loader disabling network accesses, though still
2644 * allowing local catalog accesses for resolution.
2645 *
2646 * Returns a new allocated xmlParserInputPtr, or NULL.
2647 */
2648xmlParserInputPtr
2649xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
2650 xmlParserCtxtPtr ctxt) {
2651 xmlParserInputPtr input = NULL;
2652 xmlChar *resource = NULL;
2653
2654#ifdef LIBXML_CATALOG_ENABLED
2655 xmlCatalogAllow pref;
2656
2657 /*
2658 * If the resource doesn't exists as a file,
2659 * try to load it from the resource pointed in the catalogs
2660 */
2661 pref = xmlCatalogGetDefaults();
2662
2663 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
2664 /*
2665 * Do a local lookup
2666 */
2667 if ((ctxt->catalogs != NULL) &&
2668 ((pref == XML_CATA_ALLOW_ALL) ||
2669 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2670 resource = xmlCatalogLocalResolve(ctxt->catalogs,
2671 (const xmlChar *)ID,
2672 (const xmlChar *)URL);
2673 }
2674 /*
2675 * Try a global lookup
2676 */
2677 if ((resource == NULL) &&
2678 ((pref == XML_CATA_ALLOW_ALL) ||
2679 (pref == XML_CATA_ALLOW_GLOBAL))) {
2680 resource = xmlCatalogResolve((const xmlChar *)ID,
2681 (const xmlChar *)URL);
2682 }
2683 if ((resource == NULL) && (URL != NULL))
2684 resource = xmlStrdup((const xmlChar *) URL);
2685
2686 /*
2687 * TODO: do an URI lookup on the reference
2688 */
2689 if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
2690 xmlChar *tmp = NULL;
2691
2692 if ((ctxt->catalogs != NULL) &&
2693 ((pref == XML_CATA_ALLOW_ALL) ||
2694 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2695 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
2696 }
2697 if ((tmp == NULL) &&
2698 ((pref == XML_CATA_ALLOW_ALL) ||
2699 (pref == XML_CATA_ALLOW_GLOBAL))) {
2700 tmp = xmlCatalogResolveURI(resource);
2701 }
2702
2703 if (tmp != NULL) {
2704 xmlFree(resource);
2705 resource = tmp;
2706 }
2707 }
2708 }
2709#endif
2710 if (resource == NULL)
2711 resource = (xmlChar *) URL;
2712
2713 if (resource != NULL) {
2714 if ((!xmlStrncasecmp((const xmlChar *) resource,
2715 (const xmlChar *) "ftp://", 6)) ||
2716 (!xmlStrncasecmp((const xmlChar *) resource,
2717 (const xmlChar *) "http://", 7))) {
2718 xmlGenericError(xmlGenericErrorContext,
2719 "Attempt to load network entity %s \n", resource);
2720
2721 if (resource != (xmlChar *) URL)
2722 xmlFree(resource);
2723 return(NULL);
2724 }
2725 }
2726 input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
2727 if (resource != (xmlChar *) URL)
2728 xmlFree(resource);
2729 return(input);
2730}
2731