blob: bfa809632fdb464ea799a48ada18a14ba5380463 [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;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000147}
148
149/**
150 * xmlCleanupOutputCallbacks:
151 *
152 * clears the entire output callback table. this includes the
153 * compiled-in I/O callbacks.
154 */
155void
156xmlCleanupOutputCallbacks(void)
157{
158 int i;
159
160 if (!xmlOutputCallbackInitialized)
161 return;
162
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000163 for (i = xmlOutputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000164 xmlOutputCallbackTable[i].matchcallback = NULL;
165 xmlOutputCallbackTable[i].opencallback = NULL;
166 xmlOutputCallbackTable[i].writecallback = NULL;
167 xmlOutputCallbackTable[i].closecallback = NULL;
168 }
169
170 xmlOutputCallbackNr = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000171}
172
Owen Taylor3473f882001-02-23 17:55:21 +0000173/************************************************************************
174 * *
175 * Standard I/O for file accesses *
176 * *
177 ************************************************************************/
178
179/**
180 * xmlCheckFilename
181 * @path: the path to check
182 *
183 * function checks to see if @path is a valid source
184 * (file, socket...) for XML.
185 *
186 * if stat is not available on the target machine,
187 * returns 1. if stat fails, returns 0 (if calling
188 * stat on the filename fails, it can't be right).
189 * if stat succeeds and the file is a directory,
190 * sets errno to EISDIR and returns 0. otherwise
191 * returns 1.
192 */
193
194static int
195xmlCheckFilename (const char *path)
196{
197#ifdef HAVE_STAT
198#ifdef S_ISDIR
199 struct stat stat_buffer;
200
201 if (stat(path, &stat_buffer) == -1)
202 return 0;
203
204 if (S_ISDIR(stat_buffer.st_mode)) {
205 errno = EISDIR;
206 return 0;
207 }
208
209#endif
210#endif
211 return 1;
212}
213
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000214static int
Owen Taylor3473f882001-02-23 17:55:21 +0000215xmlNop(void) {
216 return(0);
217}
218
219/**
Owen Taylor3473f882001-02-23 17:55:21 +0000220 * xmlFdRead:
221 * @context: the I/O context
222 * @buffer: where to drop data
223 * @len: number of bytes to read
224 *
225 * Read @len bytes to @buffer from the I/O channel.
226 *
227 * Returns the number of bytes written
228 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000229static int
Owen Taylor3473f882001-02-23 17:55:21 +0000230xmlFdRead (void * context, char * buffer, int len) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +0000231 return(read((int) (long) context, &buffer[0], len));
Owen Taylor3473f882001-02-23 17:55:21 +0000232}
233
234/**
235 * xmlFdWrite:
236 * @context: the I/O context
237 * @buffer: where to get data
238 * @len: number of bytes to write
239 *
240 * Write @len bytes from @buffer to the I/O channel.
241 *
242 * Returns the number of bytes written
243 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000244static int
Owen Taylor3473f882001-02-23 17:55:21 +0000245xmlFdWrite (void * context, const char * buffer, int len) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +0000246 return(write((int) (long) context, &buffer[0], len));
Owen Taylor3473f882001-02-23 17:55:21 +0000247}
248
249/**
250 * xmlFdClose:
251 * @context: the I/O context
252 *
253 * Close an I/O channel
Daniel Veillardf012a642001-07-23 19:10:52 +0000254 *
255 * Returns 0 in case of success and error code otherwise
Owen Taylor3473f882001-02-23 17:55:21 +0000256 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000257static int
Owen Taylor3473f882001-02-23 17:55:21 +0000258xmlFdClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +0000259 return ( close((int) (long) context) );
Owen Taylor3473f882001-02-23 17:55:21 +0000260}
261
262/**
263 * xmlFileMatch:
264 * @filename: the URI for matching
265 *
266 * input from FILE *
267 *
268 * Returns 1 if matches, 0 otherwise
269 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000270static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000271xmlFileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000272 return(1);
273}
274
275/**
276 * xmlFileOpen:
277 * @filename: the URI for matching
278 *
279 * input from FILE *, supports compressed input
280 * if @filename is " " then the standard input is used
281 *
282 * Returns an I/O context or NULL in case of error
283 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000284static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000285xmlFileOpen (const char *filename) {
286 const char *path = NULL;
287 FILE *fd;
288
289 if (!strcmp(filename, "-")) {
290 fd = stdin;
291 return((void *) fd);
292 }
293
294 if (!strncmp(filename, "file://localhost", 16))
295 path = &filename[16];
Daniel Veillardfe703322001-08-14 12:18:09 +0000296 else if (!strncmp(filename, "file:///", 8)) {
297#ifdef _WIN32
298 path = &filename[8];
299#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000300 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000301#endif
302 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000303 path = filename;
304
305 if (path == NULL)
306 return(NULL);
307 if (!xmlCheckFilename(path))
308 return(NULL);
309
310#ifdef WIN32
311 fd = fopen(path, "rb");
312#else
313 fd = fopen(path, "r");
314#endif /* WIN32 */
315 return((void *) fd);
316}
317
318/**
319 * xmlFileOpenW:
320 * @filename: the URI for matching
321 *
322 * output to from FILE *,
323 * if @filename is "-" then the standard output is used
324 *
325 * Returns an I/O context or NULL in case of error
326 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000327static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000328xmlFileOpenW (const char *filename) {
329 const char *path = NULL;
330 FILE *fd;
331
332 if (!strcmp(filename, "-")) {
333 fd = stdout;
334 return((void *) fd);
335 }
336
337 if (!strncmp(filename, "file://localhost", 16))
338 path = &filename[16];
Daniel Veillardfe703322001-08-14 12:18:09 +0000339 else if (!strncmp(filename, "file:///", 8)) {
340#ifdef _WIN32
341 path = &filename[8];
342#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000343 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000344#endif
345 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000346 path = filename;
347
348 if (path == NULL)
349 return(NULL);
350
351 fd = fopen(path, "w");
352 return((void *) fd);
353}
354
355/**
356 * xmlFileRead:
357 * @context: the I/O context
358 * @buffer: where to drop data
359 * @len: number of bytes to write
360 *
361 * Read @len bytes to @buffer from the I/O channel.
362 *
363 * Returns the number of bytes written
364 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000365static int
Owen Taylor3473f882001-02-23 17:55:21 +0000366xmlFileRead (void * context, char * buffer, int len) {
367 return(fread(&buffer[0], 1, len, (FILE *) context));
368}
369
370/**
371 * xmlFileWrite:
372 * @context: the I/O context
373 * @buffer: where to drop data
374 * @len: number of bytes to write
375 *
376 * Write @len bytes from @buffer to the I/O channel.
377 *
378 * Returns the number of bytes written
379 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000380static int
Owen Taylor3473f882001-02-23 17:55:21 +0000381xmlFileWrite (void * context, const char * buffer, int len) {
382 return(fwrite(&buffer[0], 1, len, (FILE *) context));
383}
384
385/**
386 * xmlFileClose:
387 * @context: the I/O context
388 *
389 * Close an I/O channel
390 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000391static int
Owen Taylor3473f882001-02-23 17:55:21 +0000392xmlFileClose (void * context) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000393 FILE *fil;
394
395 fil = (FILE *) context;
396 if (fil == stdin)
397 return(0);
398 if (fil == stdout)
399 return(0);
Daniel Veillardcd337f02001-11-22 18:20:37 +0000400 if (fil == stderr)
401 return(0);
Daniel Veillardf012a642001-07-23 19:10:52 +0000402 return ( ( fclose((FILE *) context) == EOF ) ? -1 : 0 );
Owen Taylor3473f882001-02-23 17:55:21 +0000403}
404
405/**
406 * xmlFileFlush:
407 * @context: the I/O context
408 *
409 * Flush an I/O channel
410 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000411static int
Owen Taylor3473f882001-02-23 17:55:21 +0000412xmlFileFlush (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +0000413 return ( ( fflush((FILE *) context) == EOF ) ? -1 : 0 );
Owen Taylor3473f882001-02-23 17:55:21 +0000414}
415
416#ifdef HAVE_ZLIB_H
417/************************************************************************
418 * *
419 * I/O for compressed file accesses *
420 * *
421 ************************************************************************/
422/**
423 * xmlGzfileMatch:
424 * @filename: the URI for matching
425 *
426 * input from compressed file test
427 *
428 * Returns 1 if matches, 0 otherwise
429 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000430static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000431xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000432 return(1);
433}
434
435/**
436 * xmlGzfileOpen:
437 * @filename: the URI for matching
438 *
439 * input from compressed file open
440 * if @filename is " " then the standard input is used
441 *
442 * Returns an I/O context or NULL in case of error
443 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000444static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000445xmlGzfileOpen (const char *filename) {
446 const char *path = NULL;
447 gzFile fd;
448
449 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000450 fd = gzdopen(dup(0), "rb");
Owen Taylor3473f882001-02-23 17:55:21 +0000451 return((void *) fd);
452 }
453
454 if (!strncmp(filename, "file://localhost", 16))
455 path = &filename[16];
Daniel Veillardfe703322001-08-14 12:18:09 +0000456 else if (!strncmp(filename, "file:///", 8)) {
457#ifdef _WIN32
458 path = &filename[8];
459#else
Owen Taylor3473f882001-02-23 17:55:21 +0000460 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000461#endif
462 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000463 path = filename;
464
465 if (path == NULL)
466 return(NULL);
467 if (!xmlCheckFilename(path))
468 return(NULL);
469
470 fd = gzopen(path, "rb");
471 return((void *) fd);
472}
473
474/**
475 * xmlGzfileOpenW:
476 * @filename: the URI for matching
477 * @compression: the compression factor (0 - 9 included)
478 *
479 * input from compressed file open
480 * if @filename is " " then the standard input is used
481 *
482 * Returns an I/O context or NULL in case of error
483 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000484static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000485xmlGzfileOpenW (const char *filename, int compression) {
486 const char *path = NULL;
487 char mode[15];
488 gzFile fd;
489
490 sprintf(mode, "wb%d", compression);
491 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000492 fd = gzdopen(dup(1), mode);
Owen Taylor3473f882001-02-23 17:55:21 +0000493 return((void *) fd);
494 }
495
496 if (!strncmp(filename, "file://localhost", 16))
497 path = &filename[16];
Daniel Veillardfe703322001-08-14 12:18:09 +0000498 else if (!strncmp(filename, "file:///", 8)) {
499#ifdef _WIN32
500 path = &filename[8];
501#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000502 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000503#endif
504 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000505 path = filename;
506
507 if (path == NULL)
508 return(NULL);
509
510 fd = gzopen(path, mode);
511 return((void *) fd);
512}
513
514/**
515 * xmlGzfileRead:
516 * @context: the I/O context
517 * @buffer: where to drop data
518 * @len: number of bytes to write
519 *
520 * Read @len bytes to @buffer from the compressed I/O channel.
521 *
522 * Returns the number of bytes written
523 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000524static int
Owen Taylor3473f882001-02-23 17:55:21 +0000525xmlGzfileRead (void * context, char * buffer, int len) {
526 return(gzread((gzFile) context, &buffer[0], len));
527}
528
529/**
530 * xmlGzfileWrite:
531 * @context: the I/O context
532 * @buffer: where to drop data
533 * @len: number of bytes to write
534 *
535 * Write @len bytes from @buffer to the compressed I/O channel.
536 *
537 * Returns the number of bytes written
538 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000539static int
Owen Taylor3473f882001-02-23 17:55:21 +0000540xmlGzfileWrite (void * context, const char * buffer, int len) {
541 return(gzwrite((gzFile) context, (char *) &buffer[0], len));
542}
543
544/**
545 * xmlGzfileClose:
546 * @context: the I/O context
547 *
548 * Close a compressed I/O channel
549 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000550static int
Owen Taylor3473f882001-02-23 17:55:21 +0000551xmlGzfileClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +0000552 return ( ( gzclose((gzFile) context) == Z_OK ) ? 0 : -1 );
Owen Taylor3473f882001-02-23 17:55:21 +0000553}
554#endif /* HAVE_ZLIB_H */
555
556#ifdef LIBXML_HTTP_ENABLED
557/************************************************************************
558 * *
559 * I/O for HTTP file accesses *
560 * *
561 ************************************************************************/
Daniel Veillardf012a642001-07-23 19:10:52 +0000562
563typedef struct xmlIOHTTPWriteCtxt_
564{
565 int compression;
566
567 char * uri;
568
569 void * doc_buff;
570
571} xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr;
572
573#ifdef HAVE_ZLIB_H
574
575#define DFLT_WBITS ( -15 )
576#define DFLT_MEM_LVL ( 8 )
577#define GZ_MAGIC1 ( 0x1f )
578#define GZ_MAGIC2 ( 0x8b )
579#define LXML_ZLIB_OS_CODE ( 0x03 )
580#define INIT_HTTP_BUFF_SIZE ( 32768 )
581#define DFLT_ZLIB_RATIO ( 5 )
582
583/*
584** Data structure and functions to work with sending compressed data
585** via HTTP.
586*/
587
588typedef struct xmlZMemBuff_
589{
590 unsigned long size;
591 unsigned long crc;
592
593 unsigned char * zbuff;
594 z_stream zctrl;
595
596} xmlZMemBuff, *xmlZMemBuffPtr;
597
598/**
599 * append_reverse_ulong
600 * @buff: Compressed memory buffer
601 * @data: Unsigned long to append
602 *
603 * Append a unsigned long in reverse byte order to the end of the
604 * memory buffer.
605 */
606static void
607append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) {
608
609 int idx;
610
611 if ( buff == NULL )
612 return;
613
614 /*
615 ** This is plagiarized from putLong in gzio.c (zlib source) where
616 ** the number "4" is hardcoded. If zlib is ever patched to
617 ** support 64 bit file sizes, this code would need to be patched
618 ** as well.
619 */
620
621 for ( idx = 0; idx < 4; idx++ ) {
622 *buff->zctrl.next_out = ( data & 0xff );
623 data >>= 8;
624 buff->zctrl.next_out++;
625 }
626
627 return;
628}
629
630/**
631 *
632 * xmlFreeZMemBuff
633 * @buff: The memory buffer context to clear
634 *
635 * Release all the resources associated with the compressed memory buffer.
636 */
637static void
638xmlFreeZMemBuff( xmlZMemBuffPtr buff ) {
639
640 int z_err;
641
642 if ( buff == NULL )
643 return;
644
645 xmlFree( buff->zbuff );
646 z_err = deflateEnd( &buff->zctrl );
647#ifdef DEBUG_HTTP
648 if ( z_err != Z_OK )
649 xmlGenericError( xmlGenericErrorContext,
650 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
651 z_err );
652#endif
653
654 xmlFree( buff );
655 return;
656}
657
658/**
659 * xmlCreateZMemBuff
660 *@compression: Compression value to use
661 *
662 * Create a memory buffer to hold the compressed XML document. The
663 * compressed document in memory will end up being identical to what
664 * would be created if gzopen/gzwrite/gzclose were being used to
665 * write the document to disk. The code for the header/trailer data to
666 * the compression is plagiarized from the zlib source files.
667 */
668static void *
669xmlCreateZMemBuff( int compression ) {
670
671 int z_err;
672 int hdr_lgth;
673 xmlZMemBuffPtr buff = NULL;
674
675 if ( ( compression < 1 ) || ( compression > 9 ) )
676 return ( NULL );
677
678 /* Create the control and data areas */
679
680 buff = xmlMalloc( sizeof( xmlZMemBuff ) );
681 if ( buff == NULL ) {
682 xmlGenericError( xmlGenericErrorContext,
683 "xmlCreateZMemBuff: %s\n",
684 "Failure allocating buffer context." );
685 return ( NULL );
686 }
687
688 (void)memset( buff, 0, sizeof( xmlZMemBuff ) );
689 buff->size = INIT_HTTP_BUFF_SIZE;
690 buff->zbuff = xmlMalloc( buff->size );
691 if ( buff->zbuff == NULL ) {
692 xmlFreeZMemBuff( buff );
693 xmlGenericError( xmlGenericErrorContext,
694 "xmlCreateZMemBuff: %s\n",
695 "Failure allocating data buffer." );
696 return ( NULL );
697 }
698
699 z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
700 DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
701 if ( z_err != Z_OK ) {
702 xmlFreeZMemBuff( buff );
703 buff = NULL;
704 xmlGenericError( xmlGenericErrorContext,
705 "xmlCreateZMemBuff: %s %d\n",
706 "Error initializing compression context. ZLIB error:",
707 z_err );
708 return ( NULL );
709 }
710
711 /* Set the header data. The CRC will be needed for the trailer */
712
713 buff->crc = crc32( 0L, Z_NULL, 0 );
714 hdr_lgth = sprintf( (char *)buff->zbuff, "%c%c%c%c%c%c%c%c%c%c",
715 GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED,
716 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE );
717 buff->zctrl.next_out = buff->zbuff + hdr_lgth;
718 buff->zctrl.avail_out = buff->size - hdr_lgth;
719
720 return ( buff );
721}
722
723/**
724 * xmlZMemBuffExtend
725 * @buff: Buffer used to compress and consolidate data.
726 * @ext_amt: Number of bytes to extend the buffer.
727 *
728 * Extend the internal buffer used to store the compressed data by the
729 * specified amount.
730 *
731 * Returns 0 on success or -1 on failure to extend the buffer. On failure
732 * the original buffer still exists at the original size.
733 */
734static int
735xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) {
736
737 int rc = -1;
738 size_t new_size;
739 size_t cur_used;
740
741 unsigned char * tmp_ptr = NULL;
742
743 if ( buff == NULL )
744 return ( -1 );
745
746 else if ( ext_amt == 0 )
747 return ( 0 );
748
749 cur_used = buff->zctrl.next_out - buff->zbuff;
750 new_size = buff->size + ext_amt;
751
752#ifdef DEBUG_HTTP
753 if ( cur_used > new_size )
754 xmlGenericError( xmlGenericErrorContext,
755 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
756 "Buffer overwrite detected during compressed memory",
757 "buffer extension. Overflowed by",
758 (cur_used - new_size ) );
759#endif
760
761 tmp_ptr = xmlRealloc( buff->zbuff, new_size );
762 if ( tmp_ptr != NULL ) {
763 rc = 0;
764 buff->size = new_size;
765 buff->zbuff = tmp_ptr;
766 buff->zctrl.next_out = tmp_ptr + cur_used;
767 buff->zctrl.avail_out = new_size - cur_used;
768 }
769 else {
770 xmlGenericError( xmlGenericErrorContext,
771 "xmlZMemBuffExtend: %s %lu bytes.\n",
772 "Allocation failure extending output buffer to",
773 new_size );
774 }
775
776 return ( rc );
777}
778
779/**
780 * xmlZMemBuffAppend
781 * @buff: Buffer used to compress and consolidate data
782 * @src: Uncompressed source content to append to buffer
783 * @len: Length of source data to append to buffer
784 *
785 * Compress and append data to the internal buffer. The data buffer
786 * will be expanded if needed to store the additional data.
787 *
788 * Returns the number of bytes appended to the buffer or -1 on error.
789 */
790static int
791xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) {
792
793 int z_err;
794 size_t min_accept;
795
796 if ( ( buff == NULL ) || ( src == NULL ) )
797 return ( -1 );
798
799 buff->zctrl.avail_in = len;
800 buff->zctrl.next_in = (unsigned char *)src;
801 while ( buff->zctrl.avail_in > 0 ) {
802 /*
803 ** Extend the buffer prior to deflate call if a reasonable amount
804 ** of output buffer space is not available.
805 */
806 min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO;
807 if ( buff->zctrl.avail_out <= min_accept ) {
808 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
809 return ( -1 );
810 }
811
812 z_err = deflate( &buff->zctrl, Z_NO_FLUSH );
813 if ( z_err != Z_OK ) {
814 xmlGenericError( xmlGenericErrorContext,
815 "xmlZMemBuffAppend: %s %d %s - %d",
816 "Compression error while appending",
817 len, "bytes to buffer. ZLIB error", z_err );
818 return ( -1 );
819 }
820 }
821
822 buff->crc = crc32( buff->crc, (unsigned char *)src, len );
823
824 return ( len );
825}
826
827/**
828 * xmlZMemBuffGetContent
829 * @buff: Compressed memory content buffer
830 * @data_ref: Pointer reference to point to compressed content
831 *
832 * Flushes the compression buffers, appends gzip file trailers and
833 * returns the compressed content and length of the compressed data.
834 * NOTE: The gzip trailer code here is plagiarized from zlib source.
835 *
836 * Returns the length of the compressed data or -1 on error.
837 */
838static int
839xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) {
840
841 int zlgth = -1;
842 int z_err;
843
844 if ( ( buff == NULL ) || ( data_ref == NULL ) )
845 return ( -1 );
846
847 /* Need to loop until compression output buffers are flushed */
848
849 do
850 {
851 z_err = deflate( &buff->zctrl, Z_FINISH );
852 if ( z_err == Z_OK ) {
853 /* In this case Z_OK means more buffer space needed */
854
855 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
856 return ( -1 );
857 }
858 }
859 while ( z_err == Z_OK );
860
861 /* If the compression state is not Z_STREAM_END, some error occurred */
862
863 if ( z_err == Z_STREAM_END ) {
864
865 /* Need to append the gzip data trailer */
866
867 if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) {
868 if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 )
869 return ( -1 );
870 }
871
872 /*
873 ** For whatever reason, the CRC and length data are pushed out
874 ** in reverse byte order. So a memcpy can't be used here.
875 */
876
877 append_reverse_ulong( buff, buff->crc );
878 append_reverse_ulong( buff, buff->zctrl.total_in );
879
880 zlgth = buff->zctrl.next_out - buff->zbuff;
881 *data_ref = (char *)buff->zbuff;
882 }
883
884 else
885 xmlGenericError( xmlGenericErrorContext,
886 "xmlZMemBuffGetContent: %s - %d\n",
887 "Error flushing zlib buffers. Error code", z_err );
888
889 return ( zlgth );
890}
891#endif /* HAVE_ZLIB_H */
892
893/**
894 * xmlFreeHTTPWriteCtxt
895 * @ctxt: Context to cleanup
896 *
897 * Free allocated memory and reclaim system resources.
898 *
899 * No return value.
900 */
901static void
902xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt )
903{
904 if ( ctxt->uri != NULL )
905 free( ctxt->uri );
906
907 if ( ctxt->doc_buff != NULL ) {
908
909#ifdef HAVE_ZLIB_H
910 if ( ctxt->compression > 0 ) {
911 xmlFreeZMemBuff( ctxt->doc_buff );
912 }
913 else
914#endif
915 {
916 xmlOutputBufferClose( ctxt->doc_buff );
917 }
918 }
919
920 free( ctxt );
921 return;
922}
923
924
Owen Taylor3473f882001-02-23 17:55:21 +0000925/**
926 * xmlIOHTTPMatch:
927 * @filename: the URI for matching
928 *
929 * check if the URI matches an HTTP one
930 *
931 * Returns 1 if matches, 0 otherwise
932 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000933static int
Owen Taylor3473f882001-02-23 17:55:21 +0000934xmlIOHTTPMatch (const char *filename) {
935 if (!strncmp(filename, "http://", 7))
936 return(1);
937 return(0);
938}
939
940/**
941 * xmlIOHTTPOpen:
942 * @filename: the URI for matching
943 *
944 * open an HTTP I/O channel
945 *
946 * Returns an I/O context or NULL in case of error
947 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000948static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000949xmlIOHTTPOpen (const char *filename) {
950 return(xmlNanoHTTPOpen(filename, NULL));
951}
952
953/**
Daniel Veillardf012a642001-07-23 19:10:52 +0000954 * xmlIOHTTPOpenW
955 * @post_uri: The destination URI for the document
956 * @compression: The compression desired for the document.
957 *
958 * Open a temporary buffer to collect the document for a subsequent HTTP POST
959 * request. Non-static as is called from the output buffer creation routine.
960 *
961 * Returns an I/O context or NULL in case of error.
962 */
963
964void *
965xmlIOHTTPOpenW( const char * post_uri, int compression ) {
966
967 xmlIOHTTPWriteCtxtPtr ctxt = NULL;
968
969 if ( post_uri == NULL )
970 return ( NULL );
971
972 ctxt = xmlMalloc( sizeof( xmlIOHTTPWriteCtxt ) );
973 if ( ctxt == NULL ) {
974 xmlGenericError( xmlGenericErrorContext,
975 "xmlIOHTTPOpenW: Failed to create output HTTP context.\n" );
976 return ( NULL );
977 }
978
979 (void)memset( ctxt, 0, sizeof( xmlIOHTTPWriteCtxt ) );
980
981 ctxt->uri = strdup( post_uri );
982 if ( ctxt->uri == NULL ) {
983 xmlGenericError( xmlGenericErrorContext,
984 "xmlIOHTTPOpenW: Failed to duplicate destination URI.\n" );
985 xmlFreeHTTPWriteCtxt( ctxt );
986 return ( NULL );
987 }
988
989 /*
990 ** Since the document length is required for an HTTP post,
991 ** need to put the document into a buffer. A memory buffer
992 ** is being used to avoid pushing the data to disk and back.
993 */
994
995#ifdef HAVE_ZLIB_H
996 if ( ( compression > 0 ) && ( compression <= 9 ) ) {
997
998 ctxt->compression = compression;
999 ctxt->doc_buff = xmlCreateZMemBuff( compression );
1000 }
1001 else
1002#endif
1003 {
1004 /* Any character conversions should have been done before this */
1005
1006 ctxt->doc_buff = xmlAllocOutputBuffer( NULL );
1007 }
1008
1009 if ( ctxt->doc_buff == NULL ) {
1010 xmlFreeHTTPWriteCtxt( ctxt );
1011 ctxt = NULL;
1012 }
1013
1014 return ( ctxt );
1015}
1016
1017/**
1018 * xmlIOHTTPDfltOpenW
1019 * @post_uri: The destination URI for this document.
1020 *
1021 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
1022 * HTTP post command. This function should generally not be used as
1023 * the open callback is short circuited in xmlOutputBufferCreateFile.
1024 *
1025 * Returns a pointer to the new IO context.
1026 */
1027static void *
1028xmlIOHTTPDfltOpenW( const char * post_uri ) {
1029 return ( xmlIOHTTPOpenW( post_uri, 0 ) );
1030}
1031
1032/**
Owen Taylor3473f882001-02-23 17:55:21 +00001033 * xmlIOHTTPRead:
1034 * @context: the I/O context
1035 * @buffer: where to drop data
1036 * @len: number of bytes to write
1037 *
1038 * Read @len bytes to @buffer from the I/O channel.
1039 *
1040 * Returns the number of bytes written
1041 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001042static int
Owen Taylor3473f882001-02-23 17:55:21 +00001043xmlIOHTTPRead(void * context, char * buffer, int len) {
1044 return(xmlNanoHTTPRead(context, &buffer[0], len));
1045}
1046
1047/**
Daniel Veillardf012a642001-07-23 19:10:52 +00001048 * xmlIOHTTPWrite
1049 * @context: previously opened writing context
1050 * @buffer: data to output to temporary buffer
1051 * @len: bytes to output
1052 *
1053 * Collect data from memory buffer into a temporary file for later
1054 * processing.
1055 *
1056 * Returns number of bytes written.
1057 */
1058
1059static int
1060xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
1061
1062 xmlIOHTTPWriteCtxtPtr ctxt = context;
1063
1064 if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
1065 return ( -1 );
1066
1067 if ( len > 0 ) {
1068
1069 /* Use gzwrite or fwrite as previously setup in the open call */
1070
1071#ifdef HAVE_ZLIB_H
1072 if ( ctxt->compression > 0 )
1073 len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len );
1074
1075 else
1076#endif
1077 len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
1078
1079 if ( len < 0 ) {
1080 xmlGenericError( xmlGenericErrorContext,
1081 "xmlIOHTTPWrite: %s\n%s '%s'.\n",
1082 "Error appending to internal buffer.",
1083 "Error sending document to URI",
1084 ctxt->uri );
1085 }
1086 }
1087
1088 return ( len );
1089}
1090
1091
1092/**
Owen Taylor3473f882001-02-23 17:55:21 +00001093 * xmlIOHTTPClose:
1094 * @context: the I/O context
1095 *
1096 * Close an HTTP I/O channel
1097 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001098static int
Owen Taylor3473f882001-02-23 17:55:21 +00001099xmlIOHTTPClose (void * context) {
1100 xmlNanoHTTPClose(context);
Daniel Veillardf012a642001-07-23 19:10:52 +00001101 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001102}
Daniel Veillardf012a642001-07-23 19:10:52 +00001103
1104/**
1105 * xmlIOHTTCloseWrite
1106 * @context: The I/O context
1107 * @http_mthd: The HTTP method to be used when sending the data
1108 *
1109 * Close the transmit HTTP I/O channel and actually send the data.
1110 */
1111static int
1112xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
1113
1114 int close_rc = -1;
1115 int http_rtn = 0;
1116 int content_lgth = 0;
1117 xmlIOHTTPWriteCtxtPtr ctxt = context;
1118
1119 char * http_content = NULL;
1120 char * content_encoding = NULL;
1121 char * content_type = (char *) "text/xml";
1122 void * http_ctxt = NULL;
1123
1124 if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
1125 return ( -1 );
1126
1127 /* Retrieve the content from the appropriate buffer */
1128
1129#ifdef HAVE_ZLIB_H
1130
1131 if ( ctxt->compression > 0 ) {
1132 content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
1133 content_encoding = (char *) "Content-Encoding: gzip";
1134 }
1135 else
1136#endif
1137 {
1138 /* Pull the data out of the memory output buffer */
1139
1140 xmlOutputBufferPtr dctxt = ctxt->doc_buff;
1141 http_content = (char *)dctxt->buffer->content;
1142 content_lgth = dctxt->buffer->use;
1143 }
1144
1145 if ( http_content == NULL ) {
1146 xmlGenericError( xmlGenericErrorContext,
1147 "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
1148 "Error retrieving content.\nUnable to",
1149 http_mthd, "data to URI", ctxt->uri );
1150 }
1151
1152 else {
1153
1154 http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
1155 &content_type, content_encoding,
1156 content_lgth );
1157
1158 if ( http_ctxt != NULL ) {
1159#ifdef DEBUG_HTTP
1160 /* If testing/debugging - dump reply with request content */
1161
1162 FILE * tst_file = NULL;
1163 char buffer[ 4096 ];
1164 char * dump_name = NULL;
1165 int avail;
1166
1167 xmlGenericError( xmlGenericErrorContext,
1168 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
1169 http_mthd, ctxt->uri,
1170 xmlNanoHTTPReturnCode( http_ctxt ) );
1171
1172 /*
1173 ** Since either content or reply may be gzipped,
1174 ** dump them to separate files instead of the
1175 ** standard error context.
1176 */
1177
1178 dump_name = tempnam( NULL, "lxml" );
1179 if ( dump_name != NULL ) {
1180 (void)sprintf( buffer, "%s.content", dump_name );
1181
1182 tst_file = fopen( buffer, "w" );
1183 if ( tst_file != NULL ) {
1184 xmlGenericError( xmlGenericErrorContext,
1185 "Transmitted content saved in file: %s\n", buffer );
1186
1187 fwrite( http_content, sizeof( char ),
1188 content_lgth, tst_file );
1189 fclose( tst_file );
1190 }
1191
1192 (void)sprintf( buffer, "%s.reply", dump_name );
1193 tst_file = fopen( buffer, "w" );
1194 if ( tst_file != NULL ) {
1195 xmlGenericError( xmlGenericErrorContext,
1196 "Reply content saved in file: %s\n", buffer );
1197
1198
1199 while ( (avail = xmlNanoHTTPRead( http_ctxt,
1200 buffer, sizeof( buffer ) )) > 0 ) {
1201
1202 fwrite( buffer, sizeof( char ), avail, tst_file );
1203 }
1204
1205 fclose( tst_file );
1206 }
1207
1208 free( dump_name );
1209 }
1210#endif /* DEBUG_HTTP */
1211
1212 http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
1213 if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
1214 close_rc = 0;
1215 else
1216 xmlGenericError( xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001217 "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001218 http_mthd, content_lgth,
1219 "bytes to URI", ctxt->uri,
1220 "failed. HTTP return code:", http_rtn );
1221
1222 xmlNanoHTTPClose( http_ctxt );
1223 xmlFree( content_type );
1224 }
1225 }
1226
1227 /* Final cleanups */
1228
1229 xmlFreeHTTPWriteCtxt( ctxt );
1230
1231 return ( close_rc );
1232}
1233
1234/**
1235 * xmlIOHTTPClosePut
1236 *
1237 * @context: The I/O context
1238 *
1239 * Close the transmit HTTP I/O channel and actually send data using a PUT
1240 * HTTP method.
1241 */
1242static int
1243xmlIOHTTPClosePut( void * ctxt ) {
1244 return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
1245}
1246
1247
1248/**
1249 * xmlIOHTTPClosePost
1250 *
1251 * @context: The I/O context
1252 *
1253 * Close the transmit HTTP I/O channel and actually send data using a POST
1254 * HTTP method.
1255 */
1256static int
1257xmlIOHTTPClosePost( void * ctxt ) {
1258 return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
1259}
1260
Owen Taylor3473f882001-02-23 17:55:21 +00001261#endif /* LIBXML_HTTP_ENABLED */
1262
1263#ifdef LIBXML_FTP_ENABLED
1264/************************************************************************
1265 * *
1266 * I/O for FTP file accesses *
1267 * *
1268 ************************************************************************/
1269/**
1270 * xmlIOFTPMatch:
1271 * @filename: the URI for matching
1272 *
1273 * check if the URI matches an FTP one
1274 *
1275 * Returns 1 if matches, 0 otherwise
1276 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001277static int
Owen Taylor3473f882001-02-23 17:55:21 +00001278xmlIOFTPMatch (const char *filename) {
1279 if (!strncmp(filename, "ftp://", 6))
1280 return(1);
1281 return(0);
1282}
1283
1284/**
1285 * xmlIOFTPOpen:
1286 * @filename: the URI for matching
1287 *
1288 * open an FTP I/O channel
1289 *
1290 * Returns an I/O context or NULL in case of error
1291 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001292static void *
Owen Taylor3473f882001-02-23 17:55:21 +00001293xmlIOFTPOpen (const char *filename) {
1294 return(xmlNanoFTPOpen(filename));
1295}
1296
1297/**
1298 * xmlIOFTPRead:
1299 * @context: the I/O context
1300 * @buffer: where to drop data
1301 * @len: number of bytes to write
1302 *
1303 * Read @len bytes to @buffer from the I/O channel.
1304 *
1305 * Returns the number of bytes written
1306 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001307static int
Owen Taylor3473f882001-02-23 17:55:21 +00001308xmlIOFTPRead(void * context, char * buffer, int len) {
1309 return(xmlNanoFTPRead(context, &buffer[0], len));
1310}
1311
1312/**
1313 * xmlIOFTPClose:
1314 * @context: the I/O context
1315 *
1316 * Close an FTP I/O channel
1317 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001318static int
Owen Taylor3473f882001-02-23 17:55:21 +00001319xmlIOFTPClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001320 return ( xmlNanoFTPClose(context) );
Owen Taylor3473f882001-02-23 17:55:21 +00001321}
1322#endif /* LIBXML_FTP_ENABLED */
1323
1324
1325/**
1326 * xmlRegisterInputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001327 * @matchFunc: the xmlInputMatchCallback
1328 * @openFunc: the xmlInputOpenCallback
1329 * @readFunc: the xmlInputReadCallback
1330 * @closeFunc: the xmlInputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001331 *
1332 * Register a new set of I/O callback for handling parser input.
1333 *
1334 * Returns the registered handler number or -1 in case of error
1335 */
1336int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001337xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
1338 xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
1339 xmlInputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001340 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
1341 return(-1);
1342 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001343 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
1344 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
1345 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
1346 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
Owen Taylor3473f882001-02-23 17:55:21 +00001347 return(xmlInputCallbackNr++);
1348}
1349
1350/**
1351 * xmlRegisterOutputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001352 * @matchFunc: the xmlOutputMatchCallback
1353 * @openFunc: the xmlOutputOpenCallback
1354 * @writeFunc: the xmlOutputWriteCallback
1355 * @closeFunc: the xmlOutputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001356 *
1357 * Register a new set of I/O callback for handling output.
1358 *
1359 * Returns the registered handler number or -1 in case of error
1360 */
1361int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001362xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
1363 xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
1364 xmlOutputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001365 if (xmlOutputCallbackNr >= MAX_INPUT_CALLBACK) {
1366 return(-1);
1367 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001368 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
1369 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
1370 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
1371 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
Owen Taylor3473f882001-02-23 17:55:21 +00001372 return(xmlOutputCallbackNr++);
1373}
1374
1375/**
1376 * xmlRegisterDefaultInputCallbacks:
1377 *
1378 * Registers the default compiled-in I/O handlers.
1379 */
1380void
1381#ifdef VMS
1382xmlRegisterDefInputCallbacks
1383#else
1384xmlRegisterDefaultInputCallbacks
1385#endif
1386(void) {
1387 if (xmlInputCallbackInitialized)
1388 return;
1389
1390 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
1391 xmlFileRead, xmlFileClose);
1392#ifdef HAVE_ZLIB_H
1393 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1394 xmlGzfileRead, xmlGzfileClose);
1395#endif /* HAVE_ZLIB_H */
1396
1397#ifdef LIBXML_HTTP_ENABLED
1398 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
1399 xmlIOHTTPRead, xmlIOHTTPClose);
1400#endif /* LIBXML_HTTP_ENABLED */
1401
1402#ifdef LIBXML_FTP_ENABLED
1403 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1404 xmlIOFTPRead, xmlIOFTPClose);
1405#endif /* LIBXML_FTP_ENABLED */
1406 xmlInputCallbackInitialized = 1;
1407}
1408
1409/**
1410 * xmlRegisterDefaultOutputCallbacks:
1411 *
1412 * Registers the default compiled-in I/O handlers.
1413 */
1414void
1415#ifdef VMS
1416xmlRegisterDefOutputCallbacks
1417#else
1418xmlRegisterDefaultOutputCallbacks
1419#endif
1420(void) {
1421 if (xmlOutputCallbackInitialized)
1422 return;
1423
1424 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
1425 xmlFileWrite, xmlFileClose);
Daniel Veillardf012a642001-07-23 19:10:52 +00001426
1427#ifdef LIBXML_HTTP_ENABLED
1428 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
1429 xmlIOHTTPWrite, xmlIOHTTPClosePut);
1430#endif
1431
Owen Taylor3473f882001-02-23 17:55:21 +00001432/*********************************
1433 No way a-priori to distinguish between gzipped files from
1434 uncompressed ones except opening if existing then closing
1435 and saving with same compression ratio ... a pain.
1436
1437#ifdef HAVE_ZLIB_H
1438 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1439 xmlGzfileWrite, xmlGzfileClose);
1440#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001441
1442 Nor FTP PUT ....
1443#ifdef LIBXML_FTP_ENABLED
1444 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1445 xmlIOFTPWrite, xmlIOFTPClose);
1446#endif
1447 **********************************/
1448 xmlOutputCallbackInitialized = 1;
1449}
1450
Daniel Veillardf012a642001-07-23 19:10:52 +00001451#ifdef LIBXML_HTTP_ENABLED
1452/**
1453 * xmlRegisterHTTPPostCallbacks
1454 *
1455 * By default, libxml submits HTTP output requests using the "PUT" method.
1456 * Calling this method changes the HTTP output method to use the "POST"
1457 * method instead.
1458 *
1459 */
1460void
1461xmlRegisterHTTPPostCallbacks( void ) {
1462
1463 /* Register defaults if not done previously */
1464
1465 if ( xmlOutputCallbackInitialized == 0 )
1466 xmlRegisterDefaultOutputCallbacks( );
1467
1468 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
1469 xmlIOHTTPWrite, xmlIOHTTPClosePost);
1470 return;
1471}
1472#endif
1473
Owen Taylor3473f882001-02-23 17:55:21 +00001474/**
1475 * xmlAllocParserInputBuffer:
1476 * @enc: the charset encoding if known
1477 *
1478 * Create a buffered parser input for progressive parsing
1479 *
1480 * Returns the new parser input or NULL
1481 */
1482xmlParserInputBufferPtr
1483xmlAllocParserInputBuffer(xmlCharEncoding enc) {
1484 xmlParserInputBufferPtr ret;
1485
1486 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
1487 if (ret == NULL) {
1488 xmlGenericError(xmlGenericErrorContext,
1489 "xmlAllocParserInputBuffer : out of memory!\n");
1490 return(NULL);
1491 }
1492 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
1493 ret->buffer = xmlBufferCreate();
1494 if (ret->buffer == NULL) {
1495 xmlFree(ret);
1496 return(NULL);
1497 }
1498 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
1499 ret->encoder = xmlGetCharEncodingHandler(enc);
1500 if (ret->encoder != NULL)
1501 ret->raw = xmlBufferCreate();
1502 else
1503 ret->raw = NULL;
1504 ret->readcallback = NULL;
1505 ret->closecallback = NULL;
1506 ret->context = NULL;
1507
1508 return(ret);
1509}
1510
1511/**
1512 * xmlAllocOutputBuffer:
1513 * @encoder: the encoding converter or NULL
1514 *
1515 * Create a buffered parser output
1516 *
1517 * Returns the new parser output or NULL
1518 */
1519xmlOutputBufferPtr
1520xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
1521 xmlOutputBufferPtr ret;
1522
1523 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
1524 if (ret == NULL) {
1525 xmlGenericError(xmlGenericErrorContext,
1526 "xmlAllocOutputBuffer : out of memory!\n");
1527 return(NULL);
1528 }
1529 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
1530 ret->buffer = xmlBufferCreate();
1531 if (ret->buffer == NULL) {
1532 xmlFree(ret);
1533 return(NULL);
1534 }
1535 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
1536 ret->encoder = encoder;
1537 if (encoder != NULL) {
1538 ret->conv = xmlBufferCreateSize(4000);
1539 /*
1540 * This call is designed to initiate the encoder state
1541 */
1542 xmlCharEncOutFunc(encoder, ret->conv, NULL);
1543 } else
1544 ret->conv = NULL;
1545 ret->writecallback = NULL;
1546 ret->closecallback = NULL;
1547 ret->context = NULL;
1548 ret->written = 0;
1549
1550 return(ret);
1551}
1552
1553/**
1554 * xmlFreeParserInputBuffer:
1555 * @in: a buffered parser input
1556 *
1557 * Free up the memory used by a buffered parser input
1558 */
1559void
1560xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
1561 if (in->raw) {
1562 xmlBufferFree(in->raw);
1563 in->raw = NULL;
1564 }
1565 if (in->encoder != NULL) {
1566 xmlCharEncCloseFunc(in->encoder);
1567 }
1568 if (in->closecallback != NULL) {
1569 in->closecallback(in->context);
1570 }
1571 if (in->buffer != NULL) {
1572 xmlBufferFree(in->buffer);
1573 in->buffer = NULL;
1574 }
1575
Owen Taylor3473f882001-02-23 17:55:21 +00001576 xmlFree(in);
1577}
1578
1579/**
1580 * xmlOutputBufferClose:
1581 * @out: a buffered output
1582 *
1583 * flushes and close the output I/O channel
1584 * and free up all the associated resources
1585 *
1586 * Returns the number of byte written or -1 in case of error.
1587 */
1588int
1589xmlOutputBufferClose(xmlOutputBufferPtr out) {
1590 int written;
Daniel Veillardf012a642001-07-23 19:10:52 +00001591 int err_rc = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001592
1593 if (out == NULL)
1594 return(-1);
1595 if (out->writecallback != NULL)
1596 xmlOutputBufferFlush(out);
1597 if (out->closecallback != NULL) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001598 err_rc = out->closecallback(out->context);
Owen Taylor3473f882001-02-23 17:55:21 +00001599 }
1600 written = out->written;
1601 if (out->conv) {
1602 xmlBufferFree(out->conv);
1603 out->conv = NULL;
1604 }
1605 if (out->encoder != NULL) {
1606 xmlCharEncCloseFunc(out->encoder);
1607 }
1608 if (out->buffer != NULL) {
1609 xmlBufferFree(out->buffer);
1610 out->buffer = NULL;
1611 }
1612
Owen Taylor3473f882001-02-23 17:55:21 +00001613 xmlFree(out);
Daniel Veillardf012a642001-07-23 19:10:52 +00001614 return( ( err_rc == 0 ) ? written : err_rc );
Owen Taylor3473f882001-02-23 17:55:21 +00001615}
1616
1617/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001618 * xmlParserInputBufferCreateFname:
1619 * @URI: a C string containing the URI or filename
1620 * @enc: the charset encoding if known
1621 *
1622 * VMS version of xmlParserInputBufferCreateFilename()
1623 *
1624 * Returns the new parser input or NULL
1625 */
1626/**
Owen Taylor3473f882001-02-23 17:55:21 +00001627 * xmlParserInputBufferCreateFilename:
1628 * @URI: a C string containing the URI or filename
1629 * @enc: the charset encoding if known
1630 *
1631 * Create a buffered parser input for the progressive parsing of a file
1632 * If filename is "-' then we use stdin as the input.
1633 * Automatic support for ZLIB/Compress compressed document is provided
1634 * by default if found at compile-time.
1635 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
1636 *
1637 * Returns the new parser input or NULL
1638 */
1639xmlParserInputBufferPtr
1640#ifdef VMS
1641xmlParserInputBufferCreateFname
1642#else
1643xmlParserInputBufferCreateFilename
1644#endif
1645(const char *URI, xmlCharEncoding enc) {
1646 xmlParserInputBufferPtr ret;
Daniel Veillard388236f2001-07-08 18:35:48 +00001647 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001648 void *context = NULL;
Daniel Veillard388236f2001-07-08 18:35:48 +00001649 char *unescaped;
Owen Taylor3473f882001-02-23 17:55:21 +00001650
1651 if (xmlInputCallbackInitialized == 0)
1652 xmlRegisterDefaultInputCallbacks();
1653
1654 if (URI == NULL) return(NULL);
1655
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001656#ifdef LIBXML_CATALOG_ENABLED
1657#endif
1658
Owen Taylor3473f882001-02-23 17:55:21 +00001659 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001660 * Try to find one of the input accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00001661 * Go in reverse to give precedence to user defined handlers.
Daniel Veillard388236f2001-07-08 18:35:48 +00001662 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00001663 */
Daniel Veillard388236f2001-07-08 18:35:48 +00001664 unescaped = xmlURIUnescapeString(URI, 0, NULL);
1665 if (unescaped != NULL) {
1666 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
1667 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
1668 (xmlInputCallbackTable[i].matchcallback(unescaped) != 0)) {
1669 context = xmlInputCallbackTable[i].opencallback(unescaped);
1670 if (context != NULL)
1671 break;
1672 }
1673 }
1674 xmlFree(unescaped);
1675 }
1676
1677 /*
1678 * If this failed try with a non-escaped URI this may be a strange
1679 * filename
1680 */
1681 if (context == NULL) {
1682 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
1683 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
1684 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
1685 context = xmlInputCallbackTable[i].opencallback(URI);
1686 if (context != NULL)
1687 break;
1688 }
Owen Taylor3473f882001-02-23 17:55:21 +00001689 }
1690 }
1691 if (context == NULL) {
1692 return(NULL);
1693 }
1694
1695 /*
1696 * Allocate the Input buffer front-end.
1697 */
1698 ret = xmlAllocParserInputBuffer(enc);
1699 if (ret != NULL) {
1700 ret->context = context;
1701 ret->readcallback = xmlInputCallbackTable[i].readcallback;
1702 ret->closecallback = xmlInputCallbackTable[i].closecallback;
1703 }
1704 return(ret);
1705}
1706
1707/**
1708 * xmlOutputBufferCreateFilename:
1709 * @URI: a C string containing the URI or filename
1710 * @encoder: the encoding converter or NULL
1711 * @compression: the compression ration (0 none, 9 max).
1712 *
1713 * Create a buffered output for the progressive saving of a file
1714 * If filename is "-' then we use stdout as the output.
1715 * Automatic support for ZLIB/Compress compressed document is provided
1716 * by default if found at compile-time.
1717 * TODO: currently if compression is set, the library only support
1718 * writing to a local file.
1719 *
1720 * Returns the new output or NULL
1721 */
1722xmlOutputBufferPtr
1723xmlOutputBufferCreateFilename(const char *URI,
1724 xmlCharEncodingHandlerPtr encoder,
1725 int compression) {
1726 xmlOutputBufferPtr ret;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001727 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001728 void *context = NULL;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001729 char *unescaped;
Owen Taylor3473f882001-02-23 17:55:21 +00001730
Daniel Veillardf012a642001-07-23 19:10:52 +00001731 int is_http_uri = 0; /* Can't change if HTTP disabled */
1732
Owen Taylor3473f882001-02-23 17:55:21 +00001733 if (xmlOutputCallbackInitialized == 0)
1734 xmlRegisterDefaultOutputCallbacks();
1735
1736 if (URI == NULL) return(NULL);
1737
Daniel Veillardf012a642001-07-23 19:10:52 +00001738#ifdef LIBXML_HTTP_ENABLED
1739 /* Need to prevent HTTP URI's from falling into zlib short circuit */
1740
1741 is_http_uri = xmlIOHTTPMatch( URI );
1742#endif
1743
Owen Taylor3473f882001-02-23 17:55:21 +00001744
1745 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001746 * Try to find one of the output accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00001747 * Go in reverse to give precedence to user defined handlers.
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001748 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00001749 */
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001750 unescaped = xmlURIUnescapeString(URI, 0, NULL);
1751 if (unescaped != NULL) {
1752#ifdef HAVE_ZLIB_H
1753 if ((compression > 0) && (compression <= 9) && (is_http_uri == 0)) {
1754 context = xmlGzfileOpenW(unescaped, compression);
1755 if (context != NULL) {
1756 ret = xmlAllocOutputBuffer(encoder);
1757 if (ret != NULL) {
1758 ret->context = context;
1759 ret->writecallback = xmlGzfileWrite;
1760 ret->closecallback = xmlGzfileClose;
1761 }
1762 xmlFree(unescaped);
1763 return(ret);
1764 }
1765 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001766#endif
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001767 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
1768 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
1769 (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
1770#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
1771 /* Need to pass compression parameter into HTTP open calls */
1772 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
1773 context = xmlIOHTTPOpenW(unescaped, compression);
1774 else
1775#endif
1776 context = xmlOutputCallbackTable[i].opencallback(unescaped);
1777 if (context != NULL)
1778 break;
1779 }
1780 }
1781 xmlFree(unescaped);
1782 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001783
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001784 /*
1785 * If this failed try with a non-escaped URI this may be a strange
1786 * filename
1787 */
1788 if (context == NULL) {
1789#ifdef HAVE_ZLIB_H
1790 if ((compression > 0) && (compression <= 9) && (is_http_uri == 0)) {
1791 context = xmlGzfileOpenW(URI, compression);
1792 if (context != NULL) {
1793 ret = xmlAllocOutputBuffer(encoder);
1794 if (ret != NULL) {
1795 ret->context = context;
1796 ret->writecallback = xmlGzfileWrite;
1797 ret->closecallback = xmlGzfileClose;
1798 }
1799 return(ret);
1800 }
1801 }
1802#endif
1803 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
1804 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
1805 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
1806 context = xmlOutputCallbackTable[i].opencallback(URI);
1807#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
1808 /* Need to pass compression parameter into HTTP open calls */
1809 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
1810 context = xmlIOHTTPOpenW(URI, compression);
1811 else
1812#endif
1813 context = xmlOutputCallbackTable[i].opencallback(URI);
1814 if (context != NULL)
1815 break;
1816 }
Owen Taylor3473f882001-02-23 17:55:21 +00001817 }
1818 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001819
Owen Taylor3473f882001-02-23 17:55:21 +00001820 if (context == NULL) {
1821 return(NULL);
1822 }
1823
1824 /*
1825 * Allocate the Output buffer front-end.
1826 */
1827 ret = xmlAllocOutputBuffer(encoder);
1828 if (ret != NULL) {
1829 ret->context = context;
1830 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
1831 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
1832 }
1833 return(ret);
1834}
1835
1836/**
1837 * xmlParserInputBufferCreateFile:
1838 * @file: a FILE*
1839 * @enc: the charset encoding if known
1840 *
1841 * Create a buffered parser input for the progressive parsing of a FILE *
1842 * buffered C I/O
1843 *
1844 * Returns the new parser input or NULL
1845 */
1846xmlParserInputBufferPtr
1847xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
1848 xmlParserInputBufferPtr ret;
1849
1850 if (xmlInputCallbackInitialized == 0)
1851 xmlRegisterDefaultInputCallbacks();
1852
1853 if (file == NULL) return(NULL);
1854
1855 ret = xmlAllocParserInputBuffer(enc);
1856 if (ret != NULL) {
1857 ret->context = file;
1858 ret->readcallback = xmlFileRead;
1859 ret->closecallback = xmlFileFlush;
1860 }
1861
1862 return(ret);
1863}
1864
1865/**
1866 * xmlOutputBufferCreateFile:
1867 * @file: a FILE*
1868 * @encoder: the encoding converter or NULL
1869 *
1870 * Create a buffered output for the progressive saving to a FILE *
1871 * buffered C I/O
1872 *
1873 * Returns the new parser output or NULL
1874 */
1875xmlOutputBufferPtr
1876xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
1877 xmlOutputBufferPtr ret;
1878
1879 if (xmlOutputCallbackInitialized == 0)
1880 xmlRegisterDefaultOutputCallbacks();
1881
1882 if (file == NULL) return(NULL);
1883
1884 ret = xmlAllocOutputBuffer(encoder);
1885 if (ret != NULL) {
1886 ret->context = file;
1887 ret->writecallback = xmlFileWrite;
1888 ret->closecallback = xmlFileFlush;
1889 }
1890
1891 return(ret);
1892}
1893
1894/**
1895 * xmlParserInputBufferCreateFd:
1896 * @fd: a file descriptor number
1897 * @enc: the charset encoding if known
1898 *
1899 * Create a buffered parser input for the progressive parsing for the input
1900 * from a file descriptor
1901 *
1902 * Returns the new parser input or NULL
1903 */
1904xmlParserInputBufferPtr
1905xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
1906 xmlParserInputBufferPtr ret;
1907
1908 if (fd < 0) return(NULL);
1909
1910 ret = xmlAllocParserInputBuffer(enc);
1911 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00001912 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00001913 ret->readcallback = xmlFdRead;
1914 ret->closecallback = xmlFdClose;
1915 }
1916
1917 return(ret);
1918}
1919
1920/**
1921 * xmlParserInputBufferCreateMem:
1922 * @mem: the memory input
1923 * @size: the length of the memory block
1924 * @enc: the charset encoding if known
1925 *
1926 * Create a buffered parser input for the progressive parsing for the input
1927 * from a memory area.
1928 *
1929 * Returns the new parser input or NULL
1930 */
1931xmlParserInputBufferPtr
1932xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
1933 xmlParserInputBufferPtr ret;
1934
1935 if (size <= 0) return(NULL);
1936 if (mem == NULL) return(NULL);
1937
1938 ret = xmlAllocParserInputBuffer(enc);
1939 if (ret != NULL) {
1940 ret->context = (void *) mem;
1941 ret->readcallback = (xmlInputReadCallback) xmlNop;
1942 ret->closecallback = NULL;
1943 xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size);
1944 }
1945
1946 return(ret);
1947}
1948
1949/**
1950 * xmlOutputBufferCreateFd:
1951 * @fd: a file descriptor number
1952 * @encoder: the encoding converter or NULL
1953 *
1954 * Create a buffered output for the progressive saving
1955 * to a file descriptor
1956 *
1957 * Returns the new parser output or NULL
1958 */
1959xmlOutputBufferPtr
1960xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
1961 xmlOutputBufferPtr ret;
1962
1963 if (fd < 0) return(NULL);
1964
1965 ret = xmlAllocOutputBuffer(encoder);
1966 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00001967 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00001968 ret->writecallback = xmlFdWrite;
1969 ret->closecallback = xmlFdClose;
1970 }
1971
1972 return(ret);
1973}
1974
1975/**
1976 * xmlParserInputBufferCreateIO:
1977 * @ioread: an I/O read function
1978 * @ioclose: an I/O close function
1979 * @ioctx: an I/O handler
1980 * @enc: the charset encoding if known
1981 *
1982 * Create a buffered parser input for the progressive parsing for the input
1983 * from an I/O handler
1984 *
1985 * Returns the new parser input or NULL
1986 */
1987xmlParserInputBufferPtr
1988xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
1989 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
1990 xmlParserInputBufferPtr ret;
1991
1992 if (ioread == NULL) return(NULL);
1993
1994 ret = xmlAllocParserInputBuffer(enc);
1995 if (ret != NULL) {
1996 ret->context = (void *) ioctx;
1997 ret->readcallback = ioread;
1998 ret->closecallback = ioclose;
1999 }
2000
2001 return(ret);
2002}
2003
2004/**
2005 * xmlOutputBufferCreateIO:
2006 * @iowrite: an I/O write function
2007 * @ioclose: an I/O close function
2008 * @ioctx: an I/O handler
2009 * @enc: the charset encoding if known
2010 *
2011 * Create a buffered output for the progressive saving
2012 * to an I/O handler
2013 *
2014 * Returns the new parser output or NULL
2015 */
2016xmlOutputBufferPtr
2017xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
2018 xmlOutputCloseCallback ioclose, void *ioctx,
2019 xmlCharEncodingHandlerPtr encoder) {
2020 xmlOutputBufferPtr ret;
2021
2022 if (iowrite == NULL) return(NULL);
2023
2024 ret = xmlAllocOutputBuffer(encoder);
2025 if (ret != NULL) {
2026 ret->context = (void *) ioctx;
2027 ret->writecallback = iowrite;
2028 ret->closecallback = ioclose;
2029 }
2030
2031 return(ret);
2032}
2033
2034/**
2035 * xmlParserInputBufferPush:
2036 * @in: a buffered parser input
2037 * @len: the size in bytes of the array.
2038 * @buf: an char array
2039 *
2040 * Push the content of the arry in the input buffer
2041 * This routine handle the I18N transcoding to internal UTF-8
2042 * This is used when operating the parser in progressive (push) mode.
2043 *
2044 * Returns the number of chars read and stored in the buffer, or -1
2045 * in case of error.
2046 */
2047int
2048xmlParserInputBufferPush(xmlParserInputBufferPtr in,
2049 int len, const char *buf) {
2050 int nbchars = 0;
2051
2052 if (len < 0) return(0);
2053 if (in->encoder != NULL) {
2054 /*
2055 * Store the data in the incoming raw buffer
2056 */
2057 if (in->raw == NULL) {
2058 in->raw = xmlBufferCreate();
2059 }
2060 xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
2061
2062 /*
2063 * convert as much as possible to the parser reading buffer.
2064 */
2065 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2066 if (nbchars < 0) {
2067 xmlGenericError(xmlGenericErrorContext,
2068 "xmlParserInputBufferPush: encoder error\n");
2069 return(-1);
2070 }
2071 } else {
2072 nbchars = len;
2073 xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
2074 }
2075#ifdef DEBUG_INPUT
2076 xmlGenericError(xmlGenericErrorContext,
2077 "I/O: pushed %d chars, buffer %d/%d\n",
2078 nbchars, in->buffer->use, in->buffer->size);
2079#endif
2080 return(nbchars);
2081}
2082
2083/**
2084 * xmlParserInputBufferGrow:
2085 * @in: a buffered parser input
2086 * @len: indicative value of the amount of chars to read
2087 *
2088 * Grow up the content of the input buffer, the old data are preserved
2089 * This routine handle the I18N transcoding to internal UTF-8
2090 * This routine is used when operating the parser in normal (pull) mode
2091 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002092 * TODO: one should be able to remove one extra copy by copying directly
Owen Taylor3473f882001-02-23 17:55:21 +00002093 * onto in->buffer or in->raw
2094 *
2095 * Returns the number of chars read and stored in the buffer, or -1
2096 * in case of error.
2097 */
2098int
2099xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
2100 char *buffer = NULL;
2101 int res = 0;
2102 int nbchars = 0;
2103 int buffree;
2104
2105 if ((len <= MINLEN) && (len != 4))
2106 len = MINLEN;
2107 buffree = in->buffer->size - in->buffer->use;
2108 if (buffree <= 0) {
2109 xmlGenericError(xmlGenericErrorContext,
2110 "xmlParserInputBufferGrow : buffer full !\n");
2111 return(0);
2112 }
2113 if (len > buffree)
2114 len = buffree;
2115
2116 buffer = (char *) xmlMalloc((len + 1) * sizeof(char));
2117 if (buffer == NULL) {
2118 xmlGenericError(xmlGenericErrorContext,
2119 "xmlParserInputBufferGrow : out of memory !\n");
2120 return(-1);
2121 }
2122
2123 /*
2124 * Call the read method for this I/O type.
2125 */
2126 if (in->readcallback != NULL) {
2127 res = in->readcallback(in->context, &buffer[0], len);
2128 } else {
2129 xmlGenericError(xmlGenericErrorContext,
2130 "xmlParserInputBufferGrow : no input !\n");
2131 xmlFree(buffer);
2132 return(-1);
2133 }
2134 if (res < 0) {
2135 perror ("read error");
2136 xmlFree(buffer);
2137 return(-1);
2138 }
2139 len = res;
2140 if (in->encoder != NULL) {
2141 /*
2142 * Store the data in the incoming raw buffer
2143 */
2144 if (in->raw == NULL) {
2145 in->raw = xmlBufferCreate();
2146 }
2147 xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
2148
2149 /*
2150 * convert as much as possible to the parser reading buffer.
2151 */
2152 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2153 if (nbchars < 0) {
2154 xmlGenericError(xmlGenericErrorContext,
2155 "xmlParserInputBufferGrow: encoder error\n");
2156 return(-1);
2157 }
2158 } else {
2159 nbchars = len;
2160 buffer[nbchars] = 0;
2161 xmlBufferAdd(in->buffer, (xmlChar *) buffer, nbchars);
2162 }
2163#ifdef DEBUG_INPUT
2164 xmlGenericError(xmlGenericErrorContext,
2165 "I/O: read %d chars, buffer %d/%d\n",
2166 nbchars, in->buffer->use, in->buffer->size);
2167#endif
2168 xmlFree(buffer);
2169 return(nbchars);
2170}
2171
2172/**
2173 * xmlParserInputBufferRead:
2174 * @in: a buffered parser input
2175 * @len: indicative value of the amount of chars to read
2176 *
2177 * Refresh the content of the input buffer, the old data are considered
2178 * consumed
2179 * This routine handle the I18N transcoding to internal UTF-8
2180 *
2181 * Returns the number of chars read and stored in the buffer, or -1
2182 * in case of error.
2183 */
2184int
2185xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
2186 /* xmlBufferEmpty(in->buffer); */
2187 if (in->readcallback != NULL)
2188 return(xmlParserInputBufferGrow(in, len));
2189 else
2190 return(-1);
2191}
2192
2193/**
2194 * xmlOutputBufferWrite:
2195 * @out: a buffered parser output
2196 * @len: the size in bytes of the array.
2197 * @buf: an char array
2198 *
2199 * Write the content of the array in the output I/O buffer
2200 * This routine handle the I18N transcoding from internal UTF-8
2201 * The buffer is lossless, i.e. will store in case of partial
2202 * or delayed writes.
2203 *
2204 * Returns the number of chars immediately written, or -1
2205 * in case of error.
2206 */
2207int
2208xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
2209 int nbchars = 0; /* number of chars to output to I/O */
2210 int ret; /* return from function call */
2211 int written = 0; /* number of char written to I/O so far */
2212 int chunk; /* number of byte curreent processed from buf */
2213
2214 if (len < 0) return(0);
2215
2216 do {
2217 chunk = len;
2218 if (chunk > 4 * MINLEN)
2219 chunk = 4 * MINLEN;
2220
2221 /*
2222 * first handle encoding stuff.
2223 */
2224 if (out->encoder != NULL) {
2225 /*
2226 * Store the data in the incoming raw buffer
2227 */
2228 if (out->conv == NULL) {
2229 out->conv = xmlBufferCreate();
2230 }
2231 xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2232
2233 if ((out->buffer->use < MINLEN) && (chunk == len))
2234 goto done;
2235
2236 /*
2237 * convert as much as possible to the parser reading buffer.
2238 */
2239 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
2240 if (ret < 0) {
2241 xmlGenericError(xmlGenericErrorContext,
2242 "xmlOutputBufferWrite: encoder error\n");
2243 return(-1);
2244 }
2245 nbchars = out->conv->use;
2246 } else {
2247 xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2248 nbchars = out->buffer->use;
2249 }
2250 buf += chunk;
2251 len -= chunk;
2252
2253 if ((nbchars < MINLEN) && (len <= 0))
2254 goto done;
2255
2256 if (out->writecallback) {
2257 /*
2258 * second write the stuff to the I/O channel
2259 */
2260 if (out->encoder != NULL) {
2261 ret = out->writecallback(out->context,
2262 (const char *)out->conv->content, nbchars);
2263 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002264 xmlBufferShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002265 } else {
2266 ret = out->writecallback(out->context,
2267 (const char *)out->buffer->content, nbchars);
2268 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002269 xmlBufferShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002270 }
2271 if (ret < 0) {
2272 xmlGenericError(xmlGenericErrorContext,
2273 "I/O: error %d writing %d bytes\n", ret, nbchars);
2274 return(ret);
2275 }
2276 out->written += ret;
2277 }
2278 written += nbchars;
2279 } while (len > 0);
2280
2281done:
2282#ifdef DEBUG_INPUT
2283 xmlGenericError(xmlGenericErrorContext,
2284 "I/O: wrote %d chars\n", written);
2285#endif
2286 return(written);
2287}
2288
2289/**
2290 * xmlOutputBufferWriteString:
2291 * @out: a buffered parser output
2292 * @str: a zero terminated C string
2293 *
2294 * Write the content of the string in the output I/O buffer
2295 * This routine handle the I18N transcoding from internal UTF-8
2296 * The buffer is lossless, i.e. will store in case of partial
2297 * or delayed writes.
2298 *
2299 * Returns the number of chars immediately written, or -1
2300 * in case of error.
2301 */
2302int
2303xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
2304 int len;
2305
2306 if (str == NULL)
2307 return(-1);
2308 len = strlen(str);
2309
2310 if (len > 0)
2311 return(xmlOutputBufferWrite(out, len, str));
2312 return(len);
2313}
2314
2315/**
2316 * xmlOutputBufferFlush:
2317 * @out: a buffered output
2318 *
2319 * flushes the output I/O channel
2320 *
2321 * Returns the number of byte written or -1 in case of error.
2322 */
2323int
2324xmlOutputBufferFlush(xmlOutputBufferPtr out) {
2325 int nbchars = 0, ret = 0;
2326
2327 /*
2328 * first handle encoding stuff.
2329 */
2330 if ((out->conv != NULL) && (out->encoder != NULL)) {
2331 /*
2332 * convert as much as possible to the parser reading buffer.
2333 */
2334 nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
2335 if (nbchars < 0) {
2336 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002337 "xmlOutputBufferFlush: encoder error\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002338 return(-1);
2339 }
2340 }
2341
2342 /*
2343 * second flush the stuff to the I/O channel
2344 */
2345 if ((out->conv != NULL) && (out->encoder != NULL) &&
2346 (out->writecallback != NULL)) {
2347 ret = out->writecallback(out->context,
2348 (const char *)out->conv->content, out->conv->use);
2349 if (ret >= 0)
2350 xmlBufferShrink(out->conv, ret);
2351 } else if (out->writecallback != NULL) {
2352 ret = out->writecallback(out->context,
2353 (const char *)out->buffer->content, out->buffer->use);
2354 if (ret >= 0)
2355 xmlBufferShrink(out->buffer, ret);
2356 }
2357 if (ret < 0) {
2358 xmlGenericError(xmlGenericErrorContext,
2359 "I/O: error %d flushing %d bytes\n", ret, nbchars);
2360 return(ret);
2361 }
2362 out->written += ret;
2363
2364#ifdef DEBUG_INPUT
2365 xmlGenericError(xmlGenericErrorContext,
2366 "I/O: flushed %d chars\n", ret);
2367#endif
2368 return(ret);
2369}
2370
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002371/**
Owen Taylor3473f882001-02-23 17:55:21 +00002372 * xmlParserGetDirectory:
2373 * @filename: the path to a file
2374 *
2375 * lookup the directory for that file
2376 *
2377 * Returns a new allocated string containing the directory, or NULL.
2378 */
2379char *
2380xmlParserGetDirectory(const char *filename) {
2381 char *ret = NULL;
2382 char dir[1024];
2383 char *cur;
2384 char sep = '/';
2385
2386 if (xmlInputCallbackInitialized == 0)
2387 xmlRegisterDefaultInputCallbacks();
2388
2389 if (filename == NULL) return(NULL);
2390#ifdef WIN32
2391 sep = '\\';
2392#endif
2393
2394 strncpy(dir, filename, 1023);
2395 dir[1023] = 0;
2396 cur = &dir[strlen(dir)];
2397 while (cur > dir) {
2398 if (*cur == sep) break;
2399 cur --;
2400 }
2401 if (*cur == sep) {
2402 if (cur == dir) dir[1] = 0;
2403 else *cur = 0;
2404 ret = xmlMemStrdup(dir);
2405 } else {
2406 if (getcwd(dir, 1024) != NULL) {
2407 dir[1023] = 0;
2408 ret = xmlMemStrdup(dir);
2409 }
2410 }
2411 return(ret);
2412}
2413
2414/****************************************************************
2415 * *
2416 * External entities loading *
2417 * *
2418 ****************************************************************/
2419
Daniel Veillard6990bf32001-08-23 21:17:48 +00002420#ifdef LIBXML_CATALOG_ENABLED
2421static int xmlSysIDExists(const char *URL) {
2422#ifdef HAVE_STAT
2423 int ret;
2424 struct stat info;
2425 const char *path;
2426
2427 if (URL == NULL)
2428 return(0);
2429
2430 if (!strncmp(URL, "file://localhost", 16))
2431 path = &URL[16];
2432 else if (!strncmp(URL, "file:///", 8)) {
2433#ifdef _WIN32
2434 path = &URL[8];
2435#else
2436 path = &URL[7];
2437#endif
2438 } else
2439 path = URL;
2440 ret = stat(path, &info);
2441 if (ret == 0)
2442 return(1);
2443#endif
2444 return(0);
2445}
2446#endif
2447
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002448/**
Owen Taylor3473f882001-02-23 17:55:21 +00002449 * xmlDefaultExternalEntityLoader:
2450 * @URL: the URL for the entity to load
2451 * @ID: the System ID for the entity to load
2452 * @ctxt: the context in which the entity is called or NULL
2453 *
2454 * By default we don't load external entitites, yet.
2455 *
2456 * Returns a new allocated xmlParserInputPtr, or NULL.
2457 */
2458static
2459xmlParserInputPtr
2460xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
2461 xmlParserCtxtPtr ctxt) {
2462 xmlParserInputPtr ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002463 xmlChar *resource = NULL;
2464#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002465 xmlCatalogAllow pref;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002466#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002467
2468#ifdef DEBUG_EXTERNAL_ENTITIES
2469 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf012a642001-07-23 19:10:52 +00002470 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00002471#endif
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002472#ifdef LIBXML_CATALOG_ENABLED
2473 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002474 * If the resource doesn't exists as a file,
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002475 * try to load it from the resource pointed in the catalogs
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002476 */
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002477 pref = xmlCatalogGetDefaults();
2478
Daniel Veillard6990bf32001-08-23 21:17:48 +00002479 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlSysIDExists(URL))) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002480 /*
2481 * Do a local lookup
2482 */
2483 if ((ctxt->catalogs != NULL) &&
2484 ((pref == XML_CATA_ALLOW_ALL) ||
2485 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2486 resource = xmlCatalogLocalResolve(ctxt->catalogs,
2487 (const xmlChar *)ID,
2488 (const xmlChar *)URL);
2489 }
2490 /*
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002491 * Try a global lookup
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002492 */
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002493 if ((resource == NULL) &&
2494 ((pref == XML_CATA_ALLOW_ALL) ||
2495 (pref == XML_CATA_ALLOW_GLOBAL))) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002496 resource = xmlCatalogResolve((const xmlChar *)ID,
2497 (const xmlChar *)URL);
2498 }
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002499 if ((resource == NULL) && (URL != NULL))
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00002500 resource = xmlStrdup((const xmlChar *) URL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002501
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002502 /*
2503 * TODO: do an URI lookup on the reference
2504 */
Daniel Veillard6990bf32001-08-23 21:17:48 +00002505 if ((resource != NULL) && (!xmlSysIDExists((const char *)resource))) {
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002506 xmlChar *tmp = NULL;
2507
2508 if ((ctxt->catalogs != NULL) &&
2509 ((pref == XML_CATA_ALLOW_ALL) ||
2510 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2511 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
2512 }
2513 if ((tmp == NULL) &&
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00002514 ((pref == XML_CATA_ALLOW_ALL) ||
2515 (pref == XML_CATA_ALLOW_GLOBAL))) {
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002516 tmp = xmlCatalogResolveURI(resource);
2517 }
2518
2519 if (tmp != NULL) {
2520 xmlFree(resource);
2521 resource = tmp;
2522 }
2523 }
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002524 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002525#endif
2526
2527 if (resource == NULL)
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002528 resource = (xmlChar *) URL;
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002529
2530 if (resource == NULL) {
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002531 if ((ctxt->validate) && (ctxt->sax != NULL) &&
2532 (ctxt->sax->error != NULL))
2533 ctxt->sax->error(ctxt,
2534 "failed to load external entity \"%s\"\n", ID);
2535 else if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00002536 ctxt->sax->warning(ctxt,
2537 "failed to load external entity \"%s\"\n", ID);
2538 return(NULL);
2539 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002540 ret = xmlNewInputFromFile(ctxt, (const char *)resource);
Owen Taylor3473f882001-02-23 17:55:21 +00002541 if (ret == NULL) {
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002542 if ((ctxt->validate) && (ctxt->sax != NULL) &&
2543 (ctxt->sax->error != NULL))
2544 ctxt->sax->error(ctxt,
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002545 "failed to load external entity \"%s\"\n", resource);
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002546 else if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00002547 ctxt->sax->warning(ctxt,
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002548 "failed to load external entity \"%s\"\n", resource);
Owen Taylor3473f882001-02-23 17:55:21 +00002549 }
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002550 if ((resource != NULL) && (resource != (xmlChar *) URL))
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002551 xmlFree(resource);
Owen Taylor3473f882001-02-23 17:55:21 +00002552 return(ret);
2553}
2554
2555static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
2556 xmlDefaultExternalEntityLoader;
2557
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002558/**
Owen Taylor3473f882001-02-23 17:55:21 +00002559 * xmlSetExternalEntityLoader:
2560 * @f: the new entity resolver function
2561 *
2562 * Changes the defaultexternal entity resolver function for the application
2563 */
2564void
2565xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
2566 xmlCurrentExternalEntityLoader = f;
2567}
2568
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002569/**
Owen Taylor3473f882001-02-23 17:55:21 +00002570 * xmlGetExternalEntityLoader:
2571 *
2572 * Get the default external entity resolver function for the application
2573 *
2574 * Returns the xmlExternalEntityLoader function pointer
2575 */
2576xmlExternalEntityLoader
2577xmlGetExternalEntityLoader(void) {
2578 return(xmlCurrentExternalEntityLoader);
2579}
2580
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002581/**
Owen Taylor3473f882001-02-23 17:55:21 +00002582 * xmlLoadExternalEntity:
2583 * @URL: the URL for the entity to load
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00002584 * @ID: the Public ID for the entity to load
Owen Taylor3473f882001-02-23 17:55:21 +00002585 * @ctxt: the context in which the entity is called or NULL
2586 *
2587 * Load an external entity, note that the use of this function for
2588 * unparsed entities may generate problems
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002589 * TODO: a more generic External entity API must be designed
Owen Taylor3473f882001-02-23 17:55:21 +00002590 *
2591 * Returns the xmlParserInputPtr or NULL
2592 */
2593xmlParserInputPtr
2594xmlLoadExternalEntity(const char *URL, const char *ID,
2595 xmlParserCtxtPtr ctxt) {
2596 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
2597}
2598
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00002599/************************************************************************
2600 * *
2601 * Disabling Network access *
2602 * *
2603 ************************************************************************/
2604
2605#ifdef LIBXML_CATALOG_ENABLED
2606static int
2607xmlNoNetExists(const char *URL)
2608{
2609#ifdef HAVE_STAT
2610 int ret;
2611 struct stat info;
2612 const char *path;
2613
2614 if (URL == NULL)
2615 return (0);
2616
2617 if (!xmlStrncmp(BAD_CAST URL, BAD_CAST "file://localhost", 16))
2618 path = &URL[16];
2619 else if (!xmlStrncmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
2620#ifdef _WIN32
2621 path = &URL[8];
2622#else
2623 path = &URL[7];
2624#endif
2625 } else
2626 path = URL;
2627 ret = stat(path, &info);
2628 if (ret == 0)
2629 return (1);
2630#endif
2631 return (0);
2632}
2633#endif
2634
2635/**
2636 * xmlNoNetExternalEntityLoader:
2637 * @URL: the URL for the entity to load
2638 * @ID: the System ID for the entity to load
2639 * @ctxt: the context in which the entity is called or NULL
2640 *
2641 * A specific entity loader disabling network accesses, though still
2642 * allowing local catalog accesses for resolution.
2643 *
2644 * Returns a new allocated xmlParserInputPtr, or NULL.
2645 */
2646xmlParserInputPtr
2647xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
2648 xmlParserCtxtPtr ctxt) {
2649 xmlParserInputPtr input = NULL;
2650 xmlChar *resource = NULL;
2651
2652#ifdef LIBXML_CATALOG_ENABLED
2653 xmlCatalogAllow pref;
2654
2655 /*
2656 * If the resource doesn't exists as a file,
2657 * try to load it from the resource pointed in the catalogs
2658 */
2659 pref = xmlCatalogGetDefaults();
2660
2661 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
2662 /*
2663 * Do a local lookup
2664 */
2665 if ((ctxt->catalogs != NULL) &&
2666 ((pref == XML_CATA_ALLOW_ALL) ||
2667 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2668 resource = xmlCatalogLocalResolve(ctxt->catalogs,
2669 (const xmlChar *)ID,
2670 (const xmlChar *)URL);
2671 }
2672 /*
2673 * Try a global lookup
2674 */
2675 if ((resource == NULL) &&
2676 ((pref == XML_CATA_ALLOW_ALL) ||
2677 (pref == XML_CATA_ALLOW_GLOBAL))) {
2678 resource = xmlCatalogResolve((const xmlChar *)ID,
2679 (const xmlChar *)URL);
2680 }
2681 if ((resource == NULL) && (URL != NULL))
2682 resource = xmlStrdup((const xmlChar *) URL);
2683
2684 /*
2685 * TODO: do an URI lookup on the reference
2686 */
2687 if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
2688 xmlChar *tmp = NULL;
2689
2690 if ((ctxt->catalogs != NULL) &&
2691 ((pref == XML_CATA_ALLOW_ALL) ||
2692 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2693 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
2694 }
2695 if ((tmp == NULL) &&
2696 ((pref == XML_CATA_ALLOW_ALL) ||
2697 (pref == XML_CATA_ALLOW_GLOBAL))) {
2698 tmp = xmlCatalogResolveURI(resource);
2699 }
2700
2701 if (tmp != NULL) {
2702 xmlFree(resource);
2703 resource = tmp;
2704 }
2705 }
2706 }
2707#endif
2708 if (resource == NULL)
2709 resource = (xmlChar *) URL;
2710
2711 if (resource != NULL) {
2712 if ((!xmlStrncasecmp((const xmlChar *) resource,
2713 (const xmlChar *) "ftp://", 6)) ||
2714 (!xmlStrncasecmp((const xmlChar *) resource,
2715 (const xmlChar *) "http://", 7))) {
2716 xmlGenericError(xmlGenericErrorContext,
2717 "Attempt to load network entity %s \n", resource);
2718
2719 if (resource != (xmlChar *) URL)
2720 xmlFree(resource);
2721 return(NULL);
2722 }
2723 }
2724 input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
2725 if (resource != (xmlChar *) URL)
2726 xmlFree(resource);
2727 return(input);
2728}
2729