blob: c1eb3584e773b5ca130cb006857d4bdefdde9b51 [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>
Daniel Veillard92727042002-09-17 17:59:20 +000015#ifdef HAVE_ERRNO_H
Owen Taylor3473f882001-02-23 17:55:21 +000016#include <errno.h>
Daniel Veillard92727042002-09-17 17:59:20 +000017#endif
18
Owen Taylor3473f882001-02-23 17:55:21 +000019
20#ifdef HAVE_SYS_TYPES_H
21#include <sys/types.h>
22#endif
23#ifdef HAVE_SYS_STAT_H
24#include <sys/stat.h>
25#endif
26#ifdef HAVE_FCNTL_H
27#include <fcntl.h>
28#endif
29#ifdef HAVE_UNISTD_H
30#include <unistd.h>
31#endif
32#ifdef HAVE_STDLIB_H
33#include <stdlib.h>
34#endif
35#ifdef HAVE_ZLIB_H
36#include <zlib.h>
37#endif
38
39/* Figure a portable way to know if a file is a directory. */
40#ifndef HAVE_STAT
41# ifdef HAVE__STAT
Daniel Veillard50f34372001-08-03 12:06:36 +000042 /* MS C library seems to define stat and _stat. The definition
43 is identical. Still, mapping them to each other causes a warning. */
44# ifndef _MSC_VER
45# define stat(x,y) _stat(x,y)
46# endif
Owen Taylor3473f882001-02-23 17:55:21 +000047# define HAVE_STAT
48# endif
49#endif
50#ifdef HAVE_STAT
51# ifndef S_ISDIR
52# ifdef _S_ISDIR
53# define S_ISDIR(x) _S_ISDIR(x)
54# else
55# ifdef S_IFDIR
56# ifndef S_IFMT
57# ifdef _S_IFMT
58# define S_IFMT _S_IFMT
59# endif
60# endif
61# ifdef S_IFMT
62# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
63# endif
64# endif
65# endif
66# endif
67#endif
68
69#include <libxml/xmlmemory.h>
70#include <libxml/parser.h>
71#include <libxml/parserInternals.h>
72#include <libxml/xmlIO.h>
Daniel Veillard388236f2001-07-08 18:35:48 +000073#include <libxml/uri.h>
Owen Taylor3473f882001-02-23 17:55:21 +000074#include <libxml/nanohttp.h>
75#include <libxml/nanoftp.h>
76#include <libxml/xmlerror.h>
Daniel Veillard7d6fd212001-05-10 15:34:11 +000077#ifdef LIBXML_CATALOG_ENABLED
78#include <libxml/catalog.h>
79#endif
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000080#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000081
Daniel Veillardf012a642001-07-23 19:10:52 +000082/* #define VERBOSE_FAILURE */
Daniel Veillard1fd36d22001-07-04 22:54:28 +000083/* #define DEBUG_EXTERNAL_ENTITIES */
Owen Taylor3473f882001-02-23 17:55:21 +000084/* #define DEBUG_INPUT */
85
86#ifdef DEBUG_INPUT
87#define MINLEN 40
88#else
89#define MINLEN 4000
90#endif
91
92/*
93 * Input I/O callback sets
94 */
95typedef struct _xmlInputCallback {
96 xmlInputMatchCallback matchcallback;
97 xmlInputOpenCallback opencallback;
98 xmlInputReadCallback readcallback;
99 xmlInputCloseCallback closecallback;
100} xmlInputCallback;
101
102#define MAX_INPUT_CALLBACK 15
103
Daniel Veillard22090732001-07-16 00:06:07 +0000104static xmlInputCallback xmlInputCallbackTable[MAX_INPUT_CALLBACK];
105static int xmlInputCallbackNr = 0;
106static int xmlInputCallbackInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000107
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000108#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000109/*
110 * Output I/O callback sets
111 */
112typedef struct _xmlOutputCallback {
113 xmlOutputMatchCallback matchcallback;
114 xmlOutputOpenCallback opencallback;
115 xmlOutputWriteCallback writecallback;
116 xmlOutputCloseCallback closecallback;
117} xmlOutputCallback;
118
119#define MAX_OUTPUT_CALLBACK 15
120
Daniel Veillard22090732001-07-16 00:06:07 +0000121static xmlOutputCallback xmlOutputCallbackTable[MAX_OUTPUT_CALLBACK];
122static int xmlOutputCallbackNr = 0;
123static int xmlOutputCallbackInitialized = 0;
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000124#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000125
Daniel Veillardf4862f02002-09-10 11:13:43 +0000126
127/**
Daniel Veillard01c13b52002-12-10 15:19:08 +0000128 * xmlNormalizeWindowsPath:
Daniel Veillard33300b42003-04-17 09:09:19 +0000129 * @path: the input file path
Daniel Veillardf4862f02002-09-10 11:13:43 +0000130 *
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +0000131 * This function is obsolete. Please see xmlURIFromPath in uri.c for
132 * a better solution.
Daniel Veillard33300b42003-04-17 09:09:19 +0000133 *
134 * Returns a canonicalized version of the path
Daniel Veillardf4862f02002-09-10 11:13:43 +0000135 */
136xmlChar *
137xmlNormalizeWindowsPath(const xmlChar *path)
138{
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +0000139 return xmlCanonicPath(path);
Daniel Veillardf4862f02002-09-10 11:13:43 +0000140}
141
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000142/**
143 * xmlCleanupInputCallbacks:
144 *
145 * clears the entire input callback table. this includes the
146 * compiled-in I/O.
147 */
148void
149xmlCleanupInputCallbacks(void)
150{
151 int i;
152
153 if (!xmlInputCallbackInitialized)
154 return;
155
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000156 for (i = xmlInputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000157 xmlInputCallbackTable[i].matchcallback = NULL;
158 xmlInputCallbackTable[i].opencallback = NULL;
159 xmlInputCallbackTable[i].readcallback = NULL;
160 xmlInputCallbackTable[i].closecallback = NULL;
161 }
162
163 xmlInputCallbackNr = 0;
Aleksey Sanin9c45ba82002-06-06 21:46:13 +0000164 xmlInputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000165}
166
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000167#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000168/**
169 * xmlCleanupOutputCallbacks:
170 *
171 * clears the entire output callback table. this includes the
172 * compiled-in I/O callbacks.
173 */
174void
175xmlCleanupOutputCallbacks(void)
176{
177 int i;
178
179 if (!xmlOutputCallbackInitialized)
180 return;
181
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000182 for (i = xmlOutputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000183 xmlOutputCallbackTable[i].matchcallback = NULL;
184 xmlOutputCallbackTable[i].opencallback = NULL;
185 xmlOutputCallbackTable[i].writecallback = NULL;
186 xmlOutputCallbackTable[i].closecallback = NULL;
187 }
188
189 xmlOutputCallbackNr = 0;
Aleksey Sanin9c45ba82002-06-06 21:46:13 +0000190 xmlOutputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000191}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000192#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000193
Owen Taylor3473f882001-02-23 17:55:21 +0000194/************************************************************************
195 * *
196 * Standard I/O for file accesses *
197 * *
198 ************************************************************************/
199
200/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000201 * xmlCheckFilename:
Owen Taylor3473f882001-02-23 17:55:21 +0000202 * @path: the path to check
203 *
204 * function checks to see if @path is a valid source
205 * (file, socket...) for XML.
206 *
207 * if stat is not available on the target machine,
208 * returns 1. if stat fails, returns 0 (if calling
209 * stat on the filename fails, it can't be right).
210 * if stat succeeds and the file is a directory,
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000211 * returns 2. otherwise returns 1.
Owen Taylor3473f882001-02-23 17:55:21 +0000212 */
213
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000214int
Owen Taylor3473f882001-02-23 17:55:21 +0000215xmlCheckFilename (const char *path)
216{
217#ifdef HAVE_STAT
Owen Taylor3473f882001-02-23 17:55:21 +0000218 struct stat stat_buffer;
219
220 if (stat(path, &stat_buffer) == -1)
221 return 0;
222
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000223#ifdef S_ISDIR
Owen Taylor3473f882001-02-23 17:55:21 +0000224 if (S_ISDIR(stat_buffer.st_mode)) {
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000225 return 2;
Owen Taylor3473f882001-02-23 17:55:21 +0000226 }
Owen Taylor3473f882001-02-23 17:55:21 +0000227#endif
228#endif
229 return 1;
230}
231
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000232static int
Owen Taylor3473f882001-02-23 17:55:21 +0000233xmlNop(void) {
234 return(0);
235}
236
237/**
Owen Taylor3473f882001-02-23 17:55:21 +0000238 * xmlFdRead:
239 * @context: the I/O context
240 * @buffer: where to drop data
241 * @len: number of bytes to read
242 *
243 * Read @len bytes to @buffer from the I/O channel.
244 *
245 * Returns the number of bytes written
246 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000247static int
Owen Taylor3473f882001-02-23 17:55:21 +0000248xmlFdRead (void * context, char * buffer, int len) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +0000249 return(read((int) (long) context, &buffer[0], len));
Owen Taylor3473f882001-02-23 17:55:21 +0000250}
251
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000252#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000253/**
254 * xmlFdWrite:
255 * @context: the I/O context
256 * @buffer: where to get data
257 * @len: number of bytes to write
258 *
259 * Write @len bytes from @buffer to the I/O channel.
260 *
261 * Returns the number of bytes written
262 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000263static int
Owen Taylor3473f882001-02-23 17:55:21 +0000264xmlFdWrite (void * context, const char * buffer, int len) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +0000265 return(write((int) (long) context, &buffer[0], len));
Owen Taylor3473f882001-02-23 17:55:21 +0000266}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000267#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000268
269/**
270 * xmlFdClose:
271 * @context: the I/O context
272 *
273 * Close an I/O channel
Daniel Veillardf012a642001-07-23 19:10:52 +0000274 *
275 * Returns 0 in case of success and error code otherwise
Owen Taylor3473f882001-02-23 17:55:21 +0000276 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000277static int
Owen Taylor3473f882001-02-23 17:55:21 +0000278xmlFdClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +0000279 return ( close((int) (long) context) );
Owen Taylor3473f882001-02-23 17:55:21 +0000280}
281
282/**
283 * xmlFileMatch:
284 * @filename: the URI for matching
285 *
286 * input from FILE *
287 *
288 * Returns 1 if matches, 0 otherwise
289 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000290int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000291xmlFileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000292 return(1);
293}
294
295/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000296 * xmlFileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +0000297 * @filename: the URI for matching
298 *
299 * input from FILE *, supports compressed input
300 * if @filename is " " then the standard input is used
301 *
302 * Returns an I/O context or NULL in case of error
303 */
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000304static void *
305xmlFileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +0000306 const char *path = NULL;
307 FILE *fd;
308
309 if (!strcmp(filename, "-")) {
310 fd = stdin;
311 return((void *) fd);
312 }
313
Daniel Veillardf4862f02002-09-10 11:13:43 +0000314 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000315#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000316 path = &filename[17];
317#else
Owen Taylor3473f882001-02-23 17:55:21 +0000318 path = &filename[16];
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000319#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000320 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000321#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000322 path = &filename[8];
323#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000324 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000325#endif
326 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000327 path = filename;
328
329 if (path == NULL)
330 return(NULL);
331 if (!xmlCheckFilename(path))
332 return(NULL);
333
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000334#if defined(WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
Owen Taylor3473f882001-02-23 17:55:21 +0000335 fd = fopen(path, "rb");
336#else
337 fd = fopen(path, "r");
338#endif /* WIN32 */
339 return((void *) fd);
340}
341
342/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000343 * xmlFileOpen:
344 * @filename: the URI for matching
345 *
346 * Wrapper around xmlFileOpen_real that try it with an unescaped
347 * version of @filename, if this fails fallback to @filename
Daniel Veillard71531f32003-02-05 13:19:53 +0000348 *
349 * Returns a handler or NULL in case or failure
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000350 */
351void *
352xmlFileOpen (const char *filename) {
353 char *unescaped;
354 void *retval;
355 unescaped = xmlURIUnescapeString(filename, 0, NULL);
356 if (unescaped != NULL) {
357 retval = xmlFileOpen_real(unescaped);
358 } else {
359 retval = xmlFileOpen_real(filename);
360 }
361 xmlFree(unescaped);
362 return retval;
363}
364
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000365#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000366/**
Owen Taylor3473f882001-02-23 17:55:21 +0000367 * xmlFileOpenW:
368 * @filename: the URI for matching
369 *
370 * output to from FILE *,
371 * if @filename is "-" then the standard output is used
372 *
373 * Returns an I/O context or NULL in case of error
374 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000375static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000376xmlFileOpenW (const char *filename) {
377 const char *path = NULL;
378 FILE *fd;
379
380 if (!strcmp(filename, "-")) {
381 fd = stdout;
382 return((void *) fd);
383 }
384
Daniel Veillardf4862f02002-09-10 11:13:43 +0000385 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000386#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000387 path = &filename[17];
388#else
Owen Taylor3473f882001-02-23 17:55:21 +0000389 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000390#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000391 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000392#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000393 path = &filename[8];
394#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000395 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000396#endif
397 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000398 path = filename;
399
400 if (path == NULL)
401 return(NULL);
402
Daniel Veillardcbbd78d2003-07-20 15:21:30 +0000403 fd = fopen(path, "wb");
Owen Taylor3473f882001-02-23 17:55:21 +0000404 return((void *) fd);
405}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000406#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000407
408/**
409 * xmlFileRead:
410 * @context: the I/O context
411 * @buffer: where to drop data
412 * @len: number of bytes to write
413 *
414 * Read @len bytes to @buffer from the I/O channel.
415 *
416 * Returns the number of bytes written
417 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000418int
Owen Taylor3473f882001-02-23 17:55:21 +0000419xmlFileRead (void * context, char * buffer, int len) {
420 return(fread(&buffer[0], 1, len, (FILE *) context));
421}
422
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000423#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000424/**
425 * xmlFileWrite:
426 * @context: the I/O context
427 * @buffer: where to drop data
428 * @len: number of bytes to write
429 *
430 * Write @len bytes from @buffer to the I/O channel.
431 *
432 * Returns the number of bytes written
433 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000434static int
Owen Taylor3473f882001-02-23 17:55:21 +0000435xmlFileWrite (void * context, const char * buffer, int len) {
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000436 int items;
437
438 items = fwrite(&buffer[0], len, 1, (FILE *) context);
439
440 return(items * len);
Owen Taylor3473f882001-02-23 17:55:21 +0000441}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000442#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000443
444/**
445 * xmlFileClose:
446 * @context: the I/O context
447 *
448 * Close an I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000449 *
450 * Returns 0 or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +0000451 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000452int
Owen Taylor3473f882001-02-23 17:55:21 +0000453xmlFileClose (void * context) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000454 FILE *fil;
455
456 fil = (FILE *) context;
457 if (fil == stdin)
458 return(0);
459 if (fil == stdout)
460 return(0);
Daniel Veillardcd337f02001-11-22 18:20:37 +0000461 if (fil == stderr)
462 return(0);
Daniel Veillardf012a642001-07-23 19:10:52 +0000463 return ( ( fclose((FILE *) context) == EOF ) ? -1 : 0 );
Owen Taylor3473f882001-02-23 17:55:21 +0000464}
465
466/**
467 * xmlFileFlush:
468 * @context: the I/O context
469 *
470 * Flush an I/O channel
471 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000472static int
Owen Taylor3473f882001-02-23 17:55:21 +0000473xmlFileFlush (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +0000474 return ( ( fflush((FILE *) context) == EOF ) ? -1 : 0 );
Owen Taylor3473f882001-02-23 17:55:21 +0000475}
476
477#ifdef HAVE_ZLIB_H
478/************************************************************************
479 * *
480 * I/O for compressed file accesses *
481 * *
482 ************************************************************************/
483/**
484 * xmlGzfileMatch:
485 * @filename: the URI for matching
486 *
487 * input from compressed file test
488 *
489 * Returns 1 if matches, 0 otherwise
490 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000491static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000492xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000493 return(1);
494}
495
496/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000497 * xmlGzfileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +0000498 * @filename: the URI for matching
499 *
500 * input from compressed file open
501 * if @filename is " " then the standard input is used
502 *
503 * Returns an I/O context or NULL in case of error
504 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000505static void *
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000506xmlGzfileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +0000507 const char *path = NULL;
508 gzFile fd;
509
510 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000511 fd = gzdopen(dup(0), "rb");
Owen Taylor3473f882001-02-23 17:55:21 +0000512 return((void *) fd);
513 }
514
Daniel Veillardf4862f02002-09-10 11:13:43 +0000515 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000516#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000517 path = &filename[17];
518#else
Owen Taylor3473f882001-02-23 17:55:21 +0000519 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000520#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000521 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000522#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000523 path = &filename[8];
524#else
Owen Taylor3473f882001-02-23 17:55:21 +0000525 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000526#endif
527 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000528 path = filename;
529
530 if (path == NULL)
531 return(NULL);
532 if (!xmlCheckFilename(path))
533 return(NULL);
534
535 fd = gzopen(path, "rb");
536 return((void *) fd);
537}
538
539/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000540 * xmlGzfileOpen:
541 * @filename: the URI for matching
542 *
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +0000543 * Wrapper around xmlGzfileOpen if the open fais, it will
544 * try to unescape @filename
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000545 */
546static void *
547xmlGzfileOpen (const char *filename) {
548 char *unescaped;
549 void *retval;
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +0000550
551 retval = xmlGzfileOpen_real(filename);
552 if (retval == NULL) {
553 unescaped = xmlURIUnescapeString(filename, 0, NULL);
554 if (unescaped != NULL) {
555 retval = xmlGzfileOpen_real(unescaped);
556 }
557 xmlFree(unescaped);
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000558 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000559 return retval;
560}
561
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000562#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000563/**
Owen Taylor3473f882001-02-23 17:55:21 +0000564 * xmlGzfileOpenW:
565 * @filename: the URI for matching
566 * @compression: the compression factor (0 - 9 included)
567 *
568 * input from compressed file open
569 * if @filename is " " then the standard input is used
570 *
571 * Returns an I/O context or NULL in case of error
572 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000573static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000574xmlGzfileOpenW (const char *filename, int compression) {
575 const char *path = NULL;
576 char mode[15];
577 gzFile fd;
578
Aleksey Sanin49cc9752002-06-14 17:07:10 +0000579 snprintf(mode, sizeof(mode), "wb%d", compression);
Owen Taylor3473f882001-02-23 17:55:21 +0000580 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000581 fd = gzdopen(dup(1), mode);
Owen Taylor3473f882001-02-23 17:55:21 +0000582 return((void *) fd);
583 }
584
Daniel Veillardf4862f02002-09-10 11:13:43 +0000585 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000586#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000587 path = &filename[17];
588#else
Owen Taylor3473f882001-02-23 17:55:21 +0000589 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000590#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000591 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000592#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000593 path = &filename[8];
594#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000595 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000596#endif
597 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000598 path = filename;
599
600 if (path == NULL)
601 return(NULL);
602
603 fd = gzopen(path, mode);
604 return((void *) fd);
605}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000606#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000607
608/**
609 * xmlGzfileRead:
610 * @context: the I/O context
611 * @buffer: where to drop data
612 * @len: number of bytes to write
613 *
614 * Read @len bytes to @buffer from the compressed I/O channel.
615 *
616 * Returns the number of bytes written
617 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000618static int
Owen Taylor3473f882001-02-23 17:55:21 +0000619xmlGzfileRead (void * context, char * buffer, int len) {
620 return(gzread((gzFile) context, &buffer[0], len));
621}
622
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000623#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000624/**
625 * xmlGzfileWrite:
626 * @context: the I/O context
627 * @buffer: where to drop data
628 * @len: number of bytes to write
629 *
630 * Write @len bytes from @buffer to the compressed I/O channel.
631 *
632 * Returns the number of bytes written
633 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000634static int
Owen Taylor3473f882001-02-23 17:55:21 +0000635xmlGzfileWrite (void * context, const char * buffer, int len) {
636 return(gzwrite((gzFile) context, (char *) &buffer[0], len));
637}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000638#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000639
640/**
641 * xmlGzfileClose:
642 * @context: the I/O context
643 *
644 * Close a compressed I/O channel
645 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000646static int
Owen Taylor3473f882001-02-23 17:55:21 +0000647xmlGzfileClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +0000648 return ( ( gzclose((gzFile) context) == Z_OK ) ? 0 : -1 );
Owen Taylor3473f882001-02-23 17:55:21 +0000649}
650#endif /* HAVE_ZLIB_H */
651
652#ifdef LIBXML_HTTP_ENABLED
653/************************************************************************
654 * *
655 * I/O for HTTP file accesses *
656 * *
657 ************************************************************************/
Daniel Veillardf012a642001-07-23 19:10:52 +0000658
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000659#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +0000660typedef struct xmlIOHTTPWriteCtxt_
661{
662 int compression;
663
664 char * uri;
665
666 void * doc_buff;
667
668} xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr;
669
670#ifdef HAVE_ZLIB_H
671
672#define DFLT_WBITS ( -15 )
673#define DFLT_MEM_LVL ( 8 )
674#define GZ_MAGIC1 ( 0x1f )
675#define GZ_MAGIC2 ( 0x8b )
676#define LXML_ZLIB_OS_CODE ( 0x03 )
677#define INIT_HTTP_BUFF_SIZE ( 32768 )
678#define DFLT_ZLIB_RATIO ( 5 )
679
680/*
681** Data structure and functions to work with sending compressed data
682** via HTTP.
683*/
684
685typedef struct xmlZMemBuff_
686{
687 unsigned long size;
688 unsigned long crc;
689
690 unsigned char * zbuff;
691 z_stream zctrl;
692
693} xmlZMemBuff, *xmlZMemBuffPtr;
694
695/**
696 * append_reverse_ulong
697 * @buff: Compressed memory buffer
698 * @data: Unsigned long to append
699 *
700 * Append a unsigned long in reverse byte order to the end of the
701 * memory buffer.
702 */
703static void
704append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) {
705
706 int idx;
707
708 if ( buff == NULL )
709 return;
710
711 /*
712 ** This is plagiarized from putLong in gzio.c (zlib source) where
713 ** the number "4" is hardcoded. If zlib is ever patched to
714 ** support 64 bit file sizes, this code would need to be patched
715 ** as well.
716 */
717
718 for ( idx = 0; idx < 4; idx++ ) {
719 *buff->zctrl.next_out = ( data & 0xff );
720 data >>= 8;
721 buff->zctrl.next_out++;
722 }
723
724 return;
725}
726
727/**
728 *
729 * xmlFreeZMemBuff
730 * @buff: The memory buffer context to clear
731 *
732 * Release all the resources associated with the compressed memory buffer.
733 */
734static void
735xmlFreeZMemBuff( xmlZMemBuffPtr buff ) {
William M. Brack78637da2003-07-31 14:47:38 +0000736
737#ifdef DEBUG_HTTP
Daniel Veillardf012a642001-07-23 19:10:52 +0000738 int z_err;
William M. Brack78637da2003-07-31 14:47:38 +0000739#endif
Daniel Veillardf012a642001-07-23 19:10:52 +0000740
741 if ( buff == NULL )
742 return;
743
744 xmlFree( buff->zbuff );
Daniel Veillardf012a642001-07-23 19:10:52 +0000745#ifdef DEBUG_HTTP
William M. Brack78637da2003-07-31 14:47:38 +0000746 z_err = deflateEnd( &buff->zctrl );
Daniel Veillardf012a642001-07-23 19:10:52 +0000747 if ( z_err != Z_OK )
748 xmlGenericError( xmlGenericErrorContext,
749 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
750 z_err );
William M. Brack78637da2003-07-31 14:47:38 +0000751#else
752 deflateEnd( &buff->zctrl );
William M. Brack779af002003-08-01 15:55:39 +0000753#endif
Daniel Veillardf012a642001-07-23 19:10:52 +0000754
755 xmlFree( buff );
756 return;
757}
758
759/**
760 * xmlCreateZMemBuff
761 *@compression: Compression value to use
762 *
763 * Create a memory buffer to hold the compressed XML document. The
764 * compressed document in memory will end up being identical to what
765 * would be created if gzopen/gzwrite/gzclose were being used to
766 * write the document to disk. The code for the header/trailer data to
767 * the compression is plagiarized from the zlib source files.
768 */
769static void *
770xmlCreateZMemBuff( int compression ) {
771
772 int z_err;
773 int hdr_lgth;
774 xmlZMemBuffPtr buff = NULL;
775
776 if ( ( compression < 1 ) || ( compression > 9 ) )
777 return ( NULL );
778
779 /* Create the control and data areas */
780
781 buff = xmlMalloc( sizeof( xmlZMemBuff ) );
782 if ( buff == NULL ) {
783 xmlGenericError( xmlGenericErrorContext,
784 "xmlCreateZMemBuff: %s\n",
785 "Failure allocating buffer context." );
786 return ( NULL );
787 }
788
789 (void)memset( buff, 0, sizeof( xmlZMemBuff ) );
790 buff->size = INIT_HTTP_BUFF_SIZE;
791 buff->zbuff = xmlMalloc( buff->size );
792 if ( buff->zbuff == NULL ) {
793 xmlFreeZMemBuff( buff );
794 xmlGenericError( xmlGenericErrorContext,
795 "xmlCreateZMemBuff: %s\n",
796 "Failure allocating data buffer." );
797 return ( NULL );
798 }
799
800 z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
801 DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
802 if ( z_err != Z_OK ) {
803 xmlFreeZMemBuff( buff );
804 buff = NULL;
805 xmlGenericError( xmlGenericErrorContext,
806 "xmlCreateZMemBuff: %s %d\n",
807 "Error initializing compression context. ZLIB error:",
808 z_err );
809 return ( NULL );
810 }
811
812 /* Set the header data. The CRC will be needed for the trailer */
Daniel Veillardf012a642001-07-23 19:10:52 +0000813 buff->crc = crc32( 0L, Z_NULL, 0 );
Aleksey Sanin49cc9752002-06-14 17:07:10 +0000814 hdr_lgth = snprintf( (char *)buff->zbuff, buff->size,
815 "%c%c%c%c%c%c%c%c%c%c",
Daniel Veillardf012a642001-07-23 19:10:52 +0000816 GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED,
817 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE );
818 buff->zctrl.next_out = buff->zbuff + hdr_lgth;
819 buff->zctrl.avail_out = buff->size - hdr_lgth;
820
821 return ( buff );
822}
823
824/**
825 * xmlZMemBuffExtend
826 * @buff: Buffer used to compress and consolidate data.
827 * @ext_amt: Number of bytes to extend the buffer.
828 *
829 * Extend the internal buffer used to store the compressed data by the
830 * specified amount.
831 *
832 * Returns 0 on success or -1 on failure to extend the buffer. On failure
833 * the original buffer still exists at the original size.
834 */
835static int
836xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) {
837
838 int rc = -1;
839 size_t new_size;
840 size_t cur_used;
841
842 unsigned char * tmp_ptr = NULL;
843
844 if ( buff == NULL )
845 return ( -1 );
846
847 else if ( ext_amt == 0 )
848 return ( 0 );
849
850 cur_used = buff->zctrl.next_out - buff->zbuff;
851 new_size = buff->size + ext_amt;
852
853#ifdef DEBUG_HTTP
854 if ( cur_used > new_size )
855 xmlGenericError( xmlGenericErrorContext,
856 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
857 "Buffer overwrite detected during compressed memory",
858 "buffer extension. Overflowed by",
859 (cur_used - new_size ) );
860#endif
861
862 tmp_ptr = xmlRealloc( buff->zbuff, new_size );
863 if ( tmp_ptr != NULL ) {
864 rc = 0;
865 buff->size = new_size;
866 buff->zbuff = tmp_ptr;
867 buff->zctrl.next_out = tmp_ptr + cur_used;
868 buff->zctrl.avail_out = new_size - cur_used;
869 }
870 else {
871 xmlGenericError( xmlGenericErrorContext,
872 "xmlZMemBuffExtend: %s %lu bytes.\n",
873 "Allocation failure extending output buffer to",
874 new_size );
875 }
876
877 return ( rc );
878}
879
880/**
881 * xmlZMemBuffAppend
882 * @buff: Buffer used to compress and consolidate data
883 * @src: Uncompressed source content to append to buffer
884 * @len: Length of source data to append to buffer
885 *
886 * Compress and append data to the internal buffer. The data buffer
887 * will be expanded if needed to store the additional data.
888 *
889 * Returns the number of bytes appended to the buffer or -1 on error.
890 */
891static int
892xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) {
893
894 int z_err;
895 size_t min_accept;
896
897 if ( ( buff == NULL ) || ( src == NULL ) )
898 return ( -1 );
899
900 buff->zctrl.avail_in = len;
901 buff->zctrl.next_in = (unsigned char *)src;
902 while ( buff->zctrl.avail_in > 0 ) {
903 /*
904 ** Extend the buffer prior to deflate call if a reasonable amount
905 ** of output buffer space is not available.
906 */
907 min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO;
908 if ( buff->zctrl.avail_out <= min_accept ) {
909 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
910 return ( -1 );
911 }
912
913 z_err = deflate( &buff->zctrl, Z_NO_FLUSH );
914 if ( z_err != Z_OK ) {
915 xmlGenericError( xmlGenericErrorContext,
916 "xmlZMemBuffAppend: %s %d %s - %d",
917 "Compression error while appending",
918 len, "bytes to buffer. ZLIB error", z_err );
919 return ( -1 );
920 }
921 }
922
923 buff->crc = crc32( buff->crc, (unsigned char *)src, len );
924
925 return ( len );
926}
927
928/**
929 * xmlZMemBuffGetContent
930 * @buff: Compressed memory content buffer
931 * @data_ref: Pointer reference to point to compressed content
932 *
933 * Flushes the compression buffers, appends gzip file trailers and
934 * returns the compressed content and length of the compressed data.
935 * NOTE: The gzip trailer code here is plagiarized from zlib source.
936 *
937 * Returns the length of the compressed data or -1 on error.
938 */
939static int
940xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) {
941
942 int zlgth = -1;
943 int z_err;
944
945 if ( ( buff == NULL ) || ( data_ref == NULL ) )
946 return ( -1 );
947
948 /* Need to loop until compression output buffers are flushed */
949
950 do
951 {
952 z_err = deflate( &buff->zctrl, Z_FINISH );
953 if ( z_err == Z_OK ) {
954 /* In this case Z_OK means more buffer space needed */
955
956 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
957 return ( -1 );
958 }
959 }
960 while ( z_err == Z_OK );
961
962 /* If the compression state is not Z_STREAM_END, some error occurred */
963
964 if ( z_err == Z_STREAM_END ) {
965
966 /* Need to append the gzip data trailer */
967
968 if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) {
969 if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 )
970 return ( -1 );
971 }
972
973 /*
974 ** For whatever reason, the CRC and length data are pushed out
975 ** in reverse byte order. So a memcpy can't be used here.
976 */
977
978 append_reverse_ulong( buff, buff->crc );
979 append_reverse_ulong( buff, buff->zctrl.total_in );
980
981 zlgth = buff->zctrl.next_out - buff->zbuff;
982 *data_ref = (char *)buff->zbuff;
983 }
984
985 else
986 xmlGenericError( xmlGenericErrorContext,
987 "xmlZMemBuffGetContent: %s - %d\n",
988 "Error flushing zlib buffers. Error code", z_err );
989
990 return ( zlgth );
991}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000992#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +0000993#endif /* HAVE_ZLIB_H */
994
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000995#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +0000996/**
997 * xmlFreeHTTPWriteCtxt
998 * @ctxt: Context to cleanup
999 *
1000 * Free allocated memory and reclaim system resources.
1001 *
1002 * No return value.
1003 */
1004static void
1005xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt )
1006{
1007 if ( ctxt->uri != NULL )
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001008 xmlFree( ctxt->uri );
Daniel Veillardf012a642001-07-23 19:10:52 +00001009
1010 if ( ctxt->doc_buff != NULL ) {
1011
1012#ifdef HAVE_ZLIB_H
1013 if ( ctxt->compression > 0 ) {
1014 xmlFreeZMemBuff( ctxt->doc_buff );
1015 }
1016 else
1017#endif
1018 {
1019 xmlOutputBufferClose( ctxt->doc_buff );
1020 }
1021 }
1022
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001023 xmlFree( ctxt );
Daniel Veillardf012a642001-07-23 19:10:52 +00001024 return;
1025}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001026#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001027
1028
Owen Taylor3473f882001-02-23 17:55:21 +00001029/**
1030 * xmlIOHTTPMatch:
1031 * @filename: the URI for matching
1032 *
1033 * check if the URI matches an HTTP one
1034 *
1035 * Returns 1 if matches, 0 otherwise
1036 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001037int
Owen Taylor3473f882001-02-23 17:55:21 +00001038xmlIOHTTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001039 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "http://", 7))
Owen Taylor3473f882001-02-23 17:55:21 +00001040 return(1);
1041 return(0);
1042}
1043
1044/**
1045 * xmlIOHTTPOpen:
1046 * @filename: the URI for matching
1047 *
1048 * open an HTTP I/O channel
1049 *
1050 * Returns an I/O context or NULL in case of error
1051 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001052void *
Owen Taylor3473f882001-02-23 17:55:21 +00001053xmlIOHTTPOpen (const char *filename) {
1054 return(xmlNanoHTTPOpen(filename, NULL));
1055}
1056
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001057#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001058/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001059 * xmlIOHTTPOpenW:
Daniel Veillardf012a642001-07-23 19:10:52 +00001060 * @post_uri: The destination URI for the document
1061 * @compression: The compression desired for the document.
1062 *
1063 * Open a temporary buffer to collect the document for a subsequent HTTP POST
1064 * request. Non-static as is called from the output buffer creation routine.
1065 *
1066 * Returns an I/O context or NULL in case of error.
1067 */
1068
1069void *
Daniel Veillard572577e2002-01-18 16:23:55 +00001070xmlIOHTTPOpenW(const char *post_uri, int compression)
1071{
Daniel Veillardf012a642001-07-23 19:10:52 +00001072
Daniel Veillard572577e2002-01-18 16:23:55 +00001073 xmlIOHTTPWriteCtxtPtr ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001074
Daniel Veillard572577e2002-01-18 16:23:55 +00001075 if (post_uri == NULL)
1076 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001077
Daniel Veillard572577e2002-01-18 16:23:55 +00001078 ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt));
1079 if (ctxt == NULL) {
1080 xmlGenericError(xmlGenericErrorContext,
1081 "xmlIOHTTPOpenW: Failed to create output HTTP context.\n");
1082 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001083 }
1084
Daniel Veillard572577e2002-01-18 16:23:55 +00001085 (void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt));
Daniel Veillardf012a642001-07-23 19:10:52 +00001086
Daniel Veillard572577e2002-01-18 16:23:55 +00001087 ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri);
1088 if (ctxt->uri == NULL) {
1089 xmlGenericError(xmlGenericErrorContext,
1090 "xmlIOHTTPOpenW: Failed to duplicate destination URI.\n");
1091 xmlFreeHTTPWriteCtxt(ctxt);
1092 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001093 }
1094
1095 /*
Daniel Veillard572577e2002-01-18 16:23:55 +00001096 * ** Since the document length is required for an HTTP post,
1097 * ** need to put the document into a buffer. A memory buffer
1098 * ** is being used to avoid pushing the data to disk and back.
1099 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001100
1101#ifdef HAVE_ZLIB_H
Daniel Veillard572577e2002-01-18 16:23:55 +00001102 if ((compression > 0) && (compression <= 9)) {
1103
1104 ctxt->compression = compression;
1105 ctxt->doc_buff = xmlCreateZMemBuff(compression);
1106 } else
Daniel Veillardf012a642001-07-23 19:10:52 +00001107#endif
1108 {
Daniel Veillard572577e2002-01-18 16:23:55 +00001109 /* Any character conversions should have been done before this */
Daniel Veillardf012a642001-07-23 19:10:52 +00001110
Daniel Veillard572577e2002-01-18 16:23:55 +00001111 ctxt->doc_buff = xmlAllocOutputBuffer(NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001112 }
1113
Daniel Veillard572577e2002-01-18 16:23:55 +00001114 if (ctxt->doc_buff == NULL) {
1115 xmlFreeHTTPWriteCtxt(ctxt);
1116 ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001117 }
1118
Daniel Veillard572577e2002-01-18 16:23:55 +00001119 return (ctxt);
Daniel Veillardf012a642001-07-23 19:10:52 +00001120}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001121#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001122
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001123#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001124/**
1125 * xmlIOHTTPDfltOpenW
1126 * @post_uri: The destination URI for this document.
1127 *
1128 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
1129 * HTTP post command. This function should generally not be used as
1130 * the open callback is short circuited in xmlOutputBufferCreateFile.
1131 *
1132 * Returns a pointer to the new IO context.
1133 */
1134static void *
1135xmlIOHTTPDfltOpenW( const char * post_uri ) {
1136 return ( xmlIOHTTPOpenW( post_uri, 0 ) );
1137}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001138#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001139
1140/**
Owen Taylor3473f882001-02-23 17:55:21 +00001141 * xmlIOHTTPRead:
1142 * @context: the I/O context
1143 * @buffer: where to drop data
1144 * @len: number of bytes to write
1145 *
1146 * Read @len bytes to @buffer from the I/O channel.
1147 *
1148 * Returns the number of bytes written
1149 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001150int
Owen Taylor3473f882001-02-23 17:55:21 +00001151xmlIOHTTPRead(void * context, char * buffer, int len) {
1152 return(xmlNanoHTTPRead(context, &buffer[0], len));
1153}
1154
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001155#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001156/**
Daniel Veillardf012a642001-07-23 19:10:52 +00001157 * xmlIOHTTPWrite
1158 * @context: previously opened writing context
1159 * @buffer: data to output to temporary buffer
1160 * @len: bytes to output
1161 *
1162 * Collect data from memory buffer into a temporary file for later
1163 * processing.
1164 *
1165 * Returns number of bytes written.
1166 */
1167
1168static int
1169xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
1170
1171 xmlIOHTTPWriteCtxtPtr ctxt = context;
1172
1173 if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
1174 return ( -1 );
1175
1176 if ( len > 0 ) {
1177
1178 /* Use gzwrite or fwrite as previously setup in the open call */
1179
1180#ifdef HAVE_ZLIB_H
1181 if ( ctxt->compression > 0 )
1182 len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len );
1183
1184 else
1185#endif
1186 len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
1187
1188 if ( len < 0 ) {
1189 xmlGenericError( xmlGenericErrorContext,
1190 "xmlIOHTTPWrite: %s\n%s '%s'.\n",
1191 "Error appending to internal buffer.",
1192 "Error sending document to URI",
1193 ctxt->uri );
1194 }
1195 }
1196
1197 return ( len );
1198}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001199#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001200
1201
1202/**
Owen Taylor3473f882001-02-23 17:55:21 +00001203 * xmlIOHTTPClose:
1204 * @context: the I/O context
1205 *
1206 * Close an HTTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001207 *
1208 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00001209 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001210int
Owen Taylor3473f882001-02-23 17:55:21 +00001211xmlIOHTTPClose (void * context) {
1212 xmlNanoHTTPClose(context);
Daniel Veillardf012a642001-07-23 19:10:52 +00001213 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001214}
Daniel Veillardf012a642001-07-23 19:10:52 +00001215
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001216#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001217/**
1218 * xmlIOHTTCloseWrite
1219 * @context: The I/O context
1220 * @http_mthd: The HTTP method to be used when sending the data
1221 *
1222 * Close the transmit HTTP I/O channel and actually send the data.
1223 */
1224static int
1225xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
1226
1227 int close_rc = -1;
1228 int http_rtn = 0;
1229 int content_lgth = 0;
1230 xmlIOHTTPWriteCtxtPtr ctxt = context;
1231
1232 char * http_content = NULL;
1233 char * content_encoding = NULL;
1234 char * content_type = (char *) "text/xml";
1235 void * http_ctxt = NULL;
1236
1237 if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
1238 return ( -1 );
1239
1240 /* Retrieve the content from the appropriate buffer */
1241
1242#ifdef HAVE_ZLIB_H
1243
1244 if ( ctxt->compression > 0 ) {
1245 content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
1246 content_encoding = (char *) "Content-Encoding: gzip";
1247 }
1248 else
1249#endif
1250 {
1251 /* Pull the data out of the memory output buffer */
1252
1253 xmlOutputBufferPtr dctxt = ctxt->doc_buff;
1254 http_content = (char *)dctxt->buffer->content;
1255 content_lgth = dctxt->buffer->use;
1256 }
1257
1258 if ( http_content == NULL ) {
1259 xmlGenericError( xmlGenericErrorContext,
1260 "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
1261 "Error retrieving content.\nUnable to",
1262 http_mthd, "data to URI", ctxt->uri );
1263 }
1264
1265 else {
1266
1267 http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
1268 &content_type, content_encoding,
1269 content_lgth );
1270
1271 if ( http_ctxt != NULL ) {
1272#ifdef DEBUG_HTTP
1273 /* If testing/debugging - dump reply with request content */
1274
1275 FILE * tst_file = NULL;
1276 char buffer[ 4096 ];
1277 char * dump_name = NULL;
1278 int avail;
1279
1280 xmlGenericError( xmlGenericErrorContext,
1281 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
1282 http_mthd, ctxt->uri,
1283 xmlNanoHTTPReturnCode( http_ctxt ) );
1284
1285 /*
1286 ** Since either content or reply may be gzipped,
1287 ** dump them to separate files instead of the
1288 ** standard error context.
1289 */
1290
1291 dump_name = tempnam( NULL, "lxml" );
1292 if ( dump_name != NULL ) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001293 (void)snprintf( buffer, sizeof(buffer), "%s.content", dump_name );
Daniel Veillardf012a642001-07-23 19:10:52 +00001294
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00001295 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00001296 if ( tst_file != NULL ) {
1297 xmlGenericError( xmlGenericErrorContext,
1298 "Transmitted content saved in file: %s\n", buffer );
1299
1300 fwrite( http_content, sizeof( char ),
1301 content_lgth, tst_file );
1302 fclose( tst_file );
1303 }
1304
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001305 (void)snprintf( buffer, sizeof(buffer), "%s.reply", dump_name );
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00001306 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00001307 if ( tst_file != NULL ) {
1308 xmlGenericError( xmlGenericErrorContext,
1309 "Reply content saved in file: %s\n", buffer );
1310
1311
1312 while ( (avail = xmlNanoHTTPRead( http_ctxt,
1313 buffer, sizeof( buffer ) )) > 0 ) {
1314
1315 fwrite( buffer, sizeof( char ), avail, tst_file );
1316 }
1317
1318 fclose( tst_file );
1319 }
1320
1321 free( dump_name );
1322 }
1323#endif /* DEBUG_HTTP */
1324
1325 http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
1326 if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
1327 close_rc = 0;
1328 else
1329 xmlGenericError( xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001330 "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001331 http_mthd, content_lgth,
1332 "bytes to URI", ctxt->uri,
1333 "failed. HTTP return code:", http_rtn );
1334
1335 xmlNanoHTTPClose( http_ctxt );
1336 xmlFree( content_type );
1337 }
1338 }
1339
1340 /* Final cleanups */
1341
1342 xmlFreeHTTPWriteCtxt( ctxt );
1343
1344 return ( close_rc );
1345}
1346
1347/**
1348 * xmlIOHTTPClosePut
1349 *
1350 * @context: The I/O context
1351 *
1352 * Close the transmit HTTP I/O channel and actually send data using a PUT
1353 * HTTP method.
1354 */
1355static int
1356xmlIOHTTPClosePut( void * ctxt ) {
1357 return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
1358}
1359
1360
1361/**
1362 * xmlIOHTTPClosePost
1363 *
1364 * @context: The I/O context
1365 *
1366 * Close the transmit HTTP I/O channel and actually send data using a POST
1367 * HTTP method.
1368 */
1369static int
1370xmlIOHTTPClosePost( void * ctxt ) {
1371 return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
1372}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001373#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001374
Owen Taylor3473f882001-02-23 17:55:21 +00001375#endif /* LIBXML_HTTP_ENABLED */
1376
1377#ifdef LIBXML_FTP_ENABLED
1378/************************************************************************
1379 * *
1380 * I/O for FTP file accesses *
1381 * *
1382 ************************************************************************/
1383/**
1384 * xmlIOFTPMatch:
1385 * @filename: the URI for matching
1386 *
1387 * check if the URI matches an FTP one
1388 *
1389 * Returns 1 if matches, 0 otherwise
1390 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001391int
Owen Taylor3473f882001-02-23 17:55:21 +00001392xmlIOFTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001393 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "ftp://", 6))
Owen Taylor3473f882001-02-23 17:55:21 +00001394 return(1);
1395 return(0);
1396}
1397
1398/**
1399 * xmlIOFTPOpen:
1400 * @filename: the URI for matching
1401 *
1402 * open an FTP I/O channel
1403 *
1404 * Returns an I/O context or NULL in case of error
1405 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001406void *
Owen Taylor3473f882001-02-23 17:55:21 +00001407xmlIOFTPOpen (const char *filename) {
1408 return(xmlNanoFTPOpen(filename));
1409}
1410
1411/**
1412 * xmlIOFTPRead:
1413 * @context: the I/O context
1414 * @buffer: where to drop data
1415 * @len: number of bytes to write
1416 *
1417 * Read @len bytes to @buffer from the I/O channel.
1418 *
1419 * Returns the number of bytes written
1420 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001421int
Owen Taylor3473f882001-02-23 17:55:21 +00001422xmlIOFTPRead(void * context, char * buffer, int len) {
1423 return(xmlNanoFTPRead(context, &buffer[0], len));
1424}
1425
1426/**
1427 * xmlIOFTPClose:
1428 * @context: the I/O context
1429 *
1430 * Close an FTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001431 *
1432 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00001433 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001434int
Owen Taylor3473f882001-02-23 17:55:21 +00001435xmlIOFTPClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001436 return ( xmlNanoFTPClose(context) );
Owen Taylor3473f882001-02-23 17:55:21 +00001437}
1438#endif /* LIBXML_FTP_ENABLED */
1439
1440
1441/**
1442 * xmlRegisterInputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001443 * @matchFunc: the xmlInputMatchCallback
1444 * @openFunc: the xmlInputOpenCallback
1445 * @readFunc: the xmlInputReadCallback
1446 * @closeFunc: the xmlInputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001447 *
1448 * Register a new set of I/O callback for handling parser input.
1449 *
1450 * Returns the registered handler number or -1 in case of error
1451 */
1452int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001453xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
1454 xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
1455 xmlInputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001456 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
1457 return(-1);
1458 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001459 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
1460 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
1461 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
1462 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00001463 xmlInputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00001464 return(xmlInputCallbackNr++);
1465}
1466
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001467#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001468/**
1469 * xmlRegisterOutputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001470 * @matchFunc: the xmlOutputMatchCallback
1471 * @openFunc: the xmlOutputOpenCallback
1472 * @writeFunc: the xmlOutputWriteCallback
1473 * @closeFunc: the xmlOutputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001474 *
1475 * Register a new set of I/O callback for handling output.
1476 *
1477 * Returns the registered handler number or -1 in case of error
1478 */
1479int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001480xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
1481 xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
1482 xmlOutputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001483 if (xmlOutputCallbackNr >= MAX_INPUT_CALLBACK) {
1484 return(-1);
1485 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001486 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
1487 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
1488 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
1489 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00001490 xmlOutputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00001491 return(xmlOutputCallbackNr++);
1492}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001493#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001494
1495/**
1496 * xmlRegisterDefaultInputCallbacks:
1497 *
1498 * Registers the default compiled-in I/O handlers.
1499 */
1500void
Owen Taylor3473f882001-02-23 17:55:21 +00001501xmlRegisterDefaultInputCallbacks
Owen Taylor3473f882001-02-23 17:55:21 +00001502(void) {
1503 if (xmlInputCallbackInitialized)
1504 return;
1505
1506 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
1507 xmlFileRead, xmlFileClose);
1508#ifdef HAVE_ZLIB_H
1509 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1510 xmlGzfileRead, xmlGzfileClose);
1511#endif /* HAVE_ZLIB_H */
1512
1513#ifdef LIBXML_HTTP_ENABLED
1514 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
1515 xmlIOHTTPRead, xmlIOHTTPClose);
1516#endif /* LIBXML_HTTP_ENABLED */
1517
1518#ifdef LIBXML_FTP_ENABLED
1519 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1520 xmlIOFTPRead, xmlIOFTPClose);
1521#endif /* LIBXML_FTP_ENABLED */
1522 xmlInputCallbackInitialized = 1;
1523}
1524
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001525#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001526/**
1527 * xmlRegisterDefaultOutputCallbacks:
1528 *
1529 * Registers the default compiled-in I/O handlers.
1530 */
1531void
Owen Taylor3473f882001-02-23 17:55:21 +00001532xmlRegisterDefaultOutputCallbacks
Owen Taylor3473f882001-02-23 17:55:21 +00001533(void) {
1534 if (xmlOutputCallbackInitialized)
1535 return;
1536
1537 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
1538 xmlFileWrite, xmlFileClose);
Daniel Veillardf012a642001-07-23 19:10:52 +00001539
1540#ifdef LIBXML_HTTP_ENABLED
1541 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
1542 xmlIOHTTPWrite, xmlIOHTTPClosePut);
1543#endif
1544
Owen Taylor3473f882001-02-23 17:55:21 +00001545/*********************************
1546 No way a-priori to distinguish between gzipped files from
1547 uncompressed ones except opening if existing then closing
1548 and saving with same compression ratio ... a pain.
1549
1550#ifdef HAVE_ZLIB_H
1551 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1552 xmlGzfileWrite, xmlGzfileClose);
1553#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001554
1555 Nor FTP PUT ....
1556#ifdef LIBXML_FTP_ENABLED
1557 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1558 xmlIOFTPWrite, xmlIOFTPClose);
1559#endif
1560 **********************************/
1561 xmlOutputCallbackInitialized = 1;
1562}
1563
Daniel Veillardf012a642001-07-23 19:10:52 +00001564#ifdef LIBXML_HTTP_ENABLED
1565/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001566 * xmlRegisterHTTPPostCallbacks:
Daniel Veillardf012a642001-07-23 19:10:52 +00001567 *
1568 * By default, libxml submits HTTP output requests using the "PUT" method.
1569 * Calling this method changes the HTTP output method to use the "POST"
1570 * method instead.
1571 *
1572 */
1573void
1574xmlRegisterHTTPPostCallbacks( void ) {
1575
1576 /* Register defaults if not done previously */
1577
1578 if ( xmlOutputCallbackInitialized == 0 )
1579 xmlRegisterDefaultOutputCallbacks( );
1580
1581 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
1582 xmlIOHTTPWrite, xmlIOHTTPClosePost);
1583 return;
1584}
1585#endif
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001586#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001587
Owen Taylor3473f882001-02-23 17:55:21 +00001588/**
1589 * xmlAllocParserInputBuffer:
1590 * @enc: the charset encoding if known
1591 *
1592 * Create a buffered parser input for progressive parsing
1593 *
1594 * Returns the new parser input or NULL
1595 */
1596xmlParserInputBufferPtr
1597xmlAllocParserInputBuffer(xmlCharEncoding enc) {
1598 xmlParserInputBufferPtr ret;
1599
1600 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
1601 if (ret == NULL) {
1602 xmlGenericError(xmlGenericErrorContext,
1603 "xmlAllocParserInputBuffer : out of memory!\n");
1604 return(NULL);
1605 }
1606 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00001607 ret->buffer = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00001608 if (ret->buffer == NULL) {
1609 xmlFree(ret);
1610 return(NULL);
1611 }
1612 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
1613 ret->encoder = xmlGetCharEncodingHandler(enc);
1614 if (ret->encoder != NULL)
Daniel Veillard6155d8a2003-08-19 15:01:28 +00001615 ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00001616 else
1617 ret->raw = NULL;
1618 ret->readcallback = NULL;
1619 ret->closecallback = NULL;
1620 ret->context = NULL;
William M. Brackc07329e2003-09-08 01:57:30 +00001621 ret->compressed = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00001622
1623 return(ret);
1624}
1625
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001626#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001627/**
1628 * xmlAllocOutputBuffer:
1629 * @encoder: the encoding converter or NULL
1630 *
1631 * Create a buffered parser output
1632 *
1633 * Returns the new parser output or NULL
1634 */
1635xmlOutputBufferPtr
1636xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
1637 xmlOutputBufferPtr ret;
1638
1639 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
1640 if (ret == NULL) {
1641 xmlGenericError(xmlGenericErrorContext,
1642 "xmlAllocOutputBuffer : out of memory!\n");
1643 return(NULL);
1644 }
1645 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
1646 ret->buffer = xmlBufferCreate();
1647 if (ret->buffer == NULL) {
1648 xmlFree(ret);
1649 return(NULL);
1650 }
1651 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
1652 ret->encoder = encoder;
1653 if (encoder != NULL) {
1654 ret->conv = xmlBufferCreateSize(4000);
1655 /*
1656 * This call is designed to initiate the encoder state
1657 */
1658 xmlCharEncOutFunc(encoder, ret->conv, NULL);
1659 } else
1660 ret->conv = NULL;
1661 ret->writecallback = NULL;
1662 ret->closecallback = NULL;
1663 ret->context = NULL;
1664 ret->written = 0;
1665
1666 return(ret);
1667}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001668#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001669
1670/**
1671 * xmlFreeParserInputBuffer:
1672 * @in: a buffered parser input
1673 *
1674 * Free up the memory used by a buffered parser input
1675 */
1676void
1677xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
Daniel Veillard8d8bf2c2003-09-17 19:36:25 +00001678 if (in == NULL) return;
1679
Owen Taylor3473f882001-02-23 17:55:21 +00001680 if (in->raw) {
1681 xmlBufferFree(in->raw);
1682 in->raw = NULL;
1683 }
1684 if (in->encoder != NULL) {
1685 xmlCharEncCloseFunc(in->encoder);
1686 }
1687 if (in->closecallback != NULL) {
1688 in->closecallback(in->context);
1689 }
1690 if (in->buffer != NULL) {
1691 xmlBufferFree(in->buffer);
1692 in->buffer = NULL;
1693 }
1694
Owen Taylor3473f882001-02-23 17:55:21 +00001695 xmlFree(in);
1696}
1697
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001698#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001699/**
1700 * xmlOutputBufferClose:
1701 * @out: a buffered output
1702 *
1703 * flushes and close the output I/O channel
1704 * and free up all the associated resources
1705 *
1706 * Returns the number of byte written or -1 in case of error.
1707 */
1708int
1709xmlOutputBufferClose(xmlOutputBufferPtr out) {
1710 int written;
Daniel Veillardf012a642001-07-23 19:10:52 +00001711 int err_rc = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001712
1713 if (out == NULL)
1714 return(-1);
1715 if (out->writecallback != NULL)
1716 xmlOutputBufferFlush(out);
1717 if (out->closecallback != NULL) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001718 err_rc = out->closecallback(out->context);
Owen Taylor3473f882001-02-23 17:55:21 +00001719 }
1720 written = out->written;
1721 if (out->conv) {
1722 xmlBufferFree(out->conv);
1723 out->conv = NULL;
1724 }
1725 if (out->encoder != NULL) {
1726 xmlCharEncCloseFunc(out->encoder);
1727 }
1728 if (out->buffer != NULL) {
1729 xmlBufferFree(out->buffer);
1730 out->buffer = NULL;
1731 }
1732
Owen Taylor3473f882001-02-23 17:55:21 +00001733 xmlFree(out);
Daniel Veillardf012a642001-07-23 19:10:52 +00001734 return( ( err_rc == 0 ) ? written : err_rc );
Owen Taylor3473f882001-02-23 17:55:21 +00001735}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001736#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001737
1738/**
1739 * xmlParserInputBufferCreateFilename:
1740 * @URI: a C string containing the URI or filename
1741 * @enc: the charset encoding if known
1742 *
1743 * Create a buffered parser input for the progressive parsing of a file
1744 * If filename is "-' then we use stdin as the input.
1745 * Automatic support for ZLIB/Compress compressed document is provided
1746 * by default if found at compile-time.
1747 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
1748 *
1749 * Returns the new parser input or NULL
1750 */
1751xmlParserInputBufferPtr
Daniel Veillard3e59fc52003-04-18 12:34:58 +00001752xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001753 xmlParserInputBufferPtr ret;
Daniel Veillard388236f2001-07-08 18:35:48 +00001754 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001755 void *context = NULL;
1756
1757 if (xmlInputCallbackInitialized == 0)
1758 xmlRegisterDefaultInputCallbacks();
1759
1760 if (URI == NULL) return(NULL);
1761
1762 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001763 * Try to find one of the input accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00001764 * Go in reverse to give precedence to user defined handlers.
Daniel Veillard388236f2001-07-08 18:35:48 +00001765 */
1766 if (context == NULL) {
1767 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
1768 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
1769 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00001770 context = xmlInputCallbackTable[i].opencallback(URI);
Daniel Veillard388236f2001-07-08 18:35:48 +00001771 if (context != NULL)
1772 break;
1773 }
Owen Taylor3473f882001-02-23 17:55:21 +00001774 }
1775 }
1776 if (context == NULL) {
1777 return(NULL);
1778 }
1779
1780 /*
1781 * Allocate the Input buffer front-end.
1782 */
1783 ret = xmlAllocParserInputBuffer(enc);
1784 if (ret != NULL) {
1785 ret->context = context;
1786 ret->readcallback = xmlInputCallbackTable[i].readcallback;
1787 ret->closecallback = xmlInputCallbackTable[i].closecallback;
William M. Brackc07329e2003-09-08 01:57:30 +00001788#ifdef HAVE_ZLIB_H
1789 if (xmlInputCallbackTable[i].opencallback == xmlGzfileOpen) {
1790 if (((z_stream *)context)->avail_in > 4) {
1791 char *cptr, buff4[4];
Daniel Veillard07cb8222003-09-10 10:51:05 +00001792 cptr = (char *) ((z_stream *)context)->next_in;
William M. Brackc07329e2003-09-08 01:57:30 +00001793 if (gzread(context, buff4, 4) == 4) {
1794 if (strncmp(buff4, cptr, 4) == 0)
1795 ret->compressed = 0;
1796 else
1797 ret->compressed = 1;
1798 gzrewind(context);
1799 }
1800 }
1801 }
1802#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001803 }
1804 return(ret);
1805}
1806
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001807#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001808/**
1809 * xmlOutputBufferCreateFilename:
1810 * @URI: a C string containing the URI or filename
1811 * @encoder: the encoding converter or NULL
1812 * @compression: the compression ration (0 none, 9 max).
1813 *
1814 * Create a buffered output for the progressive saving of a file
1815 * If filename is "-' then we use stdout as the output.
1816 * Automatic support for ZLIB/Compress compressed document is provided
1817 * by default if found at compile-time.
1818 * TODO: currently if compression is set, the library only support
1819 * writing to a local file.
1820 *
1821 * Returns the new output or NULL
1822 */
1823xmlOutputBufferPtr
1824xmlOutputBufferCreateFilename(const char *URI,
1825 xmlCharEncodingHandlerPtr encoder,
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001826 int compression ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00001827 xmlOutputBufferPtr ret;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001828 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001829 void *context = NULL;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001830 char *unescaped;
Owen Taylor3473f882001-02-23 17:55:21 +00001831
Daniel Veillard4432df22003-09-28 18:58:27 +00001832#ifdef LIBXML_HTTP_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001833 int is_http_uri = 0; /* Can't change if HTTP disabled */
Daniel Veillard4432df22003-09-28 18:58:27 +00001834#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001835
Owen Taylor3473f882001-02-23 17:55:21 +00001836 if (xmlOutputCallbackInitialized == 0)
1837 xmlRegisterDefaultOutputCallbacks();
1838
1839 if (URI == NULL) return(NULL);
1840
Daniel Veillardf012a642001-07-23 19:10:52 +00001841#ifdef LIBXML_HTTP_ENABLED
1842 /* Need to prevent HTTP URI's from falling into zlib short circuit */
1843
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00001844 is_http_uri = xmlIOHTTPMatch( URI );
Daniel Veillardf012a642001-07-23 19:10:52 +00001845#endif
1846
Owen Taylor3473f882001-02-23 17:55:21 +00001847
1848 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001849 * Try to find one of the output accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00001850 * Go in reverse to give precedence to user defined handlers.
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001851 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00001852 */
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00001853 unescaped = xmlURIUnescapeString(URI, 0, NULL);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001854 if (unescaped != NULL) {
1855#ifdef HAVE_ZLIB_H
1856 if ((compression > 0) && (compression <= 9) && (is_http_uri == 0)) {
1857 context = xmlGzfileOpenW(unescaped, compression);
1858 if (context != NULL) {
1859 ret = xmlAllocOutputBuffer(encoder);
1860 if (ret != NULL) {
1861 ret->context = context;
1862 ret->writecallback = xmlGzfileWrite;
1863 ret->closecallback = xmlGzfileClose;
1864 }
1865 xmlFree(unescaped);
1866 return(ret);
1867 }
1868 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001869#endif
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001870 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
1871 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
1872 (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
1873#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
1874 /* Need to pass compression parameter into HTTP open calls */
1875 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
1876 context = xmlIOHTTPOpenW(unescaped, compression);
1877 else
1878#endif
1879 context = xmlOutputCallbackTable[i].opencallback(unescaped);
1880 if (context != NULL)
1881 break;
1882 }
1883 }
1884 xmlFree(unescaped);
1885 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001886
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001887 /*
1888 * If this failed try with a non-escaped URI this may be a strange
1889 * filename
1890 */
1891 if (context == NULL) {
1892#ifdef HAVE_ZLIB_H
1893 if ((compression > 0) && (compression <= 9) && (is_http_uri == 0)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00001894 context = xmlGzfileOpenW(URI, compression);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001895 if (context != NULL) {
1896 ret = xmlAllocOutputBuffer(encoder);
1897 if (ret != NULL) {
1898 ret->context = context;
1899 ret->writecallback = xmlGzfileWrite;
1900 ret->closecallback = xmlGzfileClose;
1901 }
1902 return(ret);
1903 }
1904 }
1905#endif
1906 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
1907 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00001908 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001909#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
1910 /* Need to pass compression parameter into HTTP open calls */
1911 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
1912 context = xmlIOHTTPOpenW(URI, compression);
1913 else
1914#endif
1915 context = xmlOutputCallbackTable[i].opencallback(URI);
1916 if (context != NULL)
1917 break;
1918 }
Owen Taylor3473f882001-02-23 17:55:21 +00001919 }
1920 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001921
Owen Taylor3473f882001-02-23 17:55:21 +00001922 if (context == NULL) {
1923 return(NULL);
1924 }
1925
1926 /*
1927 * Allocate the Output buffer front-end.
1928 */
1929 ret = xmlAllocOutputBuffer(encoder);
1930 if (ret != NULL) {
1931 ret->context = context;
1932 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
1933 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
1934 }
1935 return(ret);
1936}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001937#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001938
1939/**
1940 * xmlParserInputBufferCreateFile:
1941 * @file: a FILE*
1942 * @enc: the charset encoding if known
1943 *
1944 * Create a buffered parser input for the progressive parsing of a FILE *
1945 * buffered C I/O
1946 *
1947 * Returns the new parser input or NULL
1948 */
1949xmlParserInputBufferPtr
1950xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
1951 xmlParserInputBufferPtr ret;
1952
1953 if (xmlInputCallbackInitialized == 0)
1954 xmlRegisterDefaultInputCallbacks();
1955
1956 if (file == NULL) return(NULL);
1957
1958 ret = xmlAllocParserInputBuffer(enc);
1959 if (ret != NULL) {
1960 ret->context = file;
1961 ret->readcallback = xmlFileRead;
1962 ret->closecallback = xmlFileFlush;
1963 }
1964
1965 return(ret);
1966}
1967
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001968#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001969/**
1970 * xmlOutputBufferCreateFile:
1971 * @file: a FILE*
1972 * @encoder: the encoding converter or NULL
1973 *
1974 * Create a buffered output for the progressive saving to a FILE *
1975 * buffered C I/O
1976 *
1977 * Returns the new parser output or NULL
1978 */
1979xmlOutputBufferPtr
1980xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
1981 xmlOutputBufferPtr ret;
1982
1983 if (xmlOutputCallbackInitialized == 0)
1984 xmlRegisterDefaultOutputCallbacks();
1985
1986 if (file == NULL) return(NULL);
1987
1988 ret = xmlAllocOutputBuffer(encoder);
1989 if (ret != NULL) {
1990 ret->context = file;
1991 ret->writecallback = xmlFileWrite;
1992 ret->closecallback = xmlFileFlush;
1993 }
1994
1995 return(ret);
1996}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001997#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001998
1999/**
2000 * xmlParserInputBufferCreateFd:
2001 * @fd: a file descriptor number
2002 * @enc: the charset encoding if known
2003 *
2004 * Create a buffered parser input for the progressive parsing for the input
2005 * from a file descriptor
2006 *
2007 * Returns the new parser input or NULL
2008 */
2009xmlParserInputBufferPtr
2010xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
2011 xmlParserInputBufferPtr ret;
2012
2013 if (fd < 0) return(NULL);
2014
2015 ret = xmlAllocParserInputBuffer(enc);
2016 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002017 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002018 ret->readcallback = xmlFdRead;
2019 ret->closecallback = xmlFdClose;
2020 }
2021
2022 return(ret);
2023}
2024
2025/**
2026 * xmlParserInputBufferCreateMem:
2027 * @mem: the memory input
2028 * @size: the length of the memory block
2029 * @enc: the charset encoding if known
2030 *
2031 * Create a buffered parser input for the progressive parsing for the input
2032 * from a memory area.
2033 *
2034 * Returns the new parser input or NULL
2035 */
2036xmlParserInputBufferPtr
2037xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
2038 xmlParserInputBufferPtr ret;
2039
2040 if (size <= 0) return(NULL);
2041 if (mem == NULL) return(NULL);
2042
2043 ret = xmlAllocParserInputBuffer(enc);
2044 if (ret != NULL) {
2045 ret->context = (void *) mem;
2046 ret->readcallback = (xmlInputReadCallback) xmlNop;
2047 ret->closecallback = NULL;
2048 xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size);
2049 }
2050
2051 return(ret);
2052}
2053
2054/**
Daniel Veillard53350552003-09-18 13:35:51 +00002055 * xmlParserInputBufferCreateStatic:
2056 * @mem: the memory input
2057 * @size: the length of the memory block
2058 * @enc: the charset encoding if known
2059 *
2060 * Create a buffered parser input for the progressive parsing for the input
2061 * from an immutable memory area. This will not copy the memory area to
2062 * the buffer, but the memory is expected to be available until the end of
2063 * the parsing, this is useful for example when using mmap'ed file.
2064 *
2065 * Returns the new parser input or NULL
2066 */
2067xmlParserInputBufferPtr
2068xmlParserInputBufferCreateStatic(const char *mem, int size,
2069 xmlCharEncoding enc) {
2070 xmlParserInputBufferPtr ret;
2071
2072 if (size <= 0) return(NULL);
2073 if (mem == NULL) return(NULL);
2074
2075 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2076 if (ret == NULL) {
2077 xmlGenericError(xmlGenericErrorContext,
2078 "xmlParserInputBufferCreateStatic : out of memory!\n");
2079 return(NULL);
2080 }
2081 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillarde72c5082003-09-19 12:44:05 +00002082 ret->buffer = xmlBufferCreateStatic((void *)mem, (size_t) size);
Daniel Veillard53350552003-09-18 13:35:51 +00002083 if (ret->buffer == NULL) {
2084 xmlFree(ret);
2085 return(NULL);
2086 }
2087 ret->encoder = xmlGetCharEncodingHandler(enc);
2088 if (ret->encoder != NULL)
2089 ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
2090 else
2091 ret->raw = NULL;
2092 ret->compressed = -1;
2093 ret->context = (void *) mem;
2094 ret->readcallback = NULL;
2095 ret->closecallback = NULL;
2096
2097 return(ret);
2098}
2099
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002100#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard53350552003-09-18 13:35:51 +00002101/**
Owen Taylor3473f882001-02-23 17:55:21 +00002102 * xmlOutputBufferCreateFd:
2103 * @fd: a file descriptor number
2104 * @encoder: the encoding converter or NULL
2105 *
2106 * Create a buffered output for the progressive saving
2107 * to a file descriptor
2108 *
2109 * Returns the new parser output or NULL
2110 */
2111xmlOutputBufferPtr
2112xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
2113 xmlOutputBufferPtr ret;
2114
2115 if (fd < 0) return(NULL);
2116
2117 ret = xmlAllocOutputBuffer(encoder);
2118 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002119 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002120 ret->writecallback = xmlFdWrite;
Daniel Veillard7db38712002-02-07 16:39:11 +00002121 ret->closecallback = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002122 }
2123
2124 return(ret);
2125}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002126#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002127
2128/**
2129 * xmlParserInputBufferCreateIO:
2130 * @ioread: an I/O read function
2131 * @ioclose: an I/O close function
2132 * @ioctx: an I/O handler
2133 * @enc: the charset encoding if known
2134 *
2135 * Create a buffered parser input for the progressive parsing for the input
2136 * from an I/O handler
2137 *
2138 * Returns the new parser input or NULL
2139 */
2140xmlParserInputBufferPtr
2141xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
2142 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
2143 xmlParserInputBufferPtr ret;
2144
2145 if (ioread == NULL) return(NULL);
2146
2147 ret = xmlAllocParserInputBuffer(enc);
2148 if (ret != NULL) {
2149 ret->context = (void *) ioctx;
2150 ret->readcallback = ioread;
2151 ret->closecallback = ioclose;
2152 }
2153
2154 return(ret);
2155}
2156
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002157#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002158/**
2159 * xmlOutputBufferCreateIO:
2160 * @iowrite: an I/O write function
2161 * @ioclose: an I/O close function
2162 * @ioctx: an I/O handler
Daniel Veillard9d06d302002-01-22 18:15:52 +00002163 * @encoder: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002164 *
2165 * Create a buffered output for the progressive saving
2166 * to an I/O handler
2167 *
2168 * Returns the new parser output or NULL
2169 */
2170xmlOutputBufferPtr
2171xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
2172 xmlOutputCloseCallback ioclose, void *ioctx,
2173 xmlCharEncodingHandlerPtr encoder) {
2174 xmlOutputBufferPtr ret;
2175
2176 if (iowrite == NULL) return(NULL);
2177
2178 ret = xmlAllocOutputBuffer(encoder);
2179 if (ret != NULL) {
2180 ret->context = (void *) ioctx;
2181 ret->writecallback = iowrite;
2182 ret->closecallback = ioclose;
2183 }
2184
2185 return(ret);
2186}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002187#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002188
2189/**
2190 * xmlParserInputBufferPush:
2191 * @in: a buffered parser input
2192 * @len: the size in bytes of the array.
2193 * @buf: an char array
2194 *
2195 * Push the content of the arry in the input buffer
2196 * This routine handle the I18N transcoding to internal UTF-8
2197 * This is used when operating the parser in progressive (push) mode.
2198 *
2199 * Returns the number of chars read and stored in the buffer, or -1
2200 * in case of error.
2201 */
2202int
2203xmlParserInputBufferPush(xmlParserInputBufferPtr in,
2204 int len, const char *buf) {
2205 int nbchars = 0;
2206
2207 if (len < 0) return(0);
2208 if (in->encoder != NULL) {
2209 /*
2210 * Store the data in the incoming raw buffer
2211 */
2212 if (in->raw == NULL) {
2213 in->raw = xmlBufferCreate();
2214 }
2215 xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
2216
2217 /*
2218 * convert as much as possible to the parser reading buffer.
2219 */
2220 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2221 if (nbchars < 0) {
2222 xmlGenericError(xmlGenericErrorContext,
2223 "xmlParserInputBufferPush: encoder error\n");
2224 return(-1);
2225 }
2226 } else {
2227 nbchars = len;
2228 xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
2229 }
2230#ifdef DEBUG_INPUT
2231 xmlGenericError(xmlGenericErrorContext,
2232 "I/O: pushed %d chars, buffer %d/%d\n",
2233 nbchars, in->buffer->use, in->buffer->size);
2234#endif
2235 return(nbchars);
2236}
2237
2238/**
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002239 * endOfInput:
2240 *
2241 * When reading from an Input channel indicated end of file or error
2242 * don't reread from it again.
2243 */
2244static int
2245endOfInput (void * context ATTRIBUTE_UNUSED,
2246 char * buffer ATTRIBUTE_UNUSED,
2247 int len ATTRIBUTE_UNUSED) {
2248 return(0);
2249}
2250
2251/**
Owen Taylor3473f882001-02-23 17:55:21 +00002252 * xmlParserInputBufferGrow:
2253 * @in: a buffered parser input
2254 * @len: indicative value of the amount of chars to read
2255 *
2256 * Grow up the content of the input buffer, the old data are preserved
2257 * This routine handle the I18N transcoding to internal UTF-8
2258 * This routine is used when operating the parser in normal (pull) mode
2259 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002260 * TODO: one should be able to remove one extra copy by copying directly
Owen Taylor3473f882001-02-23 17:55:21 +00002261 * onto in->buffer or in->raw
2262 *
2263 * Returns the number of chars read and stored in the buffer, or -1
2264 * in case of error.
2265 */
2266int
2267xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
2268 char *buffer = NULL;
2269 int res = 0;
2270 int nbchars = 0;
2271 int buffree;
Daniel Veillard9e412302002-06-10 15:59:44 +00002272 unsigned int needSize;
Owen Taylor3473f882001-02-23 17:55:21 +00002273
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002274 if ((len <= MINLEN) && (len != 4))
Owen Taylor3473f882001-02-23 17:55:21 +00002275 len = MINLEN;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002276
Owen Taylor3473f882001-02-23 17:55:21 +00002277 buffree = in->buffer->size - in->buffer->use;
2278 if (buffree <= 0) {
2279 xmlGenericError(xmlGenericErrorContext,
2280 "xmlParserInputBufferGrow : buffer full !\n");
2281 return(0);
2282 }
Owen Taylor3473f882001-02-23 17:55:21 +00002283
Daniel Veillarde5354492002-05-16 08:43:22 +00002284 needSize = in->buffer->use + len + 1;
2285 if (needSize > in->buffer->size){
2286 if (!xmlBufferResize(in->buffer, needSize)){
2287 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard8caa9c22003-06-02 13:35:24 +00002288 "xmlParserInputBufferGrow : out of memory!\n");
Daniel Veillarde5354492002-05-16 08:43:22 +00002289 return(0);
2290 }
Owen Taylor3473f882001-02-23 17:55:21 +00002291 }
Daniel Veillarde5354492002-05-16 08:43:22 +00002292 buffer = (char *)&in->buffer->content[in->buffer->use];
Owen Taylor3473f882001-02-23 17:55:21 +00002293
2294 /*
2295 * Call the read method for this I/O type.
2296 */
2297 if (in->readcallback != NULL) {
2298 res = in->readcallback(in->context, &buffer[0], len);
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002299 if (res <= 0)
2300 in->readcallback = endOfInput;
Owen Taylor3473f882001-02-23 17:55:21 +00002301 } else {
2302 xmlGenericError(xmlGenericErrorContext,
2303 "xmlParserInputBufferGrow : no input !\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002304 return(-1);
2305 }
2306 if (res < 0) {
Owen Taylor3473f882001-02-23 17:55:21 +00002307 return(-1);
2308 }
2309 len = res;
2310 if (in->encoder != NULL) {
2311 /*
2312 * Store the data in the incoming raw buffer
2313 */
2314 if (in->raw == NULL) {
2315 in->raw = xmlBufferCreate();
2316 }
2317 xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
2318
2319 /*
2320 * convert as much as possible to the parser reading buffer.
2321 */
2322 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2323 if (nbchars < 0) {
2324 xmlGenericError(xmlGenericErrorContext,
2325 "xmlParserInputBufferGrow: encoder error\n");
2326 return(-1);
2327 }
2328 } else {
2329 nbchars = len;
Daniel Veillarde5354492002-05-16 08:43:22 +00002330 in->buffer->use += nbchars;
2331 buffer[nbchars] = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002332 }
2333#ifdef DEBUG_INPUT
2334 xmlGenericError(xmlGenericErrorContext,
2335 "I/O: read %d chars, buffer %d/%d\n",
2336 nbchars, in->buffer->use, in->buffer->size);
2337#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002338 return(nbchars);
2339}
2340
2341/**
2342 * xmlParserInputBufferRead:
2343 * @in: a buffered parser input
2344 * @len: indicative value of the amount of chars to read
2345 *
2346 * Refresh the content of the input buffer, the old data are considered
2347 * consumed
2348 * This routine handle the I18N transcoding to internal UTF-8
2349 *
2350 * Returns the number of chars read and stored in the buffer, or -1
2351 * in case of error.
2352 */
2353int
2354xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
2355 /* xmlBufferEmpty(in->buffer); */
2356 if (in->readcallback != NULL)
2357 return(xmlParserInputBufferGrow(in, len));
Daniel Veillard53350552003-09-18 13:35:51 +00002358 else if ((in->buffer != NULL) &&
2359 (in->buffer->alloc == XML_BUFFER_ALLOC_IMMUTABLE))
2360 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002361 else
2362 return(-1);
2363}
2364
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002365#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002366/**
2367 * xmlOutputBufferWrite:
2368 * @out: a buffered parser output
2369 * @len: the size in bytes of the array.
2370 * @buf: an char array
2371 *
2372 * Write the content of the array in the output I/O buffer
2373 * This routine handle the I18N transcoding from internal UTF-8
2374 * The buffer is lossless, i.e. will store in case of partial
2375 * or delayed writes.
2376 *
2377 * Returns the number of chars immediately written, or -1
2378 * in case of error.
2379 */
2380int
2381xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
2382 int nbchars = 0; /* number of chars to output to I/O */
2383 int ret; /* return from function call */
2384 int written = 0; /* number of char written to I/O so far */
2385 int chunk; /* number of byte curreent processed from buf */
2386
2387 if (len < 0) return(0);
2388
2389 do {
2390 chunk = len;
2391 if (chunk > 4 * MINLEN)
2392 chunk = 4 * MINLEN;
2393
2394 /*
2395 * first handle encoding stuff.
2396 */
2397 if (out->encoder != NULL) {
2398 /*
2399 * Store the data in the incoming raw buffer
2400 */
2401 if (out->conv == NULL) {
2402 out->conv = xmlBufferCreate();
2403 }
2404 xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2405
2406 if ((out->buffer->use < MINLEN) && (chunk == len))
2407 goto done;
2408
2409 /*
2410 * convert as much as possible to the parser reading buffer.
2411 */
2412 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
Daniel Veillard809faa52003-02-10 15:43:53 +00002413 if ((ret < 0) && (ret != -3)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002414 xmlGenericError(xmlGenericErrorContext,
2415 "xmlOutputBufferWrite: encoder error\n");
2416 return(-1);
2417 }
2418 nbchars = out->conv->use;
2419 } else {
2420 xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2421 nbchars = out->buffer->use;
2422 }
2423 buf += chunk;
2424 len -= chunk;
2425
2426 if ((nbchars < MINLEN) && (len <= 0))
2427 goto done;
2428
2429 if (out->writecallback) {
2430 /*
2431 * second write the stuff to the I/O channel
2432 */
2433 if (out->encoder != NULL) {
2434 ret = out->writecallback(out->context,
2435 (const char *)out->conv->content, nbchars);
2436 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002437 xmlBufferShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002438 } else {
2439 ret = out->writecallback(out->context,
2440 (const char *)out->buffer->content, nbchars);
2441 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002442 xmlBufferShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002443 }
2444 if (ret < 0) {
2445 xmlGenericError(xmlGenericErrorContext,
2446 "I/O: error %d writing %d bytes\n", ret, nbchars);
2447 return(ret);
2448 }
2449 out->written += ret;
2450 }
2451 written += nbchars;
2452 } while (len > 0);
2453
2454done:
2455#ifdef DEBUG_INPUT
2456 xmlGenericError(xmlGenericErrorContext,
2457 "I/O: wrote %d chars\n", written);
2458#endif
2459 return(written);
2460}
2461
2462/**
2463 * xmlOutputBufferWriteString:
2464 * @out: a buffered parser output
2465 * @str: a zero terminated C string
2466 *
2467 * Write the content of the string in the output I/O buffer
2468 * This routine handle the I18N transcoding from internal UTF-8
2469 * The buffer is lossless, i.e. will store in case of partial
2470 * or delayed writes.
2471 *
2472 * Returns the number of chars immediately written, or -1
2473 * in case of error.
2474 */
2475int
2476xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
2477 int len;
2478
2479 if (str == NULL)
2480 return(-1);
2481 len = strlen(str);
2482
2483 if (len > 0)
2484 return(xmlOutputBufferWrite(out, len, str));
2485 return(len);
2486}
2487
2488/**
2489 * xmlOutputBufferFlush:
2490 * @out: a buffered output
2491 *
2492 * flushes the output I/O channel
2493 *
2494 * Returns the number of byte written or -1 in case of error.
2495 */
2496int
2497xmlOutputBufferFlush(xmlOutputBufferPtr out) {
2498 int nbchars = 0, ret = 0;
2499
2500 /*
2501 * first handle encoding stuff.
2502 */
2503 if ((out->conv != NULL) && (out->encoder != NULL)) {
2504 /*
2505 * convert as much as possible to the parser reading buffer.
2506 */
2507 nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
2508 if (nbchars < 0) {
2509 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002510 "xmlOutputBufferFlush: encoder error\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002511 return(-1);
2512 }
2513 }
2514
2515 /*
2516 * second flush the stuff to the I/O channel
2517 */
2518 if ((out->conv != NULL) && (out->encoder != NULL) &&
2519 (out->writecallback != NULL)) {
2520 ret = out->writecallback(out->context,
2521 (const char *)out->conv->content, out->conv->use);
2522 if (ret >= 0)
2523 xmlBufferShrink(out->conv, ret);
2524 } else if (out->writecallback != NULL) {
2525 ret = out->writecallback(out->context,
2526 (const char *)out->buffer->content, out->buffer->use);
2527 if (ret >= 0)
2528 xmlBufferShrink(out->buffer, ret);
2529 }
2530 if (ret < 0) {
2531 xmlGenericError(xmlGenericErrorContext,
2532 "I/O: error %d flushing %d bytes\n", ret, nbchars);
2533 return(ret);
2534 }
2535 out->written += ret;
2536
2537#ifdef DEBUG_INPUT
2538 xmlGenericError(xmlGenericErrorContext,
2539 "I/O: flushed %d chars\n", ret);
2540#endif
2541 return(ret);
2542}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002543#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002544
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002545/**
Owen Taylor3473f882001-02-23 17:55:21 +00002546 * xmlParserGetDirectory:
2547 * @filename: the path to a file
2548 *
2549 * lookup the directory for that file
2550 *
2551 * Returns a new allocated string containing the directory, or NULL.
2552 */
2553char *
2554xmlParserGetDirectory(const char *filename) {
2555 char *ret = NULL;
2556 char dir[1024];
2557 char *cur;
2558 char sep = '/';
2559
Igor Zlatkovic9181cc02002-09-29 17:51:06 +00002560#ifdef _WIN32_WCE /* easy way by now ... wince does not have dirs! */
2561 return NULL;
2562#endif
2563
Owen Taylor3473f882001-02-23 17:55:21 +00002564 if (xmlInputCallbackInitialized == 0)
2565 xmlRegisterDefaultInputCallbacks();
2566
2567 if (filename == NULL) return(NULL);
Daniel Veillard3c5ed912002-01-08 10:36:16 +00002568#if defined(WIN32) && !defined(__CYGWIN__)
Owen Taylor3473f882001-02-23 17:55:21 +00002569 sep = '\\';
2570#endif
2571
2572 strncpy(dir, filename, 1023);
2573 dir[1023] = 0;
2574 cur = &dir[strlen(dir)];
2575 while (cur > dir) {
2576 if (*cur == sep) break;
2577 cur --;
2578 }
2579 if (*cur == sep) {
2580 if (cur == dir) dir[1] = 0;
2581 else *cur = 0;
2582 ret = xmlMemStrdup(dir);
2583 } else {
2584 if (getcwd(dir, 1024) != NULL) {
2585 dir[1023] = 0;
2586 ret = xmlMemStrdup(dir);
2587 }
2588 }
2589 return(ret);
2590}
2591
2592/****************************************************************
2593 * *
2594 * External entities loading *
2595 * *
2596 ****************************************************************/
2597
Daniel Veillard561b7f82002-03-20 21:55:57 +00002598static int xmlSysIDExists(const char *URL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00002599#ifdef HAVE_STAT
2600 int ret;
2601 struct stat info;
2602 const char *path;
2603
2604 if (URL == NULL)
2605 return(0);
2606
Daniel Veillardf4862f02002-09-10 11:13:43 +00002607 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00002608#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00002609 path = &URL[17];
2610#else
Daniel Veillard6990bf32001-08-23 21:17:48 +00002611 path = &URL[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00002612#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002613 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00002614#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard6990bf32001-08-23 21:17:48 +00002615 path = &URL[8];
2616#else
2617 path = &URL[7];
2618#endif
2619 } else
2620 path = URL;
2621 ret = stat(path, &info);
Daniel Veillard561b7f82002-03-20 21:55:57 +00002622 if (ret == 0)
2623 return(1);
Daniel Veillard6990bf32001-08-23 21:17:48 +00002624#endif
Daniel Veillard561b7f82002-03-20 21:55:57 +00002625 return(0);
Daniel Veillard6990bf32001-08-23 21:17:48 +00002626}
Daniel Veillard6990bf32001-08-23 21:17:48 +00002627
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002628/**
Owen Taylor3473f882001-02-23 17:55:21 +00002629 * xmlDefaultExternalEntityLoader:
2630 * @URL: the URL for the entity to load
2631 * @ID: the System ID for the entity to load
2632 * @ctxt: the context in which the entity is called or NULL
2633 *
2634 * By default we don't load external entitites, yet.
2635 *
2636 * Returns a new allocated xmlParserInputPtr, or NULL.
2637 */
2638static
2639xmlParserInputPtr
2640xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
2641 xmlParserCtxtPtr ctxt) {
2642 xmlParserInputPtr ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002643 xmlChar *resource = NULL;
2644#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002645 xmlCatalogAllow pref;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002646#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002647
2648#ifdef DEBUG_EXTERNAL_ENTITIES
2649 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf012a642001-07-23 19:10:52 +00002650 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00002651#endif
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002652#ifdef LIBXML_CATALOG_ENABLED
2653 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002654 * If the resource doesn't exists as a file,
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002655 * try to load it from the resource pointed in the catalogs
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002656 */
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002657 pref = xmlCatalogGetDefaults();
2658
Daniel Veillard561b7f82002-03-20 21:55:57 +00002659 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlSysIDExists(URL))) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002660 /*
2661 * Do a local lookup
2662 */
2663 if ((ctxt->catalogs != NULL) &&
2664 ((pref == XML_CATA_ALLOW_ALL) ||
2665 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2666 resource = xmlCatalogLocalResolve(ctxt->catalogs,
2667 (const xmlChar *)ID,
2668 (const xmlChar *)URL);
2669 }
2670 /*
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002671 * Try a global lookup
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002672 */
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002673 if ((resource == NULL) &&
2674 ((pref == XML_CATA_ALLOW_ALL) ||
2675 (pref == XML_CATA_ALLOW_GLOBAL))) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002676 resource = xmlCatalogResolve((const xmlChar *)ID,
2677 (const xmlChar *)URL);
2678 }
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002679 if ((resource == NULL) && (URL != NULL))
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00002680 resource = xmlStrdup((const xmlChar *) URL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002681
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002682 /*
2683 * TODO: do an URI lookup on the reference
2684 */
Daniel Veillard561b7f82002-03-20 21:55:57 +00002685 if ((resource != NULL) && (!xmlSysIDExists((const char *)resource))) {
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002686 xmlChar *tmp = NULL;
2687
2688 if ((ctxt->catalogs != NULL) &&
2689 ((pref == XML_CATA_ALLOW_ALL) ||
2690 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2691 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
2692 }
2693 if ((tmp == NULL) &&
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00002694 ((pref == XML_CATA_ALLOW_ALL) ||
2695 (pref == XML_CATA_ALLOW_GLOBAL))) {
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002696 tmp = xmlCatalogResolveURI(resource);
2697 }
2698
2699 if (tmp != NULL) {
2700 xmlFree(resource);
2701 resource = tmp;
2702 }
2703 }
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002704 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002705#endif
2706
2707 if (resource == NULL)
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002708 resource = (xmlChar *) URL;
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002709
2710 if (resource == NULL) {
Daniel Veillardc6613042002-03-02 09:34:02 +00002711 if (ID == NULL)
2712 ID = "NULL";
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002713 if ((ctxt->validate) && (ctxt->sax != NULL) &&
2714 (ctxt->sax->error != NULL))
William M. Brack4811ba32003-09-06 18:02:53 +00002715 ctxt->sax->error(ctxt->userData,
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002716 "failed to load external entity \"%s\"\n", ID);
2717 else if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
William M. Brack4811ba32003-09-06 18:02:53 +00002718 ctxt->sax->warning(ctxt->userData,
Owen Taylor3473f882001-02-23 17:55:21 +00002719 "failed to load external entity \"%s\"\n", ID);
2720 return(NULL);
2721 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002722 ret = xmlNewInputFromFile(ctxt, (const char *)resource);
Owen Taylor3473f882001-02-23 17:55:21 +00002723 if (ret == NULL) {
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002724 if ((ctxt->validate) && (ctxt->sax != NULL) &&
2725 (ctxt->sax->error != NULL))
William M. Brack4811ba32003-09-06 18:02:53 +00002726 ctxt->sax->error(ctxt->userData,
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002727 "failed to load external entity \"%s\"\n", resource);
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002728 else if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
William M. Brack4811ba32003-09-06 18:02:53 +00002729 ctxt->sax->warning(ctxt->userData,
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002730 "failed to load external entity \"%s\"\n", resource);
Owen Taylor3473f882001-02-23 17:55:21 +00002731 }
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002732 if ((resource != NULL) && (resource != (xmlChar *) URL))
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002733 xmlFree(resource);
Owen Taylor3473f882001-02-23 17:55:21 +00002734 return(ret);
2735}
2736
2737static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
2738 xmlDefaultExternalEntityLoader;
2739
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002740/**
Owen Taylor3473f882001-02-23 17:55:21 +00002741 * xmlSetExternalEntityLoader:
2742 * @f: the new entity resolver function
2743 *
2744 * Changes the defaultexternal entity resolver function for the application
2745 */
2746void
2747xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
2748 xmlCurrentExternalEntityLoader = f;
2749}
2750
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002751/**
Owen Taylor3473f882001-02-23 17:55:21 +00002752 * xmlGetExternalEntityLoader:
2753 *
2754 * Get the default external entity resolver function for the application
2755 *
2756 * Returns the xmlExternalEntityLoader function pointer
2757 */
2758xmlExternalEntityLoader
2759xmlGetExternalEntityLoader(void) {
2760 return(xmlCurrentExternalEntityLoader);
2761}
2762
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002763/**
Owen Taylor3473f882001-02-23 17:55:21 +00002764 * xmlLoadExternalEntity:
2765 * @URL: the URL for the entity to load
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00002766 * @ID: the Public ID for the entity to load
Owen Taylor3473f882001-02-23 17:55:21 +00002767 * @ctxt: the context in which the entity is called or NULL
2768 *
2769 * Load an external entity, note that the use of this function for
2770 * unparsed entities may generate problems
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002771 * TODO: a more generic External entity API must be designed
Owen Taylor3473f882001-02-23 17:55:21 +00002772 *
2773 * Returns the xmlParserInputPtr or NULL
2774 */
2775xmlParserInputPtr
2776xmlLoadExternalEntity(const char *URL, const char *ID,
2777 xmlParserCtxtPtr ctxt) {
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00002778 if ((URL != NULL) && (xmlSysIDExists(URL) == 0)) {
2779 char *canonicFilename;
2780 xmlParserInputPtr ret;
2781
2782 canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL);
2783 if (canonicFilename == NULL) {
2784 if (xmlDefaultSAXHandler.error != NULL) {
2785 xmlDefaultSAXHandler.error(NULL, "out of memory\n");
2786 }
2787 return(NULL);
2788 }
2789
2790 ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt);
2791 xmlFree(canonicFilename);
2792 return(ret);
2793 }
Owen Taylor3473f882001-02-23 17:55:21 +00002794 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
2795}
2796
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00002797/************************************************************************
2798 * *
2799 * Disabling Network access *
2800 * *
2801 ************************************************************************/
2802
2803#ifdef LIBXML_CATALOG_ENABLED
2804static int
2805xmlNoNetExists(const char *URL)
2806{
2807#ifdef HAVE_STAT
2808 int ret;
2809 struct stat info;
2810 const char *path;
2811
2812 if (URL == NULL)
2813 return (0);
2814
Daniel Veillardf4862f02002-09-10 11:13:43 +00002815 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00002816#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00002817 path = &URL[17];
2818#else
2819 path = &URL[16];
2820#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002821 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00002822#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00002823 path = &URL[8];
2824#else
2825 path = &URL[7];
2826#endif
2827 } else
2828 path = URL;
2829 ret = stat(path, &info);
2830 if (ret == 0)
2831 return (1);
2832#endif
2833 return (0);
2834}
2835#endif
2836
2837/**
2838 * xmlNoNetExternalEntityLoader:
2839 * @URL: the URL for the entity to load
2840 * @ID: the System ID for the entity to load
2841 * @ctxt: the context in which the entity is called or NULL
2842 *
2843 * A specific entity loader disabling network accesses, though still
2844 * allowing local catalog accesses for resolution.
2845 *
2846 * Returns a new allocated xmlParserInputPtr, or NULL.
2847 */
2848xmlParserInputPtr
2849xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
2850 xmlParserCtxtPtr ctxt) {
2851 xmlParserInputPtr input = NULL;
2852 xmlChar *resource = NULL;
2853
2854#ifdef LIBXML_CATALOG_ENABLED
2855 xmlCatalogAllow pref;
2856
2857 /*
2858 * If the resource doesn't exists as a file,
2859 * try to load it from the resource pointed in the catalogs
2860 */
2861 pref = xmlCatalogGetDefaults();
2862
2863 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
2864 /*
2865 * Do a local lookup
2866 */
2867 if ((ctxt->catalogs != NULL) &&
2868 ((pref == XML_CATA_ALLOW_ALL) ||
2869 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2870 resource = xmlCatalogLocalResolve(ctxt->catalogs,
2871 (const xmlChar *)ID,
2872 (const xmlChar *)URL);
2873 }
2874 /*
2875 * Try a global lookup
2876 */
2877 if ((resource == NULL) &&
2878 ((pref == XML_CATA_ALLOW_ALL) ||
2879 (pref == XML_CATA_ALLOW_GLOBAL))) {
2880 resource = xmlCatalogResolve((const xmlChar *)ID,
2881 (const xmlChar *)URL);
2882 }
2883 if ((resource == NULL) && (URL != NULL))
2884 resource = xmlStrdup((const xmlChar *) URL);
2885
2886 /*
2887 * TODO: do an URI lookup on the reference
2888 */
2889 if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
2890 xmlChar *tmp = NULL;
2891
2892 if ((ctxt->catalogs != NULL) &&
2893 ((pref == XML_CATA_ALLOW_ALL) ||
2894 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2895 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
2896 }
2897 if ((tmp == NULL) &&
2898 ((pref == XML_CATA_ALLOW_ALL) ||
2899 (pref == XML_CATA_ALLOW_GLOBAL))) {
2900 tmp = xmlCatalogResolveURI(resource);
2901 }
2902
2903 if (tmp != NULL) {
2904 xmlFree(resource);
2905 resource = tmp;
2906 }
2907 }
2908 }
2909#endif
2910 if (resource == NULL)
2911 resource = (xmlChar *) URL;
2912
2913 if (resource != NULL) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002914 if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
2915 (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00002916 xmlGenericError(xmlGenericErrorContext,
2917 "Attempt to load network entity %s \n", resource);
2918
2919 if (resource != (xmlChar *) URL)
2920 xmlFree(resource);
2921 return(NULL);
2922 }
2923 }
2924 input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
2925 if (resource != (xmlChar *) URL)
2926 xmlFree(resource);
2927 return(input);
2928}
2929