blob: 83907f90813507a06bea345e3fa199b6b805a989 [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 ) {
William M. Brack78637da2003-07-31 14:47:38 +0000723
724#ifdef DEBUG_HTTP
Daniel Veillardf012a642001-07-23 19:10:52 +0000725 int z_err;
William M. Brack78637da2003-07-31 14:47:38 +0000726#endif
Daniel Veillardf012a642001-07-23 19:10:52 +0000727
728 if ( buff == NULL )
729 return;
730
731 xmlFree( buff->zbuff );
Daniel Veillardf012a642001-07-23 19:10:52 +0000732#ifdef DEBUG_HTTP
William M. Brack78637da2003-07-31 14:47:38 +0000733 z_err = deflateEnd( &buff->zctrl );
Daniel Veillardf012a642001-07-23 19:10:52 +0000734 if ( z_err != Z_OK )
735 xmlGenericError( xmlGenericErrorContext,
736 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
737 z_err );
William M. Brack78637da2003-07-31 14:47:38 +0000738#else
739 deflateEnd( &buff->zctrl );
William M. Brack779af002003-08-01 15:55:39 +0000740#endif
Daniel Veillardf012a642001-07-23 19:10:52 +0000741
742 xmlFree( buff );
743 return;
744}
745
746/**
747 * xmlCreateZMemBuff
748 *@compression: Compression value to use
749 *
750 * Create a memory buffer to hold the compressed XML document. The
751 * compressed document in memory will end up being identical to what
752 * would be created if gzopen/gzwrite/gzclose were being used to
753 * write the document to disk. The code for the header/trailer data to
754 * the compression is plagiarized from the zlib source files.
755 */
756static void *
757xmlCreateZMemBuff( int compression ) {
758
759 int z_err;
760 int hdr_lgth;
761 xmlZMemBuffPtr buff = NULL;
762
763 if ( ( compression < 1 ) || ( compression > 9 ) )
764 return ( NULL );
765
766 /* Create the control and data areas */
767
768 buff = xmlMalloc( sizeof( xmlZMemBuff ) );
769 if ( buff == NULL ) {
770 xmlGenericError( xmlGenericErrorContext,
771 "xmlCreateZMemBuff: %s\n",
772 "Failure allocating buffer context." );
773 return ( NULL );
774 }
775
776 (void)memset( buff, 0, sizeof( xmlZMemBuff ) );
777 buff->size = INIT_HTTP_BUFF_SIZE;
778 buff->zbuff = xmlMalloc( buff->size );
779 if ( buff->zbuff == NULL ) {
780 xmlFreeZMemBuff( buff );
781 xmlGenericError( xmlGenericErrorContext,
782 "xmlCreateZMemBuff: %s\n",
783 "Failure allocating data buffer." );
784 return ( NULL );
785 }
786
787 z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
788 DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
789 if ( z_err != Z_OK ) {
790 xmlFreeZMemBuff( buff );
791 buff = NULL;
792 xmlGenericError( xmlGenericErrorContext,
793 "xmlCreateZMemBuff: %s %d\n",
794 "Error initializing compression context. ZLIB error:",
795 z_err );
796 return ( NULL );
797 }
798
799 /* Set the header data. The CRC will be needed for the trailer */
Daniel Veillardf012a642001-07-23 19:10:52 +0000800 buff->crc = crc32( 0L, Z_NULL, 0 );
Aleksey Sanin49cc9752002-06-14 17:07:10 +0000801 hdr_lgth = snprintf( (char *)buff->zbuff, buff->size,
802 "%c%c%c%c%c%c%c%c%c%c",
Daniel Veillardf012a642001-07-23 19:10:52 +0000803 GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED,
804 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE );
805 buff->zctrl.next_out = buff->zbuff + hdr_lgth;
806 buff->zctrl.avail_out = buff->size - hdr_lgth;
807
808 return ( buff );
809}
810
811/**
812 * xmlZMemBuffExtend
813 * @buff: Buffer used to compress and consolidate data.
814 * @ext_amt: Number of bytes to extend the buffer.
815 *
816 * Extend the internal buffer used to store the compressed data by the
817 * specified amount.
818 *
819 * Returns 0 on success or -1 on failure to extend the buffer. On failure
820 * the original buffer still exists at the original size.
821 */
822static int
823xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) {
824
825 int rc = -1;
826 size_t new_size;
827 size_t cur_used;
828
829 unsigned char * tmp_ptr = NULL;
830
831 if ( buff == NULL )
832 return ( -1 );
833
834 else if ( ext_amt == 0 )
835 return ( 0 );
836
837 cur_used = buff->zctrl.next_out - buff->zbuff;
838 new_size = buff->size + ext_amt;
839
840#ifdef DEBUG_HTTP
841 if ( cur_used > new_size )
842 xmlGenericError( xmlGenericErrorContext,
843 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
844 "Buffer overwrite detected during compressed memory",
845 "buffer extension. Overflowed by",
846 (cur_used - new_size ) );
847#endif
848
849 tmp_ptr = xmlRealloc( buff->zbuff, new_size );
850 if ( tmp_ptr != NULL ) {
851 rc = 0;
852 buff->size = new_size;
853 buff->zbuff = tmp_ptr;
854 buff->zctrl.next_out = tmp_ptr + cur_used;
855 buff->zctrl.avail_out = new_size - cur_used;
856 }
857 else {
858 xmlGenericError( xmlGenericErrorContext,
859 "xmlZMemBuffExtend: %s %lu bytes.\n",
860 "Allocation failure extending output buffer to",
861 new_size );
862 }
863
864 return ( rc );
865}
866
867/**
868 * xmlZMemBuffAppend
869 * @buff: Buffer used to compress and consolidate data
870 * @src: Uncompressed source content to append to buffer
871 * @len: Length of source data to append to buffer
872 *
873 * Compress and append data to the internal buffer. The data buffer
874 * will be expanded if needed to store the additional data.
875 *
876 * Returns the number of bytes appended to the buffer or -1 on error.
877 */
878static int
879xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) {
880
881 int z_err;
882 size_t min_accept;
883
884 if ( ( buff == NULL ) || ( src == NULL ) )
885 return ( -1 );
886
887 buff->zctrl.avail_in = len;
888 buff->zctrl.next_in = (unsigned char *)src;
889 while ( buff->zctrl.avail_in > 0 ) {
890 /*
891 ** Extend the buffer prior to deflate call if a reasonable amount
892 ** of output buffer space is not available.
893 */
894 min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO;
895 if ( buff->zctrl.avail_out <= min_accept ) {
896 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
897 return ( -1 );
898 }
899
900 z_err = deflate( &buff->zctrl, Z_NO_FLUSH );
901 if ( z_err != Z_OK ) {
902 xmlGenericError( xmlGenericErrorContext,
903 "xmlZMemBuffAppend: %s %d %s - %d",
904 "Compression error while appending",
905 len, "bytes to buffer. ZLIB error", z_err );
906 return ( -1 );
907 }
908 }
909
910 buff->crc = crc32( buff->crc, (unsigned char *)src, len );
911
912 return ( len );
913}
914
915/**
916 * xmlZMemBuffGetContent
917 * @buff: Compressed memory content buffer
918 * @data_ref: Pointer reference to point to compressed content
919 *
920 * Flushes the compression buffers, appends gzip file trailers and
921 * returns the compressed content and length of the compressed data.
922 * NOTE: The gzip trailer code here is plagiarized from zlib source.
923 *
924 * Returns the length of the compressed data or -1 on error.
925 */
926static int
927xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) {
928
929 int zlgth = -1;
930 int z_err;
931
932 if ( ( buff == NULL ) || ( data_ref == NULL ) )
933 return ( -1 );
934
935 /* Need to loop until compression output buffers are flushed */
936
937 do
938 {
939 z_err = deflate( &buff->zctrl, Z_FINISH );
940 if ( z_err == Z_OK ) {
941 /* In this case Z_OK means more buffer space needed */
942
943 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
944 return ( -1 );
945 }
946 }
947 while ( z_err == Z_OK );
948
949 /* If the compression state is not Z_STREAM_END, some error occurred */
950
951 if ( z_err == Z_STREAM_END ) {
952
953 /* Need to append the gzip data trailer */
954
955 if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) {
956 if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 )
957 return ( -1 );
958 }
959
960 /*
961 ** For whatever reason, the CRC and length data are pushed out
962 ** in reverse byte order. So a memcpy can't be used here.
963 */
964
965 append_reverse_ulong( buff, buff->crc );
966 append_reverse_ulong( buff, buff->zctrl.total_in );
967
968 zlgth = buff->zctrl.next_out - buff->zbuff;
969 *data_ref = (char *)buff->zbuff;
970 }
971
972 else
973 xmlGenericError( xmlGenericErrorContext,
974 "xmlZMemBuffGetContent: %s - %d\n",
975 "Error flushing zlib buffers. Error code", z_err );
976
977 return ( zlgth );
978}
979#endif /* HAVE_ZLIB_H */
980
981/**
982 * xmlFreeHTTPWriteCtxt
983 * @ctxt: Context to cleanup
984 *
985 * Free allocated memory and reclaim system resources.
986 *
987 * No return value.
988 */
989static void
990xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt )
991{
992 if ( ctxt->uri != NULL )
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000993 xmlFree( ctxt->uri );
Daniel Veillardf012a642001-07-23 19:10:52 +0000994
995 if ( ctxt->doc_buff != NULL ) {
996
997#ifdef HAVE_ZLIB_H
998 if ( ctxt->compression > 0 ) {
999 xmlFreeZMemBuff( ctxt->doc_buff );
1000 }
1001 else
1002#endif
1003 {
1004 xmlOutputBufferClose( ctxt->doc_buff );
1005 }
1006 }
1007
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001008 xmlFree( ctxt );
Daniel Veillardf012a642001-07-23 19:10:52 +00001009 return;
1010}
1011
1012
Owen Taylor3473f882001-02-23 17:55:21 +00001013/**
1014 * xmlIOHTTPMatch:
1015 * @filename: the URI for matching
1016 *
1017 * check if the URI matches an HTTP one
1018 *
1019 * Returns 1 if matches, 0 otherwise
1020 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001021int
Owen Taylor3473f882001-02-23 17:55:21 +00001022xmlIOHTTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001023 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "http://", 7))
Owen Taylor3473f882001-02-23 17:55:21 +00001024 return(1);
1025 return(0);
1026}
1027
1028/**
1029 * xmlIOHTTPOpen:
1030 * @filename: the URI for matching
1031 *
1032 * open an HTTP I/O channel
1033 *
1034 * Returns an I/O context or NULL in case of error
1035 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001036void *
Owen Taylor3473f882001-02-23 17:55:21 +00001037xmlIOHTTPOpen (const char *filename) {
1038 return(xmlNanoHTTPOpen(filename, NULL));
1039}
1040
1041/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001042 * xmlIOHTTPOpenW:
Daniel Veillardf012a642001-07-23 19:10:52 +00001043 * @post_uri: The destination URI for the document
1044 * @compression: The compression desired for the document.
1045 *
1046 * Open a temporary buffer to collect the document for a subsequent HTTP POST
1047 * request. Non-static as is called from the output buffer creation routine.
1048 *
1049 * Returns an I/O context or NULL in case of error.
1050 */
1051
1052void *
Daniel Veillard572577e2002-01-18 16:23:55 +00001053xmlIOHTTPOpenW(const char *post_uri, int compression)
1054{
Daniel Veillardf012a642001-07-23 19:10:52 +00001055
Daniel Veillard572577e2002-01-18 16:23:55 +00001056 xmlIOHTTPWriteCtxtPtr ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001057
Daniel Veillard572577e2002-01-18 16:23:55 +00001058 if (post_uri == NULL)
1059 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001060
Daniel Veillard572577e2002-01-18 16:23:55 +00001061 ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt));
1062 if (ctxt == NULL) {
1063 xmlGenericError(xmlGenericErrorContext,
1064 "xmlIOHTTPOpenW: Failed to create output HTTP context.\n");
1065 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001066 }
1067
Daniel Veillard572577e2002-01-18 16:23:55 +00001068 (void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt));
Daniel Veillardf012a642001-07-23 19:10:52 +00001069
Daniel Veillard572577e2002-01-18 16:23:55 +00001070 ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri);
1071 if (ctxt->uri == NULL) {
1072 xmlGenericError(xmlGenericErrorContext,
1073 "xmlIOHTTPOpenW: Failed to duplicate destination URI.\n");
1074 xmlFreeHTTPWriteCtxt(ctxt);
1075 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001076 }
1077
1078 /*
Daniel Veillard572577e2002-01-18 16:23:55 +00001079 * ** Since the document length is required for an HTTP post,
1080 * ** need to put the document into a buffer. A memory buffer
1081 * ** is being used to avoid pushing the data to disk and back.
1082 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001083
1084#ifdef HAVE_ZLIB_H
Daniel Veillard572577e2002-01-18 16:23:55 +00001085 if ((compression > 0) && (compression <= 9)) {
1086
1087 ctxt->compression = compression;
1088 ctxt->doc_buff = xmlCreateZMemBuff(compression);
1089 } else
Daniel Veillardf012a642001-07-23 19:10:52 +00001090#endif
1091 {
Daniel Veillard572577e2002-01-18 16:23:55 +00001092 /* Any character conversions should have been done before this */
Daniel Veillardf012a642001-07-23 19:10:52 +00001093
Daniel Veillard572577e2002-01-18 16:23:55 +00001094 ctxt->doc_buff = xmlAllocOutputBuffer(NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001095 }
1096
Daniel Veillard572577e2002-01-18 16:23:55 +00001097 if (ctxt->doc_buff == NULL) {
1098 xmlFreeHTTPWriteCtxt(ctxt);
1099 ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001100 }
1101
Daniel Veillard572577e2002-01-18 16:23:55 +00001102 return (ctxt);
Daniel Veillardf012a642001-07-23 19:10:52 +00001103}
1104
1105/**
1106 * xmlIOHTTPDfltOpenW
1107 * @post_uri: The destination URI for this document.
1108 *
1109 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
1110 * HTTP post command. This function should generally not be used as
1111 * the open callback is short circuited in xmlOutputBufferCreateFile.
1112 *
1113 * Returns a pointer to the new IO context.
1114 */
1115static void *
1116xmlIOHTTPDfltOpenW( const char * post_uri ) {
1117 return ( xmlIOHTTPOpenW( post_uri, 0 ) );
1118}
1119
1120/**
Owen Taylor3473f882001-02-23 17:55:21 +00001121 * xmlIOHTTPRead:
1122 * @context: the I/O context
1123 * @buffer: where to drop data
1124 * @len: number of bytes to write
1125 *
1126 * Read @len bytes to @buffer from the I/O channel.
1127 *
1128 * Returns the number of bytes written
1129 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001130int
Owen Taylor3473f882001-02-23 17:55:21 +00001131xmlIOHTTPRead(void * context, char * buffer, int len) {
1132 return(xmlNanoHTTPRead(context, &buffer[0], len));
1133}
1134
1135/**
Daniel Veillardf012a642001-07-23 19:10:52 +00001136 * xmlIOHTTPWrite
1137 * @context: previously opened writing context
1138 * @buffer: data to output to temporary buffer
1139 * @len: bytes to output
1140 *
1141 * Collect data from memory buffer into a temporary file for later
1142 * processing.
1143 *
1144 * Returns number of bytes written.
1145 */
1146
1147static int
1148xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
1149
1150 xmlIOHTTPWriteCtxtPtr ctxt = context;
1151
1152 if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
1153 return ( -1 );
1154
1155 if ( len > 0 ) {
1156
1157 /* Use gzwrite or fwrite as previously setup in the open call */
1158
1159#ifdef HAVE_ZLIB_H
1160 if ( ctxt->compression > 0 )
1161 len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len );
1162
1163 else
1164#endif
1165 len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
1166
1167 if ( len < 0 ) {
1168 xmlGenericError( xmlGenericErrorContext,
1169 "xmlIOHTTPWrite: %s\n%s '%s'.\n",
1170 "Error appending to internal buffer.",
1171 "Error sending document to URI",
1172 ctxt->uri );
1173 }
1174 }
1175
1176 return ( len );
1177}
1178
1179
1180/**
Owen Taylor3473f882001-02-23 17:55:21 +00001181 * xmlIOHTTPClose:
1182 * @context: the I/O context
1183 *
1184 * Close an HTTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001185 *
1186 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00001187 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001188int
Owen Taylor3473f882001-02-23 17:55:21 +00001189xmlIOHTTPClose (void * context) {
1190 xmlNanoHTTPClose(context);
Daniel Veillardf012a642001-07-23 19:10:52 +00001191 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001192}
Daniel Veillardf012a642001-07-23 19:10:52 +00001193
1194/**
1195 * xmlIOHTTCloseWrite
1196 * @context: The I/O context
1197 * @http_mthd: The HTTP method to be used when sending the data
1198 *
1199 * Close the transmit HTTP I/O channel and actually send the data.
1200 */
1201static int
1202xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
1203
1204 int close_rc = -1;
1205 int http_rtn = 0;
1206 int content_lgth = 0;
1207 xmlIOHTTPWriteCtxtPtr ctxt = context;
1208
1209 char * http_content = NULL;
1210 char * content_encoding = NULL;
1211 char * content_type = (char *) "text/xml";
1212 void * http_ctxt = NULL;
1213
1214 if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
1215 return ( -1 );
1216
1217 /* Retrieve the content from the appropriate buffer */
1218
1219#ifdef HAVE_ZLIB_H
1220
1221 if ( ctxt->compression > 0 ) {
1222 content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
1223 content_encoding = (char *) "Content-Encoding: gzip";
1224 }
1225 else
1226#endif
1227 {
1228 /* Pull the data out of the memory output buffer */
1229
1230 xmlOutputBufferPtr dctxt = ctxt->doc_buff;
1231 http_content = (char *)dctxt->buffer->content;
1232 content_lgth = dctxt->buffer->use;
1233 }
1234
1235 if ( http_content == NULL ) {
1236 xmlGenericError( xmlGenericErrorContext,
1237 "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
1238 "Error retrieving content.\nUnable to",
1239 http_mthd, "data to URI", ctxt->uri );
1240 }
1241
1242 else {
1243
1244 http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
1245 &content_type, content_encoding,
1246 content_lgth );
1247
1248 if ( http_ctxt != NULL ) {
1249#ifdef DEBUG_HTTP
1250 /* If testing/debugging - dump reply with request content */
1251
1252 FILE * tst_file = NULL;
1253 char buffer[ 4096 ];
1254 char * dump_name = NULL;
1255 int avail;
1256
1257 xmlGenericError( xmlGenericErrorContext,
1258 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
1259 http_mthd, ctxt->uri,
1260 xmlNanoHTTPReturnCode( http_ctxt ) );
1261
1262 /*
1263 ** Since either content or reply may be gzipped,
1264 ** dump them to separate files instead of the
1265 ** standard error context.
1266 */
1267
1268 dump_name = tempnam( NULL, "lxml" );
1269 if ( dump_name != NULL ) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001270 (void)snprintf( buffer, sizeof(buffer), "%s.content", dump_name );
Daniel Veillardf012a642001-07-23 19:10:52 +00001271
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00001272 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00001273 if ( tst_file != NULL ) {
1274 xmlGenericError( xmlGenericErrorContext,
1275 "Transmitted content saved in file: %s\n", buffer );
1276
1277 fwrite( http_content, sizeof( char ),
1278 content_lgth, tst_file );
1279 fclose( tst_file );
1280 }
1281
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001282 (void)snprintf( buffer, sizeof(buffer), "%s.reply", dump_name );
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00001283 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00001284 if ( tst_file != NULL ) {
1285 xmlGenericError( xmlGenericErrorContext,
1286 "Reply content saved in file: %s\n", buffer );
1287
1288
1289 while ( (avail = xmlNanoHTTPRead( http_ctxt,
1290 buffer, sizeof( buffer ) )) > 0 ) {
1291
1292 fwrite( buffer, sizeof( char ), avail, tst_file );
1293 }
1294
1295 fclose( tst_file );
1296 }
1297
1298 free( dump_name );
1299 }
1300#endif /* DEBUG_HTTP */
1301
1302 http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
1303 if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
1304 close_rc = 0;
1305 else
1306 xmlGenericError( xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001307 "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001308 http_mthd, content_lgth,
1309 "bytes to URI", ctxt->uri,
1310 "failed. HTTP return code:", http_rtn );
1311
1312 xmlNanoHTTPClose( http_ctxt );
1313 xmlFree( content_type );
1314 }
1315 }
1316
1317 /* Final cleanups */
1318
1319 xmlFreeHTTPWriteCtxt( ctxt );
1320
1321 return ( close_rc );
1322}
1323
1324/**
1325 * xmlIOHTTPClosePut
1326 *
1327 * @context: The I/O context
1328 *
1329 * Close the transmit HTTP I/O channel and actually send data using a PUT
1330 * HTTP method.
1331 */
1332static int
1333xmlIOHTTPClosePut( void * ctxt ) {
1334 return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
1335}
1336
1337
1338/**
1339 * xmlIOHTTPClosePost
1340 *
1341 * @context: The I/O context
1342 *
1343 * Close the transmit HTTP I/O channel and actually send data using a POST
1344 * HTTP method.
1345 */
1346static int
1347xmlIOHTTPClosePost( void * ctxt ) {
1348 return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
1349}
1350
Owen Taylor3473f882001-02-23 17:55:21 +00001351#endif /* LIBXML_HTTP_ENABLED */
1352
1353#ifdef LIBXML_FTP_ENABLED
1354/************************************************************************
1355 * *
1356 * I/O for FTP file accesses *
1357 * *
1358 ************************************************************************/
1359/**
1360 * xmlIOFTPMatch:
1361 * @filename: the URI for matching
1362 *
1363 * check if the URI matches an FTP one
1364 *
1365 * Returns 1 if matches, 0 otherwise
1366 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001367int
Owen Taylor3473f882001-02-23 17:55:21 +00001368xmlIOFTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001369 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "ftp://", 6))
Owen Taylor3473f882001-02-23 17:55:21 +00001370 return(1);
1371 return(0);
1372}
1373
1374/**
1375 * xmlIOFTPOpen:
1376 * @filename: the URI for matching
1377 *
1378 * open an FTP I/O channel
1379 *
1380 * Returns an I/O context or NULL in case of error
1381 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001382void *
Owen Taylor3473f882001-02-23 17:55:21 +00001383xmlIOFTPOpen (const char *filename) {
1384 return(xmlNanoFTPOpen(filename));
1385}
1386
1387/**
1388 * xmlIOFTPRead:
1389 * @context: the I/O context
1390 * @buffer: where to drop data
1391 * @len: number of bytes to write
1392 *
1393 * Read @len bytes to @buffer from the I/O channel.
1394 *
1395 * Returns the number of bytes written
1396 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001397int
Owen Taylor3473f882001-02-23 17:55:21 +00001398xmlIOFTPRead(void * context, char * buffer, int len) {
1399 return(xmlNanoFTPRead(context, &buffer[0], len));
1400}
1401
1402/**
1403 * xmlIOFTPClose:
1404 * @context: the I/O context
1405 *
1406 * Close an FTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001407 *
1408 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00001409 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001410int
Owen Taylor3473f882001-02-23 17:55:21 +00001411xmlIOFTPClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001412 return ( xmlNanoFTPClose(context) );
Owen Taylor3473f882001-02-23 17:55:21 +00001413}
1414#endif /* LIBXML_FTP_ENABLED */
1415
1416
1417/**
1418 * xmlRegisterInputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001419 * @matchFunc: the xmlInputMatchCallback
1420 * @openFunc: the xmlInputOpenCallback
1421 * @readFunc: the xmlInputReadCallback
1422 * @closeFunc: the xmlInputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001423 *
1424 * Register a new set of I/O callback for handling parser input.
1425 *
1426 * Returns the registered handler number or -1 in case of error
1427 */
1428int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001429xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
1430 xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
1431 xmlInputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001432 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
1433 return(-1);
1434 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001435 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
1436 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
1437 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
1438 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
Owen Taylor3473f882001-02-23 17:55:21 +00001439 return(xmlInputCallbackNr++);
1440}
1441
1442/**
1443 * xmlRegisterOutputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001444 * @matchFunc: the xmlOutputMatchCallback
1445 * @openFunc: the xmlOutputOpenCallback
1446 * @writeFunc: the xmlOutputWriteCallback
1447 * @closeFunc: the xmlOutputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001448 *
1449 * Register a new set of I/O callback for handling output.
1450 *
1451 * Returns the registered handler number or -1 in case of error
1452 */
1453int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001454xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
1455 xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
1456 xmlOutputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001457 if (xmlOutputCallbackNr >= MAX_INPUT_CALLBACK) {
1458 return(-1);
1459 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001460 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
1461 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
1462 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
1463 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
Owen Taylor3473f882001-02-23 17:55:21 +00001464 return(xmlOutputCallbackNr++);
1465}
1466
1467/**
1468 * xmlRegisterDefaultInputCallbacks:
1469 *
1470 * Registers the default compiled-in I/O handlers.
1471 */
1472void
Owen Taylor3473f882001-02-23 17:55:21 +00001473xmlRegisterDefaultInputCallbacks
Owen Taylor3473f882001-02-23 17:55:21 +00001474(void) {
1475 if (xmlInputCallbackInitialized)
1476 return;
1477
1478 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
1479 xmlFileRead, xmlFileClose);
1480#ifdef HAVE_ZLIB_H
1481 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1482 xmlGzfileRead, xmlGzfileClose);
1483#endif /* HAVE_ZLIB_H */
1484
1485#ifdef LIBXML_HTTP_ENABLED
1486 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
1487 xmlIOHTTPRead, xmlIOHTTPClose);
1488#endif /* LIBXML_HTTP_ENABLED */
1489
1490#ifdef LIBXML_FTP_ENABLED
1491 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1492 xmlIOFTPRead, xmlIOFTPClose);
1493#endif /* LIBXML_FTP_ENABLED */
1494 xmlInputCallbackInitialized = 1;
1495}
1496
1497/**
1498 * xmlRegisterDefaultOutputCallbacks:
1499 *
1500 * Registers the default compiled-in I/O handlers.
1501 */
1502void
Owen Taylor3473f882001-02-23 17:55:21 +00001503xmlRegisterDefaultOutputCallbacks
Owen Taylor3473f882001-02-23 17:55:21 +00001504(void) {
1505 if (xmlOutputCallbackInitialized)
1506 return;
1507
1508 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
1509 xmlFileWrite, xmlFileClose);
Daniel Veillardf012a642001-07-23 19:10:52 +00001510
1511#ifdef LIBXML_HTTP_ENABLED
1512 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
1513 xmlIOHTTPWrite, xmlIOHTTPClosePut);
1514#endif
1515
Owen Taylor3473f882001-02-23 17:55:21 +00001516/*********************************
1517 No way a-priori to distinguish between gzipped files from
1518 uncompressed ones except opening if existing then closing
1519 and saving with same compression ratio ... a pain.
1520
1521#ifdef HAVE_ZLIB_H
1522 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1523 xmlGzfileWrite, xmlGzfileClose);
1524#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001525
1526 Nor FTP PUT ....
1527#ifdef LIBXML_FTP_ENABLED
1528 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1529 xmlIOFTPWrite, xmlIOFTPClose);
1530#endif
1531 **********************************/
1532 xmlOutputCallbackInitialized = 1;
1533}
1534
Daniel Veillardf012a642001-07-23 19:10:52 +00001535#ifdef LIBXML_HTTP_ENABLED
1536/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001537 * xmlRegisterHTTPPostCallbacks:
Daniel Veillardf012a642001-07-23 19:10:52 +00001538 *
1539 * By default, libxml submits HTTP output requests using the "PUT" method.
1540 * Calling this method changes the HTTP output method to use the "POST"
1541 * method instead.
1542 *
1543 */
1544void
1545xmlRegisterHTTPPostCallbacks( void ) {
1546
1547 /* Register defaults if not done previously */
1548
1549 if ( xmlOutputCallbackInitialized == 0 )
1550 xmlRegisterDefaultOutputCallbacks( );
1551
1552 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
1553 xmlIOHTTPWrite, xmlIOHTTPClosePost);
1554 return;
1555}
1556#endif
1557
Owen Taylor3473f882001-02-23 17:55:21 +00001558/**
1559 * xmlAllocParserInputBuffer:
1560 * @enc: the charset encoding if known
1561 *
1562 * Create a buffered parser input for progressive parsing
1563 *
1564 * Returns the new parser input or NULL
1565 */
1566xmlParserInputBufferPtr
1567xmlAllocParserInputBuffer(xmlCharEncoding enc) {
1568 xmlParserInputBufferPtr ret;
1569
1570 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
1571 if (ret == NULL) {
1572 xmlGenericError(xmlGenericErrorContext,
1573 "xmlAllocParserInputBuffer : out of memory!\n");
1574 return(NULL);
1575 }
1576 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00001577 ret->buffer = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00001578 if (ret->buffer == NULL) {
1579 xmlFree(ret);
1580 return(NULL);
1581 }
1582 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
1583 ret->encoder = xmlGetCharEncodingHandler(enc);
1584 if (ret->encoder != NULL)
Daniel Veillard6155d8a2003-08-19 15:01:28 +00001585 ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00001586 else
1587 ret->raw = NULL;
1588 ret->readcallback = NULL;
1589 ret->closecallback = NULL;
1590 ret->context = NULL;
1591
1592 return(ret);
1593}
1594
1595/**
1596 * xmlAllocOutputBuffer:
1597 * @encoder: the encoding converter or NULL
1598 *
1599 * Create a buffered parser output
1600 *
1601 * Returns the new parser output or NULL
1602 */
1603xmlOutputBufferPtr
1604xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
1605 xmlOutputBufferPtr ret;
1606
1607 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
1608 if (ret == NULL) {
1609 xmlGenericError(xmlGenericErrorContext,
1610 "xmlAllocOutputBuffer : out of memory!\n");
1611 return(NULL);
1612 }
1613 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
1614 ret->buffer = xmlBufferCreate();
1615 if (ret->buffer == NULL) {
1616 xmlFree(ret);
1617 return(NULL);
1618 }
1619 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
1620 ret->encoder = encoder;
1621 if (encoder != NULL) {
1622 ret->conv = xmlBufferCreateSize(4000);
1623 /*
1624 * This call is designed to initiate the encoder state
1625 */
1626 xmlCharEncOutFunc(encoder, ret->conv, NULL);
1627 } else
1628 ret->conv = NULL;
1629 ret->writecallback = NULL;
1630 ret->closecallback = NULL;
1631 ret->context = NULL;
1632 ret->written = 0;
1633
1634 return(ret);
1635}
1636
1637/**
1638 * xmlFreeParserInputBuffer:
1639 * @in: a buffered parser input
1640 *
1641 * Free up the memory used by a buffered parser input
1642 */
1643void
1644xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
1645 if (in->raw) {
1646 xmlBufferFree(in->raw);
1647 in->raw = NULL;
1648 }
1649 if (in->encoder != NULL) {
1650 xmlCharEncCloseFunc(in->encoder);
1651 }
1652 if (in->closecallback != NULL) {
1653 in->closecallback(in->context);
1654 }
1655 if (in->buffer != NULL) {
1656 xmlBufferFree(in->buffer);
1657 in->buffer = NULL;
1658 }
1659
Owen Taylor3473f882001-02-23 17:55:21 +00001660 xmlFree(in);
1661}
1662
1663/**
1664 * xmlOutputBufferClose:
1665 * @out: a buffered output
1666 *
1667 * flushes and close the output I/O channel
1668 * and free up all the associated resources
1669 *
1670 * Returns the number of byte written or -1 in case of error.
1671 */
1672int
1673xmlOutputBufferClose(xmlOutputBufferPtr out) {
1674 int written;
Daniel Veillardf012a642001-07-23 19:10:52 +00001675 int err_rc = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001676
1677 if (out == NULL)
1678 return(-1);
1679 if (out->writecallback != NULL)
1680 xmlOutputBufferFlush(out);
1681 if (out->closecallback != NULL) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001682 err_rc = out->closecallback(out->context);
Owen Taylor3473f882001-02-23 17:55:21 +00001683 }
1684 written = out->written;
1685 if (out->conv) {
1686 xmlBufferFree(out->conv);
1687 out->conv = NULL;
1688 }
1689 if (out->encoder != NULL) {
1690 xmlCharEncCloseFunc(out->encoder);
1691 }
1692 if (out->buffer != NULL) {
1693 xmlBufferFree(out->buffer);
1694 out->buffer = NULL;
1695 }
1696
Owen Taylor3473f882001-02-23 17:55:21 +00001697 xmlFree(out);
Daniel Veillardf012a642001-07-23 19:10:52 +00001698 return( ( err_rc == 0 ) ? written : err_rc );
Owen Taylor3473f882001-02-23 17:55:21 +00001699}
1700
1701/**
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001702 * xmlParserInputBufferCreateFname:
1703 * @URI: a C string containing the URI or filename
1704 * @enc: the charset encoding if known
1705 *
Daniel Veillard5e2dace2001-07-18 19:30:27 +00001706 * Returns the new parser input or NULL
1707 */
1708/**
Owen Taylor3473f882001-02-23 17:55:21 +00001709 * xmlParserInputBufferCreateFilename:
1710 * @URI: a C string containing the URI or filename
1711 * @enc: the charset encoding if known
1712 *
1713 * Create a buffered parser input for the progressive parsing of a file
1714 * If filename is "-' then we use stdin as the input.
1715 * Automatic support for ZLIB/Compress compressed document is provided
1716 * by default if found at compile-time.
1717 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
1718 *
1719 * Returns the new parser input or NULL
1720 */
1721xmlParserInputBufferPtr
Daniel Veillard3e59fc52003-04-18 12:34:58 +00001722xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001723 xmlParserInputBufferPtr ret;
Daniel Veillard388236f2001-07-08 18:35:48 +00001724 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001725 void *context = NULL;
1726
1727 if (xmlInputCallbackInitialized == 0)
1728 xmlRegisterDefaultInputCallbacks();
1729
1730 if (URI == NULL) return(NULL);
1731
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00001732#ifdef LIBXML_CATALOG_ENABLED
1733#endif
1734
Owen Taylor3473f882001-02-23 17:55:21 +00001735 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001736 * Try to find one of the input accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00001737 * Go in reverse to give precedence to user defined handlers.
Daniel Veillard388236f2001-07-08 18:35:48 +00001738 */
1739 if (context == NULL) {
1740 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
1741 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
1742 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00001743 context = xmlInputCallbackTable[i].opencallback(URI);
Daniel Veillard388236f2001-07-08 18:35:48 +00001744 if (context != NULL)
1745 break;
1746 }
Owen Taylor3473f882001-02-23 17:55:21 +00001747 }
1748 }
1749 if (context == NULL) {
1750 return(NULL);
1751 }
1752
1753 /*
1754 * Allocate the Input buffer front-end.
1755 */
1756 ret = xmlAllocParserInputBuffer(enc);
1757 if (ret != NULL) {
1758 ret->context = context;
1759 ret->readcallback = xmlInputCallbackTable[i].readcallback;
1760 ret->closecallback = xmlInputCallbackTable[i].closecallback;
1761 }
1762 return(ret);
1763}
1764
1765/**
1766 * xmlOutputBufferCreateFilename:
1767 * @URI: a C string containing the URI or filename
1768 * @encoder: the encoding converter or NULL
1769 * @compression: the compression ration (0 none, 9 max).
1770 *
1771 * Create a buffered output for the progressive saving of a file
1772 * If filename is "-' then we use stdout as the output.
1773 * Automatic support for ZLIB/Compress compressed document is provided
1774 * by default if found at compile-time.
1775 * TODO: currently if compression is set, the library only support
1776 * writing to a local file.
1777 *
1778 * Returns the new output or NULL
1779 */
1780xmlOutputBufferPtr
1781xmlOutputBufferCreateFilename(const char *URI,
1782 xmlCharEncodingHandlerPtr encoder,
1783 int compression) {
1784 xmlOutputBufferPtr ret;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001785 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001786 void *context = NULL;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001787 char *unescaped;
Owen Taylor3473f882001-02-23 17:55:21 +00001788
Daniel Veillardf012a642001-07-23 19:10:52 +00001789 int is_http_uri = 0; /* Can't change if HTTP disabled */
1790
Owen Taylor3473f882001-02-23 17:55:21 +00001791 if (xmlOutputCallbackInitialized == 0)
1792 xmlRegisterDefaultOutputCallbacks();
1793
1794 if (URI == NULL) return(NULL);
1795
Daniel Veillardf012a642001-07-23 19:10:52 +00001796#ifdef LIBXML_HTTP_ENABLED
1797 /* Need to prevent HTTP URI's from falling into zlib short circuit */
1798
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00001799 is_http_uri = xmlIOHTTPMatch( URI );
Daniel Veillardf012a642001-07-23 19:10:52 +00001800#endif
1801
Owen Taylor3473f882001-02-23 17:55:21 +00001802
1803 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001804 * Try to find one of the output accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00001805 * Go in reverse to give precedence to user defined handlers.
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001806 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00001807 */
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00001808 unescaped = xmlURIUnescapeString(URI, 0, NULL);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001809 if (unescaped != NULL) {
1810#ifdef HAVE_ZLIB_H
1811 if ((compression > 0) && (compression <= 9) && (is_http_uri == 0)) {
1812 context = xmlGzfileOpenW(unescaped, compression);
1813 if (context != NULL) {
1814 ret = xmlAllocOutputBuffer(encoder);
1815 if (ret != NULL) {
1816 ret->context = context;
1817 ret->writecallback = xmlGzfileWrite;
1818 ret->closecallback = xmlGzfileClose;
1819 }
1820 xmlFree(unescaped);
1821 return(ret);
1822 }
1823 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001824#endif
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001825 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
1826 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
1827 (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
1828#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
1829 /* Need to pass compression parameter into HTTP open calls */
1830 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
1831 context = xmlIOHTTPOpenW(unescaped, compression);
1832 else
1833#endif
1834 context = xmlOutputCallbackTable[i].opencallback(unescaped);
1835 if (context != NULL)
1836 break;
1837 }
1838 }
1839 xmlFree(unescaped);
1840 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001841
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001842 /*
1843 * If this failed try with a non-escaped URI this may be a strange
1844 * filename
1845 */
1846 if (context == NULL) {
1847#ifdef HAVE_ZLIB_H
1848 if ((compression > 0) && (compression <= 9) && (is_http_uri == 0)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00001849 context = xmlGzfileOpenW(URI, compression);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001850 if (context != NULL) {
1851 ret = xmlAllocOutputBuffer(encoder);
1852 if (ret != NULL) {
1853 ret->context = context;
1854 ret->writecallback = xmlGzfileWrite;
1855 ret->closecallback = xmlGzfileClose;
1856 }
1857 return(ret);
1858 }
1859 }
1860#endif
1861 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
1862 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00001863 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001864#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
1865 /* Need to pass compression parameter into HTTP open calls */
1866 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
1867 context = xmlIOHTTPOpenW(URI, compression);
1868 else
1869#endif
1870 context = xmlOutputCallbackTable[i].opencallback(URI);
1871 if (context != NULL)
1872 break;
1873 }
Owen Taylor3473f882001-02-23 17:55:21 +00001874 }
1875 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001876
Owen Taylor3473f882001-02-23 17:55:21 +00001877 if (context == NULL) {
1878 return(NULL);
1879 }
1880
1881 /*
1882 * Allocate the Output buffer front-end.
1883 */
1884 ret = xmlAllocOutputBuffer(encoder);
1885 if (ret != NULL) {
1886 ret->context = context;
1887 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
1888 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
1889 }
1890 return(ret);
1891}
1892
1893/**
1894 * xmlParserInputBufferCreateFile:
1895 * @file: a FILE*
1896 * @enc: the charset encoding if known
1897 *
1898 * Create a buffered parser input for the progressive parsing of a FILE *
1899 * buffered C I/O
1900 *
1901 * Returns the new parser input or NULL
1902 */
1903xmlParserInputBufferPtr
1904xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
1905 xmlParserInputBufferPtr ret;
1906
1907 if (xmlInputCallbackInitialized == 0)
1908 xmlRegisterDefaultInputCallbacks();
1909
1910 if (file == NULL) return(NULL);
1911
1912 ret = xmlAllocParserInputBuffer(enc);
1913 if (ret != NULL) {
1914 ret->context = file;
1915 ret->readcallback = xmlFileRead;
1916 ret->closecallback = xmlFileFlush;
1917 }
1918
1919 return(ret);
1920}
1921
1922/**
1923 * xmlOutputBufferCreateFile:
1924 * @file: a FILE*
1925 * @encoder: the encoding converter or NULL
1926 *
1927 * Create a buffered output for the progressive saving to a FILE *
1928 * buffered C I/O
1929 *
1930 * Returns the new parser output or NULL
1931 */
1932xmlOutputBufferPtr
1933xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
1934 xmlOutputBufferPtr ret;
1935
1936 if (xmlOutputCallbackInitialized == 0)
1937 xmlRegisterDefaultOutputCallbacks();
1938
1939 if (file == NULL) return(NULL);
1940
1941 ret = xmlAllocOutputBuffer(encoder);
1942 if (ret != NULL) {
1943 ret->context = file;
1944 ret->writecallback = xmlFileWrite;
1945 ret->closecallback = xmlFileFlush;
1946 }
1947
1948 return(ret);
1949}
1950
1951/**
1952 * xmlParserInputBufferCreateFd:
1953 * @fd: a file descriptor number
1954 * @enc: the charset encoding if known
1955 *
1956 * Create a buffered parser input for the progressive parsing for the input
1957 * from a file descriptor
1958 *
1959 * Returns the new parser input or NULL
1960 */
1961xmlParserInputBufferPtr
1962xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
1963 xmlParserInputBufferPtr ret;
1964
1965 if (fd < 0) return(NULL);
1966
1967 ret = xmlAllocParserInputBuffer(enc);
1968 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00001969 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00001970 ret->readcallback = xmlFdRead;
1971 ret->closecallback = xmlFdClose;
1972 }
1973
1974 return(ret);
1975}
1976
1977/**
1978 * xmlParserInputBufferCreateMem:
1979 * @mem: the memory input
1980 * @size: the length of the memory block
1981 * @enc: the charset encoding if known
1982 *
1983 * Create a buffered parser input for the progressive parsing for the input
1984 * from a memory area.
1985 *
1986 * Returns the new parser input or NULL
1987 */
1988xmlParserInputBufferPtr
1989xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
1990 xmlParserInputBufferPtr ret;
1991
1992 if (size <= 0) return(NULL);
1993 if (mem == NULL) return(NULL);
1994
1995 ret = xmlAllocParserInputBuffer(enc);
1996 if (ret != NULL) {
1997 ret->context = (void *) mem;
1998 ret->readcallback = (xmlInputReadCallback) xmlNop;
1999 ret->closecallback = NULL;
2000 xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size);
2001 }
2002
2003 return(ret);
2004}
2005
2006/**
2007 * xmlOutputBufferCreateFd:
2008 * @fd: a file descriptor number
2009 * @encoder: the encoding converter or NULL
2010 *
2011 * Create a buffered output for the progressive saving
2012 * to a file descriptor
2013 *
2014 * Returns the new parser output or NULL
2015 */
2016xmlOutputBufferPtr
2017xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
2018 xmlOutputBufferPtr ret;
2019
2020 if (fd < 0) return(NULL);
2021
2022 ret = xmlAllocOutputBuffer(encoder);
2023 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002024 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002025 ret->writecallback = xmlFdWrite;
Daniel Veillard7db38712002-02-07 16:39:11 +00002026 ret->closecallback = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002027 }
2028
2029 return(ret);
2030}
2031
2032/**
2033 * xmlParserInputBufferCreateIO:
2034 * @ioread: an I/O read function
2035 * @ioclose: an I/O close function
2036 * @ioctx: an I/O handler
2037 * @enc: the charset encoding if known
2038 *
2039 * Create a buffered parser input for the progressive parsing for the input
2040 * from an I/O handler
2041 *
2042 * Returns the new parser input or NULL
2043 */
2044xmlParserInputBufferPtr
2045xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
2046 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
2047 xmlParserInputBufferPtr ret;
2048
2049 if (ioread == NULL) return(NULL);
2050
2051 ret = xmlAllocParserInputBuffer(enc);
2052 if (ret != NULL) {
2053 ret->context = (void *) ioctx;
2054 ret->readcallback = ioread;
2055 ret->closecallback = ioclose;
2056 }
2057
2058 return(ret);
2059}
2060
2061/**
2062 * xmlOutputBufferCreateIO:
2063 * @iowrite: an I/O write function
2064 * @ioclose: an I/O close function
2065 * @ioctx: an I/O handler
Daniel Veillard9d06d302002-01-22 18:15:52 +00002066 * @encoder: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002067 *
2068 * Create a buffered output for the progressive saving
2069 * to an I/O handler
2070 *
2071 * Returns the new parser output or NULL
2072 */
2073xmlOutputBufferPtr
2074xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
2075 xmlOutputCloseCallback ioclose, void *ioctx,
2076 xmlCharEncodingHandlerPtr encoder) {
2077 xmlOutputBufferPtr ret;
2078
2079 if (iowrite == NULL) return(NULL);
2080
2081 ret = xmlAllocOutputBuffer(encoder);
2082 if (ret != NULL) {
2083 ret->context = (void *) ioctx;
2084 ret->writecallback = iowrite;
2085 ret->closecallback = ioclose;
2086 }
2087
2088 return(ret);
2089}
2090
2091/**
2092 * xmlParserInputBufferPush:
2093 * @in: a buffered parser input
2094 * @len: the size in bytes of the array.
2095 * @buf: an char array
2096 *
2097 * Push the content of the arry in the input buffer
2098 * This routine handle the I18N transcoding to internal UTF-8
2099 * This is used when operating the parser in progressive (push) mode.
2100 *
2101 * Returns the number of chars read and stored in the buffer, or -1
2102 * in case of error.
2103 */
2104int
2105xmlParserInputBufferPush(xmlParserInputBufferPtr in,
2106 int len, const char *buf) {
2107 int nbchars = 0;
2108
2109 if (len < 0) return(0);
2110 if (in->encoder != NULL) {
2111 /*
2112 * Store the data in the incoming raw buffer
2113 */
2114 if (in->raw == NULL) {
2115 in->raw = xmlBufferCreate();
2116 }
2117 xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
2118
2119 /*
2120 * convert as much as possible to the parser reading buffer.
2121 */
2122 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2123 if (nbchars < 0) {
2124 xmlGenericError(xmlGenericErrorContext,
2125 "xmlParserInputBufferPush: encoder error\n");
2126 return(-1);
2127 }
2128 } else {
2129 nbchars = len;
2130 xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
2131 }
2132#ifdef DEBUG_INPUT
2133 xmlGenericError(xmlGenericErrorContext,
2134 "I/O: pushed %d chars, buffer %d/%d\n",
2135 nbchars, in->buffer->use, in->buffer->size);
2136#endif
2137 return(nbchars);
2138}
2139
2140/**
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002141 * endOfInput:
2142 *
2143 * When reading from an Input channel indicated end of file or error
2144 * don't reread from it again.
2145 */
2146static int
2147endOfInput (void * context ATTRIBUTE_UNUSED,
2148 char * buffer ATTRIBUTE_UNUSED,
2149 int len ATTRIBUTE_UNUSED) {
2150 return(0);
2151}
2152
2153/**
Owen Taylor3473f882001-02-23 17:55:21 +00002154 * xmlParserInputBufferGrow:
2155 * @in: a buffered parser input
2156 * @len: indicative value of the amount of chars to read
2157 *
2158 * Grow up the content of the input buffer, the old data are preserved
2159 * This routine handle the I18N transcoding to internal UTF-8
2160 * This routine is used when operating the parser in normal (pull) mode
2161 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002162 * TODO: one should be able to remove one extra copy by copying directly
Owen Taylor3473f882001-02-23 17:55:21 +00002163 * onto in->buffer or in->raw
2164 *
2165 * Returns the number of chars read and stored in the buffer, or -1
2166 * in case of error.
2167 */
2168int
2169xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
2170 char *buffer = NULL;
2171 int res = 0;
2172 int nbchars = 0;
2173 int buffree;
Daniel Veillard9e412302002-06-10 15:59:44 +00002174 unsigned int needSize;
Owen Taylor3473f882001-02-23 17:55:21 +00002175
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002176 if ((len <= MINLEN) && (len != 4))
Owen Taylor3473f882001-02-23 17:55:21 +00002177 len = MINLEN;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002178
Owen Taylor3473f882001-02-23 17:55:21 +00002179 buffree = in->buffer->size - in->buffer->use;
2180 if (buffree <= 0) {
2181 xmlGenericError(xmlGenericErrorContext,
2182 "xmlParserInputBufferGrow : buffer full !\n");
2183 return(0);
2184 }
Owen Taylor3473f882001-02-23 17:55:21 +00002185
Daniel Veillarde5354492002-05-16 08:43:22 +00002186 needSize = in->buffer->use + len + 1;
2187 if (needSize > in->buffer->size){
2188 if (!xmlBufferResize(in->buffer, needSize)){
2189 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard8caa9c22003-06-02 13:35:24 +00002190 "xmlParserInputBufferGrow : out of memory!\n");
Daniel Veillarde5354492002-05-16 08:43:22 +00002191 return(0);
2192 }
Owen Taylor3473f882001-02-23 17:55:21 +00002193 }
Daniel Veillarde5354492002-05-16 08:43:22 +00002194 buffer = (char *)&in->buffer->content[in->buffer->use];
Owen Taylor3473f882001-02-23 17:55:21 +00002195
2196 /*
2197 * Call the read method for this I/O type.
2198 */
2199 if (in->readcallback != NULL) {
2200 res = in->readcallback(in->context, &buffer[0], len);
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002201 if (res <= 0)
2202 in->readcallback = endOfInput;
Owen Taylor3473f882001-02-23 17:55:21 +00002203 } else {
2204 xmlGenericError(xmlGenericErrorContext,
2205 "xmlParserInputBufferGrow : no input !\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002206 return(-1);
2207 }
2208 if (res < 0) {
Owen Taylor3473f882001-02-23 17:55:21 +00002209 return(-1);
2210 }
2211 len = res;
2212 if (in->encoder != NULL) {
2213 /*
2214 * Store the data in the incoming raw buffer
2215 */
2216 if (in->raw == NULL) {
2217 in->raw = xmlBufferCreate();
2218 }
2219 xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
2220
2221 /*
2222 * convert as much as possible to the parser reading buffer.
2223 */
2224 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2225 if (nbchars < 0) {
2226 xmlGenericError(xmlGenericErrorContext,
2227 "xmlParserInputBufferGrow: encoder error\n");
2228 return(-1);
2229 }
2230 } else {
2231 nbchars = len;
Daniel Veillarde5354492002-05-16 08:43:22 +00002232 in->buffer->use += nbchars;
2233 buffer[nbchars] = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002234 }
2235#ifdef DEBUG_INPUT
2236 xmlGenericError(xmlGenericErrorContext,
2237 "I/O: read %d chars, buffer %d/%d\n",
2238 nbchars, in->buffer->use, in->buffer->size);
2239#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002240 return(nbchars);
2241}
2242
2243/**
2244 * xmlParserInputBufferRead:
2245 * @in: a buffered parser input
2246 * @len: indicative value of the amount of chars to read
2247 *
2248 * Refresh the content of the input buffer, the old data are considered
2249 * consumed
2250 * This routine handle the I18N transcoding to internal UTF-8
2251 *
2252 * Returns the number of chars read and stored in the buffer, or -1
2253 * in case of error.
2254 */
2255int
2256xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
2257 /* xmlBufferEmpty(in->buffer); */
2258 if (in->readcallback != NULL)
2259 return(xmlParserInputBufferGrow(in, len));
2260 else
2261 return(-1);
2262}
2263
2264/**
2265 * xmlOutputBufferWrite:
2266 * @out: a buffered parser output
2267 * @len: the size in bytes of the array.
2268 * @buf: an char array
2269 *
2270 * Write the content of the array in the output I/O buffer
2271 * This routine handle the I18N transcoding from internal UTF-8
2272 * The buffer is lossless, i.e. will store in case of partial
2273 * or delayed writes.
2274 *
2275 * Returns the number of chars immediately written, or -1
2276 * in case of error.
2277 */
2278int
2279xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
2280 int nbchars = 0; /* number of chars to output to I/O */
2281 int ret; /* return from function call */
2282 int written = 0; /* number of char written to I/O so far */
2283 int chunk; /* number of byte curreent processed from buf */
2284
2285 if (len < 0) return(0);
2286
2287 do {
2288 chunk = len;
2289 if (chunk > 4 * MINLEN)
2290 chunk = 4 * MINLEN;
2291
2292 /*
2293 * first handle encoding stuff.
2294 */
2295 if (out->encoder != NULL) {
2296 /*
2297 * Store the data in the incoming raw buffer
2298 */
2299 if (out->conv == NULL) {
2300 out->conv = xmlBufferCreate();
2301 }
2302 xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2303
2304 if ((out->buffer->use < MINLEN) && (chunk == len))
2305 goto done;
2306
2307 /*
2308 * convert as much as possible to the parser reading buffer.
2309 */
2310 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
Daniel Veillard809faa52003-02-10 15:43:53 +00002311 if ((ret < 0) && (ret != -3)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002312 xmlGenericError(xmlGenericErrorContext,
2313 "xmlOutputBufferWrite: encoder error\n");
2314 return(-1);
2315 }
2316 nbchars = out->conv->use;
2317 } else {
2318 xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2319 nbchars = out->buffer->use;
2320 }
2321 buf += chunk;
2322 len -= chunk;
2323
2324 if ((nbchars < MINLEN) && (len <= 0))
2325 goto done;
2326
2327 if (out->writecallback) {
2328 /*
2329 * second write the stuff to the I/O channel
2330 */
2331 if (out->encoder != NULL) {
2332 ret = out->writecallback(out->context,
2333 (const char *)out->conv->content, nbchars);
2334 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002335 xmlBufferShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002336 } else {
2337 ret = out->writecallback(out->context,
2338 (const char *)out->buffer->content, nbchars);
2339 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002340 xmlBufferShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002341 }
2342 if (ret < 0) {
2343 xmlGenericError(xmlGenericErrorContext,
2344 "I/O: error %d writing %d bytes\n", ret, nbchars);
2345 return(ret);
2346 }
2347 out->written += ret;
2348 }
2349 written += nbchars;
2350 } while (len > 0);
2351
2352done:
2353#ifdef DEBUG_INPUT
2354 xmlGenericError(xmlGenericErrorContext,
2355 "I/O: wrote %d chars\n", written);
2356#endif
2357 return(written);
2358}
2359
2360/**
2361 * xmlOutputBufferWriteString:
2362 * @out: a buffered parser output
2363 * @str: a zero terminated C string
2364 *
2365 * Write the content of the string in the output I/O buffer
2366 * This routine handle the I18N transcoding from internal UTF-8
2367 * The buffer is lossless, i.e. will store in case of partial
2368 * or delayed writes.
2369 *
2370 * Returns the number of chars immediately written, or -1
2371 * in case of error.
2372 */
2373int
2374xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
2375 int len;
2376
2377 if (str == NULL)
2378 return(-1);
2379 len = strlen(str);
2380
2381 if (len > 0)
2382 return(xmlOutputBufferWrite(out, len, str));
2383 return(len);
2384}
2385
2386/**
2387 * xmlOutputBufferFlush:
2388 * @out: a buffered output
2389 *
2390 * flushes the output I/O channel
2391 *
2392 * Returns the number of byte written or -1 in case of error.
2393 */
2394int
2395xmlOutputBufferFlush(xmlOutputBufferPtr out) {
2396 int nbchars = 0, ret = 0;
2397
2398 /*
2399 * first handle encoding stuff.
2400 */
2401 if ((out->conv != NULL) && (out->encoder != NULL)) {
2402 /*
2403 * convert as much as possible to the parser reading buffer.
2404 */
2405 nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
2406 if (nbchars < 0) {
2407 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002408 "xmlOutputBufferFlush: encoder error\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002409 return(-1);
2410 }
2411 }
2412
2413 /*
2414 * second flush the stuff to the I/O channel
2415 */
2416 if ((out->conv != NULL) && (out->encoder != NULL) &&
2417 (out->writecallback != NULL)) {
2418 ret = out->writecallback(out->context,
2419 (const char *)out->conv->content, out->conv->use);
2420 if (ret >= 0)
2421 xmlBufferShrink(out->conv, ret);
2422 } else if (out->writecallback != NULL) {
2423 ret = out->writecallback(out->context,
2424 (const char *)out->buffer->content, out->buffer->use);
2425 if (ret >= 0)
2426 xmlBufferShrink(out->buffer, ret);
2427 }
2428 if (ret < 0) {
2429 xmlGenericError(xmlGenericErrorContext,
2430 "I/O: error %d flushing %d bytes\n", ret, nbchars);
2431 return(ret);
2432 }
2433 out->written += ret;
2434
2435#ifdef DEBUG_INPUT
2436 xmlGenericError(xmlGenericErrorContext,
2437 "I/O: flushed %d chars\n", ret);
2438#endif
2439 return(ret);
2440}
2441
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002442/**
Owen Taylor3473f882001-02-23 17:55:21 +00002443 * xmlParserGetDirectory:
2444 * @filename: the path to a file
2445 *
2446 * lookup the directory for that file
2447 *
2448 * Returns a new allocated string containing the directory, or NULL.
2449 */
2450char *
2451xmlParserGetDirectory(const char *filename) {
2452 char *ret = NULL;
2453 char dir[1024];
2454 char *cur;
2455 char sep = '/';
2456
Igor Zlatkovic9181cc02002-09-29 17:51:06 +00002457#ifdef _WIN32_WCE /* easy way by now ... wince does not have dirs! */
2458 return NULL;
2459#endif
2460
Owen Taylor3473f882001-02-23 17:55:21 +00002461 if (xmlInputCallbackInitialized == 0)
2462 xmlRegisterDefaultInputCallbacks();
2463
2464 if (filename == NULL) return(NULL);
Daniel Veillard3c5ed912002-01-08 10:36:16 +00002465#if defined(WIN32) && !defined(__CYGWIN__)
Owen Taylor3473f882001-02-23 17:55:21 +00002466 sep = '\\';
2467#endif
2468
2469 strncpy(dir, filename, 1023);
2470 dir[1023] = 0;
2471 cur = &dir[strlen(dir)];
2472 while (cur > dir) {
2473 if (*cur == sep) break;
2474 cur --;
2475 }
2476 if (*cur == sep) {
2477 if (cur == dir) dir[1] = 0;
2478 else *cur = 0;
2479 ret = xmlMemStrdup(dir);
2480 } else {
2481 if (getcwd(dir, 1024) != NULL) {
2482 dir[1023] = 0;
2483 ret = xmlMemStrdup(dir);
2484 }
2485 }
2486 return(ret);
2487}
2488
2489/****************************************************************
2490 * *
2491 * External entities loading *
2492 * *
2493 ****************************************************************/
2494
Daniel Veillard561b7f82002-03-20 21:55:57 +00002495static int xmlSysIDExists(const char *URL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00002496#ifdef HAVE_STAT
2497 int ret;
2498 struct stat info;
2499 const char *path;
2500
2501 if (URL == NULL)
2502 return(0);
2503
Daniel Veillardf4862f02002-09-10 11:13:43 +00002504 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00002505#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00002506 path = &URL[17];
2507#else
Daniel Veillard6990bf32001-08-23 21:17:48 +00002508 path = &URL[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00002509#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002510 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00002511#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard6990bf32001-08-23 21:17:48 +00002512 path = &URL[8];
2513#else
2514 path = &URL[7];
2515#endif
2516 } else
2517 path = URL;
2518 ret = stat(path, &info);
Daniel Veillard561b7f82002-03-20 21:55:57 +00002519 if (ret == 0)
2520 return(1);
Daniel Veillard6990bf32001-08-23 21:17:48 +00002521#endif
Daniel Veillard561b7f82002-03-20 21:55:57 +00002522 return(0);
Daniel Veillard6990bf32001-08-23 21:17:48 +00002523}
Daniel Veillard6990bf32001-08-23 21:17:48 +00002524
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002525/**
Owen Taylor3473f882001-02-23 17:55:21 +00002526 * xmlDefaultExternalEntityLoader:
2527 * @URL: the URL for the entity to load
2528 * @ID: the System ID for the entity to load
2529 * @ctxt: the context in which the entity is called or NULL
2530 *
2531 * By default we don't load external entitites, yet.
2532 *
2533 * Returns a new allocated xmlParserInputPtr, or NULL.
2534 */
2535static
2536xmlParserInputPtr
2537xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
2538 xmlParserCtxtPtr ctxt) {
2539 xmlParserInputPtr ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002540 xmlChar *resource = NULL;
2541#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002542 xmlCatalogAllow pref;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002543#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002544
2545#ifdef DEBUG_EXTERNAL_ENTITIES
2546 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf012a642001-07-23 19:10:52 +00002547 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00002548#endif
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002549#ifdef LIBXML_CATALOG_ENABLED
2550 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002551 * If the resource doesn't exists as a file,
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002552 * try to load it from the resource pointed in the catalogs
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002553 */
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002554 pref = xmlCatalogGetDefaults();
2555
Daniel Veillard561b7f82002-03-20 21:55:57 +00002556 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlSysIDExists(URL))) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002557 /*
2558 * Do a local lookup
2559 */
2560 if ((ctxt->catalogs != NULL) &&
2561 ((pref == XML_CATA_ALLOW_ALL) ||
2562 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2563 resource = xmlCatalogLocalResolve(ctxt->catalogs,
2564 (const xmlChar *)ID,
2565 (const xmlChar *)URL);
2566 }
2567 /*
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002568 * Try a global lookup
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002569 */
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002570 if ((resource == NULL) &&
2571 ((pref == XML_CATA_ALLOW_ALL) ||
2572 (pref == XML_CATA_ALLOW_GLOBAL))) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002573 resource = xmlCatalogResolve((const xmlChar *)ID,
2574 (const xmlChar *)URL);
2575 }
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002576 if ((resource == NULL) && (URL != NULL))
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00002577 resource = xmlStrdup((const xmlChar *) URL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002578
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002579 /*
2580 * TODO: do an URI lookup on the reference
2581 */
Daniel Veillard561b7f82002-03-20 21:55:57 +00002582 if ((resource != NULL) && (!xmlSysIDExists((const char *)resource))) {
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002583 xmlChar *tmp = NULL;
2584
2585 if ((ctxt->catalogs != NULL) &&
2586 ((pref == XML_CATA_ALLOW_ALL) ||
2587 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2588 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
2589 }
2590 if ((tmp == NULL) &&
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00002591 ((pref == XML_CATA_ALLOW_ALL) ||
2592 (pref == XML_CATA_ALLOW_GLOBAL))) {
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002593 tmp = xmlCatalogResolveURI(resource);
2594 }
2595
2596 if (tmp != NULL) {
2597 xmlFree(resource);
2598 resource = tmp;
2599 }
2600 }
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002601 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002602#endif
2603
2604 if (resource == NULL)
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002605 resource = (xmlChar *) URL;
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002606
2607 if (resource == NULL) {
Daniel Veillardc6613042002-03-02 09:34:02 +00002608 if (ID == NULL)
2609 ID = "NULL";
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002610 if ((ctxt->validate) && (ctxt->sax != NULL) &&
2611 (ctxt->sax->error != NULL))
2612 ctxt->sax->error(ctxt,
2613 "failed to load external entity \"%s\"\n", ID);
2614 else if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00002615 ctxt->sax->warning(ctxt,
2616 "failed to load external entity \"%s\"\n", ID);
2617 return(NULL);
2618 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002619 ret = xmlNewInputFromFile(ctxt, (const char *)resource);
Owen Taylor3473f882001-02-23 17:55:21 +00002620 if (ret == NULL) {
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002621 if ((ctxt->validate) && (ctxt->sax != NULL) &&
2622 (ctxt->sax->error != NULL))
2623 ctxt->sax->error(ctxt,
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002624 "failed to load external entity \"%s\"\n", resource);
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002625 else if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
Owen Taylor3473f882001-02-23 17:55:21 +00002626 ctxt->sax->warning(ctxt,
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002627 "failed to load external entity \"%s\"\n", resource);
Owen Taylor3473f882001-02-23 17:55:21 +00002628 }
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002629 if ((resource != NULL) && (resource != (xmlChar *) URL))
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002630 xmlFree(resource);
Owen Taylor3473f882001-02-23 17:55:21 +00002631 return(ret);
2632}
2633
2634static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
2635 xmlDefaultExternalEntityLoader;
2636
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002637/**
Owen Taylor3473f882001-02-23 17:55:21 +00002638 * xmlSetExternalEntityLoader:
2639 * @f: the new entity resolver function
2640 *
2641 * Changes the defaultexternal entity resolver function for the application
2642 */
2643void
2644xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
2645 xmlCurrentExternalEntityLoader = f;
2646}
2647
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002648/**
Owen Taylor3473f882001-02-23 17:55:21 +00002649 * xmlGetExternalEntityLoader:
2650 *
2651 * Get the default external entity resolver function for the application
2652 *
2653 * Returns the xmlExternalEntityLoader function pointer
2654 */
2655xmlExternalEntityLoader
2656xmlGetExternalEntityLoader(void) {
2657 return(xmlCurrentExternalEntityLoader);
2658}
2659
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002660/**
Owen Taylor3473f882001-02-23 17:55:21 +00002661 * xmlLoadExternalEntity:
2662 * @URL: the URL for the entity to load
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00002663 * @ID: the Public ID for the entity to load
Owen Taylor3473f882001-02-23 17:55:21 +00002664 * @ctxt: the context in which the entity is called or NULL
2665 *
2666 * Load an external entity, note that the use of this function for
2667 * unparsed entities may generate problems
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002668 * TODO: a more generic External entity API must be designed
Owen Taylor3473f882001-02-23 17:55:21 +00002669 *
2670 * Returns the xmlParserInputPtr or NULL
2671 */
2672xmlParserInputPtr
2673xmlLoadExternalEntity(const char *URL, const char *ID,
2674 xmlParserCtxtPtr ctxt) {
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00002675 if ((URL != NULL) && (xmlSysIDExists(URL) == 0)) {
2676 char *canonicFilename;
2677 xmlParserInputPtr ret;
2678
2679 canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL);
2680 if (canonicFilename == NULL) {
2681 if (xmlDefaultSAXHandler.error != NULL) {
2682 xmlDefaultSAXHandler.error(NULL, "out of memory\n");
2683 }
2684 return(NULL);
2685 }
2686
2687 ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt);
2688 xmlFree(canonicFilename);
2689 return(ret);
2690 }
Owen Taylor3473f882001-02-23 17:55:21 +00002691 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
2692}
2693
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00002694/************************************************************************
2695 * *
2696 * Disabling Network access *
2697 * *
2698 ************************************************************************/
2699
2700#ifdef LIBXML_CATALOG_ENABLED
2701static int
2702xmlNoNetExists(const char *URL)
2703{
2704#ifdef HAVE_STAT
2705 int ret;
2706 struct stat info;
2707 const char *path;
2708
2709 if (URL == NULL)
2710 return (0);
2711
Daniel Veillardf4862f02002-09-10 11:13:43 +00002712 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00002713#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00002714 path = &URL[17];
2715#else
2716 path = &URL[16];
2717#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002718 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00002719#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00002720 path = &URL[8];
2721#else
2722 path = &URL[7];
2723#endif
2724 } else
2725 path = URL;
2726 ret = stat(path, &info);
2727 if (ret == 0)
2728 return (1);
2729#endif
2730 return (0);
2731}
2732#endif
2733
2734/**
2735 * xmlNoNetExternalEntityLoader:
2736 * @URL: the URL for the entity to load
2737 * @ID: the System ID for the entity to load
2738 * @ctxt: the context in which the entity is called or NULL
2739 *
2740 * A specific entity loader disabling network accesses, though still
2741 * allowing local catalog accesses for resolution.
2742 *
2743 * Returns a new allocated xmlParserInputPtr, or NULL.
2744 */
2745xmlParserInputPtr
2746xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
2747 xmlParserCtxtPtr ctxt) {
2748 xmlParserInputPtr input = NULL;
2749 xmlChar *resource = NULL;
2750
2751#ifdef LIBXML_CATALOG_ENABLED
2752 xmlCatalogAllow pref;
2753
2754 /*
2755 * If the resource doesn't exists as a file,
2756 * try to load it from the resource pointed in the catalogs
2757 */
2758 pref = xmlCatalogGetDefaults();
2759
2760 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
2761 /*
2762 * Do a local lookup
2763 */
2764 if ((ctxt->catalogs != NULL) &&
2765 ((pref == XML_CATA_ALLOW_ALL) ||
2766 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2767 resource = xmlCatalogLocalResolve(ctxt->catalogs,
2768 (const xmlChar *)ID,
2769 (const xmlChar *)URL);
2770 }
2771 /*
2772 * Try a global lookup
2773 */
2774 if ((resource == NULL) &&
2775 ((pref == XML_CATA_ALLOW_ALL) ||
2776 (pref == XML_CATA_ALLOW_GLOBAL))) {
2777 resource = xmlCatalogResolve((const xmlChar *)ID,
2778 (const xmlChar *)URL);
2779 }
2780 if ((resource == NULL) && (URL != NULL))
2781 resource = xmlStrdup((const xmlChar *) URL);
2782
2783 /*
2784 * TODO: do an URI lookup on the reference
2785 */
2786 if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
2787 xmlChar *tmp = NULL;
2788
2789 if ((ctxt->catalogs != NULL) &&
2790 ((pref == XML_CATA_ALLOW_ALL) ||
2791 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2792 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
2793 }
2794 if ((tmp == NULL) &&
2795 ((pref == XML_CATA_ALLOW_ALL) ||
2796 (pref == XML_CATA_ALLOW_GLOBAL))) {
2797 tmp = xmlCatalogResolveURI(resource);
2798 }
2799
2800 if (tmp != NULL) {
2801 xmlFree(resource);
2802 resource = tmp;
2803 }
2804 }
2805 }
2806#endif
2807 if (resource == NULL)
2808 resource = (xmlChar *) URL;
2809
2810 if (resource != NULL) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002811 if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
2812 (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00002813 xmlGenericError(xmlGenericErrorContext,
2814 "Attempt to load network entity %s \n", resource);
2815
2816 if (resource != (xmlChar *) URL)
2817 xmlFree(resource);
2818 return(NULL);
2819 }
2820 }
2821 input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
2822 if (resource != (xmlChar *) URL)
2823 xmlFree(resource);
2824 return(input);
2825}
2826