blob: 3cd4c2ae25efde4d753ca15888b9364f68c0729e [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))
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000300#if defined (_WIN32) && !defined(__CYGWIN__)
301 path = &filename[17];
302#else
Owen Taylor3473f882001-02-23 17:55:21 +0000303 path = &filename[16];
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000304#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000305 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard3c5ed912002-01-08 10:36:16 +0000306#if defined (_WIN32) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000307 path = &filename[8];
308#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000309 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000310#endif
311 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000312 path = filename;
313
314 if (path == NULL)
315 return(NULL);
316 if (!xmlCheckFilename(path))
317 return(NULL);
318
Daniel Veillard3c5ed912002-01-08 10:36:16 +0000319#if defined(WIN32) || defined (__CYGWIN__)
Owen Taylor3473f882001-02-23 17:55:21 +0000320 fd = fopen(path, "rb");
321#else
322 fd = fopen(path, "r");
323#endif /* WIN32 */
324 return((void *) fd);
325}
326
327/**
328 * xmlFileOpenW:
329 * @filename: the URI for matching
330 *
331 * output to from FILE *,
332 * if @filename is "-" then the standard output is used
333 *
334 * Returns an I/O context or NULL in case of error
335 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000336static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000337xmlFileOpenW (const char *filename) {
338 const char *path = NULL;
339 FILE *fd;
340
341 if (!strcmp(filename, "-")) {
342 fd = stdout;
343 return((void *) fd);
344 }
345
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000346 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost", 16))
Owen Taylor3473f882001-02-23 17:55:21 +0000347 path = &filename[16];
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000348 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard3c5ed912002-01-08 10:36:16 +0000349#if defined (_WIN32) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000350 path = &filename[8];
351#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000352 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000353#endif
354 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000355 path = filename;
356
357 if (path == NULL)
358 return(NULL);
359
360 fd = fopen(path, "w");
361 return((void *) fd);
362}
363
364/**
365 * xmlFileRead:
366 * @context: the I/O context
367 * @buffer: where to drop data
368 * @len: number of bytes to write
369 *
370 * Read @len bytes to @buffer from the I/O channel.
371 *
372 * Returns the number of bytes written
373 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000374int
Owen Taylor3473f882001-02-23 17:55:21 +0000375xmlFileRead (void * context, char * buffer, int len) {
376 return(fread(&buffer[0], 1, len, (FILE *) context));
377}
378
379/**
380 * xmlFileWrite:
381 * @context: the I/O context
382 * @buffer: where to drop data
383 * @len: number of bytes to write
384 *
385 * Write @len bytes from @buffer to the I/O channel.
386 *
387 * Returns the number of bytes written
388 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000389static int
Owen Taylor3473f882001-02-23 17:55:21 +0000390xmlFileWrite (void * context, const char * buffer, int len) {
391 return(fwrite(&buffer[0], 1, len, (FILE *) context));
392}
393
394/**
395 * xmlFileClose:
396 * @context: the I/O context
397 *
398 * Close an I/O channel
399 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000400int
Owen Taylor3473f882001-02-23 17:55:21 +0000401xmlFileClose (void * context) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000402 FILE *fil;
403
404 fil = (FILE *) context;
405 if (fil == stdin)
406 return(0);
407 if (fil == stdout)
408 return(0);
Daniel Veillardcd337f02001-11-22 18:20:37 +0000409 if (fil == stderr)
410 return(0);
Daniel Veillardf012a642001-07-23 19:10:52 +0000411 return ( ( fclose((FILE *) context) == EOF ) ? -1 : 0 );
Owen Taylor3473f882001-02-23 17:55:21 +0000412}
413
414/**
415 * xmlFileFlush:
416 * @context: the I/O context
417 *
418 * Flush an I/O channel
419 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000420static int
Owen Taylor3473f882001-02-23 17:55:21 +0000421xmlFileFlush (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +0000422 return ( ( fflush((FILE *) context) == EOF ) ? -1 : 0 );
Owen Taylor3473f882001-02-23 17:55:21 +0000423}
424
425#ifdef HAVE_ZLIB_H
426/************************************************************************
427 * *
428 * I/O for compressed file accesses *
429 * *
430 ************************************************************************/
431/**
432 * xmlGzfileMatch:
433 * @filename: the URI for matching
434 *
435 * input from compressed file test
436 *
437 * Returns 1 if matches, 0 otherwise
438 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000439static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000440xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000441 return(1);
442}
443
444/**
445 * xmlGzfileOpen:
446 * @filename: the URI for matching
447 *
448 * input from compressed file open
449 * if @filename is " " then the standard input is used
450 *
451 * Returns an I/O context or NULL in case of error
452 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000453static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000454xmlGzfileOpen (const char *filename) {
455 const char *path = NULL;
456 gzFile fd;
457
458 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000459 fd = gzdopen(dup(0), "rb");
Owen Taylor3473f882001-02-23 17:55:21 +0000460 return((void *) fd);
461 }
462
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000463 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost", 16))
Owen Taylor3473f882001-02-23 17:55:21 +0000464 path = &filename[16];
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000465 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard3c5ed912002-01-08 10:36:16 +0000466#if defined (_WIN32) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000467 path = &filename[8];
468#else
Owen Taylor3473f882001-02-23 17:55:21 +0000469 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000470#endif
471 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000472 path = filename;
473
474 if (path == NULL)
475 return(NULL);
476 if (!xmlCheckFilename(path))
477 return(NULL);
478
479 fd = gzopen(path, "rb");
480 return((void *) fd);
481}
482
483/**
484 * xmlGzfileOpenW:
485 * @filename: the URI for matching
486 * @compression: the compression factor (0 - 9 included)
487 *
488 * input from compressed file open
489 * if @filename is " " then the standard input is used
490 *
491 * Returns an I/O context or NULL in case of error
492 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000493static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000494xmlGzfileOpenW (const char *filename, int compression) {
495 const char *path = NULL;
496 char mode[15];
497 gzFile fd;
498
Aleksey Sanin49cc9752002-06-14 17:07:10 +0000499 snprintf(mode, sizeof(mode), "wb%d", compression);
Owen Taylor3473f882001-02-23 17:55:21 +0000500 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000501 fd = gzdopen(dup(1), mode);
Owen Taylor3473f882001-02-23 17:55:21 +0000502 return((void *) fd);
503 }
504
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000505 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost", 16))
Owen Taylor3473f882001-02-23 17:55:21 +0000506 path = &filename[16];
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000507 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard3c5ed912002-01-08 10:36:16 +0000508#if defined (_WIN32) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000509 path = &filename[8];
510#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000511 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000512#endif
513 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000514 path = filename;
515
516 if (path == NULL)
517 return(NULL);
518
519 fd = gzopen(path, mode);
520 return((void *) fd);
521}
522
523/**
524 * xmlGzfileRead:
525 * @context: the I/O context
526 * @buffer: where to drop data
527 * @len: number of bytes to write
528 *
529 * Read @len bytes to @buffer from the compressed I/O channel.
530 *
531 * Returns the number of bytes written
532 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000533static int
Owen Taylor3473f882001-02-23 17:55:21 +0000534xmlGzfileRead (void * context, char * buffer, int len) {
535 return(gzread((gzFile) context, &buffer[0], len));
536}
537
538/**
539 * xmlGzfileWrite:
540 * @context: the I/O context
541 * @buffer: where to drop data
542 * @len: number of bytes to write
543 *
544 * Write @len bytes from @buffer to the compressed I/O channel.
545 *
546 * Returns the number of bytes written
547 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000548static int
Owen Taylor3473f882001-02-23 17:55:21 +0000549xmlGzfileWrite (void * context, const char * buffer, int len) {
550 return(gzwrite((gzFile) context, (char *) &buffer[0], len));
551}
552
553/**
554 * xmlGzfileClose:
555 * @context: the I/O context
556 *
557 * Close a compressed I/O channel
558 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000559static int
Owen Taylor3473f882001-02-23 17:55:21 +0000560xmlGzfileClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +0000561 return ( ( gzclose((gzFile) context) == Z_OK ) ? 0 : -1 );
Owen Taylor3473f882001-02-23 17:55:21 +0000562}
563#endif /* HAVE_ZLIB_H */
564
565#ifdef LIBXML_HTTP_ENABLED
566/************************************************************************
567 * *
568 * I/O for HTTP file accesses *
569 * *
570 ************************************************************************/
Daniel Veillardf012a642001-07-23 19:10:52 +0000571
572typedef struct xmlIOHTTPWriteCtxt_
573{
574 int compression;
575
576 char * uri;
577
578 void * doc_buff;
579
580} xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr;
581
582#ifdef HAVE_ZLIB_H
583
584#define DFLT_WBITS ( -15 )
585#define DFLT_MEM_LVL ( 8 )
586#define GZ_MAGIC1 ( 0x1f )
587#define GZ_MAGIC2 ( 0x8b )
588#define LXML_ZLIB_OS_CODE ( 0x03 )
589#define INIT_HTTP_BUFF_SIZE ( 32768 )
590#define DFLT_ZLIB_RATIO ( 5 )
591
592/*
593** Data structure and functions to work with sending compressed data
594** via HTTP.
595*/
596
597typedef struct xmlZMemBuff_
598{
599 unsigned long size;
600 unsigned long crc;
601
602 unsigned char * zbuff;
603 z_stream zctrl;
604
605} xmlZMemBuff, *xmlZMemBuffPtr;
606
607/**
608 * append_reverse_ulong
609 * @buff: Compressed memory buffer
610 * @data: Unsigned long to append
611 *
612 * Append a unsigned long in reverse byte order to the end of the
613 * memory buffer.
614 */
615static void
616append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) {
617
618 int idx;
619
620 if ( buff == NULL )
621 return;
622
623 /*
624 ** This is plagiarized from putLong in gzio.c (zlib source) where
625 ** the number "4" is hardcoded. If zlib is ever patched to
626 ** support 64 bit file sizes, this code would need to be patched
627 ** as well.
628 */
629
630 for ( idx = 0; idx < 4; idx++ ) {
631 *buff->zctrl.next_out = ( data & 0xff );
632 data >>= 8;
633 buff->zctrl.next_out++;
634 }
635
636 return;
637}
638
639/**
640 *
641 * xmlFreeZMemBuff
642 * @buff: The memory buffer context to clear
643 *
644 * Release all the resources associated with the compressed memory buffer.
645 */
646static void
647xmlFreeZMemBuff( xmlZMemBuffPtr buff ) {
648
649 int z_err;
650
651 if ( buff == NULL )
652 return;
653
654 xmlFree( buff->zbuff );
655 z_err = deflateEnd( &buff->zctrl );
656#ifdef DEBUG_HTTP
657 if ( z_err != Z_OK )
658 xmlGenericError( xmlGenericErrorContext,
659 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
660 z_err );
661#endif
662
663 xmlFree( buff );
664 return;
665}
666
667/**
668 * xmlCreateZMemBuff
669 *@compression: Compression value to use
670 *
671 * Create a memory buffer to hold the compressed XML document. The
672 * compressed document in memory will end up being identical to what
673 * would be created if gzopen/gzwrite/gzclose were being used to
674 * write the document to disk. The code for the header/trailer data to
675 * the compression is plagiarized from the zlib source files.
676 */
677static void *
678xmlCreateZMemBuff( int compression ) {
679
680 int z_err;
681 int hdr_lgth;
682 xmlZMemBuffPtr buff = NULL;
683
684 if ( ( compression < 1 ) || ( compression > 9 ) )
685 return ( NULL );
686
687 /* Create the control and data areas */
688
689 buff = xmlMalloc( sizeof( xmlZMemBuff ) );
690 if ( buff == NULL ) {
691 xmlGenericError( xmlGenericErrorContext,
692 "xmlCreateZMemBuff: %s\n",
693 "Failure allocating buffer context." );
694 return ( NULL );
695 }
696
697 (void)memset( buff, 0, sizeof( xmlZMemBuff ) );
698 buff->size = INIT_HTTP_BUFF_SIZE;
699 buff->zbuff = xmlMalloc( buff->size );
700 if ( buff->zbuff == NULL ) {
701 xmlFreeZMemBuff( buff );
702 xmlGenericError( xmlGenericErrorContext,
703 "xmlCreateZMemBuff: %s\n",
704 "Failure allocating data buffer." );
705 return ( NULL );
706 }
707
708 z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
709 DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
710 if ( z_err != Z_OK ) {
711 xmlFreeZMemBuff( buff );
712 buff = NULL;
713 xmlGenericError( xmlGenericErrorContext,
714 "xmlCreateZMemBuff: %s %d\n",
715 "Error initializing compression context. ZLIB error:",
716 z_err );
717 return ( NULL );
718 }
719
720 /* Set the header data. The CRC will be needed for the trailer */
Daniel Veillardf012a642001-07-23 19:10:52 +0000721 buff->crc = crc32( 0L, Z_NULL, 0 );
Aleksey Sanin49cc9752002-06-14 17:07:10 +0000722 hdr_lgth = snprintf( (char *)buff->zbuff, buff->size,
723 "%c%c%c%c%c%c%c%c%c%c",
Daniel Veillardf012a642001-07-23 19:10:52 +0000724 GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED,
725 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE );
726 buff->zctrl.next_out = buff->zbuff + hdr_lgth;
727 buff->zctrl.avail_out = buff->size - hdr_lgth;
728
729 return ( buff );
730}
731
732/**
733 * xmlZMemBuffExtend
734 * @buff: Buffer used to compress and consolidate data.
735 * @ext_amt: Number of bytes to extend the buffer.
736 *
737 * Extend the internal buffer used to store the compressed data by the
738 * specified amount.
739 *
740 * Returns 0 on success or -1 on failure to extend the buffer. On failure
741 * the original buffer still exists at the original size.
742 */
743static int
744xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) {
745
746 int rc = -1;
747 size_t new_size;
748 size_t cur_used;
749
750 unsigned char * tmp_ptr = NULL;
751
752 if ( buff == NULL )
753 return ( -1 );
754
755 else if ( ext_amt == 0 )
756 return ( 0 );
757
758 cur_used = buff->zctrl.next_out - buff->zbuff;
759 new_size = buff->size + ext_amt;
760
761#ifdef DEBUG_HTTP
762 if ( cur_used > new_size )
763 xmlGenericError( xmlGenericErrorContext,
764 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
765 "Buffer overwrite detected during compressed memory",
766 "buffer extension. Overflowed by",
767 (cur_used - new_size ) );
768#endif
769
770 tmp_ptr = xmlRealloc( buff->zbuff, new_size );
771 if ( tmp_ptr != NULL ) {
772 rc = 0;
773 buff->size = new_size;
774 buff->zbuff = tmp_ptr;
775 buff->zctrl.next_out = tmp_ptr + cur_used;
776 buff->zctrl.avail_out = new_size - cur_used;
777 }
778 else {
779 xmlGenericError( xmlGenericErrorContext,
780 "xmlZMemBuffExtend: %s %lu bytes.\n",
781 "Allocation failure extending output buffer to",
782 new_size );
783 }
784
785 return ( rc );
786}
787
788/**
789 * xmlZMemBuffAppend
790 * @buff: Buffer used to compress and consolidate data
791 * @src: Uncompressed source content to append to buffer
792 * @len: Length of source data to append to buffer
793 *
794 * Compress and append data to the internal buffer. The data buffer
795 * will be expanded if needed to store the additional data.
796 *
797 * Returns the number of bytes appended to the buffer or -1 on error.
798 */
799static int
800xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) {
801
802 int z_err;
803 size_t min_accept;
804
805 if ( ( buff == NULL ) || ( src == NULL ) )
806 return ( -1 );
807
808 buff->zctrl.avail_in = len;
809 buff->zctrl.next_in = (unsigned char *)src;
810 while ( buff->zctrl.avail_in > 0 ) {
811 /*
812 ** Extend the buffer prior to deflate call if a reasonable amount
813 ** of output buffer space is not available.
814 */
815 min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO;
816 if ( buff->zctrl.avail_out <= min_accept ) {
817 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
818 return ( -1 );
819 }
820
821 z_err = deflate( &buff->zctrl, Z_NO_FLUSH );
822 if ( z_err != Z_OK ) {
823 xmlGenericError( xmlGenericErrorContext,
824 "xmlZMemBuffAppend: %s %d %s - %d",
825 "Compression error while appending",
826 len, "bytes to buffer. ZLIB error", z_err );
827 return ( -1 );
828 }
829 }
830
831 buff->crc = crc32( buff->crc, (unsigned char *)src, len );
832
833 return ( len );
834}
835
836/**
837 * xmlZMemBuffGetContent
838 * @buff: Compressed memory content buffer
839 * @data_ref: Pointer reference to point to compressed content
840 *
841 * Flushes the compression buffers, appends gzip file trailers and
842 * returns the compressed content and length of the compressed data.
843 * NOTE: The gzip trailer code here is plagiarized from zlib source.
844 *
845 * Returns the length of the compressed data or -1 on error.
846 */
847static int
848xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) {
849
850 int zlgth = -1;
851 int z_err;
852
853 if ( ( buff == NULL ) || ( data_ref == NULL ) )
854 return ( -1 );
855
856 /* Need to loop until compression output buffers are flushed */
857
858 do
859 {
860 z_err = deflate( &buff->zctrl, Z_FINISH );
861 if ( z_err == Z_OK ) {
862 /* In this case Z_OK means more buffer space needed */
863
864 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
865 return ( -1 );
866 }
867 }
868 while ( z_err == Z_OK );
869
870 /* If the compression state is not Z_STREAM_END, some error occurred */
871
872 if ( z_err == Z_STREAM_END ) {
873
874 /* Need to append the gzip data trailer */
875
876 if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) {
877 if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 )
878 return ( -1 );
879 }
880
881 /*
882 ** For whatever reason, the CRC and length data are pushed out
883 ** in reverse byte order. So a memcpy can't be used here.
884 */
885
886 append_reverse_ulong( buff, buff->crc );
887 append_reverse_ulong( buff, buff->zctrl.total_in );
888
889 zlgth = buff->zctrl.next_out - buff->zbuff;
890 *data_ref = (char *)buff->zbuff;
891 }
892
893 else
894 xmlGenericError( xmlGenericErrorContext,
895 "xmlZMemBuffGetContent: %s - %d\n",
896 "Error flushing zlib buffers. Error code", z_err );
897
898 return ( zlgth );
899}
900#endif /* HAVE_ZLIB_H */
901
902/**
903 * xmlFreeHTTPWriteCtxt
904 * @ctxt: Context to cleanup
905 *
906 * Free allocated memory and reclaim system resources.
907 *
908 * No return value.
909 */
910static void
911xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt )
912{
913 if ( ctxt->uri != NULL )
914 free( ctxt->uri );
915
916 if ( ctxt->doc_buff != NULL ) {
917
918#ifdef HAVE_ZLIB_H
919 if ( ctxt->compression > 0 ) {
920 xmlFreeZMemBuff( ctxt->doc_buff );
921 }
922 else
923#endif
924 {
925 xmlOutputBufferClose( ctxt->doc_buff );
926 }
927 }
928
929 free( ctxt );
930 return;
931}
932
933
Owen Taylor3473f882001-02-23 17:55:21 +0000934/**
935 * xmlIOHTTPMatch:
936 * @filename: the URI for matching
937 *
938 * check if the URI matches an HTTP one
939 *
940 * Returns 1 if matches, 0 otherwise
941 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000942int
Owen Taylor3473f882001-02-23 17:55:21 +0000943xmlIOHTTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000944 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "http://", 7))
Owen Taylor3473f882001-02-23 17:55:21 +0000945 return(1);
946 return(0);
947}
948
949/**
950 * xmlIOHTTPOpen:
951 * @filename: the URI for matching
952 *
953 * open an HTTP I/O channel
954 *
955 * Returns an I/O context or NULL in case of error
956 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000957void *
Owen Taylor3473f882001-02-23 17:55:21 +0000958xmlIOHTTPOpen (const char *filename) {
959 return(xmlNanoHTTPOpen(filename, NULL));
960}
961
962/**
Daniel Veillardf012a642001-07-23 19:10:52 +0000963 * xmlIOHTTPOpenW
964 * @post_uri: The destination URI for the document
965 * @compression: The compression desired for the document.
966 *
967 * Open a temporary buffer to collect the document for a subsequent HTTP POST
968 * request. Non-static as is called from the output buffer creation routine.
969 *
970 * Returns an I/O context or NULL in case of error.
971 */
972
973void *
Daniel Veillard572577e2002-01-18 16:23:55 +0000974xmlIOHTTPOpenW(const char *post_uri, int compression)
975{
Daniel Veillardf012a642001-07-23 19:10:52 +0000976
Daniel Veillard572577e2002-01-18 16:23:55 +0000977 xmlIOHTTPWriteCtxtPtr ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +0000978
Daniel Veillard572577e2002-01-18 16:23:55 +0000979 if (post_uri == NULL)
980 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +0000981
Daniel Veillard572577e2002-01-18 16:23:55 +0000982 ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt));
983 if (ctxt == NULL) {
984 xmlGenericError(xmlGenericErrorContext,
985 "xmlIOHTTPOpenW: Failed to create output HTTP context.\n");
986 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +0000987 }
988
Daniel Veillard572577e2002-01-18 16:23:55 +0000989 (void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt));
Daniel Veillardf012a642001-07-23 19:10:52 +0000990
Daniel Veillard572577e2002-01-18 16:23:55 +0000991 ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri);
992 if (ctxt->uri == NULL) {
993 xmlGenericError(xmlGenericErrorContext,
994 "xmlIOHTTPOpenW: Failed to duplicate destination URI.\n");
995 xmlFreeHTTPWriteCtxt(ctxt);
996 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +0000997 }
998
999 /*
Daniel Veillard572577e2002-01-18 16:23:55 +00001000 * ** Since the document length is required for an HTTP post,
1001 * ** need to put the document into a buffer. A memory buffer
1002 * ** is being used to avoid pushing the data to disk and back.
1003 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001004
1005#ifdef HAVE_ZLIB_H
Daniel Veillard572577e2002-01-18 16:23:55 +00001006 if ((compression > 0) && (compression <= 9)) {
1007
1008 ctxt->compression = compression;
1009 ctxt->doc_buff = xmlCreateZMemBuff(compression);
1010 } else
Daniel Veillardf012a642001-07-23 19:10:52 +00001011#endif
1012 {
Daniel Veillard572577e2002-01-18 16:23:55 +00001013 /* Any character conversions should have been done before this */
Daniel Veillardf012a642001-07-23 19:10:52 +00001014
Daniel Veillard572577e2002-01-18 16:23:55 +00001015 ctxt->doc_buff = xmlAllocOutputBuffer(NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001016 }
1017
Daniel Veillard572577e2002-01-18 16:23:55 +00001018 if (ctxt->doc_buff == NULL) {
1019 xmlFreeHTTPWriteCtxt(ctxt);
1020 ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001021 }
1022
Daniel Veillard572577e2002-01-18 16:23:55 +00001023 return (ctxt);
Daniel Veillardf012a642001-07-23 19:10:52 +00001024}
1025
1026/**
1027 * xmlIOHTTPDfltOpenW
1028 * @post_uri: The destination URI for this document.
1029 *
1030 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
1031 * HTTP post command. This function should generally not be used as
1032 * the open callback is short circuited in xmlOutputBufferCreateFile.
1033 *
1034 * Returns a pointer to the new IO context.
1035 */
1036static void *
1037xmlIOHTTPDfltOpenW( const char * post_uri ) {
1038 return ( xmlIOHTTPOpenW( post_uri, 0 ) );
1039}
1040
1041/**
Owen Taylor3473f882001-02-23 17:55:21 +00001042 * xmlIOHTTPRead:
1043 * @context: the I/O context
1044 * @buffer: where to drop data
1045 * @len: number of bytes to write
1046 *
1047 * Read @len bytes to @buffer from the I/O channel.
1048 *
1049 * Returns the number of bytes written
1050 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001051int
Owen Taylor3473f882001-02-23 17:55:21 +00001052xmlIOHTTPRead(void * context, char * buffer, int len) {
1053 return(xmlNanoHTTPRead(context, &buffer[0], len));
1054}
1055
1056/**
Daniel Veillardf012a642001-07-23 19:10:52 +00001057 * xmlIOHTTPWrite
1058 * @context: previously opened writing context
1059 * @buffer: data to output to temporary buffer
1060 * @len: bytes to output
1061 *
1062 * Collect data from memory buffer into a temporary file for later
1063 * processing.
1064 *
1065 * Returns number of bytes written.
1066 */
1067
1068static int
1069xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
1070
1071 xmlIOHTTPWriteCtxtPtr ctxt = context;
1072
1073 if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
1074 return ( -1 );
1075
1076 if ( len > 0 ) {
1077
1078 /* Use gzwrite or fwrite as previously setup in the open call */
1079
1080#ifdef HAVE_ZLIB_H
1081 if ( ctxt->compression > 0 )
1082 len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len );
1083
1084 else
1085#endif
1086 len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
1087
1088 if ( len < 0 ) {
1089 xmlGenericError( xmlGenericErrorContext,
1090 "xmlIOHTTPWrite: %s\n%s '%s'.\n",
1091 "Error appending to internal buffer.",
1092 "Error sending document to URI",
1093 ctxt->uri );
1094 }
1095 }
1096
1097 return ( len );
1098}
1099
1100
1101/**
Owen Taylor3473f882001-02-23 17:55:21 +00001102 * xmlIOHTTPClose:
1103 * @context: the I/O context
1104 *
1105 * Close an HTTP I/O channel
1106 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001107int
Owen Taylor3473f882001-02-23 17:55:21 +00001108xmlIOHTTPClose (void * context) {
1109 xmlNanoHTTPClose(context);
Daniel Veillardf012a642001-07-23 19:10:52 +00001110 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001111}
Daniel Veillardf012a642001-07-23 19:10:52 +00001112
1113/**
1114 * xmlIOHTTCloseWrite
1115 * @context: The I/O context
1116 * @http_mthd: The HTTP method to be used when sending the data
1117 *
1118 * Close the transmit HTTP I/O channel and actually send the data.
1119 */
1120static int
1121xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
1122
1123 int close_rc = -1;
1124 int http_rtn = 0;
1125 int content_lgth = 0;
1126 xmlIOHTTPWriteCtxtPtr ctxt = context;
1127
1128 char * http_content = NULL;
1129 char * content_encoding = NULL;
1130 char * content_type = (char *) "text/xml";
1131 void * http_ctxt = NULL;
1132
1133 if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
1134 return ( -1 );
1135
1136 /* Retrieve the content from the appropriate buffer */
1137
1138#ifdef HAVE_ZLIB_H
1139
1140 if ( ctxt->compression > 0 ) {
1141 content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
1142 content_encoding = (char *) "Content-Encoding: gzip";
1143 }
1144 else
1145#endif
1146 {
1147 /* Pull the data out of the memory output buffer */
1148
1149 xmlOutputBufferPtr dctxt = ctxt->doc_buff;
1150 http_content = (char *)dctxt->buffer->content;
1151 content_lgth = dctxt->buffer->use;
1152 }
1153
1154 if ( http_content == NULL ) {
1155 xmlGenericError( xmlGenericErrorContext,
1156 "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
1157 "Error retrieving content.\nUnable to",
1158 http_mthd, "data to URI", ctxt->uri );
1159 }
1160
1161 else {
1162
1163 http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
1164 &content_type, content_encoding,
1165 content_lgth );
1166
1167 if ( http_ctxt != NULL ) {
1168#ifdef DEBUG_HTTP
1169 /* If testing/debugging - dump reply with request content */
1170
1171 FILE * tst_file = NULL;
1172 char buffer[ 4096 ];
1173 char * dump_name = NULL;
1174 int avail;
1175
1176 xmlGenericError( xmlGenericErrorContext,
1177 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
1178 http_mthd, ctxt->uri,
1179 xmlNanoHTTPReturnCode( http_ctxt ) );
1180
1181 /*
1182 ** Since either content or reply may be gzipped,
1183 ** dump them to separate files instead of the
1184 ** standard error context.
1185 */
1186
1187 dump_name = tempnam( NULL, "lxml" );
1188 if ( dump_name != NULL ) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001189 (void)snprintf( buffer, sizeof(buffer), "%s.content", dump_name );
Daniel Veillardf012a642001-07-23 19:10:52 +00001190
1191 tst_file = fopen( buffer, "w" );
1192 if ( tst_file != NULL ) {
1193 xmlGenericError( xmlGenericErrorContext,
1194 "Transmitted content saved in file: %s\n", buffer );
1195
1196 fwrite( http_content, sizeof( char ),
1197 content_lgth, tst_file );
1198 fclose( tst_file );
1199 }
1200
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001201 (void)snprintf( buffer, sizeof(buffer), "%s.reply", dump_name );
Daniel Veillardf012a642001-07-23 19:10:52 +00001202 tst_file = fopen( buffer, "w" );
1203 if ( tst_file != NULL ) {
1204 xmlGenericError( xmlGenericErrorContext,
1205 "Reply content saved in file: %s\n", buffer );
1206
1207
1208 while ( (avail = xmlNanoHTTPRead( http_ctxt,
1209 buffer, sizeof( buffer ) )) > 0 ) {
1210
1211 fwrite( buffer, sizeof( char ), avail, tst_file );
1212 }
1213
1214 fclose( tst_file );
1215 }
1216
1217 free( dump_name );
1218 }
1219#endif /* DEBUG_HTTP */
1220
1221 http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
1222 if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
1223 close_rc = 0;
1224 else
1225 xmlGenericError( xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001226 "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001227 http_mthd, content_lgth,
1228 "bytes to URI", ctxt->uri,
1229 "failed. HTTP return code:", http_rtn );
1230
1231 xmlNanoHTTPClose( http_ctxt );
1232 xmlFree( content_type );
1233 }
1234 }
1235
1236 /* Final cleanups */
1237
1238 xmlFreeHTTPWriteCtxt( ctxt );
1239
1240 return ( close_rc );
1241}
1242
1243/**
1244 * xmlIOHTTPClosePut
1245 *
1246 * @context: The I/O context
1247 *
1248 * Close the transmit HTTP I/O channel and actually send data using a PUT
1249 * HTTP method.
1250 */
1251static int
1252xmlIOHTTPClosePut( void * ctxt ) {
1253 return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
1254}
1255
1256
1257/**
1258 * xmlIOHTTPClosePost
1259 *
1260 * @context: The I/O context
1261 *
1262 * Close the transmit HTTP I/O channel and actually send data using a POST
1263 * HTTP method.
1264 */
1265static int
1266xmlIOHTTPClosePost( void * ctxt ) {
1267 return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
1268}
1269
Owen Taylor3473f882001-02-23 17:55:21 +00001270#endif /* LIBXML_HTTP_ENABLED */
1271
1272#ifdef LIBXML_FTP_ENABLED
1273/************************************************************************
1274 * *
1275 * I/O for FTP file accesses *
1276 * *
1277 ************************************************************************/
1278/**
1279 * xmlIOFTPMatch:
1280 * @filename: the URI for matching
1281 *
1282 * check if the URI matches an FTP one
1283 *
1284 * Returns 1 if matches, 0 otherwise
1285 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001286int
Owen Taylor3473f882001-02-23 17:55:21 +00001287xmlIOFTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001288 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "ftp://", 6))
Owen Taylor3473f882001-02-23 17:55:21 +00001289 return(1);
1290 return(0);
1291}
1292
1293/**
1294 * xmlIOFTPOpen:
1295 * @filename: the URI for matching
1296 *
1297 * open an FTP I/O channel
1298 *
1299 * Returns an I/O context or NULL in case of error
1300 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001301void *
Owen Taylor3473f882001-02-23 17:55:21 +00001302xmlIOFTPOpen (const char *filename) {
1303 return(xmlNanoFTPOpen(filename));
1304}
1305
1306/**
1307 * xmlIOFTPRead:
1308 * @context: the I/O context
1309 * @buffer: where to drop data
1310 * @len: number of bytes to write
1311 *
1312 * Read @len bytes to @buffer from the I/O channel.
1313 *
1314 * Returns the number of bytes written
1315 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001316int
Owen Taylor3473f882001-02-23 17:55:21 +00001317xmlIOFTPRead(void * context, char * buffer, int len) {
1318 return(xmlNanoFTPRead(context, &buffer[0], len));
1319}
1320
1321/**
1322 * xmlIOFTPClose:
1323 * @context: the I/O context
1324 *
1325 * Close an FTP I/O channel
1326 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001327int
Owen Taylor3473f882001-02-23 17:55:21 +00001328xmlIOFTPClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001329 return ( xmlNanoFTPClose(context) );
Owen Taylor3473f882001-02-23 17:55:21 +00001330}
1331#endif /* LIBXML_FTP_ENABLED */
1332
1333
1334/**
1335 * xmlRegisterInputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001336 * @matchFunc: the xmlInputMatchCallback
1337 * @openFunc: the xmlInputOpenCallback
1338 * @readFunc: the xmlInputReadCallback
1339 * @closeFunc: the xmlInputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001340 *
1341 * Register a new set of I/O callback for handling parser input.
1342 *
1343 * Returns the registered handler number or -1 in case of error
1344 */
1345int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001346xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
1347 xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
1348 xmlInputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001349 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
1350 return(-1);
1351 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001352 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
1353 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
1354 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
1355 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
Owen Taylor3473f882001-02-23 17:55:21 +00001356 return(xmlInputCallbackNr++);
1357}
1358
1359/**
1360 * xmlRegisterOutputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001361 * @matchFunc: the xmlOutputMatchCallback
1362 * @openFunc: the xmlOutputOpenCallback
1363 * @writeFunc: the xmlOutputWriteCallback
1364 * @closeFunc: the xmlOutputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001365 *
1366 * Register a new set of I/O callback for handling output.
1367 *
1368 * Returns the registered handler number or -1 in case of error
1369 */
1370int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001371xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
1372 xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
1373 xmlOutputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001374 if (xmlOutputCallbackNr >= MAX_INPUT_CALLBACK) {
1375 return(-1);
1376 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001377 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
1378 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
1379 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
1380 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
Owen Taylor3473f882001-02-23 17:55:21 +00001381 return(xmlOutputCallbackNr++);
1382}
1383
1384/**
1385 * xmlRegisterDefaultInputCallbacks:
1386 *
1387 * Registers the default compiled-in I/O handlers.
1388 */
1389void
1390#ifdef VMS
1391xmlRegisterDefInputCallbacks
1392#else
1393xmlRegisterDefaultInputCallbacks
1394#endif
1395(void) {
1396 if (xmlInputCallbackInitialized)
1397 return;
1398
1399 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
1400 xmlFileRead, xmlFileClose);
1401#ifdef HAVE_ZLIB_H
1402 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1403 xmlGzfileRead, xmlGzfileClose);
1404#endif /* HAVE_ZLIB_H */
1405
1406#ifdef LIBXML_HTTP_ENABLED
1407 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
1408 xmlIOHTTPRead, xmlIOHTTPClose);
1409#endif /* LIBXML_HTTP_ENABLED */
1410
1411#ifdef LIBXML_FTP_ENABLED
1412 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1413 xmlIOFTPRead, xmlIOFTPClose);
1414#endif /* LIBXML_FTP_ENABLED */
1415 xmlInputCallbackInitialized = 1;
1416}
1417
1418/**
1419 * xmlRegisterDefaultOutputCallbacks:
1420 *
1421 * Registers the default compiled-in I/O handlers.
1422 */
1423void
1424#ifdef VMS
1425xmlRegisterDefOutputCallbacks
1426#else
1427xmlRegisterDefaultOutputCallbacks
1428#endif
1429(void) {
1430 if (xmlOutputCallbackInitialized)
1431 return;
1432
1433 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
1434 xmlFileWrite, xmlFileClose);
Daniel Veillardf012a642001-07-23 19:10:52 +00001435
1436#ifdef LIBXML_HTTP_ENABLED
1437 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
1438 xmlIOHTTPWrite, xmlIOHTTPClosePut);
1439#endif
1440
Owen Taylor3473f882001-02-23 17:55:21 +00001441/*********************************
1442 No way a-priori to distinguish between gzipped files from
1443 uncompressed ones except opening if existing then closing
1444 and saving with same compression ratio ... a pain.
1445
1446#ifdef HAVE_ZLIB_H
1447 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1448 xmlGzfileWrite, xmlGzfileClose);
1449#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001450
1451 Nor FTP PUT ....
1452#ifdef LIBXML_FTP_ENABLED
1453 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1454 xmlIOFTPWrite, xmlIOFTPClose);
1455#endif
1456 **********************************/
1457 xmlOutputCallbackInitialized = 1;
1458}
1459
Daniel Veillardf012a642001-07-23 19:10:52 +00001460#ifdef LIBXML_HTTP_ENABLED
1461/**
1462 * xmlRegisterHTTPPostCallbacks
1463 *
1464 * By default, libxml submits HTTP output requests using the "PUT" method.
1465 * Calling this method changes the HTTP output method to use the "POST"
1466 * method instead.
1467 *
1468 */
1469void
1470xmlRegisterHTTPPostCallbacks( void ) {
1471
1472 /* Register defaults if not done previously */
1473
1474 if ( xmlOutputCallbackInitialized == 0 )
1475 xmlRegisterDefaultOutputCallbacks( );
1476
1477 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
1478 xmlIOHTTPWrite, xmlIOHTTPClosePost);
1479 return;
1480}
1481#endif
1482
Owen Taylor3473f882001-02-23 17:55:21 +00001483/**
1484 * xmlAllocParserInputBuffer:
1485 * @enc: the charset encoding if known
1486 *
1487 * Create a buffered parser input for progressive parsing
1488 *
1489 * Returns the new parser input or NULL
1490 */
1491xmlParserInputBufferPtr
1492xmlAllocParserInputBuffer(xmlCharEncoding enc) {
1493 xmlParserInputBufferPtr ret;
1494
1495 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
1496 if (ret == NULL) {
1497 xmlGenericError(xmlGenericErrorContext,
1498 "xmlAllocParserInputBuffer : out of memory!\n");
1499 return(NULL);
1500 }
1501 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
1502 ret->buffer = xmlBufferCreate();
1503 if (ret->buffer == NULL) {
1504 xmlFree(ret);
1505 return(NULL);
1506 }
1507 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
1508 ret->encoder = xmlGetCharEncodingHandler(enc);
1509 if (ret->encoder != NULL)
1510 ret->raw = xmlBufferCreate();
1511 else
1512 ret->raw = NULL;
1513 ret->readcallback = NULL;
1514 ret->closecallback = NULL;
1515 ret->context = NULL;
1516
1517 return(ret);
1518}
1519
1520/**
1521 * xmlAllocOutputBuffer:
1522 * @encoder: the encoding converter or NULL
1523 *
1524 * Create a buffered parser output
1525 *
1526 * Returns the new parser output or NULL
1527 */
1528xmlOutputBufferPtr
1529xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
1530 xmlOutputBufferPtr ret;
1531
1532 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
1533 if (ret == NULL) {
1534 xmlGenericError(xmlGenericErrorContext,
1535 "xmlAllocOutputBuffer : out of memory!\n");
1536 return(NULL);
1537 }
1538 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
1539 ret->buffer = xmlBufferCreate();
1540 if (ret->buffer == NULL) {
1541 xmlFree(ret);
1542 return(NULL);
1543 }
1544 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
1545 ret->encoder = encoder;
1546 if (encoder != NULL) {
1547 ret->conv = xmlBufferCreateSize(4000);
1548 /*
1549 * This call is designed to initiate the encoder state
1550 */
1551 xmlCharEncOutFunc(encoder, ret->conv, NULL);
1552 } else
1553 ret->conv = NULL;
1554 ret->writecallback = NULL;
1555 ret->closecallback = NULL;
1556 ret->context = NULL;
1557 ret->written = 0;
1558
1559 return(ret);
1560}
1561
1562/**
1563 * xmlFreeParserInputBuffer:
1564 * @in: a buffered parser input
1565 *
1566 * Free up the memory used by a buffered parser input
1567 */
1568void
1569xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
1570 if (in->raw) {
1571 xmlBufferFree(in->raw);
1572 in->raw = NULL;
1573 }
1574 if (in->encoder != NULL) {
1575 xmlCharEncCloseFunc(in->encoder);
1576 }
1577 if (in->closecallback != NULL) {
1578 in->closecallback(in->context);
1579 }
1580 if (in->buffer != NULL) {
1581 xmlBufferFree(in->buffer);
1582 in->buffer = NULL;
1583 }
1584
Owen Taylor3473f882001-02-23 17:55:21 +00001585 xmlFree(in);
1586}
1587
1588/**
1589 * xmlOutputBufferClose:
1590 * @out: a buffered output
1591 *
1592 * flushes and close the output I/O channel
1593 * and free up all the associated resources
1594 *
1595 * Returns the number of byte written or -1 in case of error.
1596 */
1597int
1598xmlOutputBufferClose(xmlOutputBufferPtr out) {
1599 int written;
Daniel Veillardf012a642001-07-23 19:10:52 +00001600 int err_rc = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001601
1602 if (out == NULL)
1603 return(-1);
1604 if (out->writecallback != NULL)
1605 xmlOutputBufferFlush(out);
1606 if (out->closecallback != NULL) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001607 err_rc = out->closecallback(out->context);
Owen Taylor3473f882001-02-23 17:55:21 +00001608 }
1609 written = out->written;
1610 if (out->conv) {
1611 xmlBufferFree(out->conv);
1612 out->conv = NULL;
1613 }
1614 if (out->encoder != NULL) {
1615 xmlCharEncCloseFunc(out->encoder);
1616 }
1617 if (out->buffer != NULL) {
1618 xmlBufferFree(out->buffer);
1619 out->buffer = NULL;
1620 }
1621
Owen Taylor3473f882001-02-23 17:55:21 +00001622 xmlFree(out);
Daniel Veillardf012a642001-07-23 19:10:52 +00001623 return( ( err_rc == 0 ) ? written : err_rc );
Owen Taylor3473f882001-02-23 17:55:21 +00001624}
1625
1626/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001627 * xmlParserInputBufferCreateFname:
1628 * @URI: a C string containing the URI or filename
1629 * @enc: the charset encoding if known
1630 *
1631 * VMS version of xmlParserInputBufferCreateFilename()
1632 *
1633 * Returns the new parser input or NULL
1634 */
1635/**
Owen Taylor3473f882001-02-23 17:55:21 +00001636 * xmlParserInputBufferCreateFilename:
1637 * @URI: a C string containing the URI or filename
1638 * @enc: the charset encoding if known
1639 *
1640 * Create a buffered parser input for the progressive parsing of a file
1641 * If filename is "-' then we use stdin as the input.
1642 * Automatic support for ZLIB/Compress compressed document is provided
1643 * by default if found at compile-time.
1644 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
1645 *
1646 * Returns the new parser input or NULL
1647 */
1648xmlParserInputBufferPtr
1649#ifdef VMS
1650xmlParserInputBufferCreateFname
1651#else
1652xmlParserInputBufferCreateFilename
1653#endif
1654(const char *URI, xmlCharEncoding enc) {
1655 xmlParserInputBufferPtr ret;
Daniel Veillard388236f2001-07-08 18:35:48 +00001656 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001657 void *context = NULL;
Daniel Veillard388236f2001-07-08 18:35:48 +00001658 char *unescaped;
Owen Taylor3473f882001-02-23 17:55:21 +00001659
1660 if (xmlInputCallbackInitialized == 0)
1661 xmlRegisterDefaultInputCallbacks();
1662
1663 if (URI == NULL) return(NULL);
1664
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001665#ifdef LIBXML_CATALOG_ENABLED
1666#endif
1667
Owen Taylor3473f882001-02-23 17:55:21 +00001668 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001669 * Try to find one of the input accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00001670 * Go in reverse to give precedence to user defined handlers.
Daniel Veillard388236f2001-07-08 18:35:48 +00001671 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00001672 */
Daniel Veillard388236f2001-07-08 18:35:48 +00001673 unescaped = xmlURIUnescapeString(URI, 0, NULL);
1674 if (unescaped != NULL) {
1675 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
1676 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
1677 (xmlInputCallbackTable[i].matchcallback(unescaped) != 0)) {
1678 context = xmlInputCallbackTable[i].opencallback(unescaped);
1679 if (context != NULL)
1680 break;
1681 }
1682 }
1683 xmlFree(unescaped);
1684 }
1685
1686 /*
1687 * If this failed try with a non-escaped URI this may be a strange
1688 * filename
1689 */
1690 if (context == NULL) {
1691 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
1692 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
1693 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
1694 context = xmlInputCallbackTable[i].opencallback(URI);
1695 if (context != NULL)
1696 break;
1697 }
Owen Taylor3473f882001-02-23 17:55:21 +00001698 }
1699 }
1700 if (context == NULL) {
1701 return(NULL);
1702 }
1703
1704 /*
1705 * Allocate the Input buffer front-end.
1706 */
1707 ret = xmlAllocParserInputBuffer(enc);
1708 if (ret != NULL) {
1709 ret->context = context;
1710 ret->readcallback = xmlInputCallbackTable[i].readcallback;
1711 ret->closecallback = xmlInputCallbackTable[i].closecallback;
1712 }
1713 return(ret);
1714}
1715
1716/**
1717 * xmlOutputBufferCreateFilename:
1718 * @URI: a C string containing the URI or filename
1719 * @encoder: the encoding converter or NULL
1720 * @compression: the compression ration (0 none, 9 max).
1721 *
1722 * Create a buffered output for the progressive saving of a file
1723 * If filename is "-' then we use stdout as the output.
1724 * Automatic support for ZLIB/Compress compressed document is provided
1725 * by default if found at compile-time.
1726 * TODO: currently if compression is set, the library only support
1727 * writing to a local file.
1728 *
1729 * Returns the new output or NULL
1730 */
1731xmlOutputBufferPtr
1732xmlOutputBufferCreateFilename(const char *URI,
1733 xmlCharEncodingHandlerPtr encoder,
1734 int compression) {
1735 xmlOutputBufferPtr ret;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001736 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001737 void *context = NULL;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001738 char *unescaped;
Owen Taylor3473f882001-02-23 17:55:21 +00001739
Daniel Veillardf012a642001-07-23 19:10:52 +00001740 int is_http_uri = 0; /* Can't change if HTTP disabled */
1741
Owen Taylor3473f882001-02-23 17:55:21 +00001742 if (xmlOutputCallbackInitialized == 0)
1743 xmlRegisterDefaultOutputCallbacks();
1744
1745 if (URI == NULL) return(NULL);
1746
Daniel Veillardf012a642001-07-23 19:10:52 +00001747#ifdef LIBXML_HTTP_ENABLED
1748 /* Need to prevent HTTP URI's from falling into zlib short circuit */
1749
1750 is_http_uri = xmlIOHTTPMatch( URI );
1751#endif
1752
Owen Taylor3473f882001-02-23 17:55:21 +00001753
1754 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001755 * Try to find one of the output accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00001756 * Go in reverse to give precedence to user defined handlers.
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001757 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00001758 */
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001759 unescaped = xmlURIUnescapeString(URI, 0, NULL);
1760 if (unescaped != NULL) {
1761#ifdef HAVE_ZLIB_H
1762 if ((compression > 0) && (compression <= 9) && (is_http_uri == 0)) {
1763 context = xmlGzfileOpenW(unescaped, compression);
1764 if (context != NULL) {
1765 ret = xmlAllocOutputBuffer(encoder);
1766 if (ret != NULL) {
1767 ret->context = context;
1768 ret->writecallback = xmlGzfileWrite;
1769 ret->closecallback = xmlGzfileClose;
1770 }
1771 xmlFree(unescaped);
1772 return(ret);
1773 }
1774 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001775#endif
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001776 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
1777 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
1778 (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
1779#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
1780 /* Need to pass compression parameter into HTTP open calls */
1781 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
1782 context = xmlIOHTTPOpenW(unescaped, compression);
1783 else
1784#endif
1785 context = xmlOutputCallbackTable[i].opencallback(unescaped);
1786 if (context != NULL)
1787 break;
1788 }
1789 }
1790 xmlFree(unescaped);
1791 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001792
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001793 /*
1794 * If this failed try with a non-escaped URI this may be a strange
1795 * filename
1796 */
1797 if (context == NULL) {
1798#ifdef HAVE_ZLIB_H
1799 if ((compression > 0) && (compression <= 9) && (is_http_uri == 0)) {
1800 context = xmlGzfileOpenW(URI, compression);
1801 if (context != NULL) {
1802 ret = xmlAllocOutputBuffer(encoder);
1803 if (ret != NULL) {
1804 ret->context = context;
1805 ret->writecallback = xmlGzfileWrite;
1806 ret->closecallback = xmlGzfileClose;
1807 }
1808 return(ret);
1809 }
1810 }
1811#endif
1812 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
1813 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
1814 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001815#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
1816 /* Need to pass compression parameter into HTTP open calls */
1817 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
1818 context = xmlIOHTTPOpenW(URI, compression);
1819 else
1820#endif
1821 context = xmlOutputCallbackTable[i].opencallback(URI);
1822 if (context != NULL)
1823 break;
1824 }
Owen Taylor3473f882001-02-23 17:55:21 +00001825 }
1826 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001827
Owen Taylor3473f882001-02-23 17:55:21 +00001828 if (context == NULL) {
1829 return(NULL);
1830 }
1831
1832 /*
1833 * Allocate the Output buffer front-end.
1834 */
1835 ret = xmlAllocOutputBuffer(encoder);
1836 if (ret != NULL) {
1837 ret->context = context;
1838 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
1839 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
1840 }
1841 return(ret);
1842}
1843
1844/**
1845 * xmlParserInputBufferCreateFile:
1846 * @file: a FILE*
1847 * @enc: the charset encoding if known
1848 *
1849 * Create a buffered parser input for the progressive parsing of a FILE *
1850 * buffered C I/O
1851 *
1852 * Returns the new parser input or NULL
1853 */
1854xmlParserInputBufferPtr
1855xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
1856 xmlParserInputBufferPtr ret;
1857
1858 if (xmlInputCallbackInitialized == 0)
1859 xmlRegisterDefaultInputCallbacks();
1860
1861 if (file == NULL) return(NULL);
1862
1863 ret = xmlAllocParserInputBuffer(enc);
1864 if (ret != NULL) {
1865 ret->context = file;
1866 ret->readcallback = xmlFileRead;
1867 ret->closecallback = xmlFileFlush;
1868 }
1869
1870 return(ret);
1871}
1872
1873/**
1874 * xmlOutputBufferCreateFile:
1875 * @file: a FILE*
1876 * @encoder: the encoding converter or NULL
1877 *
1878 * Create a buffered output for the progressive saving to a FILE *
1879 * buffered C I/O
1880 *
1881 * Returns the new parser output or NULL
1882 */
1883xmlOutputBufferPtr
1884xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
1885 xmlOutputBufferPtr ret;
1886
1887 if (xmlOutputCallbackInitialized == 0)
1888 xmlRegisterDefaultOutputCallbacks();
1889
1890 if (file == NULL) return(NULL);
1891
1892 ret = xmlAllocOutputBuffer(encoder);
1893 if (ret != NULL) {
1894 ret->context = file;
1895 ret->writecallback = xmlFileWrite;
1896 ret->closecallback = xmlFileFlush;
1897 }
1898
1899 return(ret);
1900}
1901
1902/**
1903 * xmlParserInputBufferCreateFd:
1904 * @fd: a file descriptor number
1905 * @enc: the charset encoding if known
1906 *
1907 * Create a buffered parser input for the progressive parsing for the input
1908 * from a file descriptor
1909 *
1910 * Returns the new parser input or NULL
1911 */
1912xmlParserInputBufferPtr
1913xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
1914 xmlParserInputBufferPtr ret;
1915
1916 if (fd < 0) return(NULL);
1917
1918 ret = xmlAllocParserInputBuffer(enc);
1919 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00001920 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00001921 ret->readcallback = xmlFdRead;
1922 ret->closecallback = xmlFdClose;
1923 }
1924
1925 return(ret);
1926}
1927
1928/**
1929 * xmlParserInputBufferCreateMem:
1930 * @mem: the memory input
1931 * @size: the length of the memory block
1932 * @enc: the charset encoding if known
1933 *
1934 * Create a buffered parser input for the progressive parsing for the input
1935 * from a memory area.
1936 *
1937 * Returns the new parser input or NULL
1938 */
1939xmlParserInputBufferPtr
1940xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
1941 xmlParserInputBufferPtr ret;
1942
1943 if (size <= 0) return(NULL);
1944 if (mem == NULL) return(NULL);
1945
1946 ret = xmlAllocParserInputBuffer(enc);
1947 if (ret != NULL) {
1948 ret->context = (void *) mem;
1949 ret->readcallback = (xmlInputReadCallback) xmlNop;
1950 ret->closecallback = NULL;
1951 xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size);
1952 }
1953
1954 return(ret);
1955}
1956
1957/**
1958 * xmlOutputBufferCreateFd:
1959 * @fd: a file descriptor number
1960 * @encoder: the encoding converter or NULL
1961 *
1962 * Create a buffered output for the progressive saving
1963 * to a file descriptor
1964 *
1965 * Returns the new parser output or NULL
1966 */
1967xmlOutputBufferPtr
1968xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
1969 xmlOutputBufferPtr ret;
1970
1971 if (fd < 0) return(NULL);
1972
1973 ret = xmlAllocOutputBuffer(encoder);
1974 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00001975 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00001976 ret->writecallback = xmlFdWrite;
Daniel Veillard7db38712002-02-07 16:39:11 +00001977 ret->closecallback = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001978 }
1979
1980 return(ret);
1981}
1982
1983/**
1984 * xmlParserInputBufferCreateIO:
1985 * @ioread: an I/O read function
1986 * @ioclose: an I/O close function
1987 * @ioctx: an I/O handler
1988 * @enc: the charset encoding if known
1989 *
1990 * Create a buffered parser input for the progressive parsing for the input
1991 * from an I/O handler
1992 *
1993 * Returns the new parser input or NULL
1994 */
1995xmlParserInputBufferPtr
1996xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
1997 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
1998 xmlParserInputBufferPtr ret;
1999
2000 if (ioread == NULL) return(NULL);
2001
2002 ret = xmlAllocParserInputBuffer(enc);
2003 if (ret != NULL) {
2004 ret->context = (void *) ioctx;
2005 ret->readcallback = ioread;
2006 ret->closecallback = ioclose;
2007 }
2008
2009 return(ret);
2010}
2011
2012/**
2013 * xmlOutputBufferCreateIO:
2014 * @iowrite: an I/O write function
2015 * @ioclose: an I/O close function
2016 * @ioctx: an I/O handler
Daniel Veillard9d06d302002-01-22 18:15:52 +00002017 * @encoder: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002018 *
2019 * Create a buffered output for the progressive saving
2020 * to an I/O handler
2021 *
2022 * Returns the new parser output or NULL
2023 */
2024xmlOutputBufferPtr
2025xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
2026 xmlOutputCloseCallback ioclose, void *ioctx,
2027 xmlCharEncodingHandlerPtr encoder) {
2028 xmlOutputBufferPtr ret;
2029
2030 if (iowrite == NULL) return(NULL);
2031
2032 ret = xmlAllocOutputBuffer(encoder);
2033 if (ret != NULL) {
2034 ret->context = (void *) ioctx;
2035 ret->writecallback = iowrite;
2036 ret->closecallback = ioclose;
2037 }
2038
2039 return(ret);
2040}
2041
2042/**
2043 * xmlParserInputBufferPush:
2044 * @in: a buffered parser input
2045 * @len: the size in bytes of the array.
2046 * @buf: an char array
2047 *
2048 * Push the content of the arry in the input buffer
2049 * This routine handle the I18N transcoding to internal UTF-8
2050 * This is used when operating the parser in progressive (push) mode.
2051 *
2052 * Returns the number of chars read and stored in the buffer, or -1
2053 * in case of error.
2054 */
2055int
2056xmlParserInputBufferPush(xmlParserInputBufferPtr in,
2057 int len, const char *buf) {
2058 int nbchars = 0;
2059
2060 if (len < 0) return(0);
2061 if (in->encoder != NULL) {
2062 /*
2063 * Store the data in the incoming raw buffer
2064 */
2065 if (in->raw == NULL) {
2066 in->raw = xmlBufferCreate();
2067 }
2068 xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
2069
2070 /*
2071 * convert as much as possible to the parser reading buffer.
2072 */
2073 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2074 if (nbchars < 0) {
2075 xmlGenericError(xmlGenericErrorContext,
2076 "xmlParserInputBufferPush: encoder error\n");
2077 return(-1);
2078 }
2079 } else {
2080 nbchars = len;
2081 xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
2082 }
2083#ifdef DEBUG_INPUT
2084 xmlGenericError(xmlGenericErrorContext,
2085 "I/O: pushed %d chars, buffer %d/%d\n",
2086 nbchars, in->buffer->use, in->buffer->size);
2087#endif
2088 return(nbchars);
2089}
2090
2091/**
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002092 * endOfInput:
2093 *
2094 * When reading from an Input channel indicated end of file or error
2095 * don't reread from it again.
2096 */
2097static int
2098endOfInput (void * context ATTRIBUTE_UNUSED,
2099 char * buffer ATTRIBUTE_UNUSED,
2100 int len ATTRIBUTE_UNUSED) {
2101 return(0);
2102}
2103
2104/**
Owen Taylor3473f882001-02-23 17:55:21 +00002105 * xmlParserInputBufferGrow:
2106 * @in: a buffered parser input
2107 * @len: indicative value of the amount of chars to read
2108 *
2109 * Grow up the content of the input buffer, the old data are preserved
2110 * This routine handle the I18N transcoding to internal UTF-8
2111 * This routine is used when operating the parser in normal (pull) mode
2112 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002113 * TODO: one should be able to remove one extra copy by copying directly
Owen Taylor3473f882001-02-23 17:55:21 +00002114 * onto in->buffer or in->raw
2115 *
2116 * Returns the number of chars read and stored in the buffer, or -1
2117 * in case of error.
2118 */
2119int
2120xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
2121 char *buffer = NULL;
2122 int res = 0;
2123 int nbchars = 0;
2124 int buffree;
Daniel Veillard9e412302002-06-10 15:59:44 +00002125 unsigned int needSize;
Owen Taylor3473f882001-02-23 17:55:21 +00002126
2127 if ((len <= MINLEN) && (len != 4))
2128 len = MINLEN;
2129 buffree = in->buffer->size - in->buffer->use;
2130 if (buffree <= 0) {
2131 xmlGenericError(xmlGenericErrorContext,
2132 "xmlParserInputBufferGrow : buffer full !\n");
2133 return(0);
2134 }
2135 if (len > buffree)
2136 len = buffree;
2137
Daniel Veillarde5354492002-05-16 08:43:22 +00002138 needSize = in->buffer->use + len + 1;
2139 if (needSize > in->buffer->size){
2140 if (!xmlBufferResize(in->buffer, needSize)){
2141 xmlGenericError(xmlGenericErrorContext,
2142 "xmlBufferAdd : out of memory!\n");
2143 return(0);
2144 }
Owen Taylor3473f882001-02-23 17:55:21 +00002145 }
Daniel Veillarde5354492002-05-16 08:43:22 +00002146 buffer = (char *)&in->buffer->content[in->buffer->use];
Owen Taylor3473f882001-02-23 17:55:21 +00002147
2148 /*
2149 * Call the read method for this I/O type.
2150 */
2151 if (in->readcallback != NULL) {
2152 res = in->readcallback(in->context, &buffer[0], len);
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002153 if (res <= 0)
2154 in->readcallback = endOfInput;
Owen Taylor3473f882001-02-23 17:55:21 +00002155 } else {
2156 xmlGenericError(xmlGenericErrorContext,
2157 "xmlParserInputBufferGrow : no input !\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002158 return(-1);
2159 }
2160 if (res < 0) {
Owen Taylor3473f882001-02-23 17:55:21 +00002161 return(-1);
2162 }
2163 len = res;
2164 if (in->encoder != NULL) {
2165 /*
2166 * Store the data in the incoming raw buffer
2167 */
2168 if (in->raw == NULL) {
2169 in->raw = xmlBufferCreate();
2170 }
2171 xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
2172
2173 /*
2174 * convert as much as possible to the parser reading buffer.
2175 */
2176 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2177 if (nbchars < 0) {
2178 xmlGenericError(xmlGenericErrorContext,
2179 "xmlParserInputBufferGrow: encoder error\n");
2180 return(-1);
2181 }
2182 } else {
2183 nbchars = len;
Daniel Veillarde5354492002-05-16 08:43:22 +00002184 in->buffer->use += nbchars;
2185 buffer[nbchars] = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002186 }
2187#ifdef DEBUG_INPUT
2188 xmlGenericError(xmlGenericErrorContext,
2189 "I/O: read %d chars, buffer %d/%d\n",
2190 nbchars, in->buffer->use, in->buffer->size);
2191#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002192 return(nbchars);
2193}
2194
2195/**
2196 * xmlParserInputBufferRead:
2197 * @in: a buffered parser input
2198 * @len: indicative value of the amount of chars to read
2199 *
2200 * Refresh the content of the input buffer, the old data are considered
2201 * consumed
2202 * This routine handle the I18N transcoding to internal UTF-8
2203 *
2204 * Returns the number of chars read and stored in the buffer, or -1
2205 * in case of error.
2206 */
2207int
2208xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
2209 /* xmlBufferEmpty(in->buffer); */
2210 if (in->readcallback != NULL)
2211 return(xmlParserInputBufferGrow(in, len));
2212 else
2213 return(-1);
2214}
2215
2216/**
2217 * xmlOutputBufferWrite:
2218 * @out: a buffered parser output
2219 * @len: the size in bytes of the array.
2220 * @buf: an char array
2221 *
2222 * Write the content of the array in the output I/O buffer
2223 * This routine handle the I18N transcoding from internal UTF-8
2224 * The buffer is lossless, i.e. will store in case of partial
2225 * or delayed writes.
2226 *
2227 * Returns the number of chars immediately written, or -1
2228 * in case of error.
2229 */
2230int
2231xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
2232 int nbchars = 0; /* number of chars to output to I/O */
2233 int ret; /* return from function call */
2234 int written = 0; /* number of char written to I/O so far */
2235 int chunk; /* number of byte curreent processed from buf */
2236
2237 if (len < 0) return(0);
2238
2239 do {
2240 chunk = len;
2241 if (chunk > 4 * MINLEN)
2242 chunk = 4 * MINLEN;
2243
2244 /*
2245 * first handle encoding stuff.
2246 */
2247 if (out->encoder != NULL) {
2248 /*
2249 * Store the data in the incoming raw buffer
2250 */
2251 if (out->conv == NULL) {
2252 out->conv = xmlBufferCreate();
2253 }
2254 xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2255
2256 if ((out->buffer->use < MINLEN) && (chunk == len))
2257 goto done;
2258
2259 /*
2260 * convert as much as possible to the parser reading buffer.
2261 */
2262 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
2263 if (ret < 0) {
2264 xmlGenericError(xmlGenericErrorContext,
2265 "xmlOutputBufferWrite: encoder error\n");
2266 return(-1);
2267 }
2268 nbchars = out->conv->use;
2269 } else {
2270 xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2271 nbchars = out->buffer->use;
2272 }
2273 buf += chunk;
2274 len -= chunk;
2275
2276 if ((nbchars < MINLEN) && (len <= 0))
2277 goto done;
2278
2279 if (out->writecallback) {
2280 /*
2281 * second write the stuff to the I/O channel
2282 */
2283 if (out->encoder != NULL) {
2284 ret = out->writecallback(out->context,
2285 (const char *)out->conv->content, nbchars);
2286 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002287 xmlBufferShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002288 } else {
2289 ret = out->writecallback(out->context,
2290 (const char *)out->buffer->content, nbchars);
2291 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002292 xmlBufferShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002293 }
2294 if (ret < 0) {
2295 xmlGenericError(xmlGenericErrorContext,
2296 "I/O: error %d writing %d bytes\n", ret, nbchars);
2297 return(ret);
2298 }
2299 out->written += ret;
2300 }
2301 written += nbchars;
2302 } while (len > 0);
2303
2304done:
2305#ifdef DEBUG_INPUT
2306 xmlGenericError(xmlGenericErrorContext,
2307 "I/O: wrote %d chars\n", written);
2308#endif
2309 return(written);
2310}
2311
2312/**
2313 * xmlOutputBufferWriteString:
2314 * @out: a buffered parser output
2315 * @str: a zero terminated C string
2316 *
2317 * Write the content of the string in the output I/O buffer
2318 * This routine handle the I18N transcoding from internal UTF-8
2319 * The buffer is lossless, i.e. will store in case of partial
2320 * or delayed writes.
2321 *
2322 * Returns the number of chars immediately written, or -1
2323 * in case of error.
2324 */
2325int
2326xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
2327 int len;
2328
2329 if (str == NULL)
2330 return(-1);
2331 len = strlen(str);
2332
2333 if (len > 0)
2334 return(xmlOutputBufferWrite(out, len, str));
2335 return(len);
2336}
2337
2338/**
2339 * xmlOutputBufferFlush:
2340 * @out: a buffered output
2341 *
2342 * flushes the output I/O channel
2343 *
2344 * Returns the number of byte written or -1 in case of error.
2345 */
2346int
2347xmlOutputBufferFlush(xmlOutputBufferPtr out) {
2348 int nbchars = 0, ret = 0;
2349
2350 /*
2351 * first handle encoding stuff.
2352 */
2353 if ((out->conv != NULL) && (out->encoder != NULL)) {
2354 /*
2355 * convert as much as possible to the parser reading buffer.
2356 */
2357 nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
2358 if (nbchars < 0) {
2359 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002360 "xmlOutputBufferFlush: encoder error\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002361 return(-1);
2362 }
2363 }
2364
2365 /*
2366 * second flush the stuff to the I/O channel
2367 */
2368 if ((out->conv != NULL) && (out->encoder != NULL) &&
2369 (out->writecallback != NULL)) {
2370 ret = out->writecallback(out->context,
2371 (const char *)out->conv->content, out->conv->use);
2372 if (ret >= 0)
2373 xmlBufferShrink(out->conv, ret);
2374 } else if (out->writecallback != NULL) {
2375 ret = out->writecallback(out->context,
2376 (const char *)out->buffer->content, out->buffer->use);
2377 if (ret >= 0)
2378 xmlBufferShrink(out->buffer, ret);
2379 }
2380 if (ret < 0) {
2381 xmlGenericError(xmlGenericErrorContext,
2382 "I/O: error %d flushing %d bytes\n", ret, nbchars);
2383 return(ret);
2384 }
2385 out->written += ret;
2386
2387#ifdef DEBUG_INPUT
2388 xmlGenericError(xmlGenericErrorContext,
2389 "I/O: flushed %d chars\n", ret);
2390#endif
2391 return(ret);
2392}
2393
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002394/**
Owen Taylor3473f882001-02-23 17:55:21 +00002395 * xmlParserGetDirectory:
2396 * @filename: the path to a file
2397 *
2398 * lookup the directory for that file
2399 *
2400 * Returns a new allocated string containing the directory, or NULL.
2401 */
2402char *
2403xmlParserGetDirectory(const char *filename) {
2404 char *ret = NULL;
2405 char dir[1024];
2406 char *cur;
2407 char sep = '/';
2408
2409 if (xmlInputCallbackInitialized == 0)
2410 xmlRegisterDefaultInputCallbacks();
2411
2412 if (filename == NULL) return(NULL);
Daniel Veillard3c5ed912002-01-08 10:36:16 +00002413#if defined(WIN32) && !defined(__CYGWIN__)
Owen Taylor3473f882001-02-23 17:55:21 +00002414 sep = '\\';
2415#endif
2416
2417 strncpy(dir, filename, 1023);
2418 dir[1023] = 0;
2419 cur = &dir[strlen(dir)];
2420 while (cur > dir) {
2421 if (*cur == sep) break;
2422 cur --;
2423 }
2424 if (*cur == sep) {
2425 if (cur == dir) dir[1] = 0;
2426 else *cur = 0;
2427 ret = xmlMemStrdup(dir);
2428 } else {
2429 if (getcwd(dir, 1024) != NULL) {
2430 dir[1023] = 0;
2431 ret = xmlMemStrdup(dir);
2432 }
2433 }
2434 return(ret);
2435}
2436
2437/****************************************************************
2438 * *
2439 * External entities loading *
2440 * *
2441 ****************************************************************/
2442
Daniel Veillard561b7f82002-03-20 21:55:57 +00002443#ifdef LIBXML_CATALOG_ENABLED
2444static int xmlSysIDExists(const char *URL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00002445#ifdef HAVE_STAT
2446 int ret;
2447 struct stat info;
2448 const char *path;
2449
2450 if (URL == NULL)
2451 return(0);
2452
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002453 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost", 16))
Daniel Veillard6990bf32001-08-23 21:17:48 +00002454 path = &URL[16];
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002455 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard3c5ed912002-01-08 10:36:16 +00002456#if defined (_WIN32) && !defined(__CYGWIN__)
Daniel Veillard6990bf32001-08-23 21:17:48 +00002457 path = &URL[8];
2458#else
2459 path = &URL[7];
2460#endif
2461 } else
2462 path = URL;
2463 ret = stat(path, &info);
Daniel Veillard561b7f82002-03-20 21:55:57 +00002464 if (ret == 0)
2465 return(1);
Daniel Veillard6990bf32001-08-23 21:17:48 +00002466#endif
Daniel Veillard561b7f82002-03-20 21:55:57 +00002467 return(0);
Daniel Veillard6990bf32001-08-23 21:17:48 +00002468}
Daniel Veillard561b7f82002-03-20 21:55:57 +00002469#endif
Daniel Veillard6990bf32001-08-23 21:17:48 +00002470
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002471/**
Owen Taylor3473f882001-02-23 17:55:21 +00002472 * xmlDefaultExternalEntityLoader:
2473 * @URL: the URL for the entity to load
2474 * @ID: the System ID for the entity to load
2475 * @ctxt: the context in which the entity is called or NULL
2476 *
2477 * By default we don't load external entitites, yet.
2478 *
2479 * Returns a new allocated xmlParserInputPtr, or NULL.
2480 */
2481static
2482xmlParserInputPtr
2483xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
2484 xmlParserCtxtPtr ctxt) {
2485 xmlParserInputPtr ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002486 xmlChar *resource = NULL;
2487#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002488 xmlCatalogAllow pref;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002489#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002490
2491#ifdef DEBUG_EXTERNAL_ENTITIES
2492 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf012a642001-07-23 19:10:52 +00002493 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00002494#endif
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002495#ifdef LIBXML_CATALOG_ENABLED
2496 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002497 * If the resource doesn't exists as a file,
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002498 * try to load it from the resource pointed in the catalogs
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002499 */
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002500 pref = xmlCatalogGetDefaults();
2501
Daniel Veillard561b7f82002-03-20 21:55:57 +00002502 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlSysIDExists(URL))) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002503 /*
2504 * Do a local lookup
2505 */
2506 if ((ctxt->catalogs != NULL) &&
2507 ((pref == XML_CATA_ALLOW_ALL) ||
2508 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2509 resource = xmlCatalogLocalResolve(ctxt->catalogs,
2510 (const xmlChar *)ID,
2511 (const xmlChar *)URL);
2512 }
2513 /*
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002514 * Try a global lookup
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002515 */
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002516 if ((resource == NULL) &&
2517 ((pref == XML_CATA_ALLOW_ALL) ||
2518 (pref == XML_CATA_ALLOW_GLOBAL))) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002519 resource = xmlCatalogResolve((const xmlChar *)ID,
2520 (const xmlChar *)URL);
2521 }
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002522 if ((resource == NULL) && (URL != NULL))
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00002523 resource = xmlStrdup((const xmlChar *) URL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002524
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002525 /*
2526 * TODO: do an URI lookup on the reference
2527 */
Daniel Veillard561b7f82002-03-20 21:55:57 +00002528 if ((resource != NULL) && (!xmlSysIDExists((const char *)resource))) {
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002529 xmlChar *tmp = NULL;
2530
2531 if ((ctxt->catalogs != NULL) &&
2532 ((pref == XML_CATA_ALLOW_ALL) ||
2533 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2534 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
2535 }
2536 if ((tmp == NULL) &&
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00002537 ((pref == XML_CATA_ALLOW_ALL) ||
2538 (pref == XML_CATA_ALLOW_GLOBAL))) {
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002539 tmp = xmlCatalogResolveURI(resource);
2540 }
2541
2542 if (tmp != NULL) {
2543 xmlFree(resource);
2544 resource = tmp;
2545 }
2546 }
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002547 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002548#endif
2549
2550 if (resource == NULL)
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002551 resource = (xmlChar *) URL;
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002552
2553 if (resource == NULL) {
Daniel Veillardc6613042002-03-02 09:34:02 +00002554 if (ID == NULL)
2555 ID = "NULL";
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002556 if ((ctxt->validate) && (ctxt->sax != NULL) &&
2557 (ctxt->sax->error != NULL))
2558 ctxt->sax->error(ctxt,
2559 "failed to load external entity \"%s\"\n", ID);
2560 else if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00002561 ctxt->sax->warning(ctxt,
2562 "failed to load external entity \"%s\"\n", ID);
2563 return(NULL);
2564 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002565 ret = xmlNewInputFromFile(ctxt, (const char *)resource);
Owen Taylor3473f882001-02-23 17:55:21 +00002566 if (ret == NULL) {
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002567 if ((ctxt->validate) && (ctxt->sax != NULL) &&
2568 (ctxt->sax->error != NULL))
2569 ctxt->sax->error(ctxt,
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002570 "failed to load external entity \"%s\"\n", resource);
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002571 else if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00002572 ctxt->sax->warning(ctxt,
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002573 "failed to load external entity \"%s\"\n", resource);
Owen Taylor3473f882001-02-23 17:55:21 +00002574 }
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002575 if ((resource != NULL) && (resource != (xmlChar *) URL))
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002576 xmlFree(resource);
Owen Taylor3473f882001-02-23 17:55:21 +00002577 return(ret);
2578}
2579
2580static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
2581 xmlDefaultExternalEntityLoader;
2582
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002583/**
Owen Taylor3473f882001-02-23 17:55:21 +00002584 * xmlSetExternalEntityLoader:
2585 * @f: the new entity resolver function
2586 *
2587 * Changes the defaultexternal entity resolver function for the application
2588 */
2589void
2590xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
2591 xmlCurrentExternalEntityLoader = f;
2592}
2593
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002594/**
Owen Taylor3473f882001-02-23 17:55:21 +00002595 * xmlGetExternalEntityLoader:
2596 *
2597 * Get the default external entity resolver function for the application
2598 *
2599 * Returns the xmlExternalEntityLoader function pointer
2600 */
2601xmlExternalEntityLoader
2602xmlGetExternalEntityLoader(void) {
2603 return(xmlCurrentExternalEntityLoader);
2604}
2605
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002606/**
Owen Taylor3473f882001-02-23 17:55:21 +00002607 * xmlLoadExternalEntity:
2608 * @URL: the URL for the entity to load
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00002609 * @ID: the Public ID for the entity to load
Owen Taylor3473f882001-02-23 17:55:21 +00002610 * @ctxt: the context in which the entity is called or NULL
2611 *
2612 * Load an external entity, note that the use of this function for
2613 * unparsed entities may generate problems
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002614 * TODO: a more generic External entity API must be designed
Owen Taylor3473f882001-02-23 17:55:21 +00002615 *
2616 * Returns the xmlParserInputPtr or NULL
2617 */
2618xmlParserInputPtr
2619xmlLoadExternalEntity(const char *URL, const char *ID,
2620 xmlParserCtxtPtr ctxt) {
2621 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
2622}
2623
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00002624/************************************************************************
2625 * *
2626 * Disabling Network access *
2627 * *
2628 ************************************************************************/
2629
2630#ifdef LIBXML_CATALOG_ENABLED
2631static int
2632xmlNoNetExists(const char *URL)
2633{
2634#ifdef HAVE_STAT
2635 int ret;
2636 struct stat info;
2637 const char *path;
2638
2639 if (URL == NULL)
2640 return (0);
2641
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002642 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost", 16))
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00002643 path = &URL[16];
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002644 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard3c5ed912002-01-08 10:36:16 +00002645#if defined (_WIN32) && !defined(__CYGWIN__)
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00002646 path = &URL[8];
2647#else
2648 path = &URL[7];
2649#endif
2650 } else
2651 path = URL;
2652 ret = stat(path, &info);
2653 if (ret == 0)
2654 return (1);
2655#endif
2656 return (0);
2657}
2658#endif
2659
2660/**
2661 * xmlNoNetExternalEntityLoader:
2662 * @URL: the URL for the entity to load
2663 * @ID: the System ID for the entity to load
2664 * @ctxt: the context in which the entity is called or NULL
2665 *
2666 * A specific entity loader disabling network accesses, though still
2667 * allowing local catalog accesses for resolution.
2668 *
2669 * Returns a new allocated xmlParserInputPtr, or NULL.
2670 */
2671xmlParserInputPtr
2672xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
2673 xmlParserCtxtPtr ctxt) {
2674 xmlParserInputPtr input = NULL;
2675 xmlChar *resource = NULL;
2676
2677#ifdef LIBXML_CATALOG_ENABLED
2678 xmlCatalogAllow pref;
2679
2680 /*
2681 * If the resource doesn't exists as a file,
2682 * try to load it from the resource pointed in the catalogs
2683 */
2684 pref = xmlCatalogGetDefaults();
2685
2686 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
2687 /*
2688 * Do a local lookup
2689 */
2690 if ((ctxt->catalogs != NULL) &&
2691 ((pref == XML_CATA_ALLOW_ALL) ||
2692 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2693 resource = xmlCatalogLocalResolve(ctxt->catalogs,
2694 (const xmlChar *)ID,
2695 (const xmlChar *)URL);
2696 }
2697 /*
2698 * Try a global lookup
2699 */
2700 if ((resource == NULL) &&
2701 ((pref == XML_CATA_ALLOW_ALL) ||
2702 (pref == XML_CATA_ALLOW_GLOBAL))) {
2703 resource = xmlCatalogResolve((const xmlChar *)ID,
2704 (const xmlChar *)URL);
2705 }
2706 if ((resource == NULL) && (URL != NULL))
2707 resource = xmlStrdup((const xmlChar *) URL);
2708
2709 /*
2710 * TODO: do an URI lookup on the reference
2711 */
2712 if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
2713 xmlChar *tmp = NULL;
2714
2715 if ((ctxt->catalogs != NULL) &&
2716 ((pref == XML_CATA_ALLOW_ALL) ||
2717 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2718 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
2719 }
2720 if ((tmp == NULL) &&
2721 ((pref == XML_CATA_ALLOW_ALL) ||
2722 (pref == XML_CATA_ALLOW_GLOBAL))) {
2723 tmp = xmlCatalogResolveURI(resource);
2724 }
2725
2726 if (tmp != NULL) {
2727 xmlFree(resource);
2728 resource = tmp;
2729 }
2730 }
2731 }
2732#endif
2733 if (resource == NULL)
2734 resource = (xmlChar *) URL;
2735
2736 if (resource != NULL) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002737 if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
2738 (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00002739 xmlGenericError(xmlGenericErrorContext,
2740 "Attempt to load network entity %s \n", resource);
2741
2742 if (resource != (xmlChar *) URL)
2743 xmlFree(resource);
2744 return(NULL);
2745 }
2746 }
2747 input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
2748 if (resource != (xmlChar *) URL)
2749 xmlFree(resource);
2750 return(input);
2751}
2752