blob: ce5d4667fa3347fd6834907f033ebc6ce0446a25 [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
108/*
109 * Output I/O callback sets
110 */
111typedef struct _xmlOutputCallback {
112 xmlOutputMatchCallback matchcallback;
113 xmlOutputOpenCallback opencallback;
114 xmlOutputWriteCallback writecallback;
115 xmlOutputCloseCallback closecallback;
116} xmlOutputCallback;
117
118#define MAX_OUTPUT_CALLBACK 15
119
Daniel Veillard22090732001-07-16 00:06:07 +0000120static xmlOutputCallback xmlOutputCallbackTable[MAX_OUTPUT_CALLBACK];
121static int xmlOutputCallbackNr = 0;
122static int xmlOutputCallbackInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000123
Daniel Veillardf4862f02002-09-10 11:13:43 +0000124
125/**
Daniel Veillard01c13b52002-12-10 15:19:08 +0000126 * xmlNormalizeWindowsPath:
Daniel Veillard33300b42003-04-17 09:09:19 +0000127 * @path: the input file path
Daniel Veillardf4862f02002-09-10 11:13:43 +0000128 *
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +0000129 * This function is obsolete. Please see xmlURIFromPath in uri.c for
130 * a better solution.
Daniel Veillard33300b42003-04-17 09:09:19 +0000131 *
132 * Returns a canonicalized version of the path
Daniel Veillardf4862f02002-09-10 11:13:43 +0000133 */
134xmlChar *
135xmlNormalizeWindowsPath(const xmlChar *path)
136{
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +0000137 return xmlCanonicPath(path);
Daniel Veillardf4862f02002-09-10 11:13:43 +0000138}
139
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000140/**
141 * xmlCleanupInputCallbacks:
142 *
143 * clears the entire input callback table. this includes the
144 * compiled-in I/O.
145 */
146void
147xmlCleanupInputCallbacks(void)
148{
149 int i;
150
151 if (!xmlInputCallbackInitialized)
152 return;
153
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000154 for (i = xmlInputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000155 xmlInputCallbackTable[i].matchcallback = NULL;
156 xmlInputCallbackTable[i].opencallback = NULL;
157 xmlInputCallbackTable[i].readcallback = NULL;
158 xmlInputCallbackTable[i].closecallback = NULL;
159 }
Daniel Veillard9e412302002-06-10 15:59:44 +0000160 xmlInputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000161
162 xmlInputCallbackNr = 0;
Aleksey Sanin9c45ba82002-06-06 21:46:13 +0000163 xmlInputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000164}
165
166/**
167 * xmlCleanupOutputCallbacks:
168 *
169 * clears the entire output callback table. this includes the
170 * compiled-in I/O callbacks.
171 */
172void
173xmlCleanupOutputCallbacks(void)
174{
175 int i;
176
177 if (!xmlOutputCallbackInitialized)
178 return;
179
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000180 for (i = xmlOutputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000181 xmlOutputCallbackTable[i].matchcallback = NULL;
182 xmlOutputCallbackTable[i].opencallback = NULL;
183 xmlOutputCallbackTable[i].writecallback = NULL;
184 xmlOutputCallbackTable[i].closecallback = NULL;
185 }
Daniel Veillard9e412302002-06-10 15:59:44 +0000186 xmlOutputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000187
188 xmlOutputCallbackNr = 0;
Aleksey Sanin9c45ba82002-06-06 21:46:13 +0000189 xmlOutputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000190}
191
Owen Taylor3473f882001-02-23 17:55:21 +0000192/************************************************************************
193 * *
194 * Standard I/O for file accesses *
195 * *
196 ************************************************************************/
197
198/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000199 * xmlCheckFilename:
Owen Taylor3473f882001-02-23 17:55:21 +0000200 * @path: the path to check
201 *
202 * function checks to see if @path is a valid source
203 * (file, socket...) for XML.
204 *
205 * if stat is not available on the target machine,
206 * returns 1. if stat fails, returns 0 (if calling
207 * stat on the filename fails, it can't be right).
208 * if stat succeeds and the file is a directory,
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000209 * returns 2. otherwise returns 1.
Owen Taylor3473f882001-02-23 17:55:21 +0000210 */
211
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000212int
Owen Taylor3473f882001-02-23 17:55:21 +0000213xmlCheckFilename (const char *path)
214{
215#ifdef HAVE_STAT
Owen Taylor3473f882001-02-23 17:55:21 +0000216 struct stat stat_buffer;
217
218 if (stat(path, &stat_buffer) == -1)
219 return 0;
220
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000221#ifdef S_ISDIR
Owen Taylor3473f882001-02-23 17:55:21 +0000222 if (S_ISDIR(stat_buffer.st_mode)) {
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000223 return 2;
Owen Taylor3473f882001-02-23 17:55:21 +0000224 }
Owen Taylor3473f882001-02-23 17:55:21 +0000225#endif
226#endif
227 return 1;
228}
229
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000230static int
Owen Taylor3473f882001-02-23 17:55:21 +0000231xmlNop(void) {
232 return(0);
233}
234
235/**
Owen Taylor3473f882001-02-23 17:55:21 +0000236 * xmlFdRead:
237 * @context: the I/O context
238 * @buffer: where to drop data
239 * @len: number of bytes to read
240 *
241 * Read @len bytes to @buffer from the I/O channel.
242 *
243 * Returns the number of bytes written
244 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000245static int
Owen Taylor3473f882001-02-23 17:55:21 +0000246xmlFdRead (void * context, char * buffer, int len) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +0000247 return(read((int) (long) context, &buffer[0], len));
Owen Taylor3473f882001-02-23 17:55:21 +0000248}
249
250/**
251 * xmlFdWrite:
252 * @context: the I/O context
253 * @buffer: where to get data
254 * @len: number of bytes to write
255 *
256 * Write @len bytes from @buffer to the I/O channel.
257 *
258 * Returns the number of bytes written
259 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000260static int
Owen Taylor3473f882001-02-23 17:55:21 +0000261xmlFdWrite (void * context, const char * buffer, int len) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +0000262 return(write((int) (long) context, &buffer[0], len));
Owen Taylor3473f882001-02-23 17:55:21 +0000263}
264
265/**
266 * xmlFdClose:
267 * @context: the I/O context
268 *
269 * Close an I/O channel
Daniel Veillardf012a642001-07-23 19:10:52 +0000270 *
271 * Returns 0 in case of success and error code otherwise
Owen Taylor3473f882001-02-23 17:55:21 +0000272 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000273static int
Owen Taylor3473f882001-02-23 17:55:21 +0000274xmlFdClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +0000275 return ( close((int) (long) context) );
Owen Taylor3473f882001-02-23 17:55:21 +0000276}
277
278/**
279 * xmlFileMatch:
280 * @filename: the URI for matching
281 *
282 * input from FILE *
283 *
284 * Returns 1 if matches, 0 otherwise
285 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000286int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000287xmlFileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000288 return(1);
289}
290
291/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000292 * xmlFileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +0000293 * @filename: the URI for matching
294 *
295 * input from FILE *, supports compressed input
296 * if @filename is " " then the standard input is used
297 *
298 * Returns an I/O context or NULL in case of error
299 */
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000300static void *
301xmlFileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +0000302 const char *path = NULL;
303 FILE *fd;
304
305 if (!strcmp(filename, "-")) {
306 fd = stdin;
307 return((void *) fd);
308 }
309
Daniel Veillardf4862f02002-09-10 11:13:43 +0000310 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000311#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000312 path = &filename[17];
313#else
Owen Taylor3473f882001-02-23 17:55:21 +0000314 path = &filename[16];
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000315#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000316 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000317#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000318 path = &filename[8];
319#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000320 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000321#endif
322 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000323 path = filename;
324
325 if (path == NULL)
326 return(NULL);
327 if (!xmlCheckFilename(path))
328 return(NULL);
329
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000330#if defined(WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
Owen Taylor3473f882001-02-23 17:55:21 +0000331 fd = fopen(path, "rb");
332#else
333 fd = fopen(path, "r");
334#endif /* WIN32 */
335 return((void *) fd);
336}
337
338/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000339 * xmlFileOpen:
340 * @filename: the URI for matching
341 *
342 * Wrapper around xmlFileOpen_real that try it with an unescaped
343 * version of @filename, if this fails fallback to @filename
Daniel Veillard71531f32003-02-05 13:19:53 +0000344 *
345 * Returns a handler or NULL in case or failure
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000346 */
347void *
348xmlFileOpen (const char *filename) {
349 char *unescaped;
350 void *retval;
351 unescaped = xmlURIUnescapeString(filename, 0, NULL);
352 if (unescaped != NULL) {
353 retval = xmlFileOpen_real(unescaped);
354 } else {
355 retval = xmlFileOpen_real(filename);
356 }
357 xmlFree(unescaped);
358 return retval;
359}
360
361/**
Owen Taylor3473f882001-02-23 17:55:21 +0000362 * xmlFileOpenW:
363 * @filename: the URI for matching
364 *
365 * output to from FILE *,
366 * if @filename is "-" then the standard output is used
367 *
368 * Returns an I/O context or NULL in case of error
369 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000370static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000371xmlFileOpenW (const char *filename) {
372 const char *path = NULL;
373 FILE *fd;
374
375 if (!strcmp(filename, "-")) {
376 fd = stdout;
377 return((void *) fd);
378 }
379
Daniel Veillardf4862f02002-09-10 11:13:43 +0000380 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000381#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000382 path = &filename[17];
383#else
Owen Taylor3473f882001-02-23 17:55:21 +0000384 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000385#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000386 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000387#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000388 path = &filename[8];
389#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000390 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000391#endif
392 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000393 path = filename;
394
395 if (path == NULL)
396 return(NULL);
397
Daniel Veillardcbbd78d2003-07-20 15:21:30 +0000398 fd = fopen(path, "wb");
Owen Taylor3473f882001-02-23 17:55:21 +0000399 return((void *) fd);
400}
401
402/**
403 * xmlFileRead:
404 * @context: the I/O context
405 * @buffer: where to drop data
406 * @len: number of bytes to write
407 *
408 * Read @len bytes to @buffer from the I/O channel.
409 *
410 * Returns the number of bytes written
411 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000412int
Owen Taylor3473f882001-02-23 17:55:21 +0000413xmlFileRead (void * context, char * buffer, int len) {
414 return(fread(&buffer[0], 1, len, (FILE *) context));
415}
416
417/**
418 * xmlFileWrite:
419 * @context: the I/O context
420 * @buffer: where to drop data
421 * @len: number of bytes to write
422 *
423 * Write @len bytes from @buffer to the I/O channel.
424 *
425 * Returns the number of bytes written
426 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000427static int
Owen Taylor3473f882001-02-23 17:55:21 +0000428xmlFileWrite (void * context, const char * buffer, int len) {
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000429 int items;
430
431 items = fwrite(&buffer[0], len, 1, (FILE *) context);
432
433 return(items * len);
Owen Taylor3473f882001-02-23 17:55:21 +0000434}
435
436/**
437 * xmlFileClose:
438 * @context: the I/O context
439 *
440 * Close an I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000441 *
442 * Returns 0 or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +0000443 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000444int
Owen Taylor3473f882001-02-23 17:55:21 +0000445xmlFileClose (void * context) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000446 FILE *fil;
447
448 fil = (FILE *) context;
449 if (fil == stdin)
450 return(0);
451 if (fil == stdout)
452 return(0);
Daniel Veillardcd337f02001-11-22 18:20:37 +0000453 if (fil == stderr)
454 return(0);
Daniel Veillardf012a642001-07-23 19:10:52 +0000455 return ( ( fclose((FILE *) context) == EOF ) ? -1 : 0 );
Owen Taylor3473f882001-02-23 17:55:21 +0000456}
457
458/**
459 * xmlFileFlush:
460 * @context: the I/O context
461 *
462 * Flush an I/O channel
463 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000464static int
Owen Taylor3473f882001-02-23 17:55:21 +0000465xmlFileFlush (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +0000466 return ( ( fflush((FILE *) context) == EOF ) ? -1 : 0 );
Owen Taylor3473f882001-02-23 17:55:21 +0000467}
468
469#ifdef HAVE_ZLIB_H
470/************************************************************************
471 * *
472 * I/O for compressed file accesses *
473 * *
474 ************************************************************************/
475/**
476 * xmlGzfileMatch:
477 * @filename: the URI for matching
478 *
479 * input from compressed file test
480 *
481 * Returns 1 if matches, 0 otherwise
482 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000483static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000484xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000485 return(1);
486}
487
488/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000489 * xmlGzfileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +0000490 * @filename: the URI for matching
491 *
492 * input from compressed file open
493 * if @filename is " " then the standard input is used
494 *
495 * Returns an I/O context or NULL in case of error
496 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000497static void *
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000498xmlGzfileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +0000499 const char *path = NULL;
500 gzFile fd;
501
502 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000503 fd = gzdopen(dup(0), "rb");
Owen Taylor3473f882001-02-23 17:55:21 +0000504 return((void *) fd);
505 }
506
Daniel Veillardf4862f02002-09-10 11:13:43 +0000507 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000508#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000509 path = &filename[17];
510#else
Owen Taylor3473f882001-02-23 17:55:21 +0000511 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000512#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000513 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000514#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000515 path = &filename[8];
516#else
Owen Taylor3473f882001-02-23 17:55:21 +0000517 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000518#endif
519 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000520 path = filename;
521
522 if (path == NULL)
523 return(NULL);
524 if (!xmlCheckFilename(path))
525 return(NULL);
526
527 fd = gzopen(path, "rb");
528 return((void *) fd);
529}
530
531/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000532 * xmlGzfileOpen:
533 * @filename: the URI for matching
534 *
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +0000535 * Wrapper around xmlGzfileOpen if the open fais, it will
536 * try to unescape @filename
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000537 */
538static void *
539xmlGzfileOpen (const char *filename) {
540 char *unescaped;
541 void *retval;
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +0000542
543 retval = xmlGzfileOpen_real(filename);
544 if (retval == NULL) {
545 unescaped = xmlURIUnescapeString(filename, 0, NULL);
546 if (unescaped != NULL) {
547 retval = xmlGzfileOpen_real(unescaped);
548 }
549 xmlFree(unescaped);
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000550 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000551 return retval;
552}
553
554/**
Owen Taylor3473f882001-02-23 17:55:21 +0000555 * xmlGzfileOpenW:
556 * @filename: the URI for matching
557 * @compression: the compression factor (0 - 9 included)
558 *
559 * input from compressed file open
560 * if @filename is " " then the standard input is used
561 *
562 * Returns an I/O context or NULL in case of error
563 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000564static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000565xmlGzfileOpenW (const char *filename, int compression) {
566 const char *path = NULL;
567 char mode[15];
568 gzFile fd;
569
Aleksey Sanin49cc9752002-06-14 17:07:10 +0000570 snprintf(mode, sizeof(mode), "wb%d", compression);
Owen Taylor3473f882001-02-23 17:55:21 +0000571 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000572 fd = gzdopen(dup(1), mode);
Owen Taylor3473f882001-02-23 17:55:21 +0000573 return((void *) fd);
574 }
575
Daniel Veillardf4862f02002-09-10 11:13:43 +0000576 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000577#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000578 path = &filename[17];
579#else
Owen Taylor3473f882001-02-23 17:55:21 +0000580 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000581#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000582 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000583#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000584 path = &filename[8];
585#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000586 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000587#endif
588 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000589 path = filename;
590
591 if (path == NULL)
592 return(NULL);
593
594 fd = gzopen(path, mode);
595 return((void *) fd);
596}
597
598/**
599 * xmlGzfileRead:
600 * @context: the I/O context
601 * @buffer: where to drop data
602 * @len: number of bytes to write
603 *
604 * Read @len bytes to @buffer from the compressed I/O channel.
605 *
606 * Returns the number of bytes written
607 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000608static int
Owen Taylor3473f882001-02-23 17:55:21 +0000609xmlGzfileRead (void * context, char * buffer, int len) {
610 return(gzread((gzFile) context, &buffer[0], len));
611}
612
613/**
614 * xmlGzfileWrite:
615 * @context: the I/O context
616 * @buffer: where to drop data
617 * @len: number of bytes to write
618 *
619 * Write @len bytes from @buffer to the compressed I/O channel.
620 *
621 * Returns the number of bytes written
622 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000623static int
Owen Taylor3473f882001-02-23 17:55:21 +0000624xmlGzfileWrite (void * context, const char * buffer, int len) {
625 return(gzwrite((gzFile) context, (char *) &buffer[0], len));
626}
627
628/**
629 * xmlGzfileClose:
630 * @context: the I/O context
631 *
632 * Close a compressed I/O channel
633 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000634static int
Owen Taylor3473f882001-02-23 17:55:21 +0000635xmlGzfileClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +0000636 return ( ( gzclose((gzFile) context) == Z_OK ) ? 0 : -1 );
Owen Taylor3473f882001-02-23 17:55:21 +0000637}
638#endif /* HAVE_ZLIB_H */
639
640#ifdef LIBXML_HTTP_ENABLED
641/************************************************************************
642 * *
643 * I/O for HTTP file accesses *
644 * *
645 ************************************************************************/
Daniel Veillardf012a642001-07-23 19:10:52 +0000646
647typedef struct xmlIOHTTPWriteCtxt_
648{
649 int compression;
650
651 char * uri;
652
653 void * doc_buff;
654
655} xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr;
656
657#ifdef HAVE_ZLIB_H
658
659#define DFLT_WBITS ( -15 )
660#define DFLT_MEM_LVL ( 8 )
661#define GZ_MAGIC1 ( 0x1f )
662#define GZ_MAGIC2 ( 0x8b )
663#define LXML_ZLIB_OS_CODE ( 0x03 )
664#define INIT_HTTP_BUFF_SIZE ( 32768 )
665#define DFLT_ZLIB_RATIO ( 5 )
666
667/*
668** Data structure and functions to work with sending compressed data
669** via HTTP.
670*/
671
672typedef struct xmlZMemBuff_
673{
674 unsigned long size;
675 unsigned long crc;
676
677 unsigned char * zbuff;
678 z_stream zctrl;
679
680} xmlZMemBuff, *xmlZMemBuffPtr;
681
682/**
683 * append_reverse_ulong
684 * @buff: Compressed memory buffer
685 * @data: Unsigned long to append
686 *
687 * Append a unsigned long in reverse byte order to the end of the
688 * memory buffer.
689 */
690static void
691append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) {
692
693 int idx;
694
695 if ( buff == NULL )
696 return;
697
698 /*
699 ** This is plagiarized from putLong in gzio.c (zlib source) where
700 ** the number "4" is hardcoded. If zlib is ever patched to
701 ** support 64 bit file sizes, this code would need to be patched
702 ** as well.
703 */
704
705 for ( idx = 0; idx < 4; idx++ ) {
706 *buff->zctrl.next_out = ( data & 0xff );
707 data >>= 8;
708 buff->zctrl.next_out++;
709 }
710
711 return;
712}
713
714/**
715 *
716 * xmlFreeZMemBuff
717 * @buff: The memory buffer context to clear
718 *
719 * Release all the resources associated with the compressed memory buffer.
720 */
721static void
722xmlFreeZMemBuff( xmlZMemBuffPtr buff ) {
723
724 int z_err;
725
726 if ( buff == NULL )
727 return;
728
729 xmlFree( buff->zbuff );
730 z_err = deflateEnd( &buff->zctrl );
731#ifdef DEBUG_HTTP
732 if ( z_err != Z_OK )
733 xmlGenericError( xmlGenericErrorContext,
734 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
735 z_err );
736#endif
737
738 xmlFree( buff );
739 return;
740}
741
742/**
743 * xmlCreateZMemBuff
744 *@compression: Compression value to use
745 *
746 * Create a memory buffer to hold the compressed XML document. The
747 * compressed document in memory will end up being identical to what
748 * would be created if gzopen/gzwrite/gzclose were being used to
749 * write the document to disk. The code for the header/trailer data to
750 * the compression is plagiarized from the zlib source files.
751 */
752static void *
753xmlCreateZMemBuff( int compression ) {
754
755 int z_err;
756 int hdr_lgth;
757 xmlZMemBuffPtr buff = NULL;
758
759 if ( ( compression < 1 ) || ( compression > 9 ) )
760 return ( NULL );
761
762 /* Create the control and data areas */
763
764 buff = xmlMalloc( sizeof( xmlZMemBuff ) );
765 if ( buff == NULL ) {
766 xmlGenericError( xmlGenericErrorContext,
767 "xmlCreateZMemBuff: %s\n",
768 "Failure allocating buffer context." );
769 return ( NULL );
770 }
771
772 (void)memset( buff, 0, sizeof( xmlZMemBuff ) );
773 buff->size = INIT_HTTP_BUFF_SIZE;
774 buff->zbuff = xmlMalloc( buff->size );
775 if ( buff->zbuff == NULL ) {
776 xmlFreeZMemBuff( buff );
777 xmlGenericError( xmlGenericErrorContext,
778 "xmlCreateZMemBuff: %s\n",
779 "Failure allocating data buffer." );
780 return ( NULL );
781 }
782
783 z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
784 DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
785 if ( z_err != Z_OK ) {
786 xmlFreeZMemBuff( buff );
787 buff = NULL;
788 xmlGenericError( xmlGenericErrorContext,
789 "xmlCreateZMemBuff: %s %d\n",
790 "Error initializing compression context. ZLIB error:",
791 z_err );
792 return ( NULL );
793 }
794
795 /* Set the header data. The CRC will be needed for the trailer */
Daniel Veillardf012a642001-07-23 19:10:52 +0000796 buff->crc = crc32( 0L, Z_NULL, 0 );
Aleksey Sanin49cc9752002-06-14 17:07:10 +0000797 hdr_lgth = snprintf( (char *)buff->zbuff, buff->size,
798 "%c%c%c%c%c%c%c%c%c%c",
Daniel Veillardf012a642001-07-23 19:10:52 +0000799 GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED,
800 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE );
801 buff->zctrl.next_out = buff->zbuff + hdr_lgth;
802 buff->zctrl.avail_out = buff->size - hdr_lgth;
803
804 return ( buff );
805}
806
807/**
808 * xmlZMemBuffExtend
809 * @buff: Buffer used to compress and consolidate data.
810 * @ext_amt: Number of bytes to extend the buffer.
811 *
812 * Extend the internal buffer used to store the compressed data by the
813 * specified amount.
814 *
815 * Returns 0 on success or -1 on failure to extend the buffer. On failure
816 * the original buffer still exists at the original size.
817 */
818static int
819xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) {
820
821 int rc = -1;
822 size_t new_size;
823 size_t cur_used;
824
825 unsigned char * tmp_ptr = NULL;
826
827 if ( buff == NULL )
828 return ( -1 );
829
830 else if ( ext_amt == 0 )
831 return ( 0 );
832
833 cur_used = buff->zctrl.next_out - buff->zbuff;
834 new_size = buff->size + ext_amt;
835
836#ifdef DEBUG_HTTP
837 if ( cur_used > new_size )
838 xmlGenericError( xmlGenericErrorContext,
839 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
840 "Buffer overwrite detected during compressed memory",
841 "buffer extension. Overflowed by",
842 (cur_used - new_size ) );
843#endif
844
845 tmp_ptr = xmlRealloc( buff->zbuff, new_size );
846 if ( tmp_ptr != NULL ) {
847 rc = 0;
848 buff->size = new_size;
849 buff->zbuff = tmp_ptr;
850 buff->zctrl.next_out = tmp_ptr + cur_used;
851 buff->zctrl.avail_out = new_size - cur_used;
852 }
853 else {
854 xmlGenericError( xmlGenericErrorContext,
855 "xmlZMemBuffExtend: %s %lu bytes.\n",
856 "Allocation failure extending output buffer to",
857 new_size );
858 }
859
860 return ( rc );
861}
862
863/**
864 * xmlZMemBuffAppend
865 * @buff: Buffer used to compress and consolidate data
866 * @src: Uncompressed source content to append to buffer
867 * @len: Length of source data to append to buffer
868 *
869 * Compress and append data to the internal buffer. The data buffer
870 * will be expanded if needed to store the additional data.
871 *
872 * Returns the number of bytes appended to the buffer or -1 on error.
873 */
874static int
875xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) {
876
877 int z_err;
878 size_t min_accept;
879
880 if ( ( buff == NULL ) || ( src == NULL ) )
881 return ( -1 );
882
883 buff->zctrl.avail_in = len;
884 buff->zctrl.next_in = (unsigned char *)src;
885 while ( buff->zctrl.avail_in > 0 ) {
886 /*
887 ** Extend the buffer prior to deflate call if a reasonable amount
888 ** of output buffer space is not available.
889 */
890 min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO;
891 if ( buff->zctrl.avail_out <= min_accept ) {
892 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
893 return ( -1 );
894 }
895
896 z_err = deflate( &buff->zctrl, Z_NO_FLUSH );
897 if ( z_err != Z_OK ) {
898 xmlGenericError( xmlGenericErrorContext,
899 "xmlZMemBuffAppend: %s %d %s - %d",
900 "Compression error while appending",
901 len, "bytes to buffer. ZLIB error", z_err );
902 return ( -1 );
903 }
904 }
905
906 buff->crc = crc32( buff->crc, (unsigned char *)src, len );
907
908 return ( len );
909}
910
911/**
912 * xmlZMemBuffGetContent
913 * @buff: Compressed memory content buffer
914 * @data_ref: Pointer reference to point to compressed content
915 *
916 * Flushes the compression buffers, appends gzip file trailers and
917 * returns the compressed content and length of the compressed data.
918 * NOTE: The gzip trailer code here is plagiarized from zlib source.
919 *
920 * Returns the length of the compressed data or -1 on error.
921 */
922static int
923xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) {
924
925 int zlgth = -1;
926 int z_err;
927
928 if ( ( buff == NULL ) || ( data_ref == NULL ) )
929 return ( -1 );
930
931 /* Need to loop until compression output buffers are flushed */
932
933 do
934 {
935 z_err = deflate( &buff->zctrl, Z_FINISH );
936 if ( z_err == Z_OK ) {
937 /* In this case Z_OK means more buffer space needed */
938
939 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
940 return ( -1 );
941 }
942 }
943 while ( z_err == Z_OK );
944
945 /* If the compression state is not Z_STREAM_END, some error occurred */
946
947 if ( z_err == Z_STREAM_END ) {
948
949 /* Need to append the gzip data trailer */
950
951 if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) {
952 if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 )
953 return ( -1 );
954 }
955
956 /*
957 ** For whatever reason, the CRC and length data are pushed out
958 ** in reverse byte order. So a memcpy can't be used here.
959 */
960
961 append_reverse_ulong( buff, buff->crc );
962 append_reverse_ulong( buff, buff->zctrl.total_in );
963
964 zlgth = buff->zctrl.next_out - buff->zbuff;
965 *data_ref = (char *)buff->zbuff;
966 }
967
968 else
969 xmlGenericError( xmlGenericErrorContext,
970 "xmlZMemBuffGetContent: %s - %d\n",
971 "Error flushing zlib buffers. Error code", z_err );
972
973 return ( zlgth );
974}
975#endif /* HAVE_ZLIB_H */
976
977/**
978 * xmlFreeHTTPWriteCtxt
979 * @ctxt: Context to cleanup
980 *
981 * Free allocated memory and reclaim system resources.
982 *
983 * No return value.
984 */
985static void
986xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt )
987{
988 if ( ctxt->uri != NULL )
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000989 xmlFree( ctxt->uri );
Daniel Veillardf012a642001-07-23 19:10:52 +0000990
991 if ( ctxt->doc_buff != NULL ) {
992
993#ifdef HAVE_ZLIB_H
994 if ( ctxt->compression > 0 ) {
995 xmlFreeZMemBuff( ctxt->doc_buff );
996 }
997 else
998#endif
999 {
1000 xmlOutputBufferClose( ctxt->doc_buff );
1001 }
1002 }
1003
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001004 xmlFree( ctxt );
Daniel Veillardf012a642001-07-23 19:10:52 +00001005 return;
1006}
1007
1008
Owen Taylor3473f882001-02-23 17:55:21 +00001009/**
1010 * xmlIOHTTPMatch:
1011 * @filename: the URI for matching
1012 *
1013 * check if the URI matches an HTTP one
1014 *
1015 * Returns 1 if matches, 0 otherwise
1016 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001017int
Owen Taylor3473f882001-02-23 17:55:21 +00001018xmlIOHTTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001019 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "http://", 7))
Owen Taylor3473f882001-02-23 17:55:21 +00001020 return(1);
1021 return(0);
1022}
1023
1024/**
1025 * xmlIOHTTPOpen:
1026 * @filename: the URI for matching
1027 *
1028 * open an HTTP I/O channel
1029 *
1030 * Returns an I/O context or NULL in case of error
1031 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001032void *
Owen Taylor3473f882001-02-23 17:55:21 +00001033xmlIOHTTPOpen (const char *filename) {
1034 return(xmlNanoHTTPOpen(filename, NULL));
1035}
1036
1037/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001038 * xmlIOHTTPOpenW:
Daniel Veillardf012a642001-07-23 19:10:52 +00001039 * @post_uri: The destination URI for the document
1040 * @compression: The compression desired for the document.
1041 *
1042 * Open a temporary buffer to collect the document for a subsequent HTTP POST
1043 * request. Non-static as is called from the output buffer creation routine.
1044 *
1045 * Returns an I/O context or NULL in case of error.
1046 */
1047
1048void *
Daniel Veillard572577e2002-01-18 16:23:55 +00001049xmlIOHTTPOpenW(const char *post_uri, int compression)
1050{
Daniel Veillardf012a642001-07-23 19:10:52 +00001051
Daniel Veillard572577e2002-01-18 16:23:55 +00001052 xmlIOHTTPWriteCtxtPtr ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001053
Daniel Veillard572577e2002-01-18 16:23:55 +00001054 if (post_uri == NULL)
1055 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001056
Daniel Veillard572577e2002-01-18 16:23:55 +00001057 ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt));
1058 if (ctxt == NULL) {
1059 xmlGenericError(xmlGenericErrorContext,
1060 "xmlIOHTTPOpenW: Failed to create output HTTP context.\n");
1061 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001062 }
1063
Daniel Veillard572577e2002-01-18 16:23:55 +00001064 (void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt));
Daniel Veillardf012a642001-07-23 19:10:52 +00001065
Daniel Veillard572577e2002-01-18 16:23:55 +00001066 ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri);
1067 if (ctxt->uri == NULL) {
1068 xmlGenericError(xmlGenericErrorContext,
1069 "xmlIOHTTPOpenW: Failed to duplicate destination URI.\n");
1070 xmlFreeHTTPWriteCtxt(ctxt);
1071 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001072 }
1073
1074 /*
Daniel Veillard572577e2002-01-18 16:23:55 +00001075 * ** Since the document length is required for an HTTP post,
1076 * ** need to put the document into a buffer. A memory buffer
1077 * ** is being used to avoid pushing the data to disk and back.
1078 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001079
1080#ifdef HAVE_ZLIB_H
Daniel Veillard572577e2002-01-18 16:23:55 +00001081 if ((compression > 0) && (compression <= 9)) {
1082
1083 ctxt->compression = compression;
1084 ctxt->doc_buff = xmlCreateZMemBuff(compression);
1085 } else
Daniel Veillardf012a642001-07-23 19:10:52 +00001086#endif
1087 {
Daniel Veillard572577e2002-01-18 16:23:55 +00001088 /* Any character conversions should have been done before this */
Daniel Veillardf012a642001-07-23 19:10:52 +00001089
Daniel Veillard572577e2002-01-18 16:23:55 +00001090 ctxt->doc_buff = xmlAllocOutputBuffer(NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001091 }
1092
Daniel Veillard572577e2002-01-18 16:23:55 +00001093 if (ctxt->doc_buff == NULL) {
1094 xmlFreeHTTPWriteCtxt(ctxt);
1095 ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001096 }
1097
Daniel Veillard572577e2002-01-18 16:23:55 +00001098 return (ctxt);
Daniel Veillardf012a642001-07-23 19:10:52 +00001099}
1100
1101/**
1102 * xmlIOHTTPDfltOpenW
1103 * @post_uri: The destination URI for this document.
1104 *
1105 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
1106 * HTTP post command. This function should generally not be used as
1107 * the open callback is short circuited in xmlOutputBufferCreateFile.
1108 *
1109 * Returns a pointer to the new IO context.
1110 */
1111static void *
1112xmlIOHTTPDfltOpenW( const char * post_uri ) {
1113 return ( xmlIOHTTPOpenW( post_uri, 0 ) );
1114}
1115
1116/**
Owen Taylor3473f882001-02-23 17:55:21 +00001117 * xmlIOHTTPRead:
1118 * @context: the I/O context
1119 * @buffer: where to drop data
1120 * @len: number of bytes to write
1121 *
1122 * Read @len bytes to @buffer from the I/O channel.
1123 *
1124 * Returns the number of bytes written
1125 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001126int
Owen Taylor3473f882001-02-23 17:55:21 +00001127xmlIOHTTPRead(void * context, char * buffer, int len) {
1128 return(xmlNanoHTTPRead(context, &buffer[0], len));
1129}
1130
1131/**
Daniel Veillardf012a642001-07-23 19:10:52 +00001132 * xmlIOHTTPWrite
1133 * @context: previously opened writing context
1134 * @buffer: data to output to temporary buffer
1135 * @len: bytes to output
1136 *
1137 * Collect data from memory buffer into a temporary file for later
1138 * processing.
1139 *
1140 * Returns number of bytes written.
1141 */
1142
1143static int
1144xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
1145
1146 xmlIOHTTPWriteCtxtPtr ctxt = context;
1147
1148 if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
1149 return ( -1 );
1150
1151 if ( len > 0 ) {
1152
1153 /* Use gzwrite or fwrite as previously setup in the open call */
1154
1155#ifdef HAVE_ZLIB_H
1156 if ( ctxt->compression > 0 )
1157 len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len );
1158
1159 else
1160#endif
1161 len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
1162
1163 if ( len < 0 ) {
1164 xmlGenericError( xmlGenericErrorContext,
1165 "xmlIOHTTPWrite: %s\n%s '%s'.\n",
1166 "Error appending to internal buffer.",
1167 "Error sending document to URI",
1168 ctxt->uri );
1169 }
1170 }
1171
1172 return ( len );
1173}
1174
1175
1176/**
Owen Taylor3473f882001-02-23 17:55:21 +00001177 * xmlIOHTTPClose:
1178 * @context: the I/O context
1179 *
1180 * Close an HTTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001181 *
1182 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00001183 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001184int
Owen Taylor3473f882001-02-23 17:55:21 +00001185xmlIOHTTPClose (void * context) {
1186 xmlNanoHTTPClose(context);
Daniel Veillardf012a642001-07-23 19:10:52 +00001187 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001188}
Daniel Veillardf012a642001-07-23 19:10:52 +00001189
1190/**
1191 * xmlIOHTTCloseWrite
1192 * @context: The I/O context
1193 * @http_mthd: The HTTP method to be used when sending the data
1194 *
1195 * Close the transmit HTTP I/O channel and actually send the data.
1196 */
1197static int
1198xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
1199
1200 int close_rc = -1;
1201 int http_rtn = 0;
1202 int content_lgth = 0;
1203 xmlIOHTTPWriteCtxtPtr ctxt = context;
1204
1205 char * http_content = NULL;
1206 char * content_encoding = NULL;
1207 char * content_type = (char *) "text/xml";
1208 void * http_ctxt = NULL;
1209
1210 if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
1211 return ( -1 );
1212
1213 /* Retrieve the content from the appropriate buffer */
1214
1215#ifdef HAVE_ZLIB_H
1216
1217 if ( ctxt->compression > 0 ) {
1218 content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
1219 content_encoding = (char *) "Content-Encoding: gzip";
1220 }
1221 else
1222#endif
1223 {
1224 /* Pull the data out of the memory output buffer */
1225
1226 xmlOutputBufferPtr dctxt = ctxt->doc_buff;
1227 http_content = (char *)dctxt->buffer->content;
1228 content_lgth = dctxt->buffer->use;
1229 }
1230
1231 if ( http_content == NULL ) {
1232 xmlGenericError( xmlGenericErrorContext,
1233 "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
1234 "Error retrieving content.\nUnable to",
1235 http_mthd, "data to URI", ctxt->uri );
1236 }
1237
1238 else {
1239
1240 http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
1241 &content_type, content_encoding,
1242 content_lgth );
1243
1244 if ( http_ctxt != NULL ) {
1245#ifdef DEBUG_HTTP
1246 /* If testing/debugging - dump reply with request content */
1247
1248 FILE * tst_file = NULL;
1249 char buffer[ 4096 ];
1250 char * dump_name = NULL;
1251 int avail;
1252
1253 xmlGenericError( xmlGenericErrorContext,
1254 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
1255 http_mthd, ctxt->uri,
1256 xmlNanoHTTPReturnCode( http_ctxt ) );
1257
1258 /*
1259 ** Since either content or reply may be gzipped,
1260 ** dump them to separate files instead of the
1261 ** standard error context.
1262 */
1263
1264 dump_name = tempnam( NULL, "lxml" );
1265 if ( dump_name != NULL ) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001266 (void)snprintf( buffer, sizeof(buffer), "%s.content", dump_name );
Daniel Veillardf012a642001-07-23 19:10:52 +00001267
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00001268 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00001269 if ( tst_file != NULL ) {
1270 xmlGenericError( xmlGenericErrorContext,
1271 "Transmitted content saved in file: %s\n", buffer );
1272
1273 fwrite( http_content, sizeof( char ),
1274 content_lgth, tst_file );
1275 fclose( tst_file );
1276 }
1277
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001278 (void)snprintf( buffer, sizeof(buffer), "%s.reply", dump_name );
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00001279 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00001280 if ( tst_file != NULL ) {
1281 xmlGenericError( xmlGenericErrorContext,
1282 "Reply content saved in file: %s\n", buffer );
1283
1284
1285 while ( (avail = xmlNanoHTTPRead( http_ctxt,
1286 buffer, sizeof( buffer ) )) > 0 ) {
1287
1288 fwrite( buffer, sizeof( char ), avail, tst_file );
1289 }
1290
1291 fclose( tst_file );
1292 }
1293
1294 free( dump_name );
1295 }
1296#endif /* DEBUG_HTTP */
1297
1298 http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
1299 if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
1300 close_rc = 0;
1301 else
1302 xmlGenericError( xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001303 "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001304 http_mthd, content_lgth,
1305 "bytes to URI", ctxt->uri,
1306 "failed. HTTP return code:", http_rtn );
1307
1308 xmlNanoHTTPClose( http_ctxt );
1309 xmlFree( content_type );
1310 }
1311 }
1312
1313 /* Final cleanups */
1314
1315 xmlFreeHTTPWriteCtxt( ctxt );
1316
1317 return ( close_rc );
1318}
1319
1320/**
1321 * xmlIOHTTPClosePut
1322 *
1323 * @context: The I/O context
1324 *
1325 * Close the transmit HTTP I/O channel and actually send data using a PUT
1326 * HTTP method.
1327 */
1328static int
1329xmlIOHTTPClosePut( void * ctxt ) {
1330 return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
1331}
1332
1333
1334/**
1335 * xmlIOHTTPClosePost
1336 *
1337 * @context: The I/O context
1338 *
1339 * Close the transmit HTTP I/O channel and actually send data using a POST
1340 * HTTP method.
1341 */
1342static int
1343xmlIOHTTPClosePost( void * ctxt ) {
1344 return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
1345}
1346
Owen Taylor3473f882001-02-23 17:55:21 +00001347#endif /* LIBXML_HTTP_ENABLED */
1348
1349#ifdef LIBXML_FTP_ENABLED
1350/************************************************************************
1351 * *
1352 * I/O for FTP file accesses *
1353 * *
1354 ************************************************************************/
1355/**
1356 * xmlIOFTPMatch:
1357 * @filename: the URI for matching
1358 *
1359 * check if the URI matches an FTP one
1360 *
1361 * Returns 1 if matches, 0 otherwise
1362 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001363int
Owen Taylor3473f882001-02-23 17:55:21 +00001364xmlIOFTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001365 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "ftp://", 6))
Owen Taylor3473f882001-02-23 17:55:21 +00001366 return(1);
1367 return(0);
1368}
1369
1370/**
1371 * xmlIOFTPOpen:
1372 * @filename: the URI for matching
1373 *
1374 * open an FTP I/O channel
1375 *
1376 * Returns an I/O context or NULL in case of error
1377 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001378void *
Owen Taylor3473f882001-02-23 17:55:21 +00001379xmlIOFTPOpen (const char *filename) {
1380 return(xmlNanoFTPOpen(filename));
1381}
1382
1383/**
1384 * xmlIOFTPRead:
1385 * @context: the I/O context
1386 * @buffer: where to drop data
1387 * @len: number of bytes to write
1388 *
1389 * Read @len bytes to @buffer from the I/O channel.
1390 *
1391 * Returns the number of bytes written
1392 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001393int
Owen Taylor3473f882001-02-23 17:55:21 +00001394xmlIOFTPRead(void * context, char * buffer, int len) {
1395 return(xmlNanoFTPRead(context, &buffer[0], len));
1396}
1397
1398/**
1399 * xmlIOFTPClose:
1400 * @context: the I/O context
1401 *
1402 * Close an FTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001403 *
1404 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00001405 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001406int
Owen Taylor3473f882001-02-23 17:55:21 +00001407xmlIOFTPClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001408 return ( xmlNanoFTPClose(context) );
Owen Taylor3473f882001-02-23 17:55:21 +00001409}
1410#endif /* LIBXML_FTP_ENABLED */
1411
1412
1413/**
1414 * xmlRegisterInputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001415 * @matchFunc: the xmlInputMatchCallback
1416 * @openFunc: the xmlInputOpenCallback
1417 * @readFunc: the xmlInputReadCallback
1418 * @closeFunc: the xmlInputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001419 *
1420 * Register a new set of I/O callback for handling parser input.
1421 *
1422 * Returns the registered handler number or -1 in case of error
1423 */
1424int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001425xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
1426 xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
1427 xmlInputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001428 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
1429 return(-1);
1430 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001431 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
1432 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
1433 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
1434 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
Owen Taylor3473f882001-02-23 17:55:21 +00001435 return(xmlInputCallbackNr++);
1436}
1437
1438/**
1439 * xmlRegisterOutputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001440 * @matchFunc: the xmlOutputMatchCallback
1441 * @openFunc: the xmlOutputOpenCallback
1442 * @writeFunc: the xmlOutputWriteCallback
1443 * @closeFunc: the xmlOutputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001444 *
1445 * Register a new set of I/O callback for handling output.
1446 *
1447 * Returns the registered handler number or -1 in case of error
1448 */
1449int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001450xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
1451 xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
1452 xmlOutputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001453 if (xmlOutputCallbackNr >= MAX_INPUT_CALLBACK) {
1454 return(-1);
1455 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001456 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
1457 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
1458 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
1459 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
Owen Taylor3473f882001-02-23 17:55:21 +00001460 return(xmlOutputCallbackNr++);
1461}
1462
1463/**
1464 * xmlRegisterDefaultInputCallbacks:
1465 *
1466 * Registers the default compiled-in I/O handlers.
1467 */
1468void
Owen Taylor3473f882001-02-23 17:55:21 +00001469xmlRegisterDefaultInputCallbacks
Owen Taylor3473f882001-02-23 17:55:21 +00001470(void) {
1471 if (xmlInputCallbackInitialized)
1472 return;
1473
1474 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
1475 xmlFileRead, xmlFileClose);
1476#ifdef HAVE_ZLIB_H
1477 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1478 xmlGzfileRead, xmlGzfileClose);
1479#endif /* HAVE_ZLIB_H */
1480
1481#ifdef LIBXML_HTTP_ENABLED
1482 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
1483 xmlIOHTTPRead, xmlIOHTTPClose);
1484#endif /* LIBXML_HTTP_ENABLED */
1485
1486#ifdef LIBXML_FTP_ENABLED
1487 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1488 xmlIOFTPRead, xmlIOFTPClose);
1489#endif /* LIBXML_FTP_ENABLED */
1490 xmlInputCallbackInitialized = 1;
1491}
1492
1493/**
1494 * xmlRegisterDefaultOutputCallbacks:
1495 *
1496 * Registers the default compiled-in I/O handlers.
1497 */
1498void
Owen Taylor3473f882001-02-23 17:55:21 +00001499xmlRegisterDefaultOutputCallbacks
Owen Taylor3473f882001-02-23 17:55:21 +00001500(void) {
1501 if (xmlOutputCallbackInitialized)
1502 return;
1503
1504 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
1505 xmlFileWrite, xmlFileClose);
Daniel Veillardf012a642001-07-23 19:10:52 +00001506
1507#ifdef LIBXML_HTTP_ENABLED
1508 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
1509 xmlIOHTTPWrite, xmlIOHTTPClosePut);
1510#endif
1511
Owen Taylor3473f882001-02-23 17:55:21 +00001512/*********************************
1513 No way a-priori to distinguish between gzipped files from
1514 uncompressed ones except opening if existing then closing
1515 and saving with same compression ratio ... a pain.
1516
1517#ifdef HAVE_ZLIB_H
1518 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1519 xmlGzfileWrite, xmlGzfileClose);
1520#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001521
1522 Nor FTP PUT ....
1523#ifdef LIBXML_FTP_ENABLED
1524 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1525 xmlIOFTPWrite, xmlIOFTPClose);
1526#endif
1527 **********************************/
1528 xmlOutputCallbackInitialized = 1;
1529}
1530
Daniel Veillardf012a642001-07-23 19:10:52 +00001531#ifdef LIBXML_HTTP_ENABLED
1532/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001533 * xmlRegisterHTTPPostCallbacks:
Daniel Veillardf012a642001-07-23 19:10:52 +00001534 *
1535 * By default, libxml submits HTTP output requests using the "PUT" method.
1536 * Calling this method changes the HTTP output method to use the "POST"
1537 * method instead.
1538 *
1539 */
1540void
1541xmlRegisterHTTPPostCallbacks( void ) {
1542
1543 /* Register defaults if not done previously */
1544
1545 if ( xmlOutputCallbackInitialized == 0 )
1546 xmlRegisterDefaultOutputCallbacks( );
1547
1548 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
1549 xmlIOHTTPWrite, xmlIOHTTPClosePost);
1550 return;
1551}
1552#endif
1553
Owen Taylor3473f882001-02-23 17:55:21 +00001554/**
1555 * xmlAllocParserInputBuffer:
1556 * @enc: the charset encoding if known
1557 *
1558 * Create a buffered parser input for progressive parsing
1559 *
1560 * Returns the new parser input or NULL
1561 */
1562xmlParserInputBufferPtr
1563xmlAllocParserInputBuffer(xmlCharEncoding enc) {
1564 xmlParserInputBufferPtr ret;
1565
1566 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
1567 if (ret == NULL) {
1568 xmlGenericError(xmlGenericErrorContext,
1569 "xmlAllocParserInputBuffer : out of memory!\n");
1570 return(NULL);
1571 }
1572 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
1573 ret->buffer = xmlBufferCreate();
1574 if (ret->buffer == NULL) {
1575 xmlFree(ret);
1576 return(NULL);
1577 }
1578 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
1579 ret->encoder = xmlGetCharEncodingHandler(enc);
1580 if (ret->encoder != NULL)
1581 ret->raw = xmlBufferCreate();
1582 else
1583 ret->raw = NULL;
1584 ret->readcallback = NULL;
1585 ret->closecallback = NULL;
1586 ret->context = NULL;
1587
1588 return(ret);
1589}
1590
1591/**
1592 * xmlAllocOutputBuffer:
1593 * @encoder: the encoding converter or NULL
1594 *
1595 * Create a buffered parser output
1596 *
1597 * Returns the new parser output or NULL
1598 */
1599xmlOutputBufferPtr
1600xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
1601 xmlOutputBufferPtr ret;
1602
1603 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
1604 if (ret == NULL) {
1605 xmlGenericError(xmlGenericErrorContext,
1606 "xmlAllocOutputBuffer : out of memory!\n");
1607 return(NULL);
1608 }
1609 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
1610 ret->buffer = xmlBufferCreate();
1611 if (ret->buffer == NULL) {
1612 xmlFree(ret);
1613 return(NULL);
1614 }
1615 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
1616 ret->encoder = encoder;
1617 if (encoder != NULL) {
1618 ret->conv = xmlBufferCreateSize(4000);
1619 /*
1620 * This call is designed to initiate the encoder state
1621 */
1622 xmlCharEncOutFunc(encoder, ret->conv, NULL);
1623 } else
1624 ret->conv = NULL;
1625 ret->writecallback = NULL;
1626 ret->closecallback = NULL;
1627 ret->context = NULL;
1628 ret->written = 0;
1629
1630 return(ret);
1631}
1632
1633/**
1634 * xmlFreeParserInputBuffer:
1635 * @in: a buffered parser input
1636 *
1637 * Free up the memory used by a buffered parser input
1638 */
1639void
1640xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
1641 if (in->raw) {
1642 xmlBufferFree(in->raw);
1643 in->raw = NULL;
1644 }
1645 if (in->encoder != NULL) {
1646 xmlCharEncCloseFunc(in->encoder);
1647 }
1648 if (in->closecallback != NULL) {
1649 in->closecallback(in->context);
1650 }
1651 if (in->buffer != NULL) {
1652 xmlBufferFree(in->buffer);
1653 in->buffer = NULL;
1654 }
1655
Owen Taylor3473f882001-02-23 17:55:21 +00001656 xmlFree(in);
1657}
1658
1659/**
1660 * xmlOutputBufferClose:
1661 * @out: a buffered output
1662 *
1663 * flushes and close the output I/O channel
1664 * and free up all the associated resources
1665 *
1666 * Returns the number of byte written or -1 in case of error.
1667 */
1668int
1669xmlOutputBufferClose(xmlOutputBufferPtr out) {
1670 int written;
Daniel Veillardf012a642001-07-23 19:10:52 +00001671 int err_rc = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001672
1673 if (out == NULL)
1674 return(-1);
1675 if (out->writecallback != NULL)
1676 xmlOutputBufferFlush(out);
1677 if (out->closecallback != NULL) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001678 err_rc = out->closecallback(out->context);
Owen Taylor3473f882001-02-23 17:55:21 +00001679 }
1680 written = out->written;
1681 if (out->conv) {
1682 xmlBufferFree(out->conv);
1683 out->conv = NULL;
1684 }
1685 if (out->encoder != NULL) {
1686 xmlCharEncCloseFunc(out->encoder);
1687 }
1688 if (out->buffer != NULL) {
1689 xmlBufferFree(out->buffer);
1690 out->buffer = NULL;
1691 }
1692
Owen Taylor3473f882001-02-23 17:55:21 +00001693 xmlFree(out);
Daniel Veillardf012a642001-07-23 19:10:52 +00001694 return( ( err_rc == 0 ) ? written : err_rc );
Owen Taylor3473f882001-02-23 17:55:21 +00001695}
1696
1697/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001698 * xmlParserInputBufferCreateFname:
1699 * @URI: a C string containing the URI or filename
1700 * @enc: the charset encoding if known
1701 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001702 * Returns the new parser input or NULL
1703 */
1704/**
Owen Taylor3473f882001-02-23 17:55:21 +00001705 * xmlParserInputBufferCreateFilename:
1706 * @URI: a C string containing the URI or filename
1707 * @enc: the charset encoding if known
1708 *
1709 * Create a buffered parser input for the progressive parsing of a file
1710 * If filename is "-' then we use stdin as the input.
1711 * Automatic support for ZLIB/Compress compressed document is provided
1712 * by default if found at compile-time.
1713 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
1714 *
1715 * Returns the new parser input or NULL
1716 */
1717xmlParserInputBufferPtr
Daniel Veillard3e59fc52003-04-18 12:34:58 +00001718xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001719 xmlParserInputBufferPtr ret;
Daniel Veillard388236f2001-07-08 18:35:48 +00001720 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001721 void *context = NULL;
1722
1723 if (xmlInputCallbackInitialized == 0)
1724 xmlRegisterDefaultInputCallbacks();
1725
1726 if (URI == NULL) return(NULL);
1727
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001728#ifdef LIBXML_CATALOG_ENABLED
1729#endif
1730
Owen Taylor3473f882001-02-23 17:55:21 +00001731 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001732 * Try to find one of the input accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00001733 * Go in reverse to give precedence to user defined handlers.
Daniel Veillard388236f2001-07-08 18:35:48 +00001734 */
1735 if (context == NULL) {
1736 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
1737 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
1738 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00001739 context = xmlInputCallbackTable[i].opencallback(URI);
Daniel Veillard388236f2001-07-08 18:35:48 +00001740 if (context != NULL)
1741 break;
1742 }
Owen Taylor3473f882001-02-23 17:55:21 +00001743 }
1744 }
1745 if (context == NULL) {
1746 return(NULL);
1747 }
1748
1749 /*
1750 * Allocate the Input buffer front-end.
1751 */
1752 ret = xmlAllocParserInputBuffer(enc);
1753 if (ret != NULL) {
1754 ret->context = context;
1755 ret->readcallback = xmlInputCallbackTable[i].readcallback;
1756 ret->closecallback = xmlInputCallbackTable[i].closecallback;
1757 }
1758 return(ret);
1759}
1760
1761/**
1762 * xmlOutputBufferCreateFilename:
1763 * @URI: a C string containing the URI or filename
1764 * @encoder: the encoding converter or NULL
1765 * @compression: the compression ration (0 none, 9 max).
1766 *
1767 * Create a buffered output for the progressive saving of a file
1768 * If filename is "-' then we use stdout as the output.
1769 * Automatic support for ZLIB/Compress compressed document is provided
1770 * by default if found at compile-time.
1771 * TODO: currently if compression is set, the library only support
1772 * writing to a local file.
1773 *
1774 * Returns the new output or NULL
1775 */
1776xmlOutputBufferPtr
1777xmlOutputBufferCreateFilename(const char *URI,
1778 xmlCharEncodingHandlerPtr encoder,
1779 int compression) {
1780 xmlOutputBufferPtr ret;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001781 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001782 void *context = NULL;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001783 char *unescaped;
Owen Taylor3473f882001-02-23 17:55:21 +00001784
Daniel Veillardf012a642001-07-23 19:10:52 +00001785 int is_http_uri = 0; /* Can't change if HTTP disabled */
1786
Owen Taylor3473f882001-02-23 17:55:21 +00001787 if (xmlOutputCallbackInitialized == 0)
1788 xmlRegisterDefaultOutputCallbacks();
1789
1790 if (URI == NULL) return(NULL);
1791
Daniel Veillardf012a642001-07-23 19:10:52 +00001792#ifdef LIBXML_HTTP_ENABLED
1793 /* Need to prevent HTTP URI's from falling into zlib short circuit */
1794
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00001795 is_http_uri = xmlIOHTTPMatch( URI );
Daniel Veillardf012a642001-07-23 19:10:52 +00001796#endif
1797
Owen Taylor3473f882001-02-23 17:55:21 +00001798
1799 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001800 * Try to find one of the output accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00001801 * Go in reverse to give precedence to user defined handlers.
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001802 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00001803 */
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00001804 unescaped = xmlURIUnescapeString(URI, 0, NULL);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001805 if (unescaped != NULL) {
1806#ifdef HAVE_ZLIB_H
1807 if ((compression > 0) && (compression <= 9) && (is_http_uri == 0)) {
1808 context = xmlGzfileOpenW(unescaped, compression);
1809 if (context != NULL) {
1810 ret = xmlAllocOutputBuffer(encoder);
1811 if (ret != NULL) {
1812 ret->context = context;
1813 ret->writecallback = xmlGzfileWrite;
1814 ret->closecallback = xmlGzfileClose;
1815 }
1816 xmlFree(unescaped);
1817 return(ret);
1818 }
1819 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001820#endif
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001821 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
1822 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
1823 (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
1824#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
1825 /* Need to pass compression parameter into HTTP open calls */
1826 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
1827 context = xmlIOHTTPOpenW(unescaped, compression);
1828 else
1829#endif
1830 context = xmlOutputCallbackTable[i].opencallback(unescaped);
1831 if (context != NULL)
1832 break;
1833 }
1834 }
1835 xmlFree(unescaped);
1836 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001837
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001838 /*
1839 * If this failed try with a non-escaped URI this may be a strange
1840 * filename
1841 */
1842 if (context == NULL) {
1843#ifdef HAVE_ZLIB_H
1844 if ((compression > 0) && (compression <= 9) && (is_http_uri == 0)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00001845 context = xmlGzfileOpenW(URI, compression);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001846 if (context != NULL) {
1847 ret = xmlAllocOutputBuffer(encoder);
1848 if (ret != NULL) {
1849 ret->context = context;
1850 ret->writecallback = xmlGzfileWrite;
1851 ret->closecallback = xmlGzfileClose;
1852 }
1853 return(ret);
1854 }
1855 }
1856#endif
1857 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
1858 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00001859 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001860#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
1861 /* Need to pass compression parameter into HTTP open calls */
1862 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
1863 context = xmlIOHTTPOpenW(URI, compression);
1864 else
1865#endif
1866 context = xmlOutputCallbackTable[i].opencallback(URI);
1867 if (context != NULL)
1868 break;
1869 }
Owen Taylor3473f882001-02-23 17:55:21 +00001870 }
1871 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001872
Owen Taylor3473f882001-02-23 17:55:21 +00001873 if (context == NULL) {
1874 return(NULL);
1875 }
1876
1877 /*
1878 * Allocate the Output buffer front-end.
1879 */
1880 ret = xmlAllocOutputBuffer(encoder);
1881 if (ret != NULL) {
1882 ret->context = context;
1883 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
1884 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
1885 }
1886 return(ret);
1887}
1888
1889/**
1890 * xmlParserInputBufferCreateFile:
1891 * @file: a FILE*
1892 * @enc: the charset encoding if known
1893 *
1894 * Create a buffered parser input for the progressive parsing of a FILE *
1895 * buffered C I/O
1896 *
1897 * Returns the new parser input or NULL
1898 */
1899xmlParserInputBufferPtr
1900xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
1901 xmlParserInputBufferPtr ret;
1902
1903 if (xmlInputCallbackInitialized == 0)
1904 xmlRegisterDefaultInputCallbacks();
1905
1906 if (file == NULL) return(NULL);
1907
1908 ret = xmlAllocParserInputBuffer(enc);
1909 if (ret != NULL) {
1910 ret->context = file;
1911 ret->readcallback = xmlFileRead;
1912 ret->closecallback = xmlFileFlush;
1913 }
1914
1915 return(ret);
1916}
1917
1918/**
1919 * xmlOutputBufferCreateFile:
1920 * @file: a FILE*
1921 * @encoder: the encoding converter or NULL
1922 *
1923 * Create a buffered output for the progressive saving to a FILE *
1924 * buffered C I/O
1925 *
1926 * Returns the new parser output or NULL
1927 */
1928xmlOutputBufferPtr
1929xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
1930 xmlOutputBufferPtr ret;
1931
1932 if (xmlOutputCallbackInitialized == 0)
1933 xmlRegisterDefaultOutputCallbacks();
1934
1935 if (file == NULL) return(NULL);
1936
1937 ret = xmlAllocOutputBuffer(encoder);
1938 if (ret != NULL) {
1939 ret->context = file;
1940 ret->writecallback = xmlFileWrite;
1941 ret->closecallback = xmlFileFlush;
1942 }
1943
1944 return(ret);
1945}
1946
1947/**
1948 * xmlParserInputBufferCreateFd:
1949 * @fd: a file descriptor number
1950 * @enc: the charset encoding if known
1951 *
1952 * Create a buffered parser input for the progressive parsing for the input
1953 * from a file descriptor
1954 *
1955 * Returns the new parser input or NULL
1956 */
1957xmlParserInputBufferPtr
1958xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
1959 xmlParserInputBufferPtr ret;
1960
1961 if (fd < 0) return(NULL);
1962
1963 ret = xmlAllocParserInputBuffer(enc);
1964 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00001965 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00001966 ret->readcallback = xmlFdRead;
1967 ret->closecallback = xmlFdClose;
1968 }
1969
1970 return(ret);
1971}
1972
1973/**
1974 * xmlParserInputBufferCreateMem:
1975 * @mem: the memory input
1976 * @size: the length of the memory block
1977 * @enc: the charset encoding if known
1978 *
1979 * Create a buffered parser input for the progressive parsing for the input
1980 * from a memory area.
1981 *
1982 * Returns the new parser input or NULL
1983 */
1984xmlParserInputBufferPtr
1985xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
1986 xmlParserInputBufferPtr ret;
1987
1988 if (size <= 0) return(NULL);
1989 if (mem == NULL) return(NULL);
1990
1991 ret = xmlAllocParserInputBuffer(enc);
1992 if (ret != NULL) {
1993 ret->context = (void *) mem;
1994 ret->readcallback = (xmlInputReadCallback) xmlNop;
1995 ret->closecallback = NULL;
1996 xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size);
1997 }
1998
1999 return(ret);
2000}
2001
2002/**
2003 * xmlOutputBufferCreateFd:
2004 * @fd: a file descriptor number
2005 * @encoder: the encoding converter or NULL
2006 *
2007 * Create a buffered output for the progressive saving
2008 * to a file descriptor
2009 *
2010 * Returns the new parser output or NULL
2011 */
2012xmlOutputBufferPtr
2013xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
2014 xmlOutputBufferPtr ret;
2015
2016 if (fd < 0) return(NULL);
2017
2018 ret = xmlAllocOutputBuffer(encoder);
2019 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002020 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002021 ret->writecallback = xmlFdWrite;
Daniel Veillard7db38712002-02-07 16:39:11 +00002022 ret->closecallback = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002023 }
2024
2025 return(ret);
2026}
2027
2028/**
2029 * xmlParserInputBufferCreateIO:
2030 * @ioread: an I/O read function
2031 * @ioclose: an I/O close function
2032 * @ioctx: an I/O handler
2033 * @enc: the charset encoding if known
2034 *
2035 * Create a buffered parser input for the progressive parsing for the input
2036 * from an I/O handler
2037 *
2038 * Returns the new parser input or NULL
2039 */
2040xmlParserInputBufferPtr
2041xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
2042 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
2043 xmlParserInputBufferPtr ret;
2044
2045 if (ioread == NULL) return(NULL);
2046
2047 ret = xmlAllocParserInputBuffer(enc);
2048 if (ret != NULL) {
2049 ret->context = (void *) ioctx;
2050 ret->readcallback = ioread;
2051 ret->closecallback = ioclose;
2052 }
2053
2054 return(ret);
2055}
2056
2057/**
2058 * xmlOutputBufferCreateIO:
2059 * @iowrite: an I/O write function
2060 * @ioclose: an I/O close function
2061 * @ioctx: an I/O handler
Daniel Veillard9d06d302002-01-22 18:15:52 +00002062 * @encoder: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002063 *
2064 * Create a buffered output for the progressive saving
2065 * to an I/O handler
2066 *
2067 * Returns the new parser output or NULL
2068 */
2069xmlOutputBufferPtr
2070xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
2071 xmlOutputCloseCallback ioclose, void *ioctx,
2072 xmlCharEncodingHandlerPtr encoder) {
2073 xmlOutputBufferPtr ret;
2074
2075 if (iowrite == NULL) return(NULL);
2076
2077 ret = xmlAllocOutputBuffer(encoder);
2078 if (ret != NULL) {
2079 ret->context = (void *) ioctx;
2080 ret->writecallback = iowrite;
2081 ret->closecallback = ioclose;
2082 }
2083
2084 return(ret);
2085}
2086
2087/**
2088 * xmlParserInputBufferPush:
2089 * @in: a buffered parser input
2090 * @len: the size in bytes of the array.
2091 * @buf: an char array
2092 *
2093 * Push the content of the arry in the input buffer
2094 * This routine handle the I18N transcoding to internal UTF-8
2095 * This is used when operating the parser in progressive (push) mode.
2096 *
2097 * Returns the number of chars read and stored in the buffer, or -1
2098 * in case of error.
2099 */
2100int
2101xmlParserInputBufferPush(xmlParserInputBufferPtr in,
2102 int len, const char *buf) {
2103 int nbchars = 0;
2104
2105 if (len < 0) return(0);
2106 if (in->encoder != NULL) {
2107 /*
2108 * Store the data in the incoming raw buffer
2109 */
2110 if (in->raw == NULL) {
2111 in->raw = xmlBufferCreate();
2112 }
2113 xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
2114
2115 /*
2116 * convert as much as possible to the parser reading buffer.
2117 */
2118 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2119 if (nbchars < 0) {
2120 xmlGenericError(xmlGenericErrorContext,
2121 "xmlParserInputBufferPush: encoder error\n");
2122 return(-1);
2123 }
2124 } else {
2125 nbchars = len;
2126 xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
2127 }
2128#ifdef DEBUG_INPUT
2129 xmlGenericError(xmlGenericErrorContext,
2130 "I/O: pushed %d chars, buffer %d/%d\n",
2131 nbchars, in->buffer->use, in->buffer->size);
2132#endif
2133 return(nbchars);
2134}
2135
2136/**
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002137 * endOfInput:
2138 *
2139 * When reading from an Input channel indicated end of file or error
2140 * don't reread from it again.
2141 */
2142static int
2143endOfInput (void * context ATTRIBUTE_UNUSED,
2144 char * buffer ATTRIBUTE_UNUSED,
2145 int len ATTRIBUTE_UNUSED) {
2146 return(0);
2147}
2148
2149/**
Owen Taylor3473f882001-02-23 17:55:21 +00002150 * xmlParserInputBufferGrow:
2151 * @in: a buffered parser input
2152 * @len: indicative value of the amount of chars to read
2153 *
2154 * Grow up the content of the input buffer, the old data are preserved
2155 * This routine handle the I18N transcoding to internal UTF-8
2156 * This routine is used when operating the parser in normal (pull) mode
2157 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002158 * TODO: one should be able to remove one extra copy by copying directly
Owen Taylor3473f882001-02-23 17:55:21 +00002159 * onto in->buffer or in->raw
2160 *
2161 * Returns the number of chars read and stored in the buffer, or -1
2162 * in case of error.
2163 */
2164int
2165xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
2166 char *buffer = NULL;
2167 int res = 0;
2168 int nbchars = 0;
2169 int buffree;
Daniel Veillard9e412302002-06-10 15:59:44 +00002170 unsigned int needSize;
Owen Taylor3473f882001-02-23 17:55:21 +00002171
2172 if ((len <= MINLEN) && (len != 4))
2173 len = MINLEN;
2174 buffree = in->buffer->size - in->buffer->use;
2175 if (buffree <= 0) {
2176 xmlGenericError(xmlGenericErrorContext,
2177 "xmlParserInputBufferGrow : buffer full !\n");
2178 return(0);
2179 }
2180 if (len > buffree)
2181 len = buffree;
2182
Daniel Veillarde5354492002-05-16 08:43:22 +00002183 needSize = in->buffer->use + len + 1;
2184 if (needSize > in->buffer->size){
2185 if (!xmlBufferResize(in->buffer, needSize)){
2186 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard8caa9c22003-06-02 13:35:24 +00002187 "xmlParserInputBufferGrow : out of memory!\n");
Daniel Veillarde5354492002-05-16 08:43:22 +00002188 return(0);
2189 }
Owen Taylor3473f882001-02-23 17:55:21 +00002190 }
Daniel Veillarde5354492002-05-16 08:43:22 +00002191 buffer = (char *)&in->buffer->content[in->buffer->use];
Owen Taylor3473f882001-02-23 17:55:21 +00002192
2193 /*
2194 * Call the read method for this I/O type.
2195 */
2196 if (in->readcallback != NULL) {
2197 res = in->readcallback(in->context, &buffer[0], len);
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002198 if (res <= 0)
2199 in->readcallback = endOfInput;
Owen Taylor3473f882001-02-23 17:55:21 +00002200 } else {
2201 xmlGenericError(xmlGenericErrorContext,
2202 "xmlParserInputBufferGrow : no input !\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002203 return(-1);
2204 }
2205 if (res < 0) {
Owen Taylor3473f882001-02-23 17:55:21 +00002206 return(-1);
2207 }
2208 len = res;
2209 if (in->encoder != NULL) {
2210 /*
2211 * Store the data in the incoming raw buffer
2212 */
2213 if (in->raw == NULL) {
2214 in->raw = xmlBufferCreate();
2215 }
2216 xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
2217
2218 /*
2219 * convert as much as possible to the parser reading buffer.
2220 */
2221 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2222 if (nbchars < 0) {
2223 xmlGenericError(xmlGenericErrorContext,
2224 "xmlParserInputBufferGrow: encoder error\n");
2225 return(-1);
2226 }
2227 } else {
2228 nbchars = len;
Daniel Veillarde5354492002-05-16 08:43:22 +00002229 in->buffer->use += nbchars;
2230 buffer[nbchars] = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002231 }
2232#ifdef DEBUG_INPUT
2233 xmlGenericError(xmlGenericErrorContext,
2234 "I/O: read %d chars, buffer %d/%d\n",
2235 nbchars, in->buffer->use, in->buffer->size);
2236#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002237 return(nbchars);
2238}
2239
2240/**
2241 * xmlParserInputBufferRead:
2242 * @in: a buffered parser input
2243 * @len: indicative value of the amount of chars to read
2244 *
2245 * Refresh the content of the input buffer, the old data are considered
2246 * consumed
2247 * This routine handle the I18N transcoding to internal UTF-8
2248 *
2249 * Returns the number of chars read and stored in the buffer, or -1
2250 * in case of error.
2251 */
2252int
2253xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
2254 /* xmlBufferEmpty(in->buffer); */
2255 if (in->readcallback != NULL)
2256 return(xmlParserInputBufferGrow(in, len));
2257 else
2258 return(-1);
2259}
2260
2261/**
2262 * xmlOutputBufferWrite:
2263 * @out: a buffered parser output
2264 * @len: the size in bytes of the array.
2265 * @buf: an char array
2266 *
2267 * Write the content of the array in the output I/O buffer
2268 * This routine handle the I18N transcoding from internal UTF-8
2269 * The buffer is lossless, i.e. will store in case of partial
2270 * or delayed writes.
2271 *
2272 * Returns the number of chars immediately written, or -1
2273 * in case of error.
2274 */
2275int
2276xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
2277 int nbchars = 0; /* number of chars to output to I/O */
2278 int ret; /* return from function call */
2279 int written = 0; /* number of char written to I/O so far */
2280 int chunk; /* number of byte curreent processed from buf */
2281
2282 if (len < 0) return(0);
2283
2284 do {
2285 chunk = len;
2286 if (chunk > 4 * MINLEN)
2287 chunk = 4 * MINLEN;
2288
2289 /*
2290 * first handle encoding stuff.
2291 */
2292 if (out->encoder != NULL) {
2293 /*
2294 * Store the data in the incoming raw buffer
2295 */
2296 if (out->conv == NULL) {
2297 out->conv = xmlBufferCreate();
2298 }
2299 xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2300
2301 if ((out->buffer->use < MINLEN) && (chunk == len))
2302 goto done;
2303
2304 /*
2305 * convert as much as possible to the parser reading buffer.
2306 */
2307 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
Daniel Veillard809faa52003-02-10 15:43:53 +00002308 if ((ret < 0) && (ret != -3)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002309 xmlGenericError(xmlGenericErrorContext,
2310 "xmlOutputBufferWrite: encoder error\n");
2311 return(-1);
2312 }
2313 nbchars = out->conv->use;
2314 } else {
2315 xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2316 nbchars = out->buffer->use;
2317 }
2318 buf += chunk;
2319 len -= chunk;
2320
2321 if ((nbchars < MINLEN) && (len <= 0))
2322 goto done;
2323
2324 if (out->writecallback) {
2325 /*
2326 * second write the stuff to the I/O channel
2327 */
2328 if (out->encoder != NULL) {
2329 ret = out->writecallback(out->context,
2330 (const char *)out->conv->content, nbchars);
2331 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002332 xmlBufferShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002333 } else {
2334 ret = out->writecallback(out->context,
2335 (const char *)out->buffer->content, nbchars);
2336 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002337 xmlBufferShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002338 }
2339 if (ret < 0) {
2340 xmlGenericError(xmlGenericErrorContext,
2341 "I/O: error %d writing %d bytes\n", ret, nbchars);
2342 return(ret);
2343 }
2344 out->written += ret;
2345 }
2346 written += nbchars;
2347 } while (len > 0);
2348
2349done:
2350#ifdef DEBUG_INPUT
2351 xmlGenericError(xmlGenericErrorContext,
2352 "I/O: wrote %d chars\n", written);
2353#endif
2354 return(written);
2355}
2356
2357/**
2358 * xmlOutputBufferWriteString:
2359 * @out: a buffered parser output
2360 * @str: a zero terminated C string
2361 *
2362 * Write the content of the string in the output I/O buffer
2363 * This routine handle the I18N transcoding from internal UTF-8
2364 * The buffer is lossless, i.e. will store in case of partial
2365 * or delayed writes.
2366 *
2367 * Returns the number of chars immediately written, or -1
2368 * in case of error.
2369 */
2370int
2371xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
2372 int len;
2373
2374 if (str == NULL)
2375 return(-1);
2376 len = strlen(str);
2377
2378 if (len > 0)
2379 return(xmlOutputBufferWrite(out, len, str));
2380 return(len);
2381}
2382
2383/**
2384 * xmlOutputBufferFlush:
2385 * @out: a buffered output
2386 *
2387 * flushes the output I/O channel
2388 *
2389 * Returns the number of byte written or -1 in case of error.
2390 */
2391int
2392xmlOutputBufferFlush(xmlOutputBufferPtr out) {
2393 int nbchars = 0, ret = 0;
2394
2395 /*
2396 * first handle encoding stuff.
2397 */
2398 if ((out->conv != NULL) && (out->encoder != NULL)) {
2399 /*
2400 * convert as much as possible to the parser reading buffer.
2401 */
2402 nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
2403 if (nbchars < 0) {
2404 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002405 "xmlOutputBufferFlush: encoder error\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002406 return(-1);
2407 }
2408 }
2409
2410 /*
2411 * second flush the stuff to the I/O channel
2412 */
2413 if ((out->conv != NULL) && (out->encoder != NULL) &&
2414 (out->writecallback != NULL)) {
2415 ret = out->writecallback(out->context,
2416 (const char *)out->conv->content, out->conv->use);
2417 if (ret >= 0)
2418 xmlBufferShrink(out->conv, ret);
2419 } else if (out->writecallback != NULL) {
2420 ret = out->writecallback(out->context,
2421 (const char *)out->buffer->content, out->buffer->use);
2422 if (ret >= 0)
2423 xmlBufferShrink(out->buffer, ret);
2424 }
2425 if (ret < 0) {
2426 xmlGenericError(xmlGenericErrorContext,
2427 "I/O: error %d flushing %d bytes\n", ret, nbchars);
2428 return(ret);
2429 }
2430 out->written += ret;
2431
2432#ifdef DEBUG_INPUT
2433 xmlGenericError(xmlGenericErrorContext,
2434 "I/O: flushed %d chars\n", ret);
2435#endif
2436 return(ret);
2437}
2438
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002439/**
Owen Taylor3473f882001-02-23 17:55:21 +00002440 * xmlParserGetDirectory:
2441 * @filename: the path to a file
2442 *
2443 * lookup the directory for that file
2444 *
2445 * Returns a new allocated string containing the directory, or NULL.
2446 */
2447char *
2448xmlParserGetDirectory(const char *filename) {
2449 char *ret = NULL;
2450 char dir[1024];
2451 char *cur;
2452 char sep = '/';
2453
Igor Zlatkovic9181cc02002-09-29 17:51:06 +00002454#ifdef _WIN32_WCE /* easy way by now ... wince does not have dirs! */
2455 return NULL;
2456#endif
2457
Owen Taylor3473f882001-02-23 17:55:21 +00002458 if (xmlInputCallbackInitialized == 0)
2459 xmlRegisterDefaultInputCallbacks();
2460
2461 if (filename == NULL) return(NULL);
Daniel Veillard3c5ed912002-01-08 10:36:16 +00002462#if defined(WIN32) && !defined(__CYGWIN__)
Owen Taylor3473f882001-02-23 17:55:21 +00002463 sep = '\\';
2464#endif
2465
2466 strncpy(dir, filename, 1023);
2467 dir[1023] = 0;
2468 cur = &dir[strlen(dir)];
2469 while (cur > dir) {
2470 if (*cur == sep) break;
2471 cur --;
2472 }
2473 if (*cur == sep) {
2474 if (cur == dir) dir[1] = 0;
2475 else *cur = 0;
2476 ret = xmlMemStrdup(dir);
2477 } else {
2478 if (getcwd(dir, 1024) != NULL) {
2479 dir[1023] = 0;
2480 ret = xmlMemStrdup(dir);
2481 }
2482 }
2483 return(ret);
2484}
2485
2486/****************************************************************
2487 * *
2488 * External entities loading *
2489 * *
2490 ****************************************************************/
2491
Daniel Veillard561b7f82002-03-20 21:55:57 +00002492static int xmlSysIDExists(const char *URL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00002493#ifdef HAVE_STAT
2494 int ret;
2495 struct stat info;
2496 const char *path;
2497
2498 if (URL == NULL)
2499 return(0);
2500
Daniel Veillardf4862f02002-09-10 11:13:43 +00002501 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00002502#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00002503 path = &URL[17];
2504#else
Daniel Veillard6990bf32001-08-23 21:17:48 +00002505 path = &URL[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00002506#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002507 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00002508#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard6990bf32001-08-23 21:17:48 +00002509 path = &URL[8];
2510#else
2511 path = &URL[7];
2512#endif
2513 } else
2514 path = URL;
2515 ret = stat(path, &info);
Daniel Veillard561b7f82002-03-20 21:55:57 +00002516 if (ret == 0)
2517 return(1);
Daniel Veillard6990bf32001-08-23 21:17:48 +00002518#endif
Daniel Veillard561b7f82002-03-20 21:55:57 +00002519 return(0);
Daniel Veillard6990bf32001-08-23 21:17:48 +00002520}
Daniel Veillard6990bf32001-08-23 21:17:48 +00002521
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002522/**
Owen Taylor3473f882001-02-23 17:55:21 +00002523 * xmlDefaultExternalEntityLoader:
2524 * @URL: the URL for the entity to load
2525 * @ID: the System ID for the entity to load
2526 * @ctxt: the context in which the entity is called or NULL
2527 *
2528 * By default we don't load external entitites, yet.
2529 *
2530 * Returns a new allocated xmlParserInputPtr, or NULL.
2531 */
2532static
2533xmlParserInputPtr
2534xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
2535 xmlParserCtxtPtr ctxt) {
2536 xmlParserInputPtr ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002537 xmlChar *resource = NULL;
2538#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002539 xmlCatalogAllow pref;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002540#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002541
2542#ifdef DEBUG_EXTERNAL_ENTITIES
2543 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf012a642001-07-23 19:10:52 +00002544 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00002545#endif
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002546#ifdef LIBXML_CATALOG_ENABLED
2547 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002548 * If the resource doesn't exists as a file,
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002549 * try to load it from the resource pointed in the catalogs
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002550 */
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002551 pref = xmlCatalogGetDefaults();
2552
Daniel Veillard561b7f82002-03-20 21:55:57 +00002553 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlSysIDExists(URL))) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002554 /*
2555 * Do a local lookup
2556 */
2557 if ((ctxt->catalogs != NULL) &&
2558 ((pref == XML_CATA_ALLOW_ALL) ||
2559 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2560 resource = xmlCatalogLocalResolve(ctxt->catalogs,
2561 (const xmlChar *)ID,
2562 (const xmlChar *)URL);
2563 }
2564 /*
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002565 * Try a global lookup
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002566 */
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002567 if ((resource == NULL) &&
2568 ((pref == XML_CATA_ALLOW_ALL) ||
2569 (pref == XML_CATA_ALLOW_GLOBAL))) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002570 resource = xmlCatalogResolve((const xmlChar *)ID,
2571 (const xmlChar *)URL);
2572 }
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002573 if ((resource == NULL) && (URL != NULL))
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00002574 resource = xmlStrdup((const xmlChar *) URL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002575
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002576 /*
2577 * TODO: do an URI lookup on the reference
2578 */
Daniel Veillard561b7f82002-03-20 21:55:57 +00002579 if ((resource != NULL) && (!xmlSysIDExists((const char *)resource))) {
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002580 xmlChar *tmp = NULL;
2581
2582 if ((ctxt->catalogs != NULL) &&
2583 ((pref == XML_CATA_ALLOW_ALL) ||
2584 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2585 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
2586 }
2587 if ((tmp == NULL) &&
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00002588 ((pref == XML_CATA_ALLOW_ALL) ||
2589 (pref == XML_CATA_ALLOW_GLOBAL))) {
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002590 tmp = xmlCatalogResolveURI(resource);
2591 }
2592
2593 if (tmp != NULL) {
2594 xmlFree(resource);
2595 resource = tmp;
2596 }
2597 }
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002598 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002599#endif
2600
2601 if (resource == NULL)
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002602 resource = (xmlChar *) URL;
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002603
2604 if (resource == NULL) {
Daniel Veillardc6613042002-03-02 09:34:02 +00002605 if (ID == NULL)
2606 ID = "NULL";
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002607 if ((ctxt->validate) && (ctxt->sax != NULL) &&
2608 (ctxt->sax->error != NULL))
2609 ctxt->sax->error(ctxt,
2610 "failed to load external entity \"%s\"\n", ID);
2611 else if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00002612 ctxt->sax->warning(ctxt,
2613 "failed to load external entity \"%s\"\n", ID);
2614 return(NULL);
2615 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002616 ret = xmlNewInputFromFile(ctxt, (const char *)resource);
Owen Taylor3473f882001-02-23 17:55:21 +00002617 if (ret == NULL) {
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002618 if ((ctxt->validate) && (ctxt->sax != NULL) &&
2619 (ctxt->sax->error != NULL))
2620 ctxt->sax->error(ctxt,
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002621 "failed to load external entity \"%s\"\n", resource);
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002622 else if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00002623 ctxt->sax->warning(ctxt,
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002624 "failed to load external entity \"%s\"\n", resource);
Owen Taylor3473f882001-02-23 17:55:21 +00002625 }
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002626 if ((resource != NULL) && (resource != (xmlChar *) URL))
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002627 xmlFree(resource);
Owen Taylor3473f882001-02-23 17:55:21 +00002628 return(ret);
2629}
2630
2631static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
2632 xmlDefaultExternalEntityLoader;
2633
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002634/**
Owen Taylor3473f882001-02-23 17:55:21 +00002635 * xmlSetExternalEntityLoader:
2636 * @f: the new entity resolver function
2637 *
2638 * Changes the defaultexternal entity resolver function for the application
2639 */
2640void
2641xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
2642 xmlCurrentExternalEntityLoader = f;
2643}
2644
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002645/**
Owen Taylor3473f882001-02-23 17:55:21 +00002646 * xmlGetExternalEntityLoader:
2647 *
2648 * Get the default external entity resolver function for the application
2649 *
2650 * Returns the xmlExternalEntityLoader function pointer
2651 */
2652xmlExternalEntityLoader
2653xmlGetExternalEntityLoader(void) {
2654 return(xmlCurrentExternalEntityLoader);
2655}
2656
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002657/**
Owen Taylor3473f882001-02-23 17:55:21 +00002658 * xmlLoadExternalEntity:
2659 * @URL: the URL for the entity to load
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00002660 * @ID: the Public ID for the entity to load
Owen Taylor3473f882001-02-23 17:55:21 +00002661 * @ctxt: the context in which the entity is called or NULL
2662 *
2663 * Load an external entity, note that the use of this function for
2664 * unparsed entities may generate problems
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002665 * TODO: a more generic External entity API must be designed
Owen Taylor3473f882001-02-23 17:55:21 +00002666 *
2667 * Returns the xmlParserInputPtr or NULL
2668 */
2669xmlParserInputPtr
2670xmlLoadExternalEntity(const char *URL, const char *ID,
2671 xmlParserCtxtPtr ctxt) {
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00002672 if ((URL != NULL) && (xmlSysIDExists(URL) == 0)) {
2673 char *canonicFilename;
2674 xmlParserInputPtr ret;
2675
2676 canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL);
2677 if (canonicFilename == NULL) {
2678 if (xmlDefaultSAXHandler.error != NULL) {
2679 xmlDefaultSAXHandler.error(NULL, "out of memory\n");
2680 }
2681 return(NULL);
2682 }
2683
2684 ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt);
2685 xmlFree(canonicFilename);
2686 return(ret);
2687 }
Owen Taylor3473f882001-02-23 17:55:21 +00002688 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
2689}
2690
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00002691/************************************************************************
2692 * *
2693 * Disabling Network access *
2694 * *
2695 ************************************************************************/
2696
2697#ifdef LIBXML_CATALOG_ENABLED
2698static int
2699xmlNoNetExists(const char *URL)
2700{
2701#ifdef HAVE_STAT
2702 int ret;
2703 struct stat info;
2704 const char *path;
2705
2706 if (URL == NULL)
2707 return (0);
2708
Daniel Veillardf4862f02002-09-10 11:13:43 +00002709 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00002710#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00002711 path = &URL[17];
2712#else
2713 path = &URL[16];
2714#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002715 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00002716#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00002717 path = &URL[8];
2718#else
2719 path = &URL[7];
2720#endif
2721 } else
2722 path = URL;
2723 ret = stat(path, &info);
2724 if (ret == 0)
2725 return (1);
2726#endif
2727 return (0);
2728}
2729#endif
2730
2731/**
2732 * xmlNoNetExternalEntityLoader:
2733 * @URL: the URL for the entity to load
2734 * @ID: the System ID for the entity to load
2735 * @ctxt: the context in which the entity is called or NULL
2736 *
2737 * A specific entity loader disabling network accesses, though still
2738 * allowing local catalog accesses for resolution.
2739 *
2740 * Returns a new allocated xmlParserInputPtr, or NULL.
2741 */
2742xmlParserInputPtr
2743xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
2744 xmlParserCtxtPtr ctxt) {
2745 xmlParserInputPtr input = NULL;
2746 xmlChar *resource = NULL;
2747
2748#ifdef LIBXML_CATALOG_ENABLED
2749 xmlCatalogAllow pref;
2750
2751 /*
2752 * If the resource doesn't exists as a file,
2753 * try to load it from the resource pointed in the catalogs
2754 */
2755 pref = xmlCatalogGetDefaults();
2756
2757 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
2758 /*
2759 * Do a local lookup
2760 */
2761 if ((ctxt->catalogs != NULL) &&
2762 ((pref == XML_CATA_ALLOW_ALL) ||
2763 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2764 resource = xmlCatalogLocalResolve(ctxt->catalogs,
2765 (const xmlChar *)ID,
2766 (const xmlChar *)URL);
2767 }
2768 /*
2769 * Try a global lookup
2770 */
2771 if ((resource == NULL) &&
2772 ((pref == XML_CATA_ALLOW_ALL) ||
2773 (pref == XML_CATA_ALLOW_GLOBAL))) {
2774 resource = xmlCatalogResolve((const xmlChar *)ID,
2775 (const xmlChar *)URL);
2776 }
2777 if ((resource == NULL) && (URL != NULL))
2778 resource = xmlStrdup((const xmlChar *) URL);
2779
2780 /*
2781 * TODO: do an URI lookup on the reference
2782 */
2783 if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
2784 xmlChar *tmp = NULL;
2785
2786 if ((ctxt->catalogs != NULL) &&
2787 ((pref == XML_CATA_ALLOW_ALL) ||
2788 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2789 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
2790 }
2791 if ((tmp == NULL) &&
2792 ((pref == XML_CATA_ALLOW_ALL) ||
2793 (pref == XML_CATA_ALLOW_GLOBAL))) {
2794 tmp = xmlCatalogResolveURI(resource);
2795 }
2796
2797 if (tmp != NULL) {
2798 xmlFree(resource);
2799 resource = tmp;
2800 }
2801 }
2802 }
2803#endif
2804 if (resource == NULL)
2805 resource = (xmlChar *) URL;
2806
2807 if (resource != NULL) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002808 if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
2809 (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00002810 xmlGenericError(xmlGenericErrorContext,
2811 "Attempt to load network entity %s \n", resource);
2812
2813 if (resource != (xmlChar *) URL)
2814 xmlFree(resource);
2815 return(NULL);
2816 }
2817 }
2818 input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
2819 if (resource != (xmlChar *) URL)
2820 xmlFree(resource);
2821 return(input);
2822}
2823