blob: 7c5706e5990b859079bf3327d5df8fb077261918 [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
Daniel Veillard34ce8be2002-03-18 19:37:11 +000011#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000012#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000013
Owen Taylor3473f882001-02-23 17:55:21 +000014#include <string.h>
15#include <errno.h>
16
17#ifdef HAVE_SYS_TYPES_H
18#include <sys/types.h>
19#endif
20#ifdef HAVE_SYS_STAT_H
21#include <sys/stat.h>
22#endif
23#ifdef HAVE_FCNTL_H
24#include <fcntl.h>
25#endif
26#ifdef HAVE_UNISTD_H
27#include <unistd.h>
28#endif
29#ifdef HAVE_STDLIB_H
30#include <stdlib.h>
31#endif
32#ifdef HAVE_ZLIB_H
33#include <zlib.h>
34#endif
35
36/* Figure a portable way to know if a file is a directory. */
37#ifndef HAVE_STAT
38# ifdef HAVE__STAT
Daniel Veillard50f34372001-08-03 12:06:36 +000039 /* MS C library seems to define stat and _stat. The definition
40 is identical. Still, mapping them to each other causes a warning. */
41# ifndef _MSC_VER
42# define stat(x,y) _stat(x,y)
43# endif
Owen Taylor3473f882001-02-23 17:55:21 +000044# define HAVE_STAT
45# endif
46#endif
47#ifdef HAVE_STAT
48# ifndef S_ISDIR
49# ifdef _S_ISDIR
50# define S_ISDIR(x) _S_ISDIR(x)
51# else
52# ifdef S_IFDIR
53# ifndef S_IFMT
54# ifdef _S_IFMT
55# define S_IFMT _S_IFMT
56# endif
57# endif
58# ifdef S_IFMT
59# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
60# endif
61# endif
62# endif
63# endif
64#endif
65
66#include <libxml/xmlmemory.h>
67#include <libxml/parser.h>
68#include <libxml/parserInternals.h>
69#include <libxml/xmlIO.h>
Daniel Veillard388236f2001-07-08 18:35:48 +000070#include <libxml/uri.h>
Owen Taylor3473f882001-02-23 17:55:21 +000071#include <libxml/nanohttp.h>
72#include <libxml/nanoftp.h>
73#include <libxml/xmlerror.h>
Daniel Veillard7d6fd212001-05-10 15:34:11 +000074#ifdef LIBXML_CATALOG_ENABLED
75#include <libxml/catalog.h>
76#endif
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000077#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000078
79#ifdef VMS
80#define xmlRegisterDefaultInputCallbacks xmlRegisterDefInputCallbacks
81#define xmlRegisterDefaultOutputCallbacks xmlRegisterDefOutputCallbacks
82#endif
83
Daniel Veillardf012a642001-07-23 19:10:52 +000084/* #define VERBOSE_FAILURE */
Daniel Veillard1fd36d22001-07-04 22:54:28 +000085/* #define DEBUG_EXTERNAL_ENTITIES */
Owen Taylor3473f882001-02-23 17:55:21 +000086/* #define DEBUG_INPUT */
87
88#ifdef DEBUG_INPUT
89#define MINLEN 40
90#else
91#define MINLEN 4000
92#endif
93
94/*
95 * Input I/O callback sets
96 */
97typedef struct _xmlInputCallback {
98 xmlInputMatchCallback matchcallback;
99 xmlInputOpenCallback opencallback;
100 xmlInputReadCallback readcallback;
101 xmlInputCloseCallback closecallback;
102} xmlInputCallback;
103
104#define MAX_INPUT_CALLBACK 15
105
Daniel Veillard22090732001-07-16 00:06:07 +0000106static xmlInputCallback xmlInputCallbackTable[MAX_INPUT_CALLBACK];
107static int xmlInputCallbackNr = 0;
108static int xmlInputCallbackInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000109
110/*
111 * Output I/O callback sets
112 */
113typedef struct _xmlOutputCallback {
114 xmlOutputMatchCallback matchcallback;
115 xmlOutputOpenCallback opencallback;
116 xmlOutputWriteCallback writecallback;
117 xmlOutputCloseCallback closecallback;
118} xmlOutputCallback;
119
120#define MAX_OUTPUT_CALLBACK 15
121
Daniel Veillard22090732001-07-16 00:06:07 +0000122static xmlOutputCallback xmlOutputCallbackTable[MAX_OUTPUT_CALLBACK];
123static int xmlOutputCallbackNr = 0;
124static int xmlOutputCallbackInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000125
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000126/**
127 * xmlCleanupInputCallbacks:
128 *
129 * clears the entire input callback table. this includes the
130 * compiled-in I/O.
131 */
132void
133xmlCleanupInputCallbacks(void)
134{
135 int i;
136
137 if (!xmlInputCallbackInitialized)
138 return;
139
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000140 for (i = xmlInputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000141 xmlInputCallbackTable[i].matchcallback = NULL;
142 xmlInputCallbackTable[i].opencallback = NULL;
143 xmlInputCallbackTable[i].readcallback = NULL;
144 xmlInputCallbackTable[i].closecallback = NULL;
145 }
146
147 xmlInputCallbackNr = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000148}
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;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000172}
173
Owen Taylor3473f882001-02-23 17:55:21 +0000174/************************************************************************
175 * *
176 * Standard I/O for file accesses *
177 * *
178 ************************************************************************/
179
180/**
181 * xmlCheckFilename
182 * @path: the path to check
183 *
184 * function checks to see if @path is a valid source
185 * (file, socket...) for XML.
186 *
187 * if stat is not available on the target machine,
188 * returns 1. if stat fails, returns 0 (if calling
189 * stat on the filename fails, it can't be right).
190 * if stat succeeds and the file is a directory,
191 * sets errno to EISDIR and returns 0. otherwise
192 * returns 1.
193 */
194
195static int
196xmlCheckFilename (const char *path)
197{
198#ifdef HAVE_STAT
199#ifdef S_ISDIR
200 struct stat stat_buffer;
201
202 if (stat(path, &stat_buffer) == -1)
203 return 0;
204
205 if (S_ISDIR(stat_buffer.st_mode)) {
206 errno = EISDIR;
207 return 0;
208 }
209
210#endif
211#endif
212 return 1;
213}
214
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000215static int
Owen Taylor3473f882001-02-23 17:55:21 +0000216xmlNop(void) {
217 return(0);
218}
219
220/**
Owen Taylor3473f882001-02-23 17:55:21 +0000221 * xmlFdRead:
222 * @context: the I/O context
223 * @buffer: where to drop data
224 * @len: number of bytes to read
225 *
226 * Read @len bytes to @buffer from the I/O channel.
227 *
228 * Returns the number of bytes written
229 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000230static int
Owen Taylor3473f882001-02-23 17:55:21 +0000231xmlFdRead (void * context, char * buffer, int len) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +0000232 return(read((int) (long) context, &buffer[0], len));
Owen Taylor3473f882001-02-23 17:55:21 +0000233}
234
235/**
236 * xmlFdWrite:
237 * @context: the I/O context
238 * @buffer: where to get data
239 * @len: number of bytes to write
240 *
241 * Write @len bytes from @buffer to the I/O channel.
242 *
243 * Returns the number of bytes written
244 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000245static int
Owen Taylor3473f882001-02-23 17:55:21 +0000246xmlFdWrite (void * context, const char * buffer, int len) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +0000247 return(write((int) (long) context, &buffer[0], len));
Owen Taylor3473f882001-02-23 17:55:21 +0000248}
249
250/**
251 * xmlFdClose:
252 * @context: the I/O context
253 *
254 * Close an I/O channel
Daniel Veillardf012a642001-07-23 19:10:52 +0000255 *
256 * Returns 0 in case of success and error code otherwise
Owen Taylor3473f882001-02-23 17:55:21 +0000257 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000258static int
Owen Taylor3473f882001-02-23 17:55:21 +0000259xmlFdClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +0000260 return ( close((int) (long) context) );
Owen Taylor3473f882001-02-23 17:55:21 +0000261}
262
263/**
264 * xmlFileMatch:
265 * @filename: the URI for matching
266 *
267 * input from FILE *
268 *
269 * Returns 1 if matches, 0 otherwise
270 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000271int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000272xmlFileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000273 return(1);
274}
275
276/**
277 * xmlFileOpen:
278 * @filename: the URI for matching
279 *
280 * input from FILE *, supports compressed input
281 * if @filename is " " then the standard input is used
282 *
283 * Returns an I/O context or NULL in case of error
284 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000285void *
Owen Taylor3473f882001-02-23 17:55:21 +0000286xmlFileOpen (const char *filename) {
287 const char *path = NULL;
288 FILE *fd;
289
290 if (!strcmp(filename, "-")) {
291 fd = stdin;
292 return((void *) fd);
293 }
294
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000295 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost", 16))
Owen Taylor3473f882001-02-23 17:55:21 +0000296 path = &filename[16];
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000297 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard3c5ed912002-01-08 10:36:16 +0000298#if defined (_WIN32) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000299 path = &filename[8];
300#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000301 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000302#endif
303 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000304 path = filename;
305
306 if (path == NULL)
307 return(NULL);
308 if (!xmlCheckFilename(path))
309 return(NULL);
310
Daniel Veillard3c5ed912002-01-08 10:36:16 +0000311#if defined(WIN32) || defined (__CYGWIN__)
Owen Taylor3473f882001-02-23 17:55:21 +0000312 fd = fopen(path, "rb");
313#else
314 fd = fopen(path, "r");
315#endif /* WIN32 */
316 return((void *) fd);
317}
318
319/**
320 * xmlFileOpenW:
321 * @filename: the URI for matching
322 *
323 * output to from FILE *,
324 * if @filename is "-" then the standard output is used
325 *
326 * Returns an I/O context or NULL in case of error
327 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000328static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000329xmlFileOpenW (const char *filename) {
330 const char *path = NULL;
331 FILE *fd;
332
333 if (!strcmp(filename, "-")) {
334 fd = stdout;
335 return((void *) fd);
336 }
337
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000338 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost", 16))
Owen Taylor3473f882001-02-23 17:55:21 +0000339 path = &filename[16];
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000340 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard3c5ed912002-01-08 10:36:16 +0000341#if defined (_WIN32) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000342 path = &filename[8];
343#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000344 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000345#endif
346 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000347 path = filename;
348
349 if (path == NULL)
350 return(NULL);
351
352 fd = fopen(path, "w");
353 return((void *) fd);
354}
355
356/**
357 * xmlFileRead:
358 * @context: the I/O context
359 * @buffer: where to drop data
360 * @len: number of bytes to write
361 *
362 * Read @len bytes to @buffer from the I/O channel.
363 *
364 * Returns the number of bytes written
365 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000366int
Owen Taylor3473f882001-02-23 17:55:21 +0000367xmlFileRead (void * context, char * buffer, int len) {
368 return(fread(&buffer[0], 1, len, (FILE *) context));
369}
370
371/**
372 * xmlFileWrite:
373 * @context: the I/O context
374 * @buffer: where to drop data
375 * @len: number of bytes to write
376 *
377 * Write @len bytes from @buffer to the I/O channel.
378 *
379 * Returns the number of bytes written
380 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000381static int
Owen Taylor3473f882001-02-23 17:55:21 +0000382xmlFileWrite (void * context, const char * buffer, int len) {
383 return(fwrite(&buffer[0], 1, len, (FILE *) context));
384}
385
386/**
387 * xmlFileClose:
388 * @context: the I/O context
389 *
390 * Close an I/O channel
391 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000392int
Owen Taylor3473f882001-02-23 17:55:21 +0000393xmlFileClose (void * context) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000394 FILE *fil;
395
396 fil = (FILE *) context;
397 if (fil == stdin)
398 return(0);
399 if (fil == stdout)
400 return(0);
Daniel Veillardcd337f02001-11-22 18:20:37 +0000401 if (fil == stderr)
402 return(0);
Daniel Veillardf012a642001-07-23 19:10:52 +0000403 return ( ( fclose((FILE *) context) == EOF ) ? -1 : 0 );
Owen Taylor3473f882001-02-23 17:55:21 +0000404}
405
406/**
407 * xmlFileFlush:
408 * @context: the I/O context
409 *
410 * Flush an I/O channel
411 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000412static int
Owen Taylor3473f882001-02-23 17:55:21 +0000413xmlFileFlush (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +0000414 return ( ( fflush((FILE *) context) == EOF ) ? -1 : 0 );
Owen Taylor3473f882001-02-23 17:55:21 +0000415}
416
417#ifdef HAVE_ZLIB_H
418/************************************************************************
419 * *
420 * I/O for compressed file accesses *
421 * *
422 ************************************************************************/
423/**
424 * xmlGzfileMatch:
425 * @filename: the URI for matching
426 *
427 * input from compressed file test
428 *
429 * Returns 1 if matches, 0 otherwise
430 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000431static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000432xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000433 return(1);
434}
435
436/**
437 * xmlGzfileOpen:
438 * @filename: the URI for matching
439 *
440 * input from compressed file open
441 * if @filename is " " then the standard input is used
442 *
443 * Returns an I/O context or NULL in case of error
444 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000445static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000446xmlGzfileOpen (const char *filename) {
447 const char *path = NULL;
448 gzFile fd;
449
450 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000451 fd = gzdopen(dup(0), "rb");
Owen Taylor3473f882001-02-23 17:55:21 +0000452 return((void *) fd);
453 }
454
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000455 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost", 16))
Owen Taylor3473f882001-02-23 17:55:21 +0000456 path = &filename[16];
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000457 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard3c5ed912002-01-08 10:36:16 +0000458#if defined (_WIN32) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000459 path = &filename[8];
460#else
Owen Taylor3473f882001-02-23 17:55:21 +0000461 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000462#endif
463 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000464 path = filename;
465
466 if (path == NULL)
467 return(NULL);
468 if (!xmlCheckFilename(path))
469 return(NULL);
470
471 fd = gzopen(path, "rb");
472 return((void *) fd);
473}
474
475/**
476 * xmlGzfileOpenW:
477 * @filename: the URI for matching
478 * @compression: the compression factor (0 - 9 included)
479 *
480 * input from compressed file open
481 * if @filename is " " then the standard input is used
482 *
483 * Returns an I/O context or NULL in case of error
484 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000485static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000486xmlGzfileOpenW (const char *filename, int compression) {
487 const char *path = NULL;
488 char mode[15];
489 gzFile fd;
490
491 sprintf(mode, "wb%d", compression);
492 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000493 fd = gzdopen(dup(1), mode);
Owen Taylor3473f882001-02-23 17:55:21 +0000494 return((void *) fd);
495 }
496
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000497 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost", 16))
Owen Taylor3473f882001-02-23 17:55:21 +0000498 path = &filename[16];
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000499 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard3c5ed912002-01-08 10:36:16 +0000500#if defined (_WIN32) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000501 path = &filename[8];
502#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000503 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000504#endif
505 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000506 path = filename;
507
508 if (path == NULL)
509 return(NULL);
510
511 fd = gzopen(path, mode);
512 return((void *) fd);
513}
514
515/**
516 * xmlGzfileRead:
517 * @context: the I/O context
518 * @buffer: where to drop data
519 * @len: number of bytes to write
520 *
521 * Read @len bytes to @buffer from the compressed I/O channel.
522 *
523 * Returns the number of bytes written
524 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000525static int
Owen Taylor3473f882001-02-23 17:55:21 +0000526xmlGzfileRead (void * context, char * buffer, int len) {
527 return(gzread((gzFile) context, &buffer[0], len));
528}
529
530/**
531 * xmlGzfileWrite:
532 * @context: the I/O context
533 * @buffer: where to drop data
534 * @len: number of bytes to write
535 *
536 * Write @len bytes from @buffer to the compressed I/O channel.
537 *
538 * Returns the number of bytes written
539 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000540static int
Owen Taylor3473f882001-02-23 17:55:21 +0000541xmlGzfileWrite (void * context, const char * buffer, int len) {
542 return(gzwrite((gzFile) context, (char *) &buffer[0], len));
543}
544
545/**
546 * xmlGzfileClose:
547 * @context: the I/O context
548 *
549 * Close a compressed I/O channel
550 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000551static int
Owen Taylor3473f882001-02-23 17:55:21 +0000552xmlGzfileClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +0000553 return ( ( gzclose((gzFile) context) == Z_OK ) ? 0 : -1 );
Owen Taylor3473f882001-02-23 17:55:21 +0000554}
555#endif /* HAVE_ZLIB_H */
556
557#ifdef LIBXML_HTTP_ENABLED
558/************************************************************************
559 * *
560 * I/O for HTTP file accesses *
561 * *
562 ************************************************************************/
Daniel Veillardf012a642001-07-23 19:10:52 +0000563
564typedef struct xmlIOHTTPWriteCtxt_
565{
566 int compression;
567
568 char * uri;
569
570 void * doc_buff;
571
572} xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr;
573
574#ifdef HAVE_ZLIB_H
575
576#define DFLT_WBITS ( -15 )
577#define DFLT_MEM_LVL ( 8 )
578#define GZ_MAGIC1 ( 0x1f )
579#define GZ_MAGIC2 ( 0x8b )
580#define LXML_ZLIB_OS_CODE ( 0x03 )
581#define INIT_HTTP_BUFF_SIZE ( 32768 )
582#define DFLT_ZLIB_RATIO ( 5 )
583
584/*
585** Data structure and functions to work with sending compressed data
586** via HTTP.
587*/
588
589typedef struct xmlZMemBuff_
590{
591 unsigned long size;
592 unsigned long crc;
593
594 unsigned char * zbuff;
595 z_stream zctrl;
596
597} xmlZMemBuff, *xmlZMemBuffPtr;
598
599/**
600 * append_reverse_ulong
601 * @buff: Compressed memory buffer
602 * @data: Unsigned long to append
603 *
604 * Append a unsigned long in reverse byte order to the end of the
605 * memory buffer.
606 */
607static void
608append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) {
609
610 int idx;
611
612 if ( buff == NULL )
613 return;
614
615 /*
616 ** This is plagiarized from putLong in gzio.c (zlib source) where
617 ** the number "4" is hardcoded. If zlib is ever patched to
618 ** support 64 bit file sizes, this code would need to be patched
619 ** as well.
620 */
621
622 for ( idx = 0; idx < 4; idx++ ) {
623 *buff->zctrl.next_out = ( data & 0xff );
624 data >>= 8;
625 buff->zctrl.next_out++;
626 }
627
628 return;
629}
630
631/**
632 *
633 * xmlFreeZMemBuff
634 * @buff: The memory buffer context to clear
635 *
636 * Release all the resources associated with the compressed memory buffer.
637 */
638static void
639xmlFreeZMemBuff( xmlZMemBuffPtr buff ) {
640
641 int z_err;
642
643 if ( buff == NULL )
644 return;
645
646 xmlFree( buff->zbuff );
647 z_err = deflateEnd( &buff->zctrl );
648#ifdef DEBUG_HTTP
649 if ( z_err != Z_OK )
650 xmlGenericError( xmlGenericErrorContext,
651 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
652 z_err );
653#endif
654
655 xmlFree( buff );
656 return;
657}
658
659/**
660 * xmlCreateZMemBuff
661 *@compression: Compression value to use
662 *
663 * Create a memory buffer to hold the compressed XML document. The
664 * compressed document in memory will end up being identical to what
665 * would be created if gzopen/gzwrite/gzclose were being used to
666 * write the document to disk. The code for the header/trailer data to
667 * the compression is plagiarized from the zlib source files.
668 */
669static void *
670xmlCreateZMemBuff( int compression ) {
671
672 int z_err;
673 int hdr_lgth;
674 xmlZMemBuffPtr buff = NULL;
675
676 if ( ( compression < 1 ) || ( compression > 9 ) )
677 return ( NULL );
678
679 /* Create the control and data areas */
680
681 buff = xmlMalloc( sizeof( xmlZMemBuff ) );
682 if ( buff == NULL ) {
683 xmlGenericError( xmlGenericErrorContext,
684 "xmlCreateZMemBuff: %s\n",
685 "Failure allocating buffer context." );
686 return ( NULL );
687 }
688
689 (void)memset( buff, 0, sizeof( xmlZMemBuff ) );
690 buff->size = INIT_HTTP_BUFF_SIZE;
691 buff->zbuff = xmlMalloc( buff->size );
692 if ( buff->zbuff == NULL ) {
693 xmlFreeZMemBuff( buff );
694 xmlGenericError( xmlGenericErrorContext,
695 "xmlCreateZMemBuff: %s\n",
696 "Failure allocating data buffer." );
697 return ( NULL );
698 }
699
700 z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
701 DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
702 if ( z_err != Z_OK ) {
703 xmlFreeZMemBuff( buff );
704 buff = NULL;
705 xmlGenericError( xmlGenericErrorContext,
706 "xmlCreateZMemBuff: %s %d\n",
707 "Error initializing compression context. ZLIB error:",
708 z_err );
709 return ( NULL );
710 }
711
712 /* Set the header data. The CRC will be needed for the trailer */
713
714 buff->crc = crc32( 0L, Z_NULL, 0 );
715 hdr_lgth = sprintf( (char *)buff->zbuff, "%c%c%c%c%c%c%c%c%c%c",
716 GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED,
717 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE );
718 buff->zctrl.next_out = buff->zbuff + hdr_lgth;
719 buff->zctrl.avail_out = buff->size - hdr_lgth;
720
721 return ( buff );
722}
723
724/**
725 * xmlZMemBuffExtend
726 * @buff: Buffer used to compress and consolidate data.
727 * @ext_amt: Number of bytes to extend the buffer.
728 *
729 * Extend the internal buffer used to store the compressed data by the
730 * specified amount.
731 *
732 * Returns 0 on success or -1 on failure to extend the buffer. On failure
733 * the original buffer still exists at the original size.
734 */
735static int
736xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) {
737
738 int rc = -1;
739 size_t new_size;
740 size_t cur_used;
741
742 unsigned char * tmp_ptr = NULL;
743
744 if ( buff == NULL )
745 return ( -1 );
746
747 else if ( ext_amt == 0 )
748 return ( 0 );
749
750 cur_used = buff->zctrl.next_out - buff->zbuff;
751 new_size = buff->size + ext_amt;
752
753#ifdef DEBUG_HTTP
754 if ( cur_used > new_size )
755 xmlGenericError( xmlGenericErrorContext,
756 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
757 "Buffer overwrite detected during compressed memory",
758 "buffer extension. Overflowed by",
759 (cur_used - new_size ) );
760#endif
761
762 tmp_ptr = xmlRealloc( buff->zbuff, new_size );
763 if ( tmp_ptr != NULL ) {
764 rc = 0;
765 buff->size = new_size;
766 buff->zbuff = tmp_ptr;
767 buff->zctrl.next_out = tmp_ptr + cur_used;
768 buff->zctrl.avail_out = new_size - cur_used;
769 }
770 else {
771 xmlGenericError( xmlGenericErrorContext,
772 "xmlZMemBuffExtend: %s %lu bytes.\n",
773 "Allocation failure extending output buffer to",
774 new_size );
775 }
776
777 return ( rc );
778}
779
780/**
781 * xmlZMemBuffAppend
782 * @buff: Buffer used to compress and consolidate data
783 * @src: Uncompressed source content to append to buffer
784 * @len: Length of source data to append to buffer
785 *
786 * Compress and append data to the internal buffer. The data buffer
787 * will be expanded if needed to store the additional data.
788 *
789 * Returns the number of bytes appended to the buffer or -1 on error.
790 */
791static int
792xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) {
793
794 int z_err;
795 size_t min_accept;
796
797 if ( ( buff == NULL ) || ( src == NULL ) )
798 return ( -1 );
799
800 buff->zctrl.avail_in = len;
801 buff->zctrl.next_in = (unsigned char *)src;
802 while ( buff->zctrl.avail_in > 0 ) {
803 /*
804 ** Extend the buffer prior to deflate call if a reasonable amount
805 ** of output buffer space is not available.
806 */
807 min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO;
808 if ( buff->zctrl.avail_out <= min_accept ) {
809 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
810 return ( -1 );
811 }
812
813 z_err = deflate( &buff->zctrl, Z_NO_FLUSH );
814 if ( z_err != Z_OK ) {
815 xmlGenericError( xmlGenericErrorContext,
816 "xmlZMemBuffAppend: %s %d %s - %d",
817 "Compression error while appending",
818 len, "bytes to buffer. ZLIB error", z_err );
819 return ( -1 );
820 }
821 }
822
823 buff->crc = crc32( buff->crc, (unsigned char *)src, len );
824
825 return ( len );
826}
827
828/**
829 * xmlZMemBuffGetContent
830 * @buff: Compressed memory content buffer
831 * @data_ref: Pointer reference to point to compressed content
832 *
833 * Flushes the compression buffers, appends gzip file trailers and
834 * returns the compressed content and length of the compressed data.
835 * NOTE: The gzip trailer code here is plagiarized from zlib source.
836 *
837 * Returns the length of the compressed data or -1 on error.
838 */
839static int
840xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) {
841
842 int zlgth = -1;
843 int z_err;
844
845 if ( ( buff == NULL ) || ( data_ref == NULL ) )
846 return ( -1 );
847
848 /* Need to loop until compression output buffers are flushed */
849
850 do
851 {
852 z_err = deflate( &buff->zctrl, Z_FINISH );
853 if ( z_err == Z_OK ) {
854 /* In this case Z_OK means more buffer space needed */
855
856 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
857 return ( -1 );
858 }
859 }
860 while ( z_err == Z_OK );
861
862 /* If the compression state is not Z_STREAM_END, some error occurred */
863
864 if ( z_err == Z_STREAM_END ) {
865
866 /* Need to append the gzip data trailer */
867
868 if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) {
869 if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 )
870 return ( -1 );
871 }
872
873 /*
874 ** For whatever reason, the CRC and length data are pushed out
875 ** in reverse byte order. So a memcpy can't be used here.
876 */
877
878 append_reverse_ulong( buff, buff->crc );
879 append_reverse_ulong( buff, buff->zctrl.total_in );
880
881 zlgth = buff->zctrl.next_out - buff->zbuff;
882 *data_ref = (char *)buff->zbuff;
883 }
884
885 else
886 xmlGenericError( xmlGenericErrorContext,
887 "xmlZMemBuffGetContent: %s - %d\n",
888 "Error flushing zlib buffers. Error code", z_err );
889
890 return ( zlgth );
891}
892#endif /* HAVE_ZLIB_H */
893
894/**
895 * xmlFreeHTTPWriteCtxt
896 * @ctxt: Context to cleanup
897 *
898 * Free allocated memory and reclaim system resources.
899 *
900 * No return value.
901 */
902static void
903xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt )
904{
905 if ( ctxt->uri != NULL )
906 free( ctxt->uri );
907
908 if ( ctxt->doc_buff != NULL ) {
909
910#ifdef HAVE_ZLIB_H
911 if ( ctxt->compression > 0 ) {
912 xmlFreeZMemBuff( ctxt->doc_buff );
913 }
914 else
915#endif
916 {
917 xmlOutputBufferClose( ctxt->doc_buff );
918 }
919 }
920
921 free( ctxt );
922 return;
923}
924
925
Owen Taylor3473f882001-02-23 17:55:21 +0000926/**
927 * xmlIOHTTPMatch:
928 * @filename: the URI for matching
929 *
930 * check if the URI matches an HTTP one
931 *
932 * Returns 1 if matches, 0 otherwise
933 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000934int
Owen Taylor3473f882001-02-23 17:55:21 +0000935xmlIOHTTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000936 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "http://", 7))
Owen Taylor3473f882001-02-23 17:55:21 +0000937 return(1);
938 return(0);
939}
940
941/**
942 * xmlIOHTTPOpen:
943 * @filename: the URI for matching
944 *
945 * open an HTTP I/O channel
946 *
947 * Returns an I/O context or NULL in case of error
948 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000949void *
Owen Taylor3473f882001-02-23 17:55:21 +0000950xmlIOHTTPOpen (const char *filename) {
951 return(xmlNanoHTTPOpen(filename, NULL));
952}
953
954/**
Daniel Veillardf012a642001-07-23 19:10:52 +0000955 * xmlIOHTTPOpenW
956 * @post_uri: The destination URI for the document
957 * @compression: The compression desired for the document.
958 *
959 * Open a temporary buffer to collect the document for a subsequent HTTP POST
960 * request. Non-static as is called from the output buffer creation routine.
961 *
962 * Returns an I/O context or NULL in case of error.
963 */
964
965void *
Daniel Veillard572577e2002-01-18 16:23:55 +0000966xmlIOHTTPOpenW(const char *post_uri, int compression)
967{
Daniel Veillardf012a642001-07-23 19:10:52 +0000968
Daniel Veillard572577e2002-01-18 16:23:55 +0000969 xmlIOHTTPWriteCtxtPtr ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +0000970
Daniel Veillard572577e2002-01-18 16:23:55 +0000971 if (post_uri == NULL)
972 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +0000973
Daniel Veillard572577e2002-01-18 16:23:55 +0000974 ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt));
975 if (ctxt == NULL) {
976 xmlGenericError(xmlGenericErrorContext,
977 "xmlIOHTTPOpenW: Failed to create output HTTP context.\n");
978 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +0000979 }
980
Daniel Veillard572577e2002-01-18 16:23:55 +0000981 (void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt));
Daniel Veillardf012a642001-07-23 19:10:52 +0000982
Daniel Veillard572577e2002-01-18 16:23:55 +0000983 ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri);
984 if (ctxt->uri == NULL) {
985 xmlGenericError(xmlGenericErrorContext,
986 "xmlIOHTTPOpenW: Failed to duplicate destination URI.\n");
987 xmlFreeHTTPWriteCtxt(ctxt);
988 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +0000989 }
990
991 /*
Daniel Veillard572577e2002-01-18 16:23:55 +0000992 * ** 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 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000996
997#ifdef HAVE_ZLIB_H
Daniel Veillard572577e2002-01-18 16:23:55 +0000998 if ((compression > 0) && (compression <= 9)) {
999
1000 ctxt->compression = compression;
1001 ctxt->doc_buff = xmlCreateZMemBuff(compression);
1002 } else
Daniel Veillardf012a642001-07-23 19:10:52 +00001003#endif
1004 {
Daniel Veillard572577e2002-01-18 16:23:55 +00001005 /* Any character conversions should have been done before this */
Daniel Veillardf012a642001-07-23 19:10:52 +00001006
Daniel Veillard572577e2002-01-18 16:23:55 +00001007 ctxt->doc_buff = xmlAllocOutputBuffer(NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001008 }
1009
Daniel Veillard572577e2002-01-18 16:23:55 +00001010 if (ctxt->doc_buff == NULL) {
1011 xmlFreeHTTPWriteCtxt(ctxt);
1012 ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001013 }
1014
Daniel Veillard572577e2002-01-18 16:23:55 +00001015 return (ctxt);
Daniel Veillardf012a642001-07-23 19:10:52 +00001016}
1017
1018/**
1019 * xmlIOHTTPDfltOpenW
1020 * @post_uri: The destination URI for this document.
1021 *
1022 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
1023 * HTTP post command. This function should generally not be used as
1024 * the open callback is short circuited in xmlOutputBufferCreateFile.
1025 *
1026 * Returns a pointer to the new IO context.
1027 */
1028static void *
1029xmlIOHTTPDfltOpenW( const char * post_uri ) {
1030 return ( xmlIOHTTPOpenW( post_uri, 0 ) );
1031}
1032
1033/**
Owen Taylor3473f882001-02-23 17:55:21 +00001034 * xmlIOHTTPRead:
1035 * @context: the I/O context
1036 * @buffer: where to drop data
1037 * @len: number of bytes to write
1038 *
1039 * Read @len bytes to @buffer from the I/O channel.
1040 *
1041 * Returns the number of bytes written
1042 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001043int
Owen Taylor3473f882001-02-23 17:55:21 +00001044xmlIOHTTPRead(void * context, char * buffer, int len) {
1045 return(xmlNanoHTTPRead(context, &buffer[0], len));
1046}
1047
1048/**
Daniel Veillardf012a642001-07-23 19:10:52 +00001049 * xmlIOHTTPWrite
1050 * @context: previously opened writing context
1051 * @buffer: data to output to temporary buffer
1052 * @len: bytes to output
1053 *
1054 * Collect data from memory buffer into a temporary file for later
1055 * processing.
1056 *
1057 * Returns number of bytes written.
1058 */
1059
1060static int
1061xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
1062
1063 xmlIOHTTPWriteCtxtPtr ctxt = context;
1064
1065 if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
1066 return ( -1 );
1067
1068 if ( len > 0 ) {
1069
1070 /* Use gzwrite or fwrite as previously setup in the open call */
1071
1072#ifdef HAVE_ZLIB_H
1073 if ( ctxt->compression > 0 )
1074 len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len );
1075
1076 else
1077#endif
1078 len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
1079
1080 if ( len < 0 ) {
1081 xmlGenericError( xmlGenericErrorContext,
1082 "xmlIOHTTPWrite: %s\n%s '%s'.\n",
1083 "Error appending to internal buffer.",
1084 "Error sending document to URI",
1085 ctxt->uri );
1086 }
1087 }
1088
1089 return ( len );
1090}
1091
1092
1093/**
Owen Taylor3473f882001-02-23 17:55:21 +00001094 * xmlIOHTTPClose:
1095 * @context: the I/O context
1096 *
1097 * Close an HTTP I/O channel
1098 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001099int
Owen Taylor3473f882001-02-23 17:55:21 +00001100xmlIOHTTPClose (void * context) {
1101 xmlNanoHTTPClose(context);
Daniel Veillardf012a642001-07-23 19:10:52 +00001102 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001103}
Daniel Veillardf012a642001-07-23 19:10:52 +00001104
1105/**
1106 * xmlIOHTTCloseWrite
1107 * @context: The I/O context
1108 * @http_mthd: The HTTP method to be used when sending the data
1109 *
1110 * Close the transmit HTTP I/O channel and actually send the data.
1111 */
1112static int
1113xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
1114
1115 int close_rc = -1;
1116 int http_rtn = 0;
1117 int content_lgth = 0;
1118 xmlIOHTTPWriteCtxtPtr ctxt = context;
1119
1120 char * http_content = NULL;
1121 char * content_encoding = NULL;
1122 char * content_type = (char *) "text/xml";
1123 void * http_ctxt = NULL;
1124
1125 if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
1126 return ( -1 );
1127
1128 /* Retrieve the content from the appropriate buffer */
1129
1130#ifdef HAVE_ZLIB_H
1131
1132 if ( ctxt->compression > 0 ) {
1133 content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
1134 content_encoding = (char *) "Content-Encoding: gzip";
1135 }
1136 else
1137#endif
1138 {
1139 /* Pull the data out of the memory output buffer */
1140
1141 xmlOutputBufferPtr dctxt = ctxt->doc_buff;
1142 http_content = (char *)dctxt->buffer->content;
1143 content_lgth = dctxt->buffer->use;
1144 }
1145
1146 if ( http_content == NULL ) {
1147 xmlGenericError( xmlGenericErrorContext,
1148 "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
1149 "Error retrieving content.\nUnable to",
1150 http_mthd, "data to URI", ctxt->uri );
1151 }
1152
1153 else {
1154
1155 http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
1156 &content_type, content_encoding,
1157 content_lgth );
1158
1159 if ( http_ctxt != NULL ) {
1160#ifdef DEBUG_HTTP
1161 /* If testing/debugging - dump reply with request content */
1162
1163 FILE * tst_file = NULL;
1164 char buffer[ 4096 ];
1165 char * dump_name = NULL;
1166 int avail;
1167
1168 xmlGenericError( xmlGenericErrorContext,
1169 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
1170 http_mthd, ctxt->uri,
1171 xmlNanoHTTPReturnCode( http_ctxt ) );
1172
1173 /*
1174 ** Since either content or reply may be gzipped,
1175 ** dump them to separate files instead of the
1176 ** standard error context.
1177 */
1178
1179 dump_name = tempnam( NULL, "lxml" );
1180 if ( dump_name != NULL ) {
1181 (void)sprintf( buffer, "%s.content", dump_name );
1182
1183 tst_file = fopen( buffer, "w" );
1184 if ( tst_file != NULL ) {
1185 xmlGenericError( xmlGenericErrorContext,
1186 "Transmitted content saved in file: %s\n", buffer );
1187
1188 fwrite( http_content, sizeof( char ),
1189 content_lgth, tst_file );
1190 fclose( tst_file );
1191 }
1192
1193 (void)sprintf( buffer, "%s.reply", dump_name );
1194 tst_file = fopen( buffer, "w" );
1195 if ( tst_file != NULL ) {
1196 xmlGenericError( xmlGenericErrorContext,
1197 "Reply content saved in file: %s\n", buffer );
1198
1199
1200 while ( (avail = xmlNanoHTTPRead( http_ctxt,
1201 buffer, sizeof( buffer ) )) > 0 ) {
1202
1203 fwrite( buffer, sizeof( char ), avail, tst_file );
1204 }
1205
1206 fclose( tst_file );
1207 }
1208
1209 free( dump_name );
1210 }
1211#endif /* DEBUG_HTTP */
1212
1213 http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
1214 if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
1215 close_rc = 0;
1216 else
1217 xmlGenericError( xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001218 "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001219 http_mthd, content_lgth,
1220 "bytes to URI", ctxt->uri,
1221 "failed. HTTP return code:", http_rtn );
1222
1223 xmlNanoHTTPClose( http_ctxt );
1224 xmlFree( content_type );
1225 }
1226 }
1227
1228 /* Final cleanups */
1229
1230 xmlFreeHTTPWriteCtxt( ctxt );
1231
1232 return ( close_rc );
1233}
1234
1235/**
1236 * xmlIOHTTPClosePut
1237 *
1238 * @context: The I/O context
1239 *
1240 * Close the transmit HTTP I/O channel and actually send data using a PUT
1241 * HTTP method.
1242 */
1243static int
1244xmlIOHTTPClosePut( void * ctxt ) {
1245 return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
1246}
1247
1248
1249/**
1250 * xmlIOHTTPClosePost
1251 *
1252 * @context: The I/O context
1253 *
1254 * Close the transmit HTTP I/O channel and actually send data using a POST
1255 * HTTP method.
1256 */
1257static int
1258xmlIOHTTPClosePost( void * ctxt ) {
1259 return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
1260}
1261
Owen Taylor3473f882001-02-23 17:55:21 +00001262#endif /* LIBXML_HTTP_ENABLED */
1263
1264#ifdef LIBXML_FTP_ENABLED
1265/************************************************************************
1266 * *
1267 * I/O for FTP file accesses *
1268 * *
1269 ************************************************************************/
1270/**
1271 * xmlIOFTPMatch:
1272 * @filename: the URI for matching
1273 *
1274 * check if the URI matches an FTP one
1275 *
1276 * Returns 1 if matches, 0 otherwise
1277 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001278int
Owen Taylor3473f882001-02-23 17:55:21 +00001279xmlIOFTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001280 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "ftp://", 6))
Owen Taylor3473f882001-02-23 17:55:21 +00001281 return(1);
1282 return(0);
1283}
1284
1285/**
1286 * xmlIOFTPOpen:
1287 * @filename: the URI for matching
1288 *
1289 * open an FTP I/O channel
1290 *
1291 * Returns an I/O context or NULL in case of error
1292 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001293void *
Owen Taylor3473f882001-02-23 17:55:21 +00001294xmlIOFTPOpen (const char *filename) {
1295 return(xmlNanoFTPOpen(filename));
1296}
1297
1298/**
1299 * xmlIOFTPRead:
1300 * @context: the I/O context
1301 * @buffer: where to drop data
1302 * @len: number of bytes to write
1303 *
1304 * Read @len bytes to @buffer from the I/O channel.
1305 *
1306 * Returns the number of bytes written
1307 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001308int
Owen Taylor3473f882001-02-23 17:55:21 +00001309xmlIOFTPRead(void * context, char * buffer, int len) {
1310 return(xmlNanoFTPRead(context, &buffer[0], len));
1311}
1312
1313/**
1314 * xmlIOFTPClose:
1315 * @context: the I/O context
1316 *
1317 * Close an FTP I/O channel
1318 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001319int
Owen Taylor3473f882001-02-23 17:55:21 +00001320xmlIOFTPClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001321 return ( xmlNanoFTPClose(context) );
Owen Taylor3473f882001-02-23 17:55:21 +00001322}
1323#endif /* LIBXML_FTP_ENABLED */
1324
1325
1326/**
1327 * xmlRegisterInputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001328 * @matchFunc: the xmlInputMatchCallback
1329 * @openFunc: the xmlInputOpenCallback
1330 * @readFunc: the xmlInputReadCallback
1331 * @closeFunc: the xmlInputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001332 *
1333 * Register a new set of I/O callback for handling parser input.
1334 *
1335 * Returns the registered handler number or -1 in case of error
1336 */
1337int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001338xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
1339 xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
1340 xmlInputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001341 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
1342 return(-1);
1343 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001344 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
1345 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
1346 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
1347 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
Owen Taylor3473f882001-02-23 17:55:21 +00001348 return(xmlInputCallbackNr++);
1349}
1350
1351/**
1352 * xmlRegisterOutputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001353 * @matchFunc: the xmlOutputMatchCallback
1354 * @openFunc: the xmlOutputOpenCallback
1355 * @writeFunc: the xmlOutputWriteCallback
1356 * @closeFunc: the xmlOutputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001357 *
1358 * Register a new set of I/O callback for handling output.
1359 *
1360 * Returns the registered handler number or -1 in case of error
1361 */
1362int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001363xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
1364 xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
1365 xmlOutputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001366 if (xmlOutputCallbackNr >= MAX_INPUT_CALLBACK) {
1367 return(-1);
1368 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001369 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
1370 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
1371 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
1372 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
Owen Taylor3473f882001-02-23 17:55:21 +00001373 return(xmlOutputCallbackNr++);
1374}
1375
1376/**
1377 * xmlRegisterDefaultInputCallbacks:
1378 *
1379 * Registers the default compiled-in I/O handlers.
1380 */
1381void
1382#ifdef VMS
1383xmlRegisterDefInputCallbacks
1384#else
1385xmlRegisterDefaultInputCallbacks
1386#endif
1387(void) {
1388 if (xmlInputCallbackInitialized)
1389 return;
1390
1391 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
1392 xmlFileRead, xmlFileClose);
1393#ifdef HAVE_ZLIB_H
1394 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1395 xmlGzfileRead, xmlGzfileClose);
1396#endif /* HAVE_ZLIB_H */
1397
1398#ifdef LIBXML_HTTP_ENABLED
1399 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
1400 xmlIOHTTPRead, xmlIOHTTPClose);
1401#endif /* LIBXML_HTTP_ENABLED */
1402
1403#ifdef LIBXML_FTP_ENABLED
1404 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1405 xmlIOFTPRead, xmlIOFTPClose);
1406#endif /* LIBXML_FTP_ENABLED */
1407 xmlInputCallbackInitialized = 1;
1408}
1409
1410/**
1411 * xmlRegisterDefaultOutputCallbacks:
1412 *
1413 * Registers the default compiled-in I/O handlers.
1414 */
1415void
1416#ifdef VMS
1417xmlRegisterDefOutputCallbacks
1418#else
1419xmlRegisterDefaultOutputCallbacks
1420#endif
1421(void) {
1422 if (xmlOutputCallbackInitialized)
1423 return;
1424
1425 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
1426 xmlFileWrite, xmlFileClose);
Daniel Veillardf012a642001-07-23 19:10:52 +00001427
1428#ifdef LIBXML_HTTP_ENABLED
1429 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
1430 xmlIOHTTPWrite, xmlIOHTTPClosePut);
1431#endif
1432
Owen Taylor3473f882001-02-23 17:55:21 +00001433/*********************************
1434 No way a-priori to distinguish between gzipped files from
1435 uncompressed ones except opening if existing then closing
1436 and saving with same compression ratio ... a pain.
1437
1438#ifdef HAVE_ZLIB_H
1439 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1440 xmlGzfileWrite, xmlGzfileClose);
1441#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001442
1443 Nor FTP PUT ....
1444#ifdef LIBXML_FTP_ENABLED
1445 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1446 xmlIOFTPWrite, xmlIOFTPClose);
1447#endif
1448 **********************************/
1449 xmlOutputCallbackInitialized = 1;
1450}
1451
Daniel Veillardf012a642001-07-23 19:10:52 +00001452#ifdef LIBXML_HTTP_ENABLED
1453/**
1454 * xmlRegisterHTTPPostCallbacks
1455 *
1456 * By default, libxml submits HTTP output requests using the "PUT" method.
1457 * Calling this method changes the HTTP output method to use the "POST"
1458 * method instead.
1459 *
1460 */
1461void
1462xmlRegisterHTTPPostCallbacks( void ) {
1463
1464 /* Register defaults if not done previously */
1465
1466 if ( xmlOutputCallbackInitialized == 0 )
1467 xmlRegisterDefaultOutputCallbacks( );
1468
1469 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
1470 xmlIOHTTPWrite, xmlIOHTTPClosePost);
1471 return;
1472}
1473#endif
1474
Owen Taylor3473f882001-02-23 17:55:21 +00001475/**
1476 * xmlAllocParserInputBuffer:
1477 * @enc: the charset encoding if known
1478 *
1479 * Create a buffered parser input for progressive parsing
1480 *
1481 * Returns the new parser input or NULL
1482 */
1483xmlParserInputBufferPtr
1484xmlAllocParserInputBuffer(xmlCharEncoding enc) {
1485 xmlParserInputBufferPtr ret;
1486
1487 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
1488 if (ret == NULL) {
1489 xmlGenericError(xmlGenericErrorContext,
1490 "xmlAllocParserInputBuffer : out of memory!\n");
1491 return(NULL);
1492 }
1493 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
1494 ret->buffer = xmlBufferCreate();
1495 if (ret->buffer == NULL) {
1496 xmlFree(ret);
1497 return(NULL);
1498 }
1499 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
1500 ret->encoder = xmlGetCharEncodingHandler(enc);
1501 if (ret->encoder != NULL)
1502 ret->raw = xmlBufferCreate();
1503 else
1504 ret->raw = NULL;
1505 ret->readcallback = NULL;
1506 ret->closecallback = NULL;
1507 ret->context = NULL;
1508
1509 return(ret);
1510}
1511
1512/**
1513 * xmlAllocOutputBuffer:
1514 * @encoder: the encoding converter or NULL
1515 *
1516 * Create a buffered parser output
1517 *
1518 * Returns the new parser output or NULL
1519 */
1520xmlOutputBufferPtr
1521xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
1522 xmlOutputBufferPtr ret;
1523
1524 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
1525 if (ret == NULL) {
1526 xmlGenericError(xmlGenericErrorContext,
1527 "xmlAllocOutputBuffer : out of memory!\n");
1528 return(NULL);
1529 }
1530 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
1531 ret->buffer = xmlBufferCreate();
1532 if (ret->buffer == NULL) {
1533 xmlFree(ret);
1534 return(NULL);
1535 }
1536 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
1537 ret->encoder = encoder;
1538 if (encoder != NULL) {
1539 ret->conv = xmlBufferCreateSize(4000);
1540 /*
1541 * This call is designed to initiate the encoder state
1542 */
1543 xmlCharEncOutFunc(encoder, ret->conv, NULL);
1544 } else
1545 ret->conv = NULL;
1546 ret->writecallback = NULL;
1547 ret->closecallback = NULL;
1548 ret->context = NULL;
1549 ret->written = 0;
1550
1551 return(ret);
1552}
1553
1554/**
1555 * xmlFreeParserInputBuffer:
1556 * @in: a buffered parser input
1557 *
1558 * Free up the memory used by a buffered parser input
1559 */
1560void
1561xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
1562 if (in->raw) {
1563 xmlBufferFree(in->raw);
1564 in->raw = NULL;
1565 }
1566 if (in->encoder != NULL) {
1567 xmlCharEncCloseFunc(in->encoder);
1568 }
1569 if (in->closecallback != NULL) {
1570 in->closecallback(in->context);
1571 }
1572 if (in->buffer != NULL) {
1573 xmlBufferFree(in->buffer);
1574 in->buffer = NULL;
1575 }
1576
Owen Taylor3473f882001-02-23 17:55:21 +00001577 xmlFree(in);
1578}
1579
1580/**
1581 * xmlOutputBufferClose:
1582 * @out: a buffered output
1583 *
1584 * flushes and close the output I/O channel
1585 * and free up all the associated resources
1586 *
1587 * Returns the number of byte written or -1 in case of error.
1588 */
1589int
1590xmlOutputBufferClose(xmlOutputBufferPtr out) {
1591 int written;
Daniel Veillardf012a642001-07-23 19:10:52 +00001592 int err_rc = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001593
1594 if (out == NULL)
1595 return(-1);
1596 if (out->writecallback != NULL)
1597 xmlOutputBufferFlush(out);
1598 if (out->closecallback != NULL) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001599 err_rc = out->closecallback(out->context);
Owen Taylor3473f882001-02-23 17:55:21 +00001600 }
1601 written = out->written;
1602 if (out->conv) {
1603 xmlBufferFree(out->conv);
1604 out->conv = NULL;
1605 }
1606 if (out->encoder != NULL) {
1607 xmlCharEncCloseFunc(out->encoder);
1608 }
1609 if (out->buffer != NULL) {
1610 xmlBufferFree(out->buffer);
1611 out->buffer = NULL;
1612 }
1613
Owen Taylor3473f882001-02-23 17:55:21 +00001614 xmlFree(out);
Daniel Veillardf012a642001-07-23 19:10:52 +00001615 return( ( err_rc == 0 ) ? written : err_rc );
Owen Taylor3473f882001-02-23 17:55:21 +00001616}
1617
1618/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001619 * xmlParserInputBufferCreateFname:
1620 * @URI: a C string containing the URI or filename
1621 * @enc: the charset encoding if known
1622 *
1623 * VMS version of xmlParserInputBufferCreateFilename()
1624 *
1625 * Returns the new parser input or NULL
1626 */
1627/**
Owen Taylor3473f882001-02-23 17:55:21 +00001628 * xmlParserInputBufferCreateFilename:
1629 * @URI: a C string containing the URI or filename
1630 * @enc: the charset encoding if known
1631 *
1632 * Create a buffered parser input for the progressive parsing of a file
1633 * If filename is "-' then we use stdin as the input.
1634 * Automatic support for ZLIB/Compress compressed document is provided
1635 * by default if found at compile-time.
1636 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
1637 *
1638 * Returns the new parser input or NULL
1639 */
1640xmlParserInputBufferPtr
1641#ifdef VMS
1642xmlParserInputBufferCreateFname
1643#else
1644xmlParserInputBufferCreateFilename
1645#endif
1646(const char *URI, xmlCharEncoding enc) {
1647 xmlParserInputBufferPtr ret;
Daniel Veillard388236f2001-07-08 18:35:48 +00001648 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001649 void *context = NULL;
Daniel Veillard388236f2001-07-08 18:35:48 +00001650 char *unescaped;
Owen Taylor3473f882001-02-23 17:55:21 +00001651
1652 if (xmlInputCallbackInitialized == 0)
1653 xmlRegisterDefaultInputCallbacks();
1654
1655 if (URI == NULL) return(NULL);
1656
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001657#ifdef LIBXML_CATALOG_ENABLED
1658#endif
1659
Owen Taylor3473f882001-02-23 17:55:21 +00001660 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001661 * Try to find one of the input accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00001662 * Go in reverse to give precedence to user defined handlers.
Daniel Veillard388236f2001-07-08 18:35:48 +00001663 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00001664 */
Daniel Veillard388236f2001-07-08 18:35:48 +00001665 unescaped = xmlURIUnescapeString(URI, 0, NULL);
1666 if (unescaped != NULL) {
1667 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
1668 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
1669 (xmlInputCallbackTable[i].matchcallback(unescaped) != 0)) {
1670 context = xmlInputCallbackTable[i].opencallback(unescaped);
1671 if (context != NULL)
1672 break;
1673 }
1674 }
1675 xmlFree(unescaped);
1676 }
1677
1678 /*
1679 * If this failed try with a non-escaped URI this may be a strange
1680 * filename
1681 */
1682 if (context == NULL) {
1683 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
1684 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
1685 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
1686 context = xmlInputCallbackTable[i].opencallback(URI);
1687 if (context != NULL)
1688 break;
1689 }
Owen Taylor3473f882001-02-23 17:55:21 +00001690 }
1691 }
1692 if (context == NULL) {
1693 return(NULL);
1694 }
1695
1696 /*
1697 * Allocate the Input buffer front-end.
1698 */
1699 ret = xmlAllocParserInputBuffer(enc);
1700 if (ret != NULL) {
1701 ret->context = context;
1702 ret->readcallback = xmlInputCallbackTable[i].readcallback;
1703 ret->closecallback = xmlInputCallbackTable[i].closecallback;
1704 }
1705 return(ret);
1706}
1707
1708/**
1709 * xmlOutputBufferCreateFilename:
1710 * @URI: a C string containing the URI or filename
1711 * @encoder: the encoding converter or NULL
1712 * @compression: the compression ration (0 none, 9 max).
1713 *
1714 * Create a buffered output for the progressive saving of a file
1715 * If filename is "-' then we use stdout as the output.
1716 * Automatic support for ZLIB/Compress compressed document is provided
1717 * by default if found at compile-time.
1718 * TODO: currently if compression is set, the library only support
1719 * writing to a local file.
1720 *
1721 * Returns the new output or NULL
1722 */
1723xmlOutputBufferPtr
1724xmlOutputBufferCreateFilename(const char *URI,
1725 xmlCharEncodingHandlerPtr encoder,
1726 int compression) {
1727 xmlOutputBufferPtr ret;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001728 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001729 void *context = NULL;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001730 char *unescaped;
Owen Taylor3473f882001-02-23 17:55:21 +00001731
Daniel Veillardf012a642001-07-23 19:10:52 +00001732 int is_http_uri = 0; /* Can't change if HTTP disabled */
1733
Owen Taylor3473f882001-02-23 17:55:21 +00001734 if (xmlOutputCallbackInitialized == 0)
1735 xmlRegisterDefaultOutputCallbacks();
1736
1737 if (URI == NULL) return(NULL);
1738
Daniel Veillardf012a642001-07-23 19:10:52 +00001739#ifdef LIBXML_HTTP_ENABLED
1740 /* Need to prevent HTTP URI's from falling into zlib short circuit */
1741
1742 is_http_uri = xmlIOHTTPMatch( URI );
1743#endif
1744
Owen Taylor3473f882001-02-23 17:55:21 +00001745
1746 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001747 * Try to find one of the output accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00001748 * Go in reverse to give precedence to user defined handlers.
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001749 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00001750 */
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001751 unescaped = xmlURIUnescapeString(URI, 0, NULL);
1752 if (unescaped != NULL) {
1753#ifdef HAVE_ZLIB_H
1754 if ((compression > 0) && (compression <= 9) && (is_http_uri == 0)) {
1755 context = xmlGzfileOpenW(unescaped, compression);
1756 if (context != NULL) {
1757 ret = xmlAllocOutputBuffer(encoder);
1758 if (ret != NULL) {
1759 ret->context = context;
1760 ret->writecallback = xmlGzfileWrite;
1761 ret->closecallback = xmlGzfileClose;
1762 }
1763 xmlFree(unescaped);
1764 return(ret);
1765 }
1766 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001767#endif
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001768 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
1769 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
1770 (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
1771#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
1772 /* Need to pass compression parameter into HTTP open calls */
1773 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
1774 context = xmlIOHTTPOpenW(unescaped, compression);
1775 else
1776#endif
1777 context = xmlOutputCallbackTable[i].opencallback(unescaped);
1778 if (context != NULL)
1779 break;
1780 }
1781 }
1782 xmlFree(unescaped);
1783 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001784
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001785 /*
1786 * If this failed try with a non-escaped URI this may be a strange
1787 * filename
1788 */
1789 if (context == NULL) {
1790#ifdef HAVE_ZLIB_H
1791 if ((compression > 0) && (compression <= 9) && (is_http_uri == 0)) {
1792 context = xmlGzfileOpenW(URI, compression);
1793 if (context != NULL) {
1794 ret = xmlAllocOutputBuffer(encoder);
1795 if (ret != NULL) {
1796 ret->context = context;
1797 ret->writecallback = xmlGzfileWrite;
1798 ret->closecallback = xmlGzfileClose;
1799 }
1800 return(ret);
1801 }
1802 }
1803#endif
1804 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
1805 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
1806 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001807#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;
Daniel Veillard7db38712002-02-07 16:39:11 +00001969 ret->closecallback = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001970 }
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
Daniel Veillard9d06d302002-01-22 18:15:52 +00002009 * @encoder: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002010 *
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/**
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002084 * endOfInput:
2085 *
2086 * When reading from an Input channel indicated end of file or error
2087 * don't reread from it again.
2088 */
2089static int
2090endOfInput (void * context ATTRIBUTE_UNUSED,
2091 char * buffer ATTRIBUTE_UNUSED,
2092 int len ATTRIBUTE_UNUSED) {
2093 return(0);
2094}
2095
2096/**
Owen Taylor3473f882001-02-23 17:55:21 +00002097 * xmlParserInputBufferGrow:
2098 * @in: a buffered parser input
2099 * @len: indicative value of the amount of chars to read
2100 *
2101 * Grow up the content of the input buffer, the old data are preserved
2102 * This routine handle the I18N transcoding to internal UTF-8
2103 * This routine is used when operating the parser in normal (pull) mode
2104 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002105 * TODO: one should be able to remove one extra copy by copying directly
Owen Taylor3473f882001-02-23 17:55:21 +00002106 * onto in->buffer or in->raw
2107 *
2108 * Returns the number of chars read and stored in the buffer, or -1
2109 * in case of error.
2110 */
2111int
2112xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
2113 char *buffer = NULL;
2114 int res = 0;
2115 int nbchars = 0;
2116 int buffree;
Daniel Veillarde5354492002-05-16 08:43:22 +00002117 int needSize;
Owen Taylor3473f882001-02-23 17:55:21 +00002118
2119 if ((len <= MINLEN) && (len != 4))
2120 len = MINLEN;
2121 buffree = in->buffer->size - in->buffer->use;
2122 if (buffree <= 0) {
2123 xmlGenericError(xmlGenericErrorContext,
2124 "xmlParserInputBufferGrow : buffer full !\n");
2125 return(0);
2126 }
2127 if (len > buffree)
2128 len = buffree;
2129
Daniel Veillarde5354492002-05-16 08:43:22 +00002130 needSize = in->buffer->use + len + 1;
2131 if (needSize > in->buffer->size){
2132 if (!xmlBufferResize(in->buffer, needSize)){
2133 xmlGenericError(xmlGenericErrorContext,
2134 "xmlBufferAdd : out of memory!\n");
2135 return(0);
2136 }
Owen Taylor3473f882001-02-23 17:55:21 +00002137 }
Daniel Veillarde5354492002-05-16 08:43:22 +00002138 buffer = (char *)&in->buffer->content[in->buffer->use];
Owen Taylor3473f882001-02-23 17:55:21 +00002139
2140 /*
2141 * Call the read method for this I/O type.
2142 */
2143 if (in->readcallback != NULL) {
2144 res = in->readcallback(in->context, &buffer[0], len);
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002145 if (res <= 0)
2146 in->readcallback = endOfInput;
Owen Taylor3473f882001-02-23 17:55:21 +00002147 } else {
2148 xmlGenericError(xmlGenericErrorContext,
2149 "xmlParserInputBufferGrow : no input !\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002150 return(-1);
2151 }
2152 if (res < 0) {
2153 perror ("read error");
Owen Taylor3473f882001-02-23 17:55:21 +00002154 return(-1);
2155 }
2156 len = res;
2157 if (in->encoder != NULL) {
2158 /*
2159 * Store the data in the incoming raw buffer
2160 */
2161 if (in->raw == NULL) {
2162 in->raw = xmlBufferCreate();
2163 }
2164 xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
2165
2166 /*
2167 * convert as much as possible to the parser reading buffer.
2168 */
2169 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2170 if (nbchars < 0) {
2171 xmlGenericError(xmlGenericErrorContext,
2172 "xmlParserInputBufferGrow: encoder error\n");
2173 return(-1);
2174 }
2175 } else {
2176 nbchars = len;
Daniel Veillarde5354492002-05-16 08:43:22 +00002177 in->buffer->use += nbchars;
2178 buffer[nbchars] = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002179 }
2180#ifdef DEBUG_INPUT
2181 xmlGenericError(xmlGenericErrorContext,
2182 "I/O: read %d chars, buffer %d/%d\n",
2183 nbchars, in->buffer->use, in->buffer->size);
2184#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002185 return(nbchars);
2186}
2187
2188/**
2189 * xmlParserInputBufferRead:
2190 * @in: a buffered parser input
2191 * @len: indicative value of the amount of chars to read
2192 *
2193 * Refresh the content of the input buffer, the old data are considered
2194 * consumed
2195 * This routine handle the I18N transcoding to internal UTF-8
2196 *
2197 * Returns the number of chars read and stored in the buffer, or -1
2198 * in case of error.
2199 */
2200int
2201xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
2202 /* xmlBufferEmpty(in->buffer); */
2203 if (in->readcallback != NULL)
2204 return(xmlParserInputBufferGrow(in, len));
2205 else
2206 return(-1);
2207}
2208
2209/**
2210 * xmlOutputBufferWrite:
2211 * @out: a buffered parser output
2212 * @len: the size in bytes of the array.
2213 * @buf: an char array
2214 *
2215 * Write the content of the array in the output I/O buffer
2216 * This routine handle the I18N transcoding from internal UTF-8
2217 * The buffer is lossless, i.e. will store in case of partial
2218 * or delayed writes.
2219 *
2220 * Returns the number of chars immediately written, or -1
2221 * in case of error.
2222 */
2223int
2224xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
2225 int nbchars = 0; /* number of chars to output to I/O */
2226 int ret; /* return from function call */
2227 int written = 0; /* number of char written to I/O so far */
2228 int chunk; /* number of byte curreent processed from buf */
2229
2230 if (len < 0) return(0);
2231
2232 do {
2233 chunk = len;
2234 if (chunk > 4 * MINLEN)
2235 chunk = 4 * MINLEN;
2236
2237 /*
2238 * first handle encoding stuff.
2239 */
2240 if (out->encoder != NULL) {
2241 /*
2242 * Store the data in the incoming raw buffer
2243 */
2244 if (out->conv == NULL) {
2245 out->conv = xmlBufferCreate();
2246 }
2247 xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2248
2249 if ((out->buffer->use < MINLEN) && (chunk == len))
2250 goto done;
2251
2252 /*
2253 * convert as much as possible to the parser reading buffer.
2254 */
2255 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
2256 if (ret < 0) {
2257 xmlGenericError(xmlGenericErrorContext,
2258 "xmlOutputBufferWrite: encoder error\n");
2259 return(-1);
2260 }
2261 nbchars = out->conv->use;
2262 } else {
2263 xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2264 nbchars = out->buffer->use;
2265 }
2266 buf += chunk;
2267 len -= chunk;
2268
2269 if ((nbchars < MINLEN) && (len <= 0))
2270 goto done;
2271
2272 if (out->writecallback) {
2273 /*
2274 * second write the stuff to the I/O channel
2275 */
2276 if (out->encoder != NULL) {
2277 ret = out->writecallback(out->context,
2278 (const char *)out->conv->content, nbchars);
2279 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002280 xmlBufferShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002281 } else {
2282 ret = out->writecallback(out->context,
2283 (const char *)out->buffer->content, nbchars);
2284 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002285 xmlBufferShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002286 }
2287 if (ret < 0) {
2288 xmlGenericError(xmlGenericErrorContext,
2289 "I/O: error %d writing %d bytes\n", ret, nbchars);
2290 return(ret);
2291 }
2292 out->written += ret;
2293 }
2294 written += nbchars;
2295 } while (len > 0);
2296
2297done:
2298#ifdef DEBUG_INPUT
2299 xmlGenericError(xmlGenericErrorContext,
2300 "I/O: wrote %d chars\n", written);
2301#endif
2302 return(written);
2303}
2304
2305/**
2306 * xmlOutputBufferWriteString:
2307 * @out: a buffered parser output
2308 * @str: a zero terminated C string
2309 *
2310 * Write the content of the string in the output I/O buffer
2311 * This routine handle the I18N transcoding from internal UTF-8
2312 * The buffer is lossless, i.e. will store in case of partial
2313 * or delayed writes.
2314 *
2315 * Returns the number of chars immediately written, or -1
2316 * in case of error.
2317 */
2318int
2319xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
2320 int len;
2321
2322 if (str == NULL)
2323 return(-1);
2324 len = strlen(str);
2325
2326 if (len > 0)
2327 return(xmlOutputBufferWrite(out, len, str));
2328 return(len);
2329}
2330
2331/**
2332 * xmlOutputBufferFlush:
2333 * @out: a buffered output
2334 *
2335 * flushes the output I/O channel
2336 *
2337 * Returns the number of byte written or -1 in case of error.
2338 */
2339int
2340xmlOutputBufferFlush(xmlOutputBufferPtr out) {
2341 int nbchars = 0, ret = 0;
2342
2343 /*
2344 * first handle encoding stuff.
2345 */
2346 if ((out->conv != NULL) && (out->encoder != NULL)) {
2347 /*
2348 * convert as much as possible to the parser reading buffer.
2349 */
2350 nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
2351 if (nbchars < 0) {
2352 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002353 "xmlOutputBufferFlush: encoder error\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002354 return(-1);
2355 }
2356 }
2357
2358 /*
2359 * second flush the stuff to the I/O channel
2360 */
2361 if ((out->conv != NULL) && (out->encoder != NULL) &&
2362 (out->writecallback != NULL)) {
2363 ret = out->writecallback(out->context,
2364 (const char *)out->conv->content, out->conv->use);
2365 if (ret >= 0)
2366 xmlBufferShrink(out->conv, ret);
2367 } else if (out->writecallback != NULL) {
2368 ret = out->writecallback(out->context,
2369 (const char *)out->buffer->content, out->buffer->use);
2370 if (ret >= 0)
2371 xmlBufferShrink(out->buffer, ret);
2372 }
2373 if (ret < 0) {
2374 xmlGenericError(xmlGenericErrorContext,
2375 "I/O: error %d flushing %d bytes\n", ret, nbchars);
2376 return(ret);
2377 }
2378 out->written += ret;
2379
2380#ifdef DEBUG_INPUT
2381 xmlGenericError(xmlGenericErrorContext,
2382 "I/O: flushed %d chars\n", ret);
2383#endif
2384 return(ret);
2385}
2386
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002387/**
Owen Taylor3473f882001-02-23 17:55:21 +00002388 * xmlParserGetDirectory:
2389 * @filename: the path to a file
2390 *
2391 * lookup the directory for that file
2392 *
2393 * Returns a new allocated string containing the directory, or NULL.
2394 */
2395char *
2396xmlParserGetDirectory(const char *filename) {
2397 char *ret = NULL;
2398 char dir[1024];
2399 char *cur;
2400 char sep = '/';
2401
2402 if (xmlInputCallbackInitialized == 0)
2403 xmlRegisterDefaultInputCallbacks();
2404
2405 if (filename == NULL) return(NULL);
Daniel Veillard3c5ed912002-01-08 10:36:16 +00002406#if defined(WIN32) && !defined(__CYGWIN__)
Owen Taylor3473f882001-02-23 17:55:21 +00002407 sep = '\\';
2408#endif
2409
2410 strncpy(dir, filename, 1023);
2411 dir[1023] = 0;
2412 cur = &dir[strlen(dir)];
2413 while (cur > dir) {
2414 if (*cur == sep) break;
2415 cur --;
2416 }
2417 if (*cur == sep) {
2418 if (cur == dir) dir[1] = 0;
2419 else *cur = 0;
2420 ret = xmlMemStrdup(dir);
2421 } else {
2422 if (getcwd(dir, 1024) != NULL) {
2423 dir[1023] = 0;
2424 ret = xmlMemStrdup(dir);
2425 }
2426 }
2427 return(ret);
2428}
2429
2430/****************************************************************
2431 * *
2432 * External entities loading *
2433 * *
2434 ****************************************************************/
2435
Daniel Veillard561b7f82002-03-20 21:55:57 +00002436#ifdef LIBXML_CATALOG_ENABLED
2437static int xmlSysIDExists(const char *URL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00002438#ifdef HAVE_STAT
2439 int ret;
2440 struct stat info;
2441 const char *path;
2442
2443 if (URL == NULL)
2444 return(0);
2445
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002446 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost", 16))
Daniel Veillard6990bf32001-08-23 21:17:48 +00002447 path = &URL[16];
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002448 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard3c5ed912002-01-08 10:36:16 +00002449#if defined (_WIN32) && !defined(__CYGWIN__)
Daniel Veillard6990bf32001-08-23 21:17:48 +00002450 path = &URL[8];
2451#else
2452 path = &URL[7];
2453#endif
2454 } else
2455 path = URL;
2456 ret = stat(path, &info);
Daniel Veillard561b7f82002-03-20 21:55:57 +00002457 if (ret == 0)
2458 return(1);
Daniel Veillard6990bf32001-08-23 21:17:48 +00002459#endif
Daniel Veillard561b7f82002-03-20 21:55:57 +00002460 return(0);
Daniel Veillard6990bf32001-08-23 21:17:48 +00002461}
Daniel Veillard561b7f82002-03-20 21:55:57 +00002462#endif
Daniel Veillard6990bf32001-08-23 21:17:48 +00002463
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002464/**
Owen Taylor3473f882001-02-23 17:55:21 +00002465 * xmlDefaultExternalEntityLoader:
2466 * @URL: the URL for the entity to load
2467 * @ID: the System ID for the entity to load
2468 * @ctxt: the context in which the entity is called or NULL
2469 *
2470 * By default we don't load external entitites, yet.
2471 *
2472 * Returns a new allocated xmlParserInputPtr, or NULL.
2473 */
2474static
2475xmlParserInputPtr
2476xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
2477 xmlParserCtxtPtr ctxt) {
2478 xmlParserInputPtr ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002479 xmlChar *resource = NULL;
2480#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002481 xmlCatalogAllow pref;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002482#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002483
2484#ifdef DEBUG_EXTERNAL_ENTITIES
2485 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf012a642001-07-23 19:10:52 +00002486 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00002487#endif
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002488#ifdef LIBXML_CATALOG_ENABLED
2489 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002490 * If the resource doesn't exists as a file,
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002491 * try to load it from the resource pointed in the catalogs
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002492 */
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002493 pref = xmlCatalogGetDefaults();
2494
Daniel Veillard561b7f82002-03-20 21:55:57 +00002495 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlSysIDExists(URL))) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002496 /*
2497 * Do a local lookup
2498 */
2499 if ((ctxt->catalogs != NULL) &&
2500 ((pref == XML_CATA_ALLOW_ALL) ||
2501 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2502 resource = xmlCatalogLocalResolve(ctxt->catalogs,
2503 (const xmlChar *)ID,
2504 (const xmlChar *)URL);
2505 }
2506 /*
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002507 * Try a global lookup
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002508 */
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002509 if ((resource == NULL) &&
2510 ((pref == XML_CATA_ALLOW_ALL) ||
2511 (pref == XML_CATA_ALLOW_GLOBAL))) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002512 resource = xmlCatalogResolve((const xmlChar *)ID,
2513 (const xmlChar *)URL);
2514 }
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002515 if ((resource == NULL) && (URL != NULL))
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00002516 resource = xmlStrdup((const xmlChar *) URL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002517
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002518 /*
2519 * TODO: do an URI lookup on the reference
2520 */
Daniel Veillard561b7f82002-03-20 21:55:57 +00002521 if ((resource != NULL) && (!xmlSysIDExists((const char *)resource))) {
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002522 xmlChar *tmp = NULL;
2523
2524 if ((ctxt->catalogs != NULL) &&
2525 ((pref == XML_CATA_ALLOW_ALL) ||
2526 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2527 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
2528 }
2529 if ((tmp == NULL) &&
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00002530 ((pref == XML_CATA_ALLOW_ALL) ||
2531 (pref == XML_CATA_ALLOW_GLOBAL))) {
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002532 tmp = xmlCatalogResolveURI(resource);
2533 }
2534
2535 if (tmp != NULL) {
2536 xmlFree(resource);
2537 resource = tmp;
2538 }
2539 }
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002540 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002541#endif
2542
2543 if (resource == NULL)
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002544 resource = (xmlChar *) URL;
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002545
2546 if (resource == NULL) {
Daniel Veillardc6613042002-03-02 09:34:02 +00002547 if (ID == NULL)
2548 ID = "NULL";
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002549 if ((ctxt->validate) && (ctxt->sax != NULL) &&
2550 (ctxt->sax->error != NULL))
2551 ctxt->sax->error(ctxt,
2552 "failed to load external entity \"%s\"\n", ID);
2553 else if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00002554 ctxt->sax->warning(ctxt,
2555 "failed to load external entity \"%s\"\n", ID);
2556 return(NULL);
2557 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002558 ret = xmlNewInputFromFile(ctxt, (const char *)resource);
Owen Taylor3473f882001-02-23 17:55:21 +00002559 if (ret == NULL) {
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002560 if ((ctxt->validate) && (ctxt->sax != NULL) &&
2561 (ctxt->sax->error != NULL))
2562 ctxt->sax->error(ctxt,
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002563 "failed to load external entity \"%s\"\n", resource);
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002564 else if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00002565 ctxt->sax->warning(ctxt,
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002566 "failed to load external entity \"%s\"\n", resource);
Owen Taylor3473f882001-02-23 17:55:21 +00002567 }
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002568 if ((resource != NULL) && (resource != (xmlChar *) URL))
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002569 xmlFree(resource);
Owen Taylor3473f882001-02-23 17:55:21 +00002570 return(ret);
2571}
2572
2573static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
2574 xmlDefaultExternalEntityLoader;
2575
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002576/**
Owen Taylor3473f882001-02-23 17:55:21 +00002577 * xmlSetExternalEntityLoader:
2578 * @f: the new entity resolver function
2579 *
2580 * Changes the defaultexternal entity resolver function for the application
2581 */
2582void
2583xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
2584 xmlCurrentExternalEntityLoader = f;
2585}
2586
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002587/**
Owen Taylor3473f882001-02-23 17:55:21 +00002588 * xmlGetExternalEntityLoader:
2589 *
2590 * Get the default external entity resolver function for the application
2591 *
2592 * Returns the xmlExternalEntityLoader function pointer
2593 */
2594xmlExternalEntityLoader
2595xmlGetExternalEntityLoader(void) {
2596 return(xmlCurrentExternalEntityLoader);
2597}
2598
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002599/**
Owen Taylor3473f882001-02-23 17:55:21 +00002600 * xmlLoadExternalEntity:
2601 * @URL: the URL for the entity to load
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00002602 * @ID: the Public ID for the entity to load
Owen Taylor3473f882001-02-23 17:55:21 +00002603 * @ctxt: the context in which the entity is called or NULL
2604 *
2605 * Load an external entity, note that the use of this function for
2606 * unparsed entities may generate problems
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002607 * TODO: a more generic External entity API must be designed
Owen Taylor3473f882001-02-23 17:55:21 +00002608 *
2609 * Returns the xmlParserInputPtr or NULL
2610 */
2611xmlParserInputPtr
2612xmlLoadExternalEntity(const char *URL, const char *ID,
2613 xmlParserCtxtPtr ctxt) {
2614 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
2615}
2616
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00002617/************************************************************************
2618 * *
2619 * Disabling Network access *
2620 * *
2621 ************************************************************************/
2622
2623#ifdef LIBXML_CATALOG_ENABLED
2624static int
2625xmlNoNetExists(const char *URL)
2626{
2627#ifdef HAVE_STAT
2628 int ret;
2629 struct stat info;
2630 const char *path;
2631
2632 if (URL == NULL)
2633 return (0);
2634
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002635 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost", 16))
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00002636 path = &URL[16];
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002637 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard3c5ed912002-01-08 10:36:16 +00002638#if defined (_WIN32) && !defined(__CYGWIN__)
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00002639 path = &URL[8];
2640#else
2641 path = &URL[7];
2642#endif
2643 } else
2644 path = URL;
2645 ret = stat(path, &info);
2646 if (ret == 0)
2647 return (1);
2648#endif
2649 return (0);
2650}
2651#endif
2652
2653/**
2654 * xmlNoNetExternalEntityLoader:
2655 * @URL: the URL for the entity to load
2656 * @ID: the System ID for the entity to load
2657 * @ctxt: the context in which the entity is called or NULL
2658 *
2659 * A specific entity loader disabling network accesses, though still
2660 * allowing local catalog accesses for resolution.
2661 *
2662 * Returns a new allocated xmlParserInputPtr, or NULL.
2663 */
2664xmlParserInputPtr
2665xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
2666 xmlParserCtxtPtr ctxt) {
2667 xmlParserInputPtr input = NULL;
2668 xmlChar *resource = NULL;
2669
2670#ifdef LIBXML_CATALOG_ENABLED
2671 xmlCatalogAllow pref;
2672
2673 /*
2674 * If the resource doesn't exists as a file,
2675 * try to load it from the resource pointed in the catalogs
2676 */
2677 pref = xmlCatalogGetDefaults();
2678
2679 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
2680 /*
2681 * Do a local lookup
2682 */
2683 if ((ctxt->catalogs != NULL) &&
2684 ((pref == XML_CATA_ALLOW_ALL) ||
2685 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2686 resource = xmlCatalogLocalResolve(ctxt->catalogs,
2687 (const xmlChar *)ID,
2688 (const xmlChar *)URL);
2689 }
2690 /*
2691 * Try a global lookup
2692 */
2693 if ((resource == NULL) &&
2694 ((pref == XML_CATA_ALLOW_ALL) ||
2695 (pref == XML_CATA_ALLOW_GLOBAL))) {
2696 resource = xmlCatalogResolve((const xmlChar *)ID,
2697 (const xmlChar *)URL);
2698 }
2699 if ((resource == NULL) && (URL != NULL))
2700 resource = xmlStrdup((const xmlChar *) URL);
2701
2702 /*
2703 * TODO: do an URI lookup on the reference
2704 */
2705 if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
2706 xmlChar *tmp = NULL;
2707
2708 if ((ctxt->catalogs != NULL) &&
2709 ((pref == XML_CATA_ALLOW_ALL) ||
2710 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2711 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
2712 }
2713 if ((tmp == NULL) &&
2714 ((pref == XML_CATA_ALLOW_ALL) ||
2715 (pref == XML_CATA_ALLOW_GLOBAL))) {
2716 tmp = xmlCatalogResolveURI(resource);
2717 }
2718
2719 if (tmp != NULL) {
2720 xmlFree(resource);
2721 resource = tmp;
2722 }
2723 }
2724 }
2725#endif
2726 if (resource == NULL)
2727 resource = (xmlChar *) URL;
2728
2729 if (resource != NULL) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002730 if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
2731 (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00002732 xmlGenericError(xmlGenericErrorContext,
2733 "Attempt to load network entity %s \n", resource);
2734
2735 if (resource != (xmlChar *) URL)
2736 xmlFree(resource);
2737 return(NULL);
2738 }
2739 }
2740 input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
2741 if (resource != (xmlChar *) URL)
2742 xmlFree(resource);
2743 return(input);
2744}
2745