blob: a3d73c349067c9c198b5b7abeab148538f67d5cf [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 }
Daniel Veillard9e412302002-06-10 15:59:44 +0000146 xmlInputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000147
148 xmlInputCallbackNr = 0;
Aleksey Sanin9c45ba82002-06-06 21:46:13 +0000149 xmlInputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000150}
151
152/**
153 * xmlCleanupOutputCallbacks:
154 *
155 * clears the entire output callback table. this includes the
156 * compiled-in I/O callbacks.
157 */
158void
159xmlCleanupOutputCallbacks(void)
160{
161 int i;
162
163 if (!xmlOutputCallbackInitialized)
164 return;
165
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000166 for (i = xmlOutputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000167 xmlOutputCallbackTable[i].matchcallback = NULL;
168 xmlOutputCallbackTable[i].opencallback = NULL;
169 xmlOutputCallbackTable[i].writecallback = NULL;
170 xmlOutputCallbackTable[i].closecallback = NULL;
171 }
Daniel Veillard9e412302002-06-10 15:59:44 +0000172 xmlOutputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000173
174 xmlOutputCallbackNr = 0;
Aleksey Sanin9c45ba82002-06-06 21:46:13 +0000175 xmlOutputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000176}
177
Owen Taylor3473f882001-02-23 17:55:21 +0000178/************************************************************************
179 * *
180 * Standard I/O for file accesses *
181 * *
182 ************************************************************************/
183
184/**
185 * xmlCheckFilename
186 * @path: the path to check
187 *
188 * function checks to see if @path is a valid source
189 * (file, socket...) for XML.
190 *
191 * if stat is not available on the target machine,
192 * returns 1. if stat fails, returns 0 (if calling
193 * stat on the filename fails, it can't be right).
194 * if stat succeeds and the file is a directory,
195 * sets errno to EISDIR and returns 0. otherwise
196 * returns 1.
197 */
198
199static int
200xmlCheckFilename (const char *path)
201{
202#ifdef HAVE_STAT
203#ifdef S_ISDIR
204 struct stat stat_buffer;
205
206 if (stat(path, &stat_buffer) == -1)
207 return 0;
208
209 if (S_ISDIR(stat_buffer.st_mode)) {
210 errno = EISDIR;
211 return 0;
212 }
213
214#endif
215#endif
216 return 1;
217}
218
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000219static int
Owen Taylor3473f882001-02-23 17:55:21 +0000220xmlNop(void) {
221 return(0);
222}
223
224/**
Owen Taylor3473f882001-02-23 17:55:21 +0000225 * xmlFdRead:
226 * @context: the I/O context
227 * @buffer: where to drop data
228 * @len: number of bytes to read
229 *
230 * Read @len bytes to @buffer from the I/O channel.
231 *
232 * Returns the number of bytes written
233 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000234static int
Owen Taylor3473f882001-02-23 17:55:21 +0000235xmlFdRead (void * context, char * buffer, int len) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +0000236 return(read((int) (long) context, &buffer[0], len));
Owen Taylor3473f882001-02-23 17:55:21 +0000237}
238
239/**
240 * xmlFdWrite:
241 * @context: the I/O context
242 * @buffer: where to get data
243 * @len: number of bytes to write
244 *
245 * Write @len bytes from @buffer to the I/O channel.
246 *
247 * Returns the number of bytes written
248 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000249static int
Owen Taylor3473f882001-02-23 17:55:21 +0000250xmlFdWrite (void * context, const char * buffer, int len) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +0000251 return(write((int) (long) context, &buffer[0], len));
Owen Taylor3473f882001-02-23 17:55:21 +0000252}
253
254/**
255 * xmlFdClose:
256 * @context: the I/O context
257 *
258 * Close an I/O channel
Daniel Veillardf012a642001-07-23 19:10:52 +0000259 *
260 * Returns 0 in case of success and error code otherwise
Owen Taylor3473f882001-02-23 17:55:21 +0000261 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000262static int
Owen Taylor3473f882001-02-23 17:55:21 +0000263xmlFdClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +0000264 return ( close((int) (long) context) );
Owen Taylor3473f882001-02-23 17:55:21 +0000265}
266
267/**
268 * xmlFileMatch:
269 * @filename: the URI for matching
270 *
271 * input from FILE *
272 *
273 * Returns 1 if matches, 0 otherwise
274 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000275int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000276xmlFileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000277 return(1);
278}
279
280/**
281 * xmlFileOpen:
282 * @filename: the URI for matching
283 *
284 * input from FILE *, supports compressed input
285 * if @filename is " " then the standard input is used
286 *
287 * Returns an I/O context or NULL in case of error
288 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000289void *
Owen Taylor3473f882001-02-23 17:55:21 +0000290xmlFileOpen (const char *filename) {
291 const char *path = NULL;
292 FILE *fd;
293
294 if (!strcmp(filename, "-")) {
295 fd = stdin;
296 return((void *) fd);
297 }
298
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000299 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost", 16))
Owen Taylor3473f882001-02-23 17:55:21 +0000300 path = &filename[16];
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000301 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard3c5ed912002-01-08 10:36:16 +0000302#if defined (_WIN32) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000303 path = &filename[8];
304#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000305 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000306#endif
307 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000308 path = filename;
309
310 if (path == NULL)
311 return(NULL);
312 if (!xmlCheckFilename(path))
313 return(NULL);
314
Daniel Veillard3c5ed912002-01-08 10:36:16 +0000315#if defined(WIN32) || defined (__CYGWIN__)
Owen Taylor3473f882001-02-23 17:55:21 +0000316 fd = fopen(path, "rb");
317#else
318 fd = fopen(path, "r");
319#endif /* WIN32 */
320 return((void *) fd);
321}
322
323/**
324 * xmlFileOpenW:
325 * @filename: the URI for matching
326 *
327 * output to from FILE *,
328 * if @filename is "-" then the standard output is used
329 *
330 * Returns an I/O context or NULL in case of error
331 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000332static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000333xmlFileOpenW (const char *filename) {
334 const char *path = NULL;
335 FILE *fd;
336
337 if (!strcmp(filename, "-")) {
338 fd = stdout;
339 return((void *) fd);
340 }
341
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000342 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost", 16))
Owen Taylor3473f882001-02-23 17:55:21 +0000343 path = &filename[16];
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000344 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard3c5ed912002-01-08 10:36:16 +0000345#if defined (_WIN32) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000346 path = &filename[8];
347#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000348 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000349#endif
350 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000351 path = filename;
352
353 if (path == NULL)
354 return(NULL);
355
356 fd = fopen(path, "w");
357 return((void *) fd);
358}
359
360/**
361 * xmlFileRead:
362 * @context: the I/O context
363 * @buffer: where to drop data
364 * @len: number of bytes to write
365 *
366 * Read @len bytes to @buffer from the I/O channel.
367 *
368 * Returns the number of bytes written
369 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000370int
Owen Taylor3473f882001-02-23 17:55:21 +0000371xmlFileRead (void * context, char * buffer, int len) {
372 return(fread(&buffer[0], 1, len, (FILE *) context));
373}
374
375/**
376 * xmlFileWrite:
377 * @context: the I/O context
378 * @buffer: where to drop data
379 * @len: number of bytes to write
380 *
381 * Write @len bytes from @buffer to the I/O channel.
382 *
383 * Returns the number of bytes written
384 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000385static int
Owen Taylor3473f882001-02-23 17:55:21 +0000386xmlFileWrite (void * context, const char * buffer, int len) {
387 return(fwrite(&buffer[0], 1, len, (FILE *) context));
388}
389
390/**
391 * xmlFileClose:
392 * @context: the I/O context
393 *
394 * Close an I/O channel
395 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000396int
Owen Taylor3473f882001-02-23 17:55:21 +0000397xmlFileClose (void * context) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000398 FILE *fil;
399
400 fil = (FILE *) context;
401 if (fil == stdin)
402 return(0);
403 if (fil == stdout)
404 return(0);
Daniel Veillardcd337f02001-11-22 18:20:37 +0000405 if (fil == stderr)
406 return(0);
Daniel Veillardf012a642001-07-23 19:10:52 +0000407 return ( ( fclose((FILE *) context) == EOF ) ? -1 : 0 );
Owen Taylor3473f882001-02-23 17:55:21 +0000408}
409
410/**
411 * xmlFileFlush:
412 * @context: the I/O context
413 *
414 * Flush an I/O channel
415 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000416static int
Owen Taylor3473f882001-02-23 17:55:21 +0000417xmlFileFlush (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +0000418 return ( ( fflush((FILE *) context) == EOF ) ? -1 : 0 );
Owen Taylor3473f882001-02-23 17:55:21 +0000419}
420
421#ifdef HAVE_ZLIB_H
422/************************************************************************
423 * *
424 * I/O for compressed file accesses *
425 * *
426 ************************************************************************/
427/**
428 * xmlGzfileMatch:
429 * @filename: the URI for matching
430 *
431 * input from compressed file test
432 *
433 * Returns 1 if matches, 0 otherwise
434 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000435static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000436xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000437 return(1);
438}
439
440/**
441 * xmlGzfileOpen:
442 * @filename: the URI for matching
443 *
444 * input from compressed file open
445 * if @filename is " " then the standard input is used
446 *
447 * Returns an I/O context or NULL in case of error
448 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000449static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000450xmlGzfileOpen (const char *filename) {
451 const char *path = NULL;
452 gzFile fd;
453
454 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000455 fd = gzdopen(dup(0), "rb");
Owen Taylor3473f882001-02-23 17:55:21 +0000456 return((void *) fd);
457 }
458
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000459 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost", 16))
Owen Taylor3473f882001-02-23 17:55:21 +0000460 path = &filename[16];
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000461 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard3c5ed912002-01-08 10:36:16 +0000462#if defined (_WIN32) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000463 path = &filename[8];
464#else
Owen Taylor3473f882001-02-23 17:55:21 +0000465 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000466#endif
467 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000468 path = filename;
469
470 if (path == NULL)
471 return(NULL);
472 if (!xmlCheckFilename(path))
473 return(NULL);
474
475 fd = gzopen(path, "rb");
476 return((void *) fd);
477}
478
479/**
480 * xmlGzfileOpenW:
481 * @filename: the URI for matching
482 * @compression: the compression factor (0 - 9 included)
483 *
484 * input from compressed file open
485 * if @filename is " " then the standard input is used
486 *
487 * Returns an I/O context or NULL in case of error
488 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000489static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000490xmlGzfileOpenW (const char *filename, int compression) {
491 const char *path = NULL;
492 char mode[15];
493 gzFile fd;
494
Aleksey Sanin49cc9752002-06-14 17:07:10 +0000495 snprintf(mode, sizeof(mode), "wb%d", compression);
Owen Taylor3473f882001-02-23 17:55:21 +0000496 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000497 fd = gzdopen(dup(1), mode);
Owen Taylor3473f882001-02-23 17:55:21 +0000498 return((void *) fd);
499 }
500
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000501 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost", 16))
Owen Taylor3473f882001-02-23 17:55:21 +0000502 path = &filename[16];
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000503 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard3c5ed912002-01-08 10:36:16 +0000504#if defined (_WIN32) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000505 path = &filename[8];
506#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000507 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000508#endif
509 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000510 path = filename;
511
512 if (path == NULL)
513 return(NULL);
514
515 fd = gzopen(path, mode);
516 return((void *) fd);
517}
518
519/**
520 * xmlGzfileRead:
521 * @context: the I/O context
522 * @buffer: where to drop data
523 * @len: number of bytes to write
524 *
525 * Read @len bytes to @buffer from the compressed I/O channel.
526 *
527 * Returns the number of bytes written
528 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000529static int
Owen Taylor3473f882001-02-23 17:55:21 +0000530xmlGzfileRead (void * context, char * buffer, int len) {
531 return(gzread((gzFile) context, &buffer[0], len));
532}
533
534/**
535 * xmlGzfileWrite:
536 * @context: the I/O context
537 * @buffer: where to drop data
538 * @len: number of bytes to write
539 *
540 * Write @len bytes from @buffer to the compressed I/O channel.
541 *
542 * Returns the number of bytes written
543 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000544static int
Owen Taylor3473f882001-02-23 17:55:21 +0000545xmlGzfileWrite (void * context, const char * buffer, int len) {
546 return(gzwrite((gzFile) context, (char *) &buffer[0], len));
547}
548
549/**
550 * xmlGzfileClose:
551 * @context: the I/O context
552 *
553 * Close a compressed I/O channel
554 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000555static int
Owen Taylor3473f882001-02-23 17:55:21 +0000556xmlGzfileClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +0000557 return ( ( gzclose((gzFile) context) == Z_OK ) ? 0 : -1 );
Owen Taylor3473f882001-02-23 17:55:21 +0000558}
559#endif /* HAVE_ZLIB_H */
560
561#ifdef LIBXML_HTTP_ENABLED
562/************************************************************************
563 * *
564 * I/O for HTTP file accesses *
565 * *
566 ************************************************************************/
Daniel Veillardf012a642001-07-23 19:10:52 +0000567
568typedef struct xmlIOHTTPWriteCtxt_
569{
570 int compression;
571
572 char * uri;
573
574 void * doc_buff;
575
576} xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr;
577
578#ifdef HAVE_ZLIB_H
579
580#define DFLT_WBITS ( -15 )
581#define DFLT_MEM_LVL ( 8 )
582#define GZ_MAGIC1 ( 0x1f )
583#define GZ_MAGIC2 ( 0x8b )
584#define LXML_ZLIB_OS_CODE ( 0x03 )
585#define INIT_HTTP_BUFF_SIZE ( 32768 )
586#define DFLT_ZLIB_RATIO ( 5 )
587
588/*
589** Data structure and functions to work with sending compressed data
590** via HTTP.
591*/
592
593typedef struct xmlZMemBuff_
594{
595 unsigned long size;
596 unsigned long crc;
597
598 unsigned char * zbuff;
599 z_stream zctrl;
600
601} xmlZMemBuff, *xmlZMemBuffPtr;
602
603/**
604 * append_reverse_ulong
605 * @buff: Compressed memory buffer
606 * @data: Unsigned long to append
607 *
608 * Append a unsigned long in reverse byte order to the end of the
609 * memory buffer.
610 */
611static void
612append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) {
613
614 int idx;
615
616 if ( buff == NULL )
617 return;
618
619 /*
620 ** This is plagiarized from putLong in gzio.c (zlib source) where
621 ** the number "4" is hardcoded. If zlib is ever patched to
622 ** support 64 bit file sizes, this code would need to be patched
623 ** as well.
624 */
625
626 for ( idx = 0; idx < 4; idx++ ) {
627 *buff->zctrl.next_out = ( data & 0xff );
628 data >>= 8;
629 buff->zctrl.next_out++;
630 }
631
632 return;
633}
634
635/**
636 *
637 * xmlFreeZMemBuff
638 * @buff: The memory buffer context to clear
639 *
640 * Release all the resources associated with the compressed memory buffer.
641 */
642static void
643xmlFreeZMemBuff( xmlZMemBuffPtr buff ) {
644
645 int z_err;
646
647 if ( buff == NULL )
648 return;
649
650 xmlFree( buff->zbuff );
651 z_err = deflateEnd( &buff->zctrl );
652#ifdef DEBUG_HTTP
653 if ( z_err != Z_OK )
654 xmlGenericError( xmlGenericErrorContext,
655 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
656 z_err );
657#endif
658
659 xmlFree( buff );
660 return;
661}
662
663/**
664 * xmlCreateZMemBuff
665 *@compression: Compression value to use
666 *
667 * Create a memory buffer to hold the compressed XML document. The
668 * compressed document in memory will end up being identical to what
669 * would be created if gzopen/gzwrite/gzclose were being used to
670 * write the document to disk. The code for the header/trailer data to
671 * the compression is plagiarized from the zlib source files.
672 */
673static void *
674xmlCreateZMemBuff( int compression ) {
675
676 int z_err;
677 int hdr_lgth;
678 xmlZMemBuffPtr buff = NULL;
679
680 if ( ( compression < 1 ) || ( compression > 9 ) )
681 return ( NULL );
682
683 /* Create the control and data areas */
684
685 buff = xmlMalloc( sizeof( xmlZMemBuff ) );
686 if ( buff == NULL ) {
687 xmlGenericError( xmlGenericErrorContext,
688 "xmlCreateZMemBuff: %s\n",
689 "Failure allocating buffer context." );
690 return ( NULL );
691 }
692
693 (void)memset( buff, 0, sizeof( xmlZMemBuff ) );
694 buff->size = INIT_HTTP_BUFF_SIZE;
695 buff->zbuff = xmlMalloc( buff->size );
696 if ( buff->zbuff == NULL ) {
697 xmlFreeZMemBuff( buff );
698 xmlGenericError( xmlGenericErrorContext,
699 "xmlCreateZMemBuff: %s\n",
700 "Failure allocating data buffer." );
701 return ( NULL );
702 }
703
704 z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
705 DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
706 if ( z_err != Z_OK ) {
707 xmlFreeZMemBuff( buff );
708 buff = NULL;
709 xmlGenericError( xmlGenericErrorContext,
710 "xmlCreateZMemBuff: %s %d\n",
711 "Error initializing compression context. ZLIB error:",
712 z_err );
713 return ( NULL );
714 }
715
716 /* Set the header data. The CRC will be needed for the trailer */
Daniel Veillardf012a642001-07-23 19:10:52 +0000717 buff->crc = crc32( 0L, Z_NULL, 0 );
Aleksey Sanin49cc9752002-06-14 17:07:10 +0000718 hdr_lgth = snprintf( (char *)buff->zbuff, buff->size,
719 "%c%c%c%c%c%c%c%c%c%c",
Daniel Veillardf012a642001-07-23 19:10:52 +0000720 GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED,
721 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE );
722 buff->zctrl.next_out = buff->zbuff + hdr_lgth;
723 buff->zctrl.avail_out = buff->size - hdr_lgth;
724
725 return ( buff );
726}
727
728/**
729 * xmlZMemBuffExtend
730 * @buff: Buffer used to compress and consolidate data.
731 * @ext_amt: Number of bytes to extend the buffer.
732 *
733 * Extend the internal buffer used to store the compressed data by the
734 * specified amount.
735 *
736 * Returns 0 on success or -1 on failure to extend the buffer. On failure
737 * the original buffer still exists at the original size.
738 */
739static int
740xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) {
741
742 int rc = -1;
743 size_t new_size;
744 size_t cur_used;
745
746 unsigned char * tmp_ptr = NULL;
747
748 if ( buff == NULL )
749 return ( -1 );
750
751 else if ( ext_amt == 0 )
752 return ( 0 );
753
754 cur_used = buff->zctrl.next_out - buff->zbuff;
755 new_size = buff->size + ext_amt;
756
757#ifdef DEBUG_HTTP
758 if ( cur_used > new_size )
759 xmlGenericError( xmlGenericErrorContext,
760 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
761 "Buffer overwrite detected during compressed memory",
762 "buffer extension. Overflowed by",
763 (cur_used - new_size ) );
764#endif
765
766 tmp_ptr = xmlRealloc( buff->zbuff, new_size );
767 if ( tmp_ptr != NULL ) {
768 rc = 0;
769 buff->size = new_size;
770 buff->zbuff = tmp_ptr;
771 buff->zctrl.next_out = tmp_ptr + cur_used;
772 buff->zctrl.avail_out = new_size - cur_used;
773 }
774 else {
775 xmlGenericError( xmlGenericErrorContext,
776 "xmlZMemBuffExtend: %s %lu bytes.\n",
777 "Allocation failure extending output buffer to",
778 new_size );
779 }
780
781 return ( rc );
782}
783
784/**
785 * xmlZMemBuffAppend
786 * @buff: Buffer used to compress and consolidate data
787 * @src: Uncompressed source content to append to buffer
788 * @len: Length of source data to append to buffer
789 *
790 * Compress and append data to the internal buffer. The data buffer
791 * will be expanded if needed to store the additional data.
792 *
793 * Returns the number of bytes appended to the buffer or -1 on error.
794 */
795static int
796xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) {
797
798 int z_err;
799 size_t min_accept;
800
801 if ( ( buff == NULL ) || ( src == NULL ) )
802 return ( -1 );
803
804 buff->zctrl.avail_in = len;
805 buff->zctrl.next_in = (unsigned char *)src;
806 while ( buff->zctrl.avail_in > 0 ) {
807 /*
808 ** Extend the buffer prior to deflate call if a reasonable amount
809 ** of output buffer space is not available.
810 */
811 min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO;
812 if ( buff->zctrl.avail_out <= min_accept ) {
813 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
814 return ( -1 );
815 }
816
817 z_err = deflate( &buff->zctrl, Z_NO_FLUSH );
818 if ( z_err != Z_OK ) {
819 xmlGenericError( xmlGenericErrorContext,
820 "xmlZMemBuffAppend: %s %d %s - %d",
821 "Compression error while appending",
822 len, "bytes to buffer. ZLIB error", z_err );
823 return ( -1 );
824 }
825 }
826
827 buff->crc = crc32( buff->crc, (unsigned char *)src, len );
828
829 return ( len );
830}
831
832/**
833 * xmlZMemBuffGetContent
834 * @buff: Compressed memory content buffer
835 * @data_ref: Pointer reference to point to compressed content
836 *
837 * Flushes the compression buffers, appends gzip file trailers and
838 * returns the compressed content and length of the compressed data.
839 * NOTE: The gzip trailer code here is plagiarized from zlib source.
840 *
841 * Returns the length of the compressed data or -1 on error.
842 */
843static int
844xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) {
845
846 int zlgth = -1;
847 int z_err;
848
849 if ( ( buff == NULL ) || ( data_ref == NULL ) )
850 return ( -1 );
851
852 /* Need to loop until compression output buffers are flushed */
853
854 do
855 {
856 z_err = deflate( &buff->zctrl, Z_FINISH );
857 if ( z_err == Z_OK ) {
858 /* In this case Z_OK means more buffer space needed */
859
860 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
861 return ( -1 );
862 }
863 }
864 while ( z_err == Z_OK );
865
866 /* If the compression state is not Z_STREAM_END, some error occurred */
867
868 if ( z_err == Z_STREAM_END ) {
869
870 /* Need to append the gzip data trailer */
871
872 if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) {
873 if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 )
874 return ( -1 );
875 }
876
877 /*
878 ** For whatever reason, the CRC and length data are pushed out
879 ** in reverse byte order. So a memcpy can't be used here.
880 */
881
882 append_reverse_ulong( buff, buff->crc );
883 append_reverse_ulong( buff, buff->zctrl.total_in );
884
885 zlgth = buff->zctrl.next_out - buff->zbuff;
886 *data_ref = (char *)buff->zbuff;
887 }
888
889 else
890 xmlGenericError( xmlGenericErrorContext,
891 "xmlZMemBuffGetContent: %s - %d\n",
892 "Error flushing zlib buffers. Error code", z_err );
893
894 return ( zlgth );
895}
896#endif /* HAVE_ZLIB_H */
897
898/**
899 * xmlFreeHTTPWriteCtxt
900 * @ctxt: Context to cleanup
901 *
902 * Free allocated memory and reclaim system resources.
903 *
904 * No return value.
905 */
906static void
907xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt )
908{
909 if ( ctxt->uri != NULL )
910 free( ctxt->uri );
911
912 if ( ctxt->doc_buff != NULL ) {
913
914#ifdef HAVE_ZLIB_H
915 if ( ctxt->compression > 0 ) {
916 xmlFreeZMemBuff( ctxt->doc_buff );
917 }
918 else
919#endif
920 {
921 xmlOutputBufferClose( ctxt->doc_buff );
922 }
923 }
924
925 free( ctxt );
926 return;
927}
928
929
Owen Taylor3473f882001-02-23 17:55:21 +0000930/**
931 * xmlIOHTTPMatch:
932 * @filename: the URI for matching
933 *
934 * check if the URI matches an HTTP one
935 *
936 * Returns 1 if matches, 0 otherwise
937 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000938int
Owen Taylor3473f882001-02-23 17:55:21 +0000939xmlIOHTTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000940 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "http://", 7))
Owen Taylor3473f882001-02-23 17:55:21 +0000941 return(1);
942 return(0);
943}
944
945/**
946 * xmlIOHTTPOpen:
947 * @filename: the URI for matching
948 *
949 * open an HTTP I/O channel
950 *
951 * Returns an I/O context or NULL in case of error
952 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000953void *
Owen Taylor3473f882001-02-23 17:55:21 +0000954xmlIOHTTPOpen (const char *filename) {
955 return(xmlNanoHTTPOpen(filename, NULL));
956}
957
958/**
Daniel Veillardf012a642001-07-23 19:10:52 +0000959 * xmlIOHTTPOpenW
960 * @post_uri: The destination URI for the document
961 * @compression: The compression desired for the document.
962 *
963 * Open a temporary buffer to collect the document for a subsequent HTTP POST
964 * request. Non-static as is called from the output buffer creation routine.
965 *
966 * Returns an I/O context or NULL in case of error.
967 */
968
969void *
Daniel Veillard572577e2002-01-18 16:23:55 +0000970xmlIOHTTPOpenW(const char *post_uri, int compression)
971{
Daniel Veillardf012a642001-07-23 19:10:52 +0000972
Daniel Veillard572577e2002-01-18 16:23:55 +0000973 xmlIOHTTPWriteCtxtPtr ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +0000974
Daniel Veillard572577e2002-01-18 16:23:55 +0000975 if (post_uri == NULL)
976 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +0000977
Daniel Veillard572577e2002-01-18 16:23:55 +0000978 ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt));
979 if (ctxt == NULL) {
980 xmlGenericError(xmlGenericErrorContext,
981 "xmlIOHTTPOpenW: Failed to create output HTTP context.\n");
982 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +0000983 }
984
Daniel Veillard572577e2002-01-18 16:23:55 +0000985 (void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt));
Daniel Veillardf012a642001-07-23 19:10:52 +0000986
Daniel Veillard572577e2002-01-18 16:23:55 +0000987 ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri);
988 if (ctxt->uri == NULL) {
989 xmlGenericError(xmlGenericErrorContext,
990 "xmlIOHTTPOpenW: Failed to duplicate destination URI.\n");
991 xmlFreeHTTPWriteCtxt(ctxt);
992 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +0000993 }
994
995 /*
Daniel Veillard572577e2002-01-18 16:23:55 +0000996 * ** Since the document length is required for an HTTP post,
997 * ** need to put the document into a buffer. A memory buffer
998 * ** is being used to avoid pushing the data to disk and back.
999 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001000
1001#ifdef HAVE_ZLIB_H
Daniel Veillard572577e2002-01-18 16:23:55 +00001002 if ((compression > 0) && (compression <= 9)) {
1003
1004 ctxt->compression = compression;
1005 ctxt->doc_buff = xmlCreateZMemBuff(compression);
1006 } else
Daniel Veillardf012a642001-07-23 19:10:52 +00001007#endif
1008 {
Daniel Veillard572577e2002-01-18 16:23:55 +00001009 /* Any character conversions should have been done before this */
Daniel Veillardf012a642001-07-23 19:10:52 +00001010
Daniel Veillard572577e2002-01-18 16:23:55 +00001011 ctxt->doc_buff = xmlAllocOutputBuffer(NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001012 }
1013
Daniel Veillard572577e2002-01-18 16:23:55 +00001014 if (ctxt->doc_buff == NULL) {
1015 xmlFreeHTTPWriteCtxt(ctxt);
1016 ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001017 }
1018
Daniel Veillard572577e2002-01-18 16:23:55 +00001019 return (ctxt);
Daniel Veillardf012a642001-07-23 19:10:52 +00001020}
1021
1022/**
1023 * xmlIOHTTPDfltOpenW
1024 * @post_uri: The destination URI for this document.
1025 *
1026 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
1027 * HTTP post command. This function should generally not be used as
1028 * the open callback is short circuited in xmlOutputBufferCreateFile.
1029 *
1030 * Returns a pointer to the new IO context.
1031 */
1032static void *
1033xmlIOHTTPDfltOpenW( const char * post_uri ) {
1034 return ( xmlIOHTTPOpenW( post_uri, 0 ) );
1035}
1036
1037/**
Owen Taylor3473f882001-02-23 17:55:21 +00001038 * xmlIOHTTPRead:
1039 * @context: the I/O context
1040 * @buffer: where to drop data
1041 * @len: number of bytes to write
1042 *
1043 * Read @len bytes to @buffer from the I/O channel.
1044 *
1045 * Returns the number of bytes written
1046 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001047int
Owen Taylor3473f882001-02-23 17:55:21 +00001048xmlIOHTTPRead(void * context, char * buffer, int len) {
1049 return(xmlNanoHTTPRead(context, &buffer[0], len));
1050}
1051
1052/**
Daniel Veillardf012a642001-07-23 19:10:52 +00001053 * xmlIOHTTPWrite
1054 * @context: previously opened writing context
1055 * @buffer: data to output to temporary buffer
1056 * @len: bytes to output
1057 *
1058 * Collect data from memory buffer into a temporary file for later
1059 * processing.
1060 *
1061 * Returns number of bytes written.
1062 */
1063
1064static int
1065xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
1066
1067 xmlIOHTTPWriteCtxtPtr ctxt = context;
1068
1069 if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
1070 return ( -1 );
1071
1072 if ( len > 0 ) {
1073
1074 /* Use gzwrite or fwrite as previously setup in the open call */
1075
1076#ifdef HAVE_ZLIB_H
1077 if ( ctxt->compression > 0 )
1078 len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len );
1079
1080 else
1081#endif
1082 len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
1083
1084 if ( len < 0 ) {
1085 xmlGenericError( xmlGenericErrorContext,
1086 "xmlIOHTTPWrite: %s\n%s '%s'.\n",
1087 "Error appending to internal buffer.",
1088 "Error sending document to URI",
1089 ctxt->uri );
1090 }
1091 }
1092
1093 return ( len );
1094}
1095
1096
1097/**
Owen Taylor3473f882001-02-23 17:55:21 +00001098 * xmlIOHTTPClose:
1099 * @context: the I/O context
1100 *
1101 * Close an HTTP I/O channel
1102 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001103int
Owen Taylor3473f882001-02-23 17:55:21 +00001104xmlIOHTTPClose (void * context) {
1105 xmlNanoHTTPClose(context);
Daniel Veillardf012a642001-07-23 19:10:52 +00001106 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001107}
Daniel Veillardf012a642001-07-23 19:10:52 +00001108
1109/**
1110 * xmlIOHTTCloseWrite
1111 * @context: The I/O context
1112 * @http_mthd: The HTTP method to be used when sending the data
1113 *
1114 * Close the transmit HTTP I/O channel and actually send the data.
1115 */
1116static int
1117xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
1118
1119 int close_rc = -1;
1120 int http_rtn = 0;
1121 int content_lgth = 0;
1122 xmlIOHTTPWriteCtxtPtr ctxt = context;
1123
1124 char * http_content = NULL;
1125 char * content_encoding = NULL;
1126 char * content_type = (char *) "text/xml";
1127 void * http_ctxt = NULL;
1128
1129 if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
1130 return ( -1 );
1131
1132 /* Retrieve the content from the appropriate buffer */
1133
1134#ifdef HAVE_ZLIB_H
1135
1136 if ( ctxt->compression > 0 ) {
1137 content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
1138 content_encoding = (char *) "Content-Encoding: gzip";
1139 }
1140 else
1141#endif
1142 {
1143 /* Pull the data out of the memory output buffer */
1144
1145 xmlOutputBufferPtr dctxt = ctxt->doc_buff;
1146 http_content = (char *)dctxt->buffer->content;
1147 content_lgth = dctxt->buffer->use;
1148 }
1149
1150 if ( http_content == NULL ) {
1151 xmlGenericError( xmlGenericErrorContext,
1152 "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
1153 "Error retrieving content.\nUnable to",
1154 http_mthd, "data to URI", ctxt->uri );
1155 }
1156
1157 else {
1158
1159 http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
1160 &content_type, content_encoding,
1161 content_lgth );
1162
1163 if ( http_ctxt != NULL ) {
1164#ifdef DEBUG_HTTP
1165 /* If testing/debugging - dump reply with request content */
1166
1167 FILE * tst_file = NULL;
1168 char buffer[ 4096 ];
1169 char * dump_name = NULL;
1170 int avail;
1171
1172 xmlGenericError( xmlGenericErrorContext,
1173 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
1174 http_mthd, ctxt->uri,
1175 xmlNanoHTTPReturnCode( http_ctxt ) );
1176
1177 /*
1178 ** Since either content or reply may be gzipped,
1179 ** dump them to separate files instead of the
1180 ** standard error context.
1181 */
1182
1183 dump_name = tempnam( NULL, "lxml" );
1184 if ( dump_name != NULL ) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001185 (void)snprintf( buffer, sizeof(buffer), "%s.content", dump_name );
Daniel Veillardf012a642001-07-23 19:10:52 +00001186
1187 tst_file = fopen( buffer, "w" );
1188 if ( tst_file != NULL ) {
1189 xmlGenericError( xmlGenericErrorContext,
1190 "Transmitted content saved in file: %s\n", buffer );
1191
1192 fwrite( http_content, sizeof( char ),
1193 content_lgth, tst_file );
1194 fclose( tst_file );
1195 }
1196
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001197 (void)snprintf( buffer, sizeof(buffer), "%s.reply", dump_name );
Daniel Veillardf012a642001-07-23 19:10:52 +00001198 tst_file = fopen( buffer, "w" );
1199 if ( tst_file != NULL ) {
1200 xmlGenericError( xmlGenericErrorContext,
1201 "Reply content saved in file: %s\n", buffer );
1202
1203
1204 while ( (avail = xmlNanoHTTPRead( http_ctxt,
1205 buffer, sizeof( buffer ) )) > 0 ) {
1206
1207 fwrite( buffer, sizeof( char ), avail, tst_file );
1208 }
1209
1210 fclose( tst_file );
1211 }
1212
1213 free( dump_name );
1214 }
1215#endif /* DEBUG_HTTP */
1216
1217 http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
1218 if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
1219 close_rc = 0;
1220 else
1221 xmlGenericError( xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001222 "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001223 http_mthd, content_lgth,
1224 "bytes to URI", ctxt->uri,
1225 "failed. HTTP return code:", http_rtn );
1226
1227 xmlNanoHTTPClose( http_ctxt );
1228 xmlFree( content_type );
1229 }
1230 }
1231
1232 /* Final cleanups */
1233
1234 xmlFreeHTTPWriteCtxt( ctxt );
1235
1236 return ( close_rc );
1237}
1238
1239/**
1240 * xmlIOHTTPClosePut
1241 *
1242 * @context: The I/O context
1243 *
1244 * Close the transmit HTTP I/O channel and actually send data using a PUT
1245 * HTTP method.
1246 */
1247static int
1248xmlIOHTTPClosePut( void * ctxt ) {
1249 return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
1250}
1251
1252
1253/**
1254 * xmlIOHTTPClosePost
1255 *
1256 * @context: The I/O context
1257 *
1258 * Close the transmit HTTP I/O channel and actually send data using a POST
1259 * HTTP method.
1260 */
1261static int
1262xmlIOHTTPClosePost( void * ctxt ) {
1263 return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
1264}
1265
Owen Taylor3473f882001-02-23 17:55:21 +00001266#endif /* LIBXML_HTTP_ENABLED */
1267
1268#ifdef LIBXML_FTP_ENABLED
1269/************************************************************************
1270 * *
1271 * I/O for FTP file accesses *
1272 * *
1273 ************************************************************************/
1274/**
1275 * xmlIOFTPMatch:
1276 * @filename: the URI for matching
1277 *
1278 * check if the URI matches an FTP one
1279 *
1280 * Returns 1 if matches, 0 otherwise
1281 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001282int
Owen Taylor3473f882001-02-23 17:55:21 +00001283xmlIOFTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001284 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "ftp://", 6))
Owen Taylor3473f882001-02-23 17:55:21 +00001285 return(1);
1286 return(0);
1287}
1288
1289/**
1290 * xmlIOFTPOpen:
1291 * @filename: the URI for matching
1292 *
1293 * open an FTP I/O channel
1294 *
1295 * Returns an I/O context or NULL in case of error
1296 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001297void *
Owen Taylor3473f882001-02-23 17:55:21 +00001298xmlIOFTPOpen (const char *filename) {
1299 return(xmlNanoFTPOpen(filename));
1300}
1301
1302/**
1303 * xmlIOFTPRead:
1304 * @context: the I/O context
1305 * @buffer: where to drop data
1306 * @len: number of bytes to write
1307 *
1308 * Read @len bytes to @buffer from the I/O channel.
1309 *
1310 * Returns the number of bytes written
1311 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001312int
Owen Taylor3473f882001-02-23 17:55:21 +00001313xmlIOFTPRead(void * context, char * buffer, int len) {
1314 return(xmlNanoFTPRead(context, &buffer[0], len));
1315}
1316
1317/**
1318 * xmlIOFTPClose:
1319 * @context: the I/O context
1320 *
1321 * Close an FTP I/O channel
1322 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001323int
Owen Taylor3473f882001-02-23 17:55:21 +00001324xmlIOFTPClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001325 return ( xmlNanoFTPClose(context) );
Owen Taylor3473f882001-02-23 17:55:21 +00001326}
1327#endif /* LIBXML_FTP_ENABLED */
1328
1329
1330/**
1331 * xmlRegisterInputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001332 * @matchFunc: the xmlInputMatchCallback
1333 * @openFunc: the xmlInputOpenCallback
1334 * @readFunc: the xmlInputReadCallback
1335 * @closeFunc: the xmlInputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001336 *
1337 * Register a new set of I/O callback for handling parser input.
1338 *
1339 * Returns the registered handler number or -1 in case of error
1340 */
1341int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001342xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
1343 xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
1344 xmlInputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001345 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
1346 return(-1);
1347 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001348 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
1349 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
1350 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
1351 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
Owen Taylor3473f882001-02-23 17:55:21 +00001352 return(xmlInputCallbackNr++);
1353}
1354
1355/**
1356 * xmlRegisterOutputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001357 * @matchFunc: the xmlOutputMatchCallback
1358 * @openFunc: the xmlOutputOpenCallback
1359 * @writeFunc: the xmlOutputWriteCallback
1360 * @closeFunc: the xmlOutputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001361 *
1362 * Register a new set of I/O callback for handling output.
1363 *
1364 * Returns the registered handler number or -1 in case of error
1365 */
1366int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001367xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
1368 xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
1369 xmlOutputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001370 if (xmlOutputCallbackNr >= MAX_INPUT_CALLBACK) {
1371 return(-1);
1372 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001373 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
1374 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
1375 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
1376 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
Owen Taylor3473f882001-02-23 17:55:21 +00001377 return(xmlOutputCallbackNr++);
1378}
1379
1380/**
1381 * xmlRegisterDefaultInputCallbacks:
1382 *
1383 * Registers the default compiled-in I/O handlers.
1384 */
1385void
1386#ifdef VMS
1387xmlRegisterDefInputCallbacks
1388#else
1389xmlRegisterDefaultInputCallbacks
1390#endif
1391(void) {
1392 if (xmlInputCallbackInitialized)
1393 return;
1394
1395 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
1396 xmlFileRead, xmlFileClose);
1397#ifdef HAVE_ZLIB_H
1398 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1399 xmlGzfileRead, xmlGzfileClose);
1400#endif /* HAVE_ZLIB_H */
1401
1402#ifdef LIBXML_HTTP_ENABLED
1403 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
1404 xmlIOHTTPRead, xmlIOHTTPClose);
1405#endif /* LIBXML_HTTP_ENABLED */
1406
1407#ifdef LIBXML_FTP_ENABLED
1408 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1409 xmlIOFTPRead, xmlIOFTPClose);
1410#endif /* LIBXML_FTP_ENABLED */
1411 xmlInputCallbackInitialized = 1;
1412}
1413
1414/**
1415 * xmlRegisterDefaultOutputCallbacks:
1416 *
1417 * Registers the default compiled-in I/O handlers.
1418 */
1419void
1420#ifdef VMS
1421xmlRegisterDefOutputCallbacks
1422#else
1423xmlRegisterDefaultOutputCallbacks
1424#endif
1425(void) {
1426 if (xmlOutputCallbackInitialized)
1427 return;
1428
1429 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
1430 xmlFileWrite, xmlFileClose);
Daniel Veillardf012a642001-07-23 19:10:52 +00001431
1432#ifdef LIBXML_HTTP_ENABLED
1433 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
1434 xmlIOHTTPWrite, xmlIOHTTPClosePut);
1435#endif
1436
Owen Taylor3473f882001-02-23 17:55:21 +00001437/*********************************
1438 No way a-priori to distinguish between gzipped files from
1439 uncompressed ones except opening if existing then closing
1440 and saving with same compression ratio ... a pain.
1441
1442#ifdef HAVE_ZLIB_H
1443 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1444 xmlGzfileWrite, xmlGzfileClose);
1445#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001446
1447 Nor FTP PUT ....
1448#ifdef LIBXML_FTP_ENABLED
1449 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1450 xmlIOFTPWrite, xmlIOFTPClose);
1451#endif
1452 **********************************/
1453 xmlOutputCallbackInitialized = 1;
1454}
1455
Daniel Veillardf012a642001-07-23 19:10:52 +00001456#ifdef LIBXML_HTTP_ENABLED
1457/**
1458 * xmlRegisterHTTPPostCallbacks
1459 *
1460 * By default, libxml submits HTTP output requests using the "PUT" method.
1461 * Calling this method changes the HTTP output method to use the "POST"
1462 * method instead.
1463 *
1464 */
1465void
1466xmlRegisterHTTPPostCallbacks( void ) {
1467
1468 /* Register defaults if not done previously */
1469
1470 if ( xmlOutputCallbackInitialized == 0 )
1471 xmlRegisterDefaultOutputCallbacks( );
1472
1473 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
1474 xmlIOHTTPWrite, xmlIOHTTPClosePost);
1475 return;
1476}
1477#endif
1478
Owen Taylor3473f882001-02-23 17:55:21 +00001479/**
1480 * xmlAllocParserInputBuffer:
1481 * @enc: the charset encoding if known
1482 *
1483 * Create a buffered parser input for progressive parsing
1484 *
1485 * Returns the new parser input or NULL
1486 */
1487xmlParserInputBufferPtr
1488xmlAllocParserInputBuffer(xmlCharEncoding enc) {
1489 xmlParserInputBufferPtr ret;
1490
1491 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
1492 if (ret == NULL) {
1493 xmlGenericError(xmlGenericErrorContext,
1494 "xmlAllocParserInputBuffer : out of memory!\n");
1495 return(NULL);
1496 }
1497 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
1498 ret->buffer = xmlBufferCreate();
1499 if (ret->buffer == NULL) {
1500 xmlFree(ret);
1501 return(NULL);
1502 }
1503 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
1504 ret->encoder = xmlGetCharEncodingHandler(enc);
1505 if (ret->encoder != NULL)
1506 ret->raw = xmlBufferCreate();
1507 else
1508 ret->raw = NULL;
1509 ret->readcallback = NULL;
1510 ret->closecallback = NULL;
1511 ret->context = NULL;
1512
1513 return(ret);
1514}
1515
1516/**
1517 * xmlAllocOutputBuffer:
1518 * @encoder: the encoding converter or NULL
1519 *
1520 * Create a buffered parser output
1521 *
1522 * Returns the new parser output or NULL
1523 */
1524xmlOutputBufferPtr
1525xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
1526 xmlOutputBufferPtr ret;
1527
1528 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
1529 if (ret == NULL) {
1530 xmlGenericError(xmlGenericErrorContext,
1531 "xmlAllocOutputBuffer : out of memory!\n");
1532 return(NULL);
1533 }
1534 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
1535 ret->buffer = xmlBufferCreate();
1536 if (ret->buffer == NULL) {
1537 xmlFree(ret);
1538 return(NULL);
1539 }
1540 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
1541 ret->encoder = encoder;
1542 if (encoder != NULL) {
1543 ret->conv = xmlBufferCreateSize(4000);
1544 /*
1545 * This call is designed to initiate the encoder state
1546 */
1547 xmlCharEncOutFunc(encoder, ret->conv, NULL);
1548 } else
1549 ret->conv = NULL;
1550 ret->writecallback = NULL;
1551 ret->closecallback = NULL;
1552 ret->context = NULL;
1553 ret->written = 0;
1554
1555 return(ret);
1556}
1557
1558/**
1559 * xmlFreeParserInputBuffer:
1560 * @in: a buffered parser input
1561 *
1562 * Free up the memory used by a buffered parser input
1563 */
1564void
1565xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
1566 if (in->raw) {
1567 xmlBufferFree(in->raw);
1568 in->raw = NULL;
1569 }
1570 if (in->encoder != NULL) {
1571 xmlCharEncCloseFunc(in->encoder);
1572 }
1573 if (in->closecallback != NULL) {
1574 in->closecallback(in->context);
1575 }
1576 if (in->buffer != NULL) {
1577 xmlBufferFree(in->buffer);
1578 in->buffer = NULL;
1579 }
1580
Owen Taylor3473f882001-02-23 17:55:21 +00001581 xmlFree(in);
1582}
1583
1584/**
1585 * xmlOutputBufferClose:
1586 * @out: a buffered output
1587 *
1588 * flushes and close the output I/O channel
1589 * and free up all the associated resources
1590 *
1591 * Returns the number of byte written or -1 in case of error.
1592 */
1593int
1594xmlOutputBufferClose(xmlOutputBufferPtr out) {
1595 int written;
Daniel Veillardf012a642001-07-23 19:10:52 +00001596 int err_rc = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001597
1598 if (out == NULL)
1599 return(-1);
1600 if (out->writecallback != NULL)
1601 xmlOutputBufferFlush(out);
1602 if (out->closecallback != NULL) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001603 err_rc = out->closecallback(out->context);
Owen Taylor3473f882001-02-23 17:55:21 +00001604 }
1605 written = out->written;
1606 if (out->conv) {
1607 xmlBufferFree(out->conv);
1608 out->conv = NULL;
1609 }
1610 if (out->encoder != NULL) {
1611 xmlCharEncCloseFunc(out->encoder);
1612 }
1613 if (out->buffer != NULL) {
1614 xmlBufferFree(out->buffer);
1615 out->buffer = NULL;
1616 }
1617
Owen Taylor3473f882001-02-23 17:55:21 +00001618 xmlFree(out);
Daniel Veillardf012a642001-07-23 19:10:52 +00001619 return( ( err_rc == 0 ) ? written : err_rc );
Owen Taylor3473f882001-02-23 17:55:21 +00001620}
1621
1622/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001623 * xmlParserInputBufferCreateFname:
1624 * @URI: a C string containing the URI or filename
1625 * @enc: the charset encoding if known
1626 *
1627 * VMS version of xmlParserInputBufferCreateFilename()
1628 *
1629 * Returns the new parser input or NULL
1630 */
1631/**
Owen Taylor3473f882001-02-23 17:55:21 +00001632 * xmlParserInputBufferCreateFilename:
1633 * @URI: a C string containing the URI or filename
1634 * @enc: the charset encoding if known
1635 *
1636 * Create a buffered parser input for the progressive parsing of a file
1637 * If filename is "-' then we use stdin as the input.
1638 * Automatic support for ZLIB/Compress compressed document is provided
1639 * by default if found at compile-time.
1640 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
1641 *
1642 * Returns the new parser input or NULL
1643 */
1644xmlParserInputBufferPtr
1645#ifdef VMS
1646xmlParserInputBufferCreateFname
1647#else
1648xmlParserInputBufferCreateFilename
1649#endif
1650(const char *URI, xmlCharEncoding enc) {
1651 xmlParserInputBufferPtr ret;
Daniel Veillard388236f2001-07-08 18:35:48 +00001652 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001653 void *context = NULL;
Daniel Veillard388236f2001-07-08 18:35:48 +00001654 char *unescaped;
Owen Taylor3473f882001-02-23 17:55:21 +00001655
1656 if (xmlInputCallbackInitialized == 0)
1657 xmlRegisterDefaultInputCallbacks();
1658
1659 if (URI == NULL) return(NULL);
1660
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001661#ifdef LIBXML_CATALOG_ENABLED
1662#endif
1663
Owen Taylor3473f882001-02-23 17:55:21 +00001664 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001665 * Try to find one of the input accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00001666 * Go in reverse to give precedence to user defined handlers.
Daniel Veillard388236f2001-07-08 18:35:48 +00001667 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00001668 */
Daniel Veillard388236f2001-07-08 18:35:48 +00001669 unescaped = xmlURIUnescapeString(URI, 0, NULL);
1670 if (unescaped != NULL) {
1671 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
1672 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
1673 (xmlInputCallbackTable[i].matchcallback(unescaped) != 0)) {
1674 context = xmlInputCallbackTable[i].opencallback(unescaped);
1675 if (context != NULL)
1676 break;
1677 }
1678 }
1679 xmlFree(unescaped);
1680 }
1681
1682 /*
1683 * If this failed try with a non-escaped URI this may be a strange
1684 * filename
1685 */
1686 if (context == NULL) {
1687 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
1688 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
1689 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
1690 context = xmlInputCallbackTable[i].opencallback(URI);
1691 if (context != NULL)
1692 break;
1693 }
Owen Taylor3473f882001-02-23 17:55:21 +00001694 }
1695 }
1696 if (context == NULL) {
1697 return(NULL);
1698 }
1699
1700 /*
1701 * Allocate the Input buffer front-end.
1702 */
1703 ret = xmlAllocParserInputBuffer(enc);
1704 if (ret != NULL) {
1705 ret->context = context;
1706 ret->readcallback = xmlInputCallbackTable[i].readcallback;
1707 ret->closecallback = xmlInputCallbackTable[i].closecallback;
1708 }
1709 return(ret);
1710}
1711
1712/**
1713 * xmlOutputBufferCreateFilename:
1714 * @URI: a C string containing the URI or filename
1715 * @encoder: the encoding converter or NULL
1716 * @compression: the compression ration (0 none, 9 max).
1717 *
1718 * Create a buffered output for the progressive saving of a file
1719 * If filename is "-' then we use stdout as the output.
1720 * Automatic support for ZLIB/Compress compressed document is provided
1721 * by default if found at compile-time.
1722 * TODO: currently if compression is set, the library only support
1723 * writing to a local file.
1724 *
1725 * Returns the new output or NULL
1726 */
1727xmlOutputBufferPtr
1728xmlOutputBufferCreateFilename(const char *URI,
1729 xmlCharEncodingHandlerPtr encoder,
1730 int compression) {
1731 xmlOutputBufferPtr ret;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001732 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001733 void *context = NULL;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001734 char *unescaped;
Owen Taylor3473f882001-02-23 17:55:21 +00001735
Daniel Veillardf012a642001-07-23 19:10:52 +00001736 int is_http_uri = 0; /* Can't change if HTTP disabled */
1737
Owen Taylor3473f882001-02-23 17:55:21 +00001738 if (xmlOutputCallbackInitialized == 0)
1739 xmlRegisterDefaultOutputCallbacks();
1740
1741 if (URI == NULL) return(NULL);
1742
Daniel Veillardf012a642001-07-23 19:10:52 +00001743#ifdef LIBXML_HTTP_ENABLED
1744 /* Need to prevent HTTP URI's from falling into zlib short circuit */
1745
1746 is_http_uri = xmlIOHTTPMatch( URI );
1747#endif
1748
Owen Taylor3473f882001-02-23 17:55:21 +00001749
1750 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001751 * Try to find one of the output accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00001752 * Go in reverse to give precedence to user defined handlers.
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001753 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00001754 */
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001755 unescaped = xmlURIUnescapeString(URI, 0, NULL);
1756 if (unescaped != NULL) {
1757#ifdef HAVE_ZLIB_H
1758 if ((compression > 0) && (compression <= 9) && (is_http_uri == 0)) {
1759 context = xmlGzfileOpenW(unescaped, compression);
1760 if (context != NULL) {
1761 ret = xmlAllocOutputBuffer(encoder);
1762 if (ret != NULL) {
1763 ret->context = context;
1764 ret->writecallback = xmlGzfileWrite;
1765 ret->closecallback = xmlGzfileClose;
1766 }
1767 xmlFree(unescaped);
1768 return(ret);
1769 }
1770 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001771#endif
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001772 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
1773 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
1774 (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
1775#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
1776 /* Need to pass compression parameter into HTTP open calls */
1777 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
1778 context = xmlIOHTTPOpenW(unescaped, compression);
1779 else
1780#endif
1781 context = xmlOutputCallbackTable[i].opencallback(unescaped);
1782 if (context != NULL)
1783 break;
1784 }
1785 }
1786 xmlFree(unescaped);
1787 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001788
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001789 /*
1790 * If this failed try with a non-escaped URI this may be a strange
1791 * filename
1792 */
1793 if (context == NULL) {
1794#ifdef HAVE_ZLIB_H
1795 if ((compression > 0) && (compression <= 9) && (is_http_uri == 0)) {
1796 context = xmlGzfileOpenW(URI, compression);
1797 if (context != NULL) {
1798 ret = xmlAllocOutputBuffer(encoder);
1799 if (ret != NULL) {
1800 ret->context = context;
1801 ret->writecallback = xmlGzfileWrite;
1802 ret->closecallback = xmlGzfileClose;
1803 }
1804 return(ret);
1805 }
1806 }
1807#endif
1808 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
1809 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
1810 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001811#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
1812 /* Need to pass compression parameter into HTTP open calls */
1813 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
1814 context = xmlIOHTTPOpenW(URI, compression);
1815 else
1816#endif
1817 context = xmlOutputCallbackTable[i].opencallback(URI);
1818 if (context != NULL)
1819 break;
1820 }
Owen Taylor3473f882001-02-23 17:55:21 +00001821 }
1822 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001823
Owen Taylor3473f882001-02-23 17:55:21 +00001824 if (context == NULL) {
1825 return(NULL);
1826 }
1827
1828 /*
1829 * Allocate the Output buffer front-end.
1830 */
1831 ret = xmlAllocOutputBuffer(encoder);
1832 if (ret != NULL) {
1833 ret->context = context;
1834 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
1835 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
1836 }
1837 return(ret);
1838}
1839
1840/**
1841 * xmlParserInputBufferCreateFile:
1842 * @file: a FILE*
1843 * @enc: the charset encoding if known
1844 *
1845 * Create a buffered parser input for the progressive parsing of a FILE *
1846 * buffered C I/O
1847 *
1848 * Returns the new parser input or NULL
1849 */
1850xmlParserInputBufferPtr
1851xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
1852 xmlParserInputBufferPtr ret;
1853
1854 if (xmlInputCallbackInitialized == 0)
1855 xmlRegisterDefaultInputCallbacks();
1856
1857 if (file == NULL) return(NULL);
1858
1859 ret = xmlAllocParserInputBuffer(enc);
1860 if (ret != NULL) {
1861 ret->context = file;
1862 ret->readcallback = xmlFileRead;
1863 ret->closecallback = xmlFileFlush;
1864 }
1865
1866 return(ret);
1867}
1868
1869/**
1870 * xmlOutputBufferCreateFile:
1871 * @file: a FILE*
1872 * @encoder: the encoding converter or NULL
1873 *
1874 * Create a buffered output for the progressive saving to a FILE *
1875 * buffered C I/O
1876 *
1877 * Returns the new parser output or NULL
1878 */
1879xmlOutputBufferPtr
1880xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
1881 xmlOutputBufferPtr ret;
1882
1883 if (xmlOutputCallbackInitialized == 0)
1884 xmlRegisterDefaultOutputCallbacks();
1885
1886 if (file == NULL) return(NULL);
1887
1888 ret = xmlAllocOutputBuffer(encoder);
1889 if (ret != NULL) {
1890 ret->context = file;
1891 ret->writecallback = xmlFileWrite;
1892 ret->closecallback = xmlFileFlush;
1893 }
1894
1895 return(ret);
1896}
1897
1898/**
1899 * xmlParserInputBufferCreateFd:
1900 * @fd: a file descriptor number
1901 * @enc: the charset encoding if known
1902 *
1903 * Create a buffered parser input for the progressive parsing for the input
1904 * from a file descriptor
1905 *
1906 * Returns the new parser input or NULL
1907 */
1908xmlParserInputBufferPtr
1909xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
1910 xmlParserInputBufferPtr ret;
1911
1912 if (fd < 0) return(NULL);
1913
1914 ret = xmlAllocParserInputBuffer(enc);
1915 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00001916 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00001917 ret->readcallback = xmlFdRead;
1918 ret->closecallback = xmlFdClose;
1919 }
1920
1921 return(ret);
1922}
1923
1924/**
1925 * xmlParserInputBufferCreateMem:
1926 * @mem: the memory input
1927 * @size: the length of the memory block
1928 * @enc: the charset encoding if known
1929 *
1930 * Create a buffered parser input for the progressive parsing for the input
1931 * from a memory area.
1932 *
1933 * Returns the new parser input or NULL
1934 */
1935xmlParserInputBufferPtr
1936xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
1937 xmlParserInputBufferPtr ret;
1938
1939 if (size <= 0) return(NULL);
1940 if (mem == NULL) return(NULL);
1941
1942 ret = xmlAllocParserInputBuffer(enc);
1943 if (ret != NULL) {
1944 ret->context = (void *) mem;
1945 ret->readcallback = (xmlInputReadCallback) xmlNop;
1946 ret->closecallback = NULL;
1947 xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size);
1948 }
1949
1950 return(ret);
1951}
1952
1953/**
1954 * xmlOutputBufferCreateFd:
1955 * @fd: a file descriptor number
1956 * @encoder: the encoding converter or NULL
1957 *
1958 * Create a buffered output for the progressive saving
1959 * to a file descriptor
1960 *
1961 * Returns the new parser output or NULL
1962 */
1963xmlOutputBufferPtr
1964xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
1965 xmlOutputBufferPtr ret;
1966
1967 if (fd < 0) return(NULL);
1968
1969 ret = xmlAllocOutputBuffer(encoder);
1970 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00001971 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00001972 ret->writecallback = xmlFdWrite;
Daniel Veillard7db38712002-02-07 16:39:11 +00001973 ret->closecallback = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001974 }
1975
1976 return(ret);
1977}
1978
1979/**
1980 * xmlParserInputBufferCreateIO:
1981 * @ioread: an I/O read function
1982 * @ioclose: an I/O close function
1983 * @ioctx: an I/O handler
1984 * @enc: the charset encoding if known
1985 *
1986 * Create a buffered parser input for the progressive parsing for the input
1987 * from an I/O handler
1988 *
1989 * Returns the new parser input or NULL
1990 */
1991xmlParserInputBufferPtr
1992xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
1993 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
1994 xmlParserInputBufferPtr ret;
1995
1996 if (ioread == NULL) return(NULL);
1997
1998 ret = xmlAllocParserInputBuffer(enc);
1999 if (ret != NULL) {
2000 ret->context = (void *) ioctx;
2001 ret->readcallback = ioread;
2002 ret->closecallback = ioclose;
2003 }
2004
2005 return(ret);
2006}
2007
2008/**
2009 * xmlOutputBufferCreateIO:
2010 * @iowrite: an I/O write function
2011 * @ioclose: an I/O close function
2012 * @ioctx: an I/O handler
Daniel Veillard9d06d302002-01-22 18:15:52 +00002013 * @encoder: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002014 *
2015 * Create a buffered output for the progressive saving
2016 * to an I/O handler
2017 *
2018 * Returns the new parser output or NULL
2019 */
2020xmlOutputBufferPtr
2021xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
2022 xmlOutputCloseCallback ioclose, void *ioctx,
2023 xmlCharEncodingHandlerPtr encoder) {
2024 xmlOutputBufferPtr ret;
2025
2026 if (iowrite == NULL) return(NULL);
2027
2028 ret = xmlAllocOutputBuffer(encoder);
2029 if (ret != NULL) {
2030 ret->context = (void *) ioctx;
2031 ret->writecallback = iowrite;
2032 ret->closecallback = ioclose;
2033 }
2034
2035 return(ret);
2036}
2037
2038/**
2039 * xmlParserInputBufferPush:
2040 * @in: a buffered parser input
2041 * @len: the size in bytes of the array.
2042 * @buf: an char array
2043 *
2044 * Push the content of the arry in the input buffer
2045 * This routine handle the I18N transcoding to internal UTF-8
2046 * This is used when operating the parser in progressive (push) mode.
2047 *
2048 * Returns the number of chars read and stored in the buffer, or -1
2049 * in case of error.
2050 */
2051int
2052xmlParserInputBufferPush(xmlParserInputBufferPtr in,
2053 int len, const char *buf) {
2054 int nbchars = 0;
2055
2056 if (len < 0) return(0);
2057 if (in->encoder != NULL) {
2058 /*
2059 * Store the data in the incoming raw buffer
2060 */
2061 if (in->raw == NULL) {
2062 in->raw = xmlBufferCreate();
2063 }
2064 xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
2065
2066 /*
2067 * convert as much as possible to the parser reading buffer.
2068 */
2069 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2070 if (nbchars < 0) {
2071 xmlGenericError(xmlGenericErrorContext,
2072 "xmlParserInputBufferPush: encoder error\n");
2073 return(-1);
2074 }
2075 } else {
2076 nbchars = len;
2077 xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
2078 }
2079#ifdef DEBUG_INPUT
2080 xmlGenericError(xmlGenericErrorContext,
2081 "I/O: pushed %d chars, buffer %d/%d\n",
2082 nbchars, in->buffer->use, in->buffer->size);
2083#endif
2084 return(nbchars);
2085}
2086
2087/**
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002088 * endOfInput:
2089 *
2090 * When reading from an Input channel indicated end of file or error
2091 * don't reread from it again.
2092 */
2093static int
2094endOfInput (void * context ATTRIBUTE_UNUSED,
2095 char * buffer ATTRIBUTE_UNUSED,
2096 int len ATTRIBUTE_UNUSED) {
2097 return(0);
2098}
2099
2100/**
Owen Taylor3473f882001-02-23 17:55:21 +00002101 * xmlParserInputBufferGrow:
2102 * @in: a buffered parser input
2103 * @len: indicative value of the amount of chars to read
2104 *
2105 * Grow up the content of the input buffer, the old data are preserved
2106 * This routine handle the I18N transcoding to internal UTF-8
2107 * This routine is used when operating the parser in normal (pull) mode
2108 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002109 * TODO: one should be able to remove one extra copy by copying directly
Owen Taylor3473f882001-02-23 17:55:21 +00002110 * onto in->buffer or in->raw
2111 *
2112 * Returns the number of chars read and stored in the buffer, or -1
2113 * in case of error.
2114 */
2115int
2116xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
2117 char *buffer = NULL;
2118 int res = 0;
2119 int nbchars = 0;
2120 int buffree;
Daniel Veillard9e412302002-06-10 15:59:44 +00002121 unsigned int needSize;
Owen Taylor3473f882001-02-23 17:55:21 +00002122
2123 if ((len <= MINLEN) && (len != 4))
2124 len = MINLEN;
2125 buffree = in->buffer->size - in->buffer->use;
2126 if (buffree <= 0) {
2127 xmlGenericError(xmlGenericErrorContext,
2128 "xmlParserInputBufferGrow : buffer full !\n");
2129 return(0);
2130 }
2131 if (len > buffree)
2132 len = buffree;
2133
Daniel Veillarde5354492002-05-16 08:43:22 +00002134 needSize = in->buffer->use + len + 1;
2135 if (needSize > in->buffer->size){
2136 if (!xmlBufferResize(in->buffer, needSize)){
2137 xmlGenericError(xmlGenericErrorContext,
2138 "xmlBufferAdd : out of memory!\n");
2139 return(0);
2140 }
Owen Taylor3473f882001-02-23 17:55:21 +00002141 }
Daniel Veillarde5354492002-05-16 08:43:22 +00002142 buffer = (char *)&in->buffer->content[in->buffer->use];
Owen Taylor3473f882001-02-23 17:55:21 +00002143
2144 /*
2145 * Call the read method for this I/O type.
2146 */
2147 if (in->readcallback != NULL) {
2148 res = in->readcallback(in->context, &buffer[0], len);
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002149 if (res <= 0)
2150 in->readcallback = endOfInput;
Owen Taylor3473f882001-02-23 17:55:21 +00002151 } else {
2152 xmlGenericError(xmlGenericErrorContext,
2153 "xmlParserInputBufferGrow : no input !\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002154 return(-1);
2155 }
2156 if (res < 0) {
2157 perror ("read error");
Owen Taylor3473f882001-02-23 17:55:21 +00002158 return(-1);
2159 }
2160 len = res;
2161 if (in->encoder != NULL) {
2162 /*
2163 * Store the data in the incoming raw buffer
2164 */
2165 if (in->raw == NULL) {
2166 in->raw = xmlBufferCreate();
2167 }
2168 xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
2169
2170 /*
2171 * convert as much as possible to the parser reading buffer.
2172 */
2173 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2174 if (nbchars < 0) {
2175 xmlGenericError(xmlGenericErrorContext,
2176 "xmlParserInputBufferGrow: encoder error\n");
2177 return(-1);
2178 }
2179 } else {
2180 nbchars = len;
Daniel Veillarde5354492002-05-16 08:43:22 +00002181 in->buffer->use += nbchars;
2182 buffer[nbchars] = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002183 }
2184#ifdef DEBUG_INPUT
2185 xmlGenericError(xmlGenericErrorContext,
2186 "I/O: read %d chars, buffer %d/%d\n",
2187 nbchars, in->buffer->use, in->buffer->size);
2188#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002189 return(nbchars);
2190}
2191
2192/**
2193 * xmlParserInputBufferRead:
2194 * @in: a buffered parser input
2195 * @len: indicative value of the amount of chars to read
2196 *
2197 * Refresh the content of the input buffer, the old data are considered
2198 * consumed
2199 * This routine handle the I18N transcoding to internal UTF-8
2200 *
2201 * Returns the number of chars read and stored in the buffer, or -1
2202 * in case of error.
2203 */
2204int
2205xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
2206 /* xmlBufferEmpty(in->buffer); */
2207 if (in->readcallback != NULL)
2208 return(xmlParserInputBufferGrow(in, len));
2209 else
2210 return(-1);
2211}
2212
2213/**
2214 * xmlOutputBufferWrite:
2215 * @out: a buffered parser output
2216 * @len: the size in bytes of the array.
2217 * @buf: an char array
2218 *
2219 * Write the content of the array in the output I/O buffer
2220 * This routine handle the I18N transcoding from internal UTF-8
2221 * The buffer is lossless, i.e. will store in case of partial
2222 * or delayed writes.
2223 *
2224 * Returns the number of chars immediately written, or -1
2225 * in case of error.
2226 */
2227int
2228xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
2229 int nbchars = 0; /* number of chars to output to I/O */
2230 int ret; /* return from function call */
2231 int written = 0; /* number of char written to I/O so far */
2232 int chunk; /* number of byte curreent processed from buf */
2233
2234 if (len < 0) return(0);
2235
2236 do {
2237 chunk = len;
2238 if (chunk > 4 * MINLEN)
2239 chunk = 4 * MINLEN;
2240
2241 /*
2242 * first handle encoding stuff.
2243 */
2244 if (out->encoder != NULL) {
2245 /*
2246 * Store the data in the incoming raw buffer
2247 */
2248 if (out->conv == NULL) {
2249 out->conv = xmlBufferCreate();
2250 }
2251 xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2252
2253 if ((out->buffer->use < MINLEN) && (chunk == len))
2254 goto done;
2255
2256 /*
2257 * convert as much as possible to the parser reading buffer.
2258 */
2259 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
2260 if (ret < 0) {
2261 xmlGenericError(xmlGenericErrorContext,
2262 "xmlOutputBufferWrite: encoder error\n");
2263 return(-1);
2264 }
2265 nbchars = out->conv->use;
2266 } else {
2267 xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2268 nbchars = out->buffer->use;
2269 }
2270 buf += chunk;
2271 len -= chunk;
2272
2273 if ((nbchars < MINLEN) && (len <= 0))
2274 goto done;
2275
2276 if (out->writecallback) {
2277 /*
2278 * second write the stuff to the I/O channel
2279 */
2280 if (out->encoder != NULL) {
2281 ret = out->writecallback(out->context,
2282 (const char *)out->conv->content, nbchars);
2283 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002284 xmlBufferShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002285 } else {
2286 ret = out->writecallback(out->context,
2287 (const char *)out->buffer->content, nbchars);
2288 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002289 xmlBufferShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002290 }
2291 if (ret < 0) {
2292 xmlGenericError(xmlGenericErrorContext,
2293 "I/O: error %d writing %d bytes\n", ret, nbchars);
2294 return(ret);
2295 }
2296 out->written += ret;
2297 }
2298 written += nbchars;
2299 } while (len > 0);
2300
2301done:
2302#ifdef DEBUG_INPUT
2303 xmlGenericError(xmlGenericErrorContext,
2304 "I/O: wrote %d chars\n", written);
2305#endif
2306 return(written);
2307}
2308
2309/**
2310 * xmlOutputBufferWriteString:
2311 * @out: a buffered parser output
2312 * @str: a zero terminated C string
2313 *
2314 * Write the content of the string in the output I/O buffer
2315 * This routine handle the I18N transcoding from internal UTF-8
2316 * The buffer is lossless, i.e. will store in case of partial
2317 * or delayed writes.
2318 *
2319 * Returns the number of chars immediately written, or -1
2320 * in case of error.
2321 */
2322int
2323xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
2324 int len;
2325
2326 if (str == NULL)
2327 return(-1);
2328 len = strlen(str);
2329
2330 if (len > 0)
2331 return(xmlOutputBufferWrite(out, len, str));
2332 return(len);
2333}
2334
2335/**
2336 * xmlOutputBufferFlush:
2337 * @out: a buffered output
2338 *
2339 * flushes the output I/O channel
2340 *
2341 * Returns the number of byte written or -1 in case of error.
2342 */
2343int
2344xmlOutputBufferFlush(xmlOutputBufferPtr out) {
2345 int nbchars = 0, ret = 0;
2346
2347 /*
2348 * first handle encoding stuff.
2349 */
2350 if ((out->conv != NULL) && (out->encoder != NULL)) {
2351 /*
2352 * convert as much as possible to the parser reading buffer.
2353 */
2354 nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
2355 if (nbchars < 0) {
2356 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002357 "xmlOutputBufferFlush: encoder error\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002358 return(-1);
2359 }
2360 }
2361
2362 /*
2363 * second flush the stuff to the I/O channel
2364 */
2365 if ((out->conv != NULL) && (out->encoder != NULL) &&
2366 (out->writecallback != NULL)) {
2367 ret = out->writecallback(out->context,
2368 (const char *)out->conv->content, out->conv->use);
2369 if (ret >= 0)
2370 xmlBufferShrink(out->conv, ret);
2371 } else if (out->writecallback != NULL) {
2372 ret = out->writecallback(out->context,
2373 (const char *)out->buffer->content, out->buffer->use);
2374 if (ret >= 0)
2375 xmlBufferShrink(out->buffer, ret);
2376 }
2377 if (ret < 0) {
2378 xmlGenericError(xmlGenericErrorContext,
2379 "I/O: error %d flushing %d bytes\n", ret, nbchars);
2380 return(ret);
2381 }
2382 out->written += ret;
2383
2384#ifdef DEBUG_INPUT
2385 xmlGenericError(xmlGenericErrorContext,
2386 "I/O: flushed %d chars\n", ret);
2387#endif
2388 return(ret);
2389}
2390
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002391/**
Owen Taylor3473f882001-02-23 17:55:21 +00002392 * xmlParserGetDirectory:
2393 * @filename: the path to a file
2394 *
2395 * lookup the directory for that file
2396 *
2397 * Returns a new allocated string containing the directory, or NULL.
2398 */
2399char *
2400xmlParserGetDirectory(const char *filename) {
2401 char *ret = NULL;
2402 char dir[1024];
2403 char *cur;
2404 char sep = '/';
2405
2406 if (xmlInputCallbackInitialized == 0)
2407 xmlRegisterDefaultInputCallbacks();
2408
2409 if (filename == NULL) return(NULL);
Daniel Veillard3c5ed912002-01-08 10:36:16 +00002410#if defined(WIN32) && !defined(__CYGWIN__)
Owen Taylor3473f882001-02-23 17:55:21 +00002411 sep = '\\';
2412#endif
2413
2414 strncpy(dir, filename, 1023);
2415 dir[1023] = 0;
2416 cur = &dir[strlen(dir)];
2417 while (cur > dir) {
2418 if (*cur == sep) break;
2419 cur --;
2420 }
2421 if (*cur == sep) {
2422 if (cur == dir) dir[1] = 0;
2423 else *cur = 0;
2424 ret = xmlMemStrdup(dir);
2425 } else {
2426 if (getcwd(dir, 1024) != NULL) {
2427 dir[1023] = 0;
2428 ret = xmlMemStrdup(dir);
2429 }
2430 }
2431 return(ret);
2432}
2433
2434/****************************************************************
2435 * *
2436 * External entities loading *
2437 * *
2438 ****************************************************************/
2439
Daniel Veillard561b7f82002-03-20 21:55:57 +00002440#ifdef LIBXML_CATALOG_ENABLED
2441static int xmlSysIDExists(const char *URL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00002442#ifdef HAVE_STAT
2443 int ret;
2444 struct stat info;
2445 const char *path;
2446
2447 if (URL == NULL)
2448 return(0);
2449
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002450 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost", 16))
Daniel Veillard6990bf32001-08-23 21:17:48 +00002451 path = &URL[16];
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002452 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard3c5ed912002-01-08 10:36:16 +00002453#if defined (_WIN32) && !defined(__CYGWIN__)
Daniel Veillard6990bf32001-08-23 21:17:48 +00002454 path = &URL[8];
2455#else
2456 path = &URL[7];
2457#endif
2458 } else
2459 path = URL;
2460 ret = stat(path, &info);
Daniel Veillard561b7f82002-03-20 21:55:57 +00002461 if (ret == 0)
2462 return(1);
Daniel Veillard6990bf32001-08-23 21:17:48 +00002463#endif
Daniel Veillard561b7f82002-03-20 21:55:57 +00002464 return(0);
Daniel Veillard6990bf32001-08-23 21:17:48 +00002465}
Daniel Veillard561b7f82002-03-20 21:55:57 +00002466#endif
Daniel Veillard6990bf32001-08-23 21:17:48 +00002467
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002468/**
Owen Taylor3473f882001-02-23 17:55:21 +00002469 * xmlDefaultExternalEntityLoader:
2470 * @URL: the URL for the entity to load
2471 * @ID: the System ID for the entity to load
2472 * @ctxt: the context in which the entity is called or NULL
2473 *
2474 * By default we don't load external entitites, yet.
2475 *
2476 * Returns a new allocated xmlParserInputPtr, or NULL.
2477 */
2478static
2479xmlParserInputPtr
2480xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
2481 xmlParserCtxtPtr ctxt) {
2482 xmlParserInputPtr ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002483 xmlChar *resource = NULL;
2484#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002485 xmlCatalogAllow pref;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002486#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002487
2488#ifdef DEBUG_EXTERNAL_ENTITIES
2489 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf012a642001-07-23 19:10:52 +00002490 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00002491#endif
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002492#ifdef LIBXML_CATALOG_ENABLED
2493 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002494 * If the resource doesn't exists as a file,
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002495 * try to load it from the resource pointed in the catalogs
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002496 */
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002497 pref = xmlCatalogGetDefaults();
2498
Daniel Veillard561b7f82002-03-20 21:55:57 +00002499 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlSysIDExists(URL))) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002500 /*
2501 * Do a local lookup
2502 */
2503 if ((ctxt->catalogs != NULL) &&
2504 ((pref == XML_CATA_ALLOW_ALL) ||
2505 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2506 resource = xmlCatalogLocalResolve(ctxt->catalogs,
2507 (const xmlChar *)ID,
2508 (const xmlChar *)URL);
2509 }
2510 /*
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002511 * Try a global lookup
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002512 */
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002513 if ((resource == NULL) &&
2514 ((pref == XML_CATA_ALLOW_ALL) ||
2515 (pref == XML_CATA_ALLOW_GLOBAL))) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002516 resource = xmlCatalogResolve((const xmlChar *)ID,
2517 (const xmlChar *)URL);
2518 }
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002519 if ((resource == NULL) && (URL != NULL))
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00002520 resource = xmlStrdup((const xmlChar *) URL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002521
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002522 /*
2523 * TODO: do an URI lookup on the reference
2524 */
Daniel Veillard561b7f82002-03-20 21:55:57 +00002525 if ((resource != NULL) && (!xmlSysIDExists((const char *)resource))) {
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002526 xmlChar *tmp = NULL;
2527
2528 if ((ctxt->catalogs != NULL) &&
2529 ((pref == XML_CATA_ALLOW_ALL) ||
2530 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2531 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
2532 }
2533 if ((tmp == NULL) &&
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00002534 ((pref == XML_CATA_ALLOW_ALL) ||
2535 (pref == XML_CATA_ALLOW_GLOBAL))) {
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002536 tmp = xmlCatalogResolveURI(resource);
2537 }
2538
2539 if (tmp != NULL) {
2540 xmlFree(resource);
2541 resource = tmp;
2542 }
2543 }
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002544 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002545#endif
2546
2547 if (resource == NULL)
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002548 resource = (xmlChar *) URL;
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002549
2550 if (resource == NULL) {
Daniel Veillardc6613042002-03-02 09:34:02 +00002551 if (ID == NULL)
2552 ID = "NULL";
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002553 if ((ctxt->validate) && (ctxt->sax != NULL) &&
2554 (ctxt->sax->error != NULL))
2555 ctxt->sax->error(ctxt,
2556 "failed to load external entity \"%s\"\n", ID);
2557 else if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00002558 ctxt->sax->warning(ctxt,
2559 "failed to load external entity \"%s\"\n", ID);
2560 return(NULL);
2561 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002562 ret = xmlNewInputFromFile(ctxt, (const char *)resource);
Owen Taylor3473f882001-02-23 17:55:21 +00002563 if (ret == NULL) {
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002564 if ((ctxt->validate) && (ctxt->sax != NULL) &&
2565 (ctxt->sax->error != NULL))
2566 ctxt->sax->error(ctxt,
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002567 "failed to load external entity \"%s\"\n", resource);
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002568 else if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00002569 ctxt->sax->warning(ctxt,
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002570 "failed to load external entity \"%s\"\n", resource);
Owen Taylor3473f882001-02-23 17:55:21 +00002571 }
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002572 if ((resource != NULL) && (resource != (xmlChar *) URL))
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002573 xmlFree(resource);
Owen Taylor3473f882001-02-23 17:55:21 +00002574 return(ret);
2575}
2576
2577static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
2578 xmlDefaultExternalEntityLoader;
2579
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002580/**
Owen Taylor3473f882001-02-23 17:55:21 +00002581 * xmlSetExternalEntityLoader:
2582 * @f: the new entity resolver function
2583 *
2584 * Changes the defaultexternal entity resolver function for the application
2585 */
2586void
2587xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
2588 xmlCurrentExternalEntityLoader = f;
2589}
2590
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002591/**
Owen Taylor3473f882001-02-23 17:55:21 +00002592 * xmlGetExternalEntityLoader:
2593 *
2594 * Get the default external entity resolver function for the application
2595 *
2596 * Returns the xmlExternalEntityLoader function pointer
2597 */
2598xmlExternalEntityLoader
2599xmlGetExternalEntityLoader(void) {
2600 return(xmlCurrentExternalEntityLoader);
2601}
2602
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002603/**
Owen Taylor3473f882001-02-23 17:55:21 +00002604 * xmlLoadExternalEntity:
2605 * @URL: the URL for the entity to load
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00002606 * @ID: the Public ID for the entity to load
Owen Taylor3473f882001-02-23 17:55:21 +00002607 * @ctxt: the context in which the entity is called or NULL
2608 *
2609 * Load an external entity, note that the use of this function for
2610 * unparsed entities may generate problems
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002611 * TODO: a more generic External entity API must be designed
Owen Taylor3473f882001-02-23 17:55:21 +00002612 *
2613 * Returns the xmlParserInputPtr or NULL
2614 */
2615xmlParserInputPtr
2616xmlLoadExternalEntity(const char *URL, const char *ID,
2617 xmlParserCtxtPtr ctxt) {
2618 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
2619}
2620
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00002621/************************************************************************
2622 * *
2623 * Disabling Network access *
2624 * *
2625 ************************************************************************/
2626
2627#ifdef LIBXML_CATALOG_ENABLED
2628static int
2629xmlNoNetExists(const char *URL)
2630{
2631#ifdef HAVE_STAT
2632 int ret;
2633 struct stat info;
2634 const char *path;
2635
2636 if (URL == NULL)
2637 return (0);
2638
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002639 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost", 16))
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00002640 path = &URL[16];
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002641 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard3c5ed912002-01-08 10:36:16 +00002642#if defined (_WIN32) && !defined(__CYGWIN__)
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00002643 path = &URL[8];
2644#else
2645 path = &URL[7];
2646#endif
2647 } else
2648 path = URL;
2649 ret = stat(path, &info);
2650 if (ret == 0)
2651 return (1);
2652#endif
2653 return (0);
2654}
2655#endif
2656
2657/**
2658 * xmlNoNetExternalEntityLoader:
2659 * @URL: the URL for the entity to load
2660 * @ID: the System ID for the entity to load
2661 * @ctxt: the context in which the entity is called or NULL
2662 *
2663 * A specific entity loader disabling network accesses, though still
2664 * allowing local catalog accesses for resolution.
2665 *
2666 * Returns a new allocated xmlParserInputPtr, or NULL.
2667 */
2668xmlParserInputPtr
2669xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
2670 xmlParserCtxtPtr ctxt) {
2671 xmlParserInputPtr input = NULL;
2672 xmlChar *resource = NULL;
2673
2674#ifdef LIBXML_CATALOG_ENABLED
2675 xmlCatalogAllow pref;
2676
2677 /*
2678 * If the resource doesn't exists as a file,
2679 * try to load it from the resource pointed in the catalogs
2680 */
2681 pref = xmlCatalogGetDefaults();
2682
2683 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
2684 /*
2685 * Do a local lookup
2686 */
2687 if ((ctxt->catalogs != NULL) &&
2688 ((pref == XML_CATA_ALLOW_ALL) ||
2689 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2690 resource = xmlCatalogLocalResolve(ctxt->catalogs,
2691 (const xmlChar *)ID,
2692 (const xmlChar *)URL);
2693 }
2694 /*
2695 * Try a global lookup
2696 */
2697 if ((resource == NULL) &&
2698 ((pref == XML_CATA_ALLOW_ALL) ||
2699 (pref == XML_CATA_ALLOW_GLOBAL))) {
2700 resource = xmlCatalogResolve((const xmlChar *)ID,
2701 (const xmlChar *)URL);
2702 }
2703 if ((resource == NULL) && (URL != NULL))
2704 resource = xmlStrdup((const xmlChar *) URL);
2705
2706 /*
2707 * TODO: do an URI lookup on the reference
2708 */
2709 if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
2710 xmlChar *tmp = NULL;
2711
2712 if ((ctxt->catalogs != NULL) &&
2713 ((pref == XML_CATA_ALLOW_ALL) ||
2714 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2715 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
2716 }
2717 if ((tmp == NULL) &&
2718 ((pref == XML_CATA_ALLOW_ALL) ||
2719 (pref == XML_CATA_ALLOW_GLOBAL))) {
2720 tmp = xmlCatalogResolveURI(resource);
2721 }
2722
2723 if (tmp != NULL) {
2724 xmlFree(resource);
2725 resource = tmp;
2726 }
2727 }
2728 }
2729#endif
2730 if (resource == NULL)
2731 resource = (xmlChar *) URL;
2732
2733 if (resource != NULL) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002734 if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
2735 (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00002736 xmlGenericError(xmlGenericErrorContext,
2737 "Attempt to load network entity %s \n", resource);
2738
2739 if (resource != (xmlChar *) URL)
2740 xmlFree(resource);
2741 return(NULL);
2742 }
2743 }
2744 input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
2745 if (resource != (xmlChar *) URL)
2746 xmlFree(resource);
2747 return(input);
2748}
2749