blob: af8a44e3e70b0497bd0eb2f23999d3abbc07083a [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 }
160
161 xmlInputCallbackNr = 0;
Aleksey Sanin9c45ba82002-06-06 21:46:13 +0000162 xmlInputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000163}
164
165/**
166 * xmlCleanupOutputCallbacks:
167 *
168 * clears the entire output callback table. this includes the
169 * compiled-in I/O callbacks.
170 */
171void
172xmlCleanupOutputCallbacks(void)
173{
174 int i;
175
176 if (!xmlOutputCallbackInitialized)
177 return;
178
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000179 for (i = xmlOutputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000180 xmlOutputCallbackTable[i].matchcallback = NULL;
181 xmlOutputCallbackTable[i].opencallback = NULL;
182 xmlOutputCallbackTable[i].writecallback = NULL;
183 xmlOutputCallbackTable[i].closecallback = NULL;
184 }
185
186 xmlOutputCallbackNr = 0;
Aleksey Sanin9c45ba82002-06-06 21:46:13 +0000187 xmlOutputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000188}
189
Owen Taylor3473f882001-02-23 17:55:21 +0000190/************************************************************************
191 * *
192 * Standard I/O for file accesses *
193 * *
194 ************************************************************************/
195
196/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000197 * xmlCheckFilename:
Owen Taylor3473f882001-02-23 17:55:21 +0000198 * @path: the path to check
199 *
200 * function checks to see if @path is a valid source
201 * (file, socket...) for XML.
202 *
203 * if stat is not available on the target machine,
204 * returns 1. if stat fails, returns 0 (if calling
205 * stat on the filename fails, it can't be right).
206 * if stat succeeds and the file is a directory,
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000207 * returns 2. otherwise returns 1.
Owen Taylor3473f882001-02-23 17:55:21 +0000208 */
209
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000210int
Owen Taylor3473f882001-02-23 17:55:21 +0000211xmlCheckFilename (const char *path)
212{
213#ifdef HAVE_STAT
Owen Taylor3473f882001-02-23 17:55:21 +0000214 struct stat stat_buffer;
215
216 if (stat(path, &stat_buffer) == -1)
217 return 0;
218
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000219#ifdef S_ISDIR
Owen Taylor3473f882001-02-23 17:55:21 +0000220 if (S_ISDIR(stat_buffer.st_mode)) {
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000221 return 2;
Owen Taylor3473f882001-02-23 17:55:21 +0000222 }
Owen Taylor3473f882001-02-23 17:55:21 +0000223#endif
224#endif
225 return 1;
226}
227
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000228static int
Owen Taylor3473f882001-02-23 17:55:21 +0000229xmlNop(void) {
230 return(0);
231}
232
233/**
Owen Taylor3473f882001-02-23 17:55:21 +0000234 * xmlFdRead:
235 * @context: the I/O context
236 * @buffer: where to drop data
237 * @len: number of bytes to read
238 *
239 * Read @len bytes to @buffer from the I/O channel.
240 *
241 * Returns the number of bytes written
242 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000243static int
Owen Taylor3473f882001-02-23 17:55:21 +0000244xmlFdRead (void * context, char * buffer, int len) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +0000245 return(read((int) (long) context, &buffer[0], len));
Owen Taylor3473f882001-02-23 17:55:21 +0000246}
247
248/**
249 * xmlFdWrite:
250 * @context: the I/O context
251 * @buffer: where to get data
252 * @len: number of bytes to write
253 *
254 * Write @len bytes from @buffer to the I/O channel.
255 *
256 * Returns the number of bytes written
257 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000258static int
Owen Taylor3473f882001-02-23 17:55:21 +0000259xmlFdWrite (void * context, const char * buffer, int len) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +0000260 return(write((int) (long) context, &buffer[0], len));
Owen Taylor3473f882001-02-23 17:55:21 +0000261}
262
263/**
264 * xmlFdClose:
265 * @context: the I/O context
266 *
267 * Close an I/O channel
Daniel Veillardf012a642001-07-23 19:10:52 +0000268 *
269 * Returns 0 in case of success and error code otherwise
Owen Taylor3473f882001-02-23 17:55:21 +0000270 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000271static int
Owen Taylor3473f882001-02-23 17:55:21 +0000272xmlFdClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +0000273 return ( close((int) (long) context) );
Owen Taylor3473f882001-02-23 17:55:21 +0000274}
275
276/**
277 * xmlFileMatch:
278 * @filename: the URI for matching
279 *
280 * input from FILE *
281 *
282 * Returns 1 if matches, 0 otherwise
283 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000284int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000285xmlFileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000286 return(1);
287}
288
289/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000290 * xmlFileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +0000291 * @filename: the URI for matching
292 *
293 * input from FILE *, supports compressed input
294 * if @filename is " " then the standard input is used
295 *
296 * Returns an I/O context or NULL in case of error
297 */
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000298static void *
299xmlFileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +0000300 const char *path = NULL;
301 FILE *fd;
302
303 if (!strcmp(filename, "-")) {
304 fd = stdin;
305 return((void *) fd);
306 }
307
Daniel Veillardf4862f02002-09-10 11:13:43 +0000308 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000309#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000310 path = &filename[17];
311#else
Owen Taylor3473f882001-02-23 17:55:21 +0000312 path = &filename[16];
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000313#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000314 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000315#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000316 path = &filename[8];
317#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000318 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000319#endif
320 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000321 path = filename;
322
323 if (path == NULL)
324 return(NULL);
325 if (!xmlCheckFilename(path))
326 return(NULL);
327
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000328#if defined(WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
Owen Taylor3473f882001-02-23 17:55:21 +0000329 fd = fopen(path, "rb");
330#else
331 fd = fopen(path, "r");
332#endif /* WIN32 */
333 return((void *) fd);
334}
335
336/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000337 * xmlFileOpen:
338 * @filename: the URI for matching
339 *
340 * Wrapper around xmlFileOpen_real that try it with an unescaped
341 * version of @filename, if this fails fallback to @filename
Daniel Veillard71531f32003-02-05 13:19:53 +0000342 *
343 * Returns a handler or NULL in case or failure
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000344 */
345void *
346xmlFileOpen (const char *filename) {
347 char *unescaped;
348 void *retval;
349 unescaped = xmlURIUnescapeString(filename, 0, NULL);
350 if (unescaped != NULL) {
351 retval = xmlFileOpen_real(unescaped);
352 } else {
353 retval = xmlFileOpen_real(filename);
354 }
355 xmlFree(unescaped);
356 return retval;
357}
358
359/**
Owen Taylor3473f882001-02-23 17:55:21 +0000360 * xmlFileOpenW:
361 * @filename: the URI for matching
362 *
363 * output to from FILE *,
364 * if @filename is "-" then the standard output is used
365 *
366 * Returns an I/O context or NULL in case of error
367 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000368static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000369xmlFileOpenW (const char *filename) {
370 const char *path = NULL;
371 FILE *fd;
372
373 if (!strcmp(filename, "-")) {
374 fd = stdout;
375 return((void *) fd);
376 }
377
Daniel Veillardf4862f02002-09-10 11:13:43 +0000378 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000379#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000380 path = &filename[17];
381#else
Owen Taylor3473f882001-02-23 17:55:21 +0000382 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000383#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000384 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000385#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000386 path = &filename[8];
387#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000388 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000389#endif
390 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000391 path = filename;
392
393 if (path == NULL)
394 return(NULL);
395
Daniel Veillardcbbd78d2003-07-20 15:21:30 +0000396 fd = fopen(path, "wb");
Owen Taylor3473f882001-02-23 17:55:21 +0000397 return((void *) fd);
398}
399
400/**
401 * xmlFileRead:
402 * @context: the I/O context
403 * @buffer: where to drop data
404 * @len: number of bytes to write
405 *
406 * Read @len bytes to @buffer from the I/O channel.
407 *
408 * Returns the number of bytes written
409 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000410int
Owen Taylor3473f882001-02-23 17:55:21 +0000411xmlFileRead (void * context, char * buffer, int len) {
412 return(fread(&buffer[0], 1, len, (FILE *) context));
413}
414
415/**
416 * xmlFileWrite:
417 * @context: the I/O context
418 * @buffer: where to drop data
419 * @len: number of bytes to write
420 *
421 * Write @len bytes from @buffer to the I/O channel.
422 *
423 * Returns the number of bytes written
424 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000425static int
Owen Taylor3473f882001-02-23 17:55:21 +0000426xmlFileWrite (void * context, const char * buffer, int len) {
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000427 int items;
428
429 items = fwrite(&buffer[0], len, 1, (FILE *) context);
430
431 return(items * len);
Owen Taylor3473f882001-02-23 17:55:21 +0000432}
433
434/**
435 * xmlFileClose:
436 * @context: the I/O context
437 *
438 * Close an I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000439 *
440 * Returns 0 or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +0000441 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000442int
Owen Taylor3473f882001-02-23 17:55:21 +0000443xmlFileClose (void * context) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000444 FILE *fil;
445
446 fil = (FILE *) context;
447 if (fil == stdin)
448 return(0);
449 if (fil == stdout)
450 return(0);
Daniel Veillardcd337f02001-11-22 18:20:37 +0000451 if (fil == stderr)
452 return(0);
Daniel Veillardf012a642001-07-23 19:10:52 +0000453 return ( ( fclose((FILE *) context) == EOF ) ? -1 : 0 );
Owen Taylor3473f882001-02-23 17:55:21 +0000454}
455
456/**
457 * xmlFileFlush:
458 * @context: the I/O context
459 *
460 * Flush an I/O channel
461 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000462static int
Owen Taylor3473f882001-02-23 17:55:21 +0000463xmlFileFlush (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +0000464 return ( ( fflush((FILE *) context) == EOF ) ? -1 : 0 );
Owen Taylor3473f882001-02-23 17:55:21 +0000465}
466
467#ifdef HAVE_ZLIB_H
468/************************************************************************
469 * *
470 * I/O for compressed file accesses *
471 * *
472 ************************************************************************/
473/**
474 * xmlGzfileMatch:
475 * @filename: the URI for matching
476 *
477 * input from compressed file test
478 *
479 * Returns 1 if matches, 0 otherwise
480 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000481static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000482xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000483 return(1);
484}
485
486/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000487 * xmlGzfileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +0000488 * @filename: the URI for matching
489 *
490 * input from compressed file open
491 * if @filename is " " then the standard input is used
492 *
493 * Returns an I/O context or NULL in case of error
494 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000495static void *
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000496xmlGzfileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +0000497 const char *path = NULL;
498 gzFile fd;
499
500 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000501 fd = gzdopen(dup(0), "rb");
Owen Taylor3473f882001-02-23 17:55:21 +0000502 return((void *) fd);
503 }
504
Daniel Veillardf4862f02002-09-10 11:13:43 +0000505 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000506#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000507 path = &filename[17];
508#else
Owen Taylor3473f882001-02-23 17:55:21 +0000509 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000510#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000511 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000512#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000513 path = &filename[8];
514#else
Owen Taylor3473f882001-02-23 17:55:21 +0000515 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000516#endif
517 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000518 path = filename;
519
520 if (path == NULL)
521 return(NULL);
522 if (!xmlCheckFilename(path))
523 return(NULL);
524
525 fd = gzopen(path, "rb");
526 return((void *) fd);
527}
528
529/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000530 * xmlGzfileOpen:
531 * @filename: the URI for matching
532 *
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +0000533 * Wrapper around xmlGzfileOpen if the open fais, it will
534 * try to unescape @filename
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000535 */
536static void *
537xmlGzfileOpen (const char *filename) {
538 char *unescaped;
539 void *retval;
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +0000540
541 retval = xmlGzfileOpen_real(filename);
542 if (retval == NULL) {
543 unescaped = xmlURIUnescapeString(filename, 0, NULL);
544 if (unescaped != NULL) {
545 retval = xmlGzfileOpen_real(unescaped);
546 }
547 xmlFree(unescaped);
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000548 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000549 return retval;
550}
551
552/**
Owen Taylor3473f882001-02-23 17:55:21 +0000553 * xmlGzfileOpenW:
554 * @filename: the URI for matching
555 * @compression: the compression factor (0 - 9 included)
556 *
557 * input from compressed file open
558 * if @filename is " " then the standard input is used
559 *
560 * Returns an I/O context or NULL in case of error
561 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000562static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000563xmlGzfileOpenW (const char *filename, int compression) {
564 const char *path = NULL;
565 char mode[15];
566 gzFile fd;
567
Aleksey Sanin49cc9752002-06-14 17:07:10 +0000568 snprintf(mode, sizeof(mode), "wb%d", compression);
Owen Taylor3473f882001-02-23 17:55:21 +0000569 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000570 fd = gzdopen(dup(1), mode);
Owen Taylor3473f882001-02-23 17:55:21 +0000571 return((void *) fd);
572 }
573
Daniel Veillardf4862f02002-09-10 11:13:43 +0000574 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000575#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000576 path = &filename[17];
577#else
Owen Taylor3473f882001-02-23 17:55:21 +0000578 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000579#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000580 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000581#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000582 path = &filename[8];
583#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000584 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000585#endif
586 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000587 path = filename;
588
589 if (path == NULL)
590 return(NULL);
591
592 fd = gzopen(path, mode);
593 return((void *) fd);
594}
595
596/**
597 * xmlGzfileRead:
598 * @context: the I/O context
599 * @buffer: where to drop data
600 * @len: number of bytes to write
601 *
602 * Read @len bytes to @buffer from the compressed I/O channel.
603 *
604 * Returns the number of bytes written
605 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000606static int
Owen Taylor3473f882001-02-23 17:55:21 +0000607xmlGzfileRead (void * context, char * buffer, int len) {
608 return(gzread((gzFile) context, &buffer[0], len));
609}
610
611/**
612 * xmlGzfileWrite:
613 * @context: the I/O context
614 * @buffer: where to drop data
615 * @len: number of bytes to write
616 *
617 * Write @len bytes from @buffer to the compressed I/O channel.
618 *
619 * Returns the number of bytes written
620 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000621static int
Owen Taylor3473f882001-02-23 17:55:21 +0000622xmlGzfileWrite (void * context, const char * buffer, int len) {
623 return(gzwrite((gzFile) context, (char *) &buffer[0], len));
624}
625
626/**
627 * xmlGzfileClose:
628 * @context: the I/O context
629 *
630 * Close a compressed I/O channel
631 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000632static int
Owen Taylor3473f882001-02-23 17:55:21 +0000633xmlGzfileClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +0000634 return ( ( gzclose((gzFile) context) == Z_OK ) ? 0 : -1 );
Owen Taylor3473f882001-02-23 17:55:21 +0000635}
636#endif /* HAVE_ZLIB_H */
637
638#ifdef LIBXML_HTTP_ENABLED
639/************************************************************************
640 * *
641 * I/O for HTTP file accesses *
642 * *
643 ************************************************************************/
Daniel Veillardf012a642001-07-23 19:10:52 +0000644
645typedef struct xmlIOHTTPWriteCtxt_
646{
647 int compression;
648
649 char * uri;
650
651 void * doc_buff;
652
653} xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr;
654
655#ifdef HAVE_ZLIB_H
656
657#define DFLT_WBITS ( -15 )
658#define DFLT_MEM_LVL ( 8 )
659#define GZ_MAGIC1 ( 0x1f )
660#define GZ_MAGIC2 ( 0x8b )
661#define LXML_ZLIB_OS_CODE ( 0x03 )
662#define INIT_HTTP_BUFF_SIZE ( 32768 )
663#define DFLT_ZLIB_RATIO ( 5 )
664
665/*
666** Data structure and functions to work with sending compressed data
667** via HTTP.
668*/
669
670typedef struct xmlZMemBuff_
671{
672 unsigned long size;
673 unsigned long crc;
674
675 unsigned char * zbuff;
676 z_stream zctrl;
677
678} xmlZMemBuff, *xmlZMemBuffPtr;
679
680/**
681 * append_reverse_ulong
682 * @buff: Compressed memory buffer
683 * @data: Unsigned long to append
684 *
685 * Append a unsigned long in reverse byte order to the end of the
686 * memory buffer.
687 */
688static void
689append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) {
690
691 int idx;
692
693 if ( buff == NULL )
694 return;
695
696 /*
697 ** This is plagiarized from putLong in gzio.c (zlib source) where
698 ** the number "4" is hardcoded. If zlib is ever patched to
699 ** support 64 bit file sizes, this code would need to be patched
700 ** as well.
701 */
702
703 for ( idx = 0; idx < 4; idx++ ) {
704 *buff->zctrl.next_out = ( data & 0xff );
705 data >>= 8;
706 buff->zctrl.next_out++;
707 }
708
709 return;
710}
711
712/**
713 *
714 * xmlFreeZMemBuff
715 * @buff: The memory buffer context to clear
716 *
717 * Release all the resources associated with the compressed memory buffer.
718 */
719static void
720xmlFreeZMemBuff( xmlZMemBuffPtr buff ) {
William M. Brack78637da2003-07-31 14:47:38 +0000721
722#ifdef DEBUG_HTTP
Daniel Veillardf012a642001-07-23 19:10:52 +0000723 int z_err;
William M. Brack78637da2003-07-31 14:47:38 +0000724#endif
Daniel Veillardf012a642001-07-23 19:10:52 +0000725
726 if ( buff == NULL )
727 return;
728
729 xmlFree( buff->zbuff );
Daniel Veillardf012a642001-07-23 19:10:52 +0000730#ifdef DEBUG_HTTP
William M. Brack78637da2003-07-31 14:47:38 +0000731 z_err = deflateEnd( &buff->zctrl );
Daniel Veillardf012a642001-07-23 19:10:52 +0000732 if ( z_err != Z_OK )
733 xmlGenericError( xmlGenericErrorContext,
734 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
735 z_err );
William M. Brack78637da2003-07-31 14:47:38 +0000736#else
737 deflateEnd( &buff->zctrl );
William M. Brack779af002003-08-01 15:55:39 +0000738#endif
Daniel Veillardf012a642001-07-23 19:10:52 +0000739
740 xmlFree( buff );
741 return;
742}
743
744/**
745 * xmlCreateZMemBuff
746 *@compression: Compression value to use
747 *
748 * Create a memory buffer to hold the compressed XML document. The
749 * compressed document in memory will end up being identical to what
750 * would be created if gzopen/gzwrite/gzclose were being used to
751 * write the document to disk. The code for the header/trailer data to
752 * the compression is plagiarized from the zlib source files.
753 */
754static void *
755xmlCreateZMemBuff( int compression ) {
756
757 int z_err;
758 int hdr_lgth;
759 xmlZMemBuffPtr buff = NULL;
760
761 if ( ( compression < 1 ) || ( compression > 9 ) )
762 return ( NULL );
763
764 /* Create the control and data areas */
765
766 buff = xmlMalloc( sizeof( xmlZMemBuff ) );
767 if ( buff == NULL ) {
768 xmlGenericError( xmlGenericErrorContext,
769 "xmlCreateZMemBuff: %s\n",
770 "Failure allocating buffer context." );
771 return ( NULL );
772 }
773
774 (void)memset( buff, 0, sizeof( xmlZMemBuff ) );
775 buff->size = INIT_HTTP_BUFF_SIZE;
776 buff->zbuff = xmlMalloc( buff->size );
777 if ( buff->zbuff == NULL ) {
778 xmlFreeZMemBuff( buff );
779 xmlGenericError( xmlGenericErrorContext,
780 "xmlCreateZMemBuff: %s\n",
781 "Failure allocating data buffer." );
782 return ( NULL );
783 }
784
785 z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
786 DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
787 if ( z_err != Z_OK ) {
788 xmlFreeZMemBuff( buff );
789 buff = NULL;
790 xmlGenericError( xmlGenericErrorContext,
791 "xmlCreateZMemBuff: %s %d\n",
792 "Error initializing compression context. ZLIB error:",
793 z_err );
794 return ( NULL );
795 }
796
797 /* Set the header data. The CRC will be needed for the trailer */
Daniel Veillardf012a642001-07-23 19:10:52 +0000798 buff->crc = crc32( 0L, Z_NULL, 0 );
Aleksey Sanin49cc9752002-06-14 17:07:10 +0000799 hdr_lgth = snprintf( (char *)buff->zbuff, buff->size,
800 "%c%c%c%c%c%c%c%c%c%c",
Daniel Veillardf012a642001-07-23 19:10:52 +0000801 GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED,
802 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE );
803 buff->zctrl.next_out = buff->zbuff + hdr_lgth;
804 buff->zctrl.avail_out = buff->size - hdr_lgth;
805
806 return ( buff );
807}
808
809/**
810 * xmlZMemBuffExtend
811 * @buff: Buffer used to compress and consolidate data.
812 * @ext_amt: Number of bytes to extend the buffer.
813 *
814 * Extend the internal buffer used to store the compressed data by the
815 * specified amount.
816 *
817 * Returns 0 on success or -1 on failure to extend the buffer. On failure
818 * the original buffer still exists at the original size.
819 */
820static int
821xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) {
822
823 int rc = -1;
824 size_t new_size;
825 size_t cur_used;
826
827 unsigned char * tmp_ptr = NULL;
828
829 if ( buff == NULL )
830 return ( -1 );
831
832 else if ( ext_amt == 0 )
833 return ( 0 );
834
835 cur_used = buff->zctrl.next_out - buff->zbuff;
836 new_size = buff->size + ext_amt;
837
838#ifdef DEBUG_HTTP
839 if ( cur_used > new_size )
840 xmlGenericError( xmlGenericErrorContext,
841 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
842 "Buffer overwrite detected during compressed memory",
843 "buffer extension. Overflowed by",
844 (cur_used - new_size ) );
845#endif
846
847 tmp_ptr = xmlRealloc( buff->zbuff, new_size );
848 if ( tmp_ptr != NULL ) {
849 rc = 0;
850 buff->size = new_size;
851 buff->zbuff = tmp_ptr;
852 buff->zctrl.next_out = tmp_ptr + cur_used;
853 buff->zctrl.avail_out = new_size - cur_used;
854 }
855 else {
856 xmlGenericError( xmlGenericErrorContext,
857 "xmlZMemBuffExtend: %s %lu bytes.\n",
858 "Allocation failure extending output buffer to",
859 new_size );
860 }
861
862 return ( rc );
863}
864
865/**
866 * xmlZMemBuffAppend
867 * @buff: Buffer used to compress and consolidate data
868 * @src: Uncompressed source content to append to buffer
869 * @len: Length of source data to append to buffer
870 *
871 * Compress and append data to the internal buffer. The data buffer
872 * will be expanded if needed to store the additional data.
873 *
874 * Returns the number of bytes appended to the buffer or -1 on error.
875 */
876static int
877xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) {
878
879 int z_err;
880 size_t min_accept;
881
882 if ( ( buff == NULL ) || ( src == NULL ) )
883 return ( -1 );
884
885 buff->zctrl.avail_in = len;
886 buff->zctrl.next_in = (unsigned char *)src;
887 while ( buff->zctrl.avail_in > 0 ) {
888 /*
889 ** Extend the buffer prior to deflate call if a reasonable amount
890 ** of output buffer space is not available.
891 */
892 min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO;
893 if ( buff->zctrl.avail_out <= min_accept ) {
894 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
895 return ( -1 );
896 }
897
898 z_err = deflate( &buff->zctrl, Z_NO_FLUSH );
899 if ( z_err != Z_OK ) {
900 xmlGenericError( xmlGenericErrorContext,
901 "xmlZMemBuffAppend: %s %d %s - %d",
902 "Compression error while appending",
903 len, "bytes to buffer. ZLIB error", z_err );
904 return ( -1 );
905 }
906 }
907
908 buff->crc = crc32( buff->crc, (unsigned char *)src, len );
909
910 return ( len );
911}
912
913/**
914 * xmlZMemBuffGetContent
915 * @buff: Compressed memory content buffer
916 * @data_ref: Pointer reference to point to compressed content
917 *
918 * Flushes the compression buffers, appends gzip file trailers and
919 * returns the compressed content and length of the compressed data.
920 * NOTE: The gzip trailer code here is plagiarized from zlib source.
921 *
922 * Returns the length of the compressed data or -1 on error.
923 */
924static int
925xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) {
926
927 int zlgth = -1;
928 int z_err;
929
930 if ( ( buff == NULL ) || ( data_ref == NULL ) )
931 return ( -1 );
932
933 /* Need to loop until compression output buffers are flushed */
934
935 do
936 {
937 z_err = deflate( &buff->zctrl, Z_FINISH );
938 if ( z_err == Z_OK ) {
939 /* In this case Z_OK means more buffer space needed */
940
941 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
942 return ( -1 );
943 }
944 }
945 while ( z_err == Z_OK );
946
947 /* If the compression state is not Z_STREAM_END, some error occurred */
948
949 if ( z_err == Z_STREAM_END ) {
950
951 /* Need to append the gzip data trailer */
952
953 if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) {
954 if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 )
955 return ( -1 );
956 }
957
958 /*
959 ** For whatever reason, the CRC and length data are pushed out
960 ** in reverse byte order. So a memcpy can't be used here.
961 */
962
963 append_reverse_ulong( buff, buff->crc );
964 append_reverse_ulong( buff, buff->zctrl.total_in );
965
966 zlgth = buff->zctrl.next_out - buff->zbuff;
967 *data_ref = (char *)buff->zbuff;
968 }
969
970 else
971 xmlGenericError( xmlGenericErrorContext,
972 "xmlZMemBuffGetContent: %s - %d\n",
973 "Error flushing zlib buffers. Error code", z_err );
974
975 return ( zlgth );
976}
977#endif /* HAVE_ZLIB_H */
978
979/**
980 * xmlFreeHTTPWriteCtxt
981 * @ctxt: Context to cleanup
982 *
983 * Free allocated memory and reclaim system resources.
984 *
985 * No return value.
986 */
987static void
988xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt )
989{
990 if ( ctxt->uri != NULL )
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000991 xmlFree( ctxt->uri );
Daniel Veillardf012a642001-07-23 19:10:52 +0000992
993 if ( ctxt->doc_buff != NULL ) {
994
995#ifdef HAVE_ZLIB_H
996 if ( ctxt->compression > 0 ) {
997 xmlFreeZMemBuff( ctxt->doc_buff );
998 }
999 else
1000#endif
1001 {
1002 xmlOutputBufferClose( ctxt->doc_buff );
1003 }
1004 }
1005
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001006 xmlFree( ctxt );
Daniel Veillardf012a642001-07-23 19:10:52 +00001007 return;
1008}
1009
1010
Owen Taylor3473f882001-02-23 17:55:21 +00001011/**
1012 * xmlIOHTTPMatch:
1013 * @filename: the URI for matching
1014 *
1015 * check if the URI matches an HTTP one
1016 *
1017 * Returns 1 if matches, 0 otherwise
1018 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001019int
Owen Taylor3473f882001-02-23 17:55:21 +00001020xmlIOHTTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001021 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "http://", 7))
Owen Taylor3473f882001-02-23 17:55:21 +00001022 return(1);
1023 return(0);
1024}
1025
1026/**
1027 * xmlIOHTTPOpen:
1028 * @filename: the URI for matching
1029 *
1030 * open an HTTP I/O channel
1031 *
1032 * Returns an I/O context or NULL in case of error
1033 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001034void *
Owen Taylor3473f882001-02-23 17:55:21 +00001035xmlIOHTTPOpen (const char *filename) {
1036 return(xmlNanoHTTPOpen(filename, NULL));
1037}
1038
1039/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001040 * xmlIOHTTPOpenW:
Daniel Veillardf012a642001-07-23 19:10:52 +00001041 * @post_uri: The destination URI for the document
1042 * @compression: The compression desired for the document.
1043 *
1044 * Open a temporary buffer to collect the document for a subsequent HTTP POST
1045 * request. Non-static as is called from the output buffer creation routine.
1046 *
1047 * Returns an I/O context or NULL in case of error.
1048 */
1049
1050void *
Daniel Veillard572577e2002-01-18 16:23:55 +00001051xmlIOHTTPOpenW(const char *post_uri, int compression)
1052{
Daniel Veillardf012a642001-07-23 19:10:52 +00001053
Daniel Veillard572577e2002-01-18 16:23:55 +00001054 xmlIOHTTPWriteCtxtPtr ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001055
Daniel Veillard572577e2002-01-18 16:23:55 +00001056 if (post_uri == NULL)
1057 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001058
Daniel Veillard572577e2002-01-18 16:23:55 +00001059 ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt));
1060 if (ctxt == NULL) {
1061 xmlGenericError(xmlGenericErrorContext,
1062 "xmlIOHTTPOpenW: Failed to create output HTTP context.\n");
1063 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001064 }
1065
Daniel Veillard572577e2002-01-18 16:23:55 +00001066 (void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt));
Daniel Veillardf012a642001-07-23 19:10:52 +00001067
Daniel Veillard572577e2002-01-18 16:23:55 +00001068 ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri);
1069 if (ctxt->uri == NULL) {
1070 xmlGenericError(xmlGenericErrorContext,
1071 "xmlIOHTTPOpenW: Failed to duplicate destination URI.\n");
1072 xmlFreeHTTPWriteCtxt(ctxt);
1073 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001074 }
1075
1076 /*
Daniel Veillard572577e2002-01-18 16:23:55 +00001077 * ** Since the document length is required for an HTTP post,
1078 * ** need to put the document into a buffer. A memory buffer
1079 * ** is being used to avoid pushing the data to disk and back.
1080 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001081
1082#ifdef HAVE_ZLIB_H
Daniel Veillard572577e2002-01-18 16:23:55 +00001083 if ((compression > 0) && (compression <= 9)) {
1084
1085 ctxt->compression = compression;
1086 ctxt->doc_buff = xmlCreateZMemBuff(compression);
1087 } else
Daniel Veillardf012a642001-07-23 19:10:52 +00001088#endif
1089 {
Daniel Veillard572577e2002-01-18 16:23:55 +00001090 /* Any character conversions should have been done before this */
Daniel Veillardf012a642001-07-23 19:10:52 +00001091
Daniel Veillard572577e2002-01-18 16:23:55 +00001092 ctxt->doc_buff = xmlAllocOutputBuffer(NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001093 }
1094
Daniel Veillard572577e2002-01-18 16:23:55 +00001095 if (ctxt->doc_buff == NULL) {
1096 xmlFreeHTTPWriteCtxt(ctxt);
1097 ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001098 }
1099
Daniel Veillard572577e2002-01-18 16:23:55 +00001100 return (ctxt);
Daniel Veillardf012a642001-07-23 19:10:52 +00001101}
1102
1103/**
1104 * xmlIOHTTPDfltOpenW
1105 * @post_uri: The destination URI for this document.
1106 *
1107 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
1108 * HTTP post command. This function should generally not be used as
1109 * the open callback is short circuited in xmlOutputBufferCreateFile.
1110 *
1111 * Returns a pointer to the new IO context.
1112 */
1113static void *
1114xmlIOHTTPDfltOpenW( const char * post_uri ) {
1115 return ( xmlIOHTTPOpenW( post_uri, 0 ) );
1116}
1117
1118/**
Owen Taylor3473f882001-02-23 17:55:21 +00001119 * xmlIOHTTPRead:
1120 * @context: the I/O context
1121 * @buffer: where to drop data
1122 * @len: number of bytes to write
1123 *
1124 * Read @len bytes to @buffer from the I/O channel.
1125 *
1126 * Returns the number of bytes written
1127 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001128int
Owen Taylor3473f882001-02-23 17:55:21 +00001129xmlIOHTTPRead(void * context, char * buffer, int len) {
1130 return(xmlNanoHTTPRead(context, &buffer[0], len));
1131}
1132
1133/**
Daniel Veillardf012a642001-07-23 19:10:52 +00001134 * xmlIOHTTPWrite
1135 * @context: previously opened writing context
1136 * @buffer: data to output to temporary buffer
1137 * @len: bytes to output
1138 *
1139 * Collect data from memory buffer into a temporary file for later
1140 * processing.
1141 *
1142 * Returns number of bytes written.
1143 */
1144
1145static int
1146xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
1147
1148 xmlIOHTTPWriteCtxtPtr ctxt = context;
1149
1150 if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
1151 return ( -1 );
1152
1153 if ( len > 0 ) {
1154
1155 /* Use gzwrite or fwrite as previously setup in the open call */
1156
1157#ifdef HAVE_ZLIB_H
1158 if ( ctxt->compression > 0 )
1159 len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len );
1160
1161 else
1162#endif
1163 len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
1164
1165 if ( len < 0 ) {
1166 xmlGenericError( xmlGenericErrorContext,
1167 "xmlIOHTTPWrite: %s\n%s '%s'.\n",
1168 "Error appending to internal buffer.",
1169 "Error sending document to URI",
1170 ctxt->uri );
1171 }
1172 }
1173
1174 return ( len );
1175}
1176
1177
1178/**
Owen Taylor3473f882001-02-23 17:55:21 +00001179 * xmlIOHTTPClose:
1180 * @context: the I/O context
1181 *
1182 * Close an HTTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001183 *
1184 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00001185 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001186int
Owen Taylor3473f882001-02-23 17:55:21 +00001187xmlIOHTTPClose (void * context) {
1188 xmlNanoHTTPClose(context);
Daniel Veillardf012a642001-07-23 19:10:52 +00001189 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001190}
Daniel Veillardf012a642001-07-23 19:10:52 +00001191
1192/**
1193 * xmlIOHTTCloseWrite
1194 * @context: The I/O context
1195 * @http_mthd: The HTTP method to be used when sending the data
1196 *
1197 * Close the transmit HTTP I/O channel and actually send the data.
1198 */
1199static int
1200xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
1201
1202 int close_rc = -1;
1203 int http_rtn = 0;
1204 int content_lgth = 0;
1205 xmlIOHTTPWriteCtxtPtr ctxt = context;
1206
1207 char * http_content = NULL;
1208 char * content_encoding = NULL;
1209 char * content_type = (char *) "text/xml";
1210 void * http_ctxt = NULL;
1211
1212 if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
1213 return ( -1 );
1214
1215 /* Retrieve the content from the appropriate buffer */
1216
1217#ifdef HAVE_ZLIB_H
1218
1219 if ( ctxt->compression > 0 ) {
1220 content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
1221 content_encoding = (char *) "Content-Encoding: gzip";
1222 }
1223 else
1224#endif
1225 {
1226 /* Pull the data out of the memory output buffer */
1227
1228 xmlOutputBufferPtr dctxt = ctxt->doc_buff;
1229 http_content = (char *)dctxt->buffer->content;
1230 content_lgth = dctxt->buffer->use;
1231 }
1232
1233 if ( http_content == NULL ) {
1234 xmlGenericError( xmlGenericErrorContext,
1235 "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
1236 "Error retrieving content.\nUnable to",
1237 http_mthd, "data to URI", ctxt->uri );
1238 }
1239
1240 else {
1241
1242 http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
1243 &content_type, content_encoding,
1244 content_lgth );
1245
1246 if ( http_ctxt != NULL ) {
1247#ifdef DEBUG_HTTP
1248 /* If testing/debugging - dump reply with request content */
1249
1250 FILE * tst_file = NULL;
1251 char buffer[ 4096 ];
1252 char * dump_name = NULL;
1253 int avail;
1254
1255 xmlGenericError( xmlGenericErrorContext,
1256 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
1257 http_mthd, ctxt->uri,
1258 xmlNanoHTTPReturnCode( http_ctxt ) );
1259
1260 /*
1261 ** Since either content or reply may be gzipped,
1262 ** dump them to separate files instead of the
1263 ** standard error context.
1264 */
1265
1266 dump_name = tempnam( NULL, "lxml" );
1267 if ( dump_name != NULL ) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001268 (void)snprintf( buffer, sizeof(buffer), "%s.content", dump_name );
Daniel Veillardf012a642001-07-23 19:10:52 +00001269
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00001270 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00001271 if ( tst_file != NULL ) {
1272 xmlGenericError( xmlGenericErrorContext,
1273 "Transmitted content saved in file: %s\n", buffer );
1274
1275 fwrite( http_content, sizeof( char ),
1276 content_lgth, tst_file );
1277 fclose( tst_file );
1278 }
1279
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001280 (void)snprintf( buffer, sizeof(buffer), "%s.reply", dump_name );
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00001281 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00001282 if ( tst_file != NULL ) {
1283 xmlGenericError( xmlGenericErrorContext,
1284 "Reply content saved in file: %s\n", buffer );
1285
1286
1287 while ( (avail = xmlNanoHTTPRead( http_ctxt,
1288 buffer, sizeof( buffer ) )) > 0 ) {
1289
1290 fwrite( buffer, sizeof( char ), avail, tst_file );
1291 }
1292
1293 fclose( tst_file );
1294 }
1295
1296 free( dump_name );
1297 }
1298#endif /* DEBUG_HTTP */
1299
1300 http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
1301 if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
1302 close_rc = 0;
1303 else
1304 xmlGenericError( xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001305 "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001306 http_mthd, content_lgth,
1307 "bytes to URI", ctxt->uri,
1308 "failed. HTTP return code:", http_rtn );
1309
1310 xmlNanoHTTPClose( http_ctxt );
1311 xmlFree( content_type );
1312 }
1313 }
1314
1315 /* Final cleanups */
1316
1317 xmlFreeHTTPWriteCtxt( ctxt );
1318
1319 return ( close_rc );
1320}
1321
1322/**
1323 * xmlIOHTTPClosePut
1324 *
1325 * @context: The I/O context
1326 *
1327 * Close the transmit HTTP I/O channel and actually send data using a PUT
1328 * HTTP method.
1329 */
1330static int
1331xmlIOHTTPClosePut( void * ctxt ) {
1332 return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
1333}
1334
1335
1336/**
1337 * xmlIOHTTPClosePost
1338 *
1339 * @context: The I/O context
1340 *
1341 * Close the transmit HTTP I/O channel and actually send data using a POST
1342 * HTTP method.
1343 */
1344static int
1345xmlIOHTTPClosePost( void * ctxt ) {
1346 return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
1347}
1348
Owen Taylor3473f882001-02-23 17:55:21 +00001349#endif /* LIBXML_HTTP_ENABLED */
1350
1351#ifdef LIBXML_FTP_ENABLED
1352/************************************************************************
1353 * *
1354 * I/O for FTP file accesses *
1355 * *
1356 ************************************************************************/
1357/**
1358 * xmlIOFTPMatch:
1359 * @filename: the URI for matching
1360 *
1361 * check if the URI matches an FTP one
1362 *
1363 * Returns 1 if matches, 0 otherwise
1364 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001365int
Owen Taylor3473f882001-02-23 17:55:21 +00001366xmlIOFTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001367 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "ftp://", 6))
Owen Taylor3473f882001-02-23 17:55:21 +00001368 return(1);
1369 return(0);
1370}
1371
1372/**
1373 * xmlIOFTPOpen:
1374 * @filename: the URI for matching
1375 *
1376 * open an FTP I/O channel
1377 *
1378 * Returns an I/O context or NULL in case of error
1379 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001380void *
Owen Taylor3473f882001-02-23 17:55:21 +00001381xmlIOFTPOpen (const char *filename) {
1382 return(xmlNanoFTPOpen(filename));
1383}
1384
1385/**
1386 * xmlIOFTPRead:
1387 * @context: the I/O context
1388 * @buffer: where to drop data
1389 * @len: number of bytes to write
1390 *
1391 * Read @len bytes to @buffer from the I/O channel.
1392 *
1393 * Returns the number of bytes written
1394 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001395int
Owen Taylor3473f882001-02-23 17:55:21 +00001396xmlIOFTPRead(void * context, char * buffer, int len) {
1397 return(xmlNanoFTPRead(context, &buffer[0], len));
1398}
1399
1400/**
1401 * xmlIOFTPClose:
1402 * @context: the I/O context
1403 *
1404 * Close an FTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001405 *
1406 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00001407 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001408int
Owen Taylor3473f882001-02-23 17:55:21 +00001409xmlIOFTPClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001410 return ( xmlNanoFTPClose(context) );
Owen Taylor3473f882001-02-23 17:55:21 +00001411}
1412#endif /* LIBXML_FTP_ENABLED */
1413
1414
1415/**
1416 * xmlRegisterInputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001417 * @matchFunc: the xmlInputMatchCallback
1418 * @openFunc: the xmlInputOpenCallback
1419 * @readFunc: the xmlInputReadCallback
1420 * @closeFunc: the xmlInputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001421 *
1422 * Register a new set of I/O callback for handling parser input.
1423 *
1424 * Returns the registered handler number or -1 in case of error
1425 */
1426int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001427xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
1428 xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
1429 xmlInputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001430 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
1431 return(-1);
1432 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001433 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
1434 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
1435 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
1436 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00001437 xmlInputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00001438 return(xmlInputCallbackNr++);
1439}
1440
1441/**
1442 * xmlRegisterOutputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001443 * @matchFunc: the xmlOutputMatchCallback
1444 * @openFunc: the xmlOutputOpenCallback
1445 * @writeFunc: the xmlOutputWriteCallback
1446 * @closeFunc: the xmlOutputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001447 *
1448 * Register a new set of I/O callback for handling output.
1449 *
1450 * Returns the registered handler number or -1 in case of error
1451 */
1452int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001453xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
1454 xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
1455 xmlOutputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001456 if (xmlOutputCallbackNr >= MAX_INPUT_CALLBACK) {
1457 return(-1);
1458 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001459 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
1460 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
1461 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
1462 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00001463 xmlOutputCallbackInitialized = 1;
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;
William M. Brackc07329e2003-09-08 01:57:30 +00001591 ret->compressed = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00001592
1593 return(ret);
1594}
1595
1596/**
1597 * xmlAllocOutputBuffer:
1598 * @encoder: the encoding converter or NULL
1599 *
1600 * Create a buffered parser output
1601 *
1602 * Returns the new parser output or NULL
1603 */
1604xmlOutputBufferPtr
1605xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
1606 xmlOutputBufferPtr ret;
1607
1608 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
1609 if (ret == NULL) {
1610 xmlGenericError(xmlGenericErrorContext,
1611 "xmlAllocOutputBuffer : out of memory!\n");
1612 return(NULL);
1613 }
1614 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
1615 ret->buffer = xmlBufferCreate();
1616 if (ret->buffer == NULL) {
1617 xmlFree(ret);
1618 return(NULL);
1619 }
1620 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
1621 ret->encoder = encoder;
1622 if (encoder != NULL) {
1623 ret->conv = xmlBufferCreateSize(4000);
1624 /*
1625 * This call is designed to initiate the encoder state
1626 */
1627 xmlCharEncOutFunc(encoder, ret->conv, NULL);
1628 } else
1629 ret->conv = NULL;
1630 ret->writecallback = NULL;
1631 ret->closecallback = NULL;
1632 ret->context = NULL;
1633 ret->written = 0;
1634
1635 return(ret);
1636}
1637
1638/**
1639 * xmlFreeParserInputBuffer:
1640 * @in: a buffered parser input
1641 *
1642 * Free up the memory used by a buffered parser input
1643 */
1644void
1645xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
Daniel Veillard8d8bf2c2003-09-17 19:36:25 +00001646 if (in == NULL) return;
1647
Owen Taylor3473f882001-02-23 17:55:21 +00001648 if (in->raw) {
1649 xmlBufferFree(in->raw);
1650 in->raw = NULL;
1651 }
1652 if (in->encoder != NULL) {
1653 xmlCharEncCloseFunc(in->encoder);
1654 }
1655 if (in->closecallback != NULL) {
1656 in->closecallback(in->context);
1657 }
1658 if (in->buffer != NULL) {
1659 xmlBufferFree(in->buffer);
1660 in->buffer = NULL;
1661 }
1662
Owen Taylor3473f882001-02-23 17:55:21 +00001663 xmlFree(in);
1664}
1665
1666/**
1667 * xmlOutputBufferClose:
1668 * @out: a buffered output
1669 *
1670 * flushes and close the output I/O channel
1671 * and free up all the associated resources
1672 *
1673 * Returns the number of byte written or -1 in case of error.
1674 */
1675int
1676xmlOutputBufferClose(xmlOutputBufferPtr out) {
1677 int written;
Daniel Veillardf012a642001-07-23 19:10:52 +00001678 int err_rc = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001679
1680 if (out == NULL)
1681 return(-1);
1682 if (out->writecallback != NULL)
1683 xmlOutputBufferFlush(out);
1684 if (out->closecallback != NULL) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001685 err_rc = out->closecallback(out->context);
Owen Taylor3473f882001-02-23 17:55:21 +00001686 }
1687 written = out->written;
1688 if (out->conv) {
1689 xmlBufferFree(out->conv);
1690 out->conv = NULL;
1691 }
1692 if (out->encoder != NULL) {
1693 xmlCharEncCloseFunc(out->encoder);
1694 }
1695 if (out->buffer != NULL) {
1696 xmlBufferFree(out->buffer);
1697 out->buffer = NULL;
1698 }
1699
Owen Taylor3473f882001-02-23 17:55:21 +00001700 xmlFree(out);
Daniel Veillardf012a642001-07-23 19:10:52 +00001701 return( ( err_rc == 0 ) ? written : err_rc );
Owen Taylor3473f882001-02-23 17:55:21 +00001702}
1703
1704/**
1705 * xmlParserInputBufferCreateFilename:
1706 * @URI: a C string containing the URI or filename
1707 * @enc: the charset encoding if known
1708 *
1709 * Create a buffered parser input for the progressive parsing of a file
1710 * If filename is "-' then we use stdin as the input.
1711 * Automatic support for ZLIB/Compress compressed document is provided
1712 * by default if found at compile-time.
1713 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
1714 *
1715 * Returns the new parser input or NULL
1716 */
1717xmlParserInputBufferPtr
Daniel Veillard3e59fc52003-04-18 12:34:58 +00001718xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001719 xmlParserInputBufferPtr ret;
Daniel Veillard388236f2001-07-08 18:35:48 +00001720 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001721 void *context = NULL;
1722
1723 if (xmlInputCallbackInitialized == 0)
1724 xmlRegisterDefaultInputCallbacks();
1725
1726 if (URI == NULL) return(NULL);
1727
1728 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001729 * Try to find one of the input accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00001730 * Go in reverse to give precedence to user defined handlers.
Daniel Veillard388236f2001-07-08 18:35:48 +00001731 */
1732 if (context == NULL) {
1733 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
1734 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
1735 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00001736 context = xmlInputCallbackTable[i].opencallback(URI);
Daniel Veillard388236f2001-07-08 18:35:48 +00001737 if (context != NULL)
1738 break;
1739 }
Owen Taylor3473f882001-02-23 17:55:21 +00001740 }
1741 }
1742 if (context == NULL) {
1743 return(NULL);
1744 }
1745
1746 /*
1747 * Allocate the Input buffer front-end.
1748 */
1749 ret = xmlAllocParserInputBuffer(enc);
1750 if (ret != NULL) {
1751 ret->context = context;
1752 ret->readcallback = xmlInputCallbackTable[i].readcallback;
1753 ret->closecallback = xmlInputCallbackTable[i].closecallback;
William M. Brackc07329e2003-09-08 01:57:30 +00001754#ifdef HAVE_ZLIB_H
1755 if (xmlInputCallbackTable[i].opencallback == xmlGzfileOpen) {
1756 if (((z_stream *)context)->avail_in > 4) {
1757 char *cptr, buff4[4];
Daniel Veillard07cb8222003-09-10 10:51:05 +00001758 cptr = (char *) ((z_stream *)context)->next_in;
William M. Brackc07329e2003-09-08 01:57:30 +00001759 if (gzread(context, buff4, 4) == 4) {
1760 if (strncmp(buff4, cptr, 4) == 0)
1761 ret->compressed = 0;
1762 else
1763 ret->compressed = 1;
1764 gzrewind(context);
1765 }
1766 }
1767 }
1768#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001769 }
1770 return(ret);
1771}
1772
1773/**
1774 * xmlOutputBufferCreateFilename:
1775 * @URI: a C string containing the URI or filename
1776 * @encoder: the encoding converter or NULL
1777 * @compression: the compression ration (0 none, 9 max).
1778 *
1779 * Create a buffered output for the progressive saving of a file
1780 * If filename is "-' then we use stdout as the output.
1781 * Automatic support for ZLIB/Compress compressed document is provided
1782 * by default if found at compile-time.
1783 * TODO: currently if compression is set, the library only support
1784 * writing to a local file.
1785 *
1786 * Returns the new output or NULL
1787 */
1788xmlOutputBufferPtr
1789xmlOutputBufferCreateFilename(const char *URI,
1790 xmlCharEncodingHandlerPtr encoder,
1791 int compression) {
1792 xmlOutputBufferPtr ret;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001793 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001794 void *context = NULL;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001795 char *unescaped;
Owen Taylor3473f882001-02-23 17:55:21 +00001796
Daniel Veillardf012a642001-07-23 19:10:52 +00001797 int is_http_uri = 0; /* Can't change if HTTP disabled */
1798
Owen Taylor3473f882001-02-23 17:55:21 +00001799 if (xmlOutputCallbackInitialized == 0)
1800 xmlRegisterDefaultOutputCallbacks();
1801
1802 if (URI == NULL) return(NULL);
1803
Daniel Veillardf012a642001-07-23 19:10:52 +00001804#ifdef LIBXML_HTTP_ENABLED
1805 /* Need to prevent HTTP URI's from falling into zlib short circuit */
1806
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00001807 is_http_uri = xmlIOHTTPMatch( URI );
Daniel Veillardf012a642001-07-23 19:10:52 +00001808#endif
1809
Owen Taylor3473f882001-02-23 17:55:21 +00001810
1811 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00001812 * Try to find one of the output accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00001813 * Go in reverse to give precedence to user defined handlers.
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001814 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00001815 */
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00001816 unescaped = xmlURIUnescapeString(URI, 0, NULL);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001817 if (unescaped != NULL) {
1818#ifdef HAVE_ZLIB_H
1819 if ((compression > 0) && (compression <= 9) && (is_http_uri == 0)) {
1820 context = xmlGzfileOpenW(unescaped, compression);
1821 if (context != NULL) {
1822 ret = xmlAllocOutputBuffer(encoder);
1823 if (ret != NULL) {
1824 ret->context = context;
1825 ret->writecallback = xmlGzfileWrite;
1826 ret->closecallback = xmlGzfileClose;
1827 }
1828 xmlFree(unescaped);
1829 return(ret);
1830 }
1831 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001832#endif
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001833 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
1834 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
1835 (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
1836#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
1837 /* Need to pass compression parameter into HTTP open calls */
1838 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
1839 context = xmlIOHTTPOpenW(unescaped, compression);
1840 else
1841#endif
1842 context = xmlOutputCallbackTable[i].opencallback(unescaped);
1843 if (context != NULL)
1844 break;
1845 }
1846 }
1847 xmlFree(unescaped);
1848 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001849
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001850 /*
1851 * If this failed try with a non-escaped URI this may be a strange
1852 * filename
1853 */
1854 if (context == NULL) {
1855#ifdef HAVE_ZLIB_H
1856 if ((compression > 0) && (compression <= 9) && (is_http_uri == 0)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00001857 context = xmlGzfileOpenW(URI, compression);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001858 if (context != NULL) {
1859 ret = xmlAllocOutputBuffer(encoder);
1860 if (ret != NULL) {
1861 ret->context = context;
1862 ret->writecallback = xmlGzfileWrite;
1863 ret->closecallback = xmlGzfileClose;
1864 }
1865 return(ret);
1866 }
1867 }
1868#endif
1869 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
1870 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00001871 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00001872#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
1873 /* Need to pass compression parameter into HTTP open calls */
1874 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
1875 context = xmlIOHTTPOpenW(URI, compression);
1876 else
1877#endif
1878 context = xmlOutputCallbackTable[i].opencallback(URI);
1879 if (context != NULL)
1880 break;
1881 }
Owen Taylor3473f882001-02-23 17:55:21 +00001882 }
1883 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001884
Owen Taylor3473f882001-02-23 17:55:21 +00001885 if (context == NULL) {
1886 return(NULL);
1887 }
1888
1889 /*
1890 * Allocate the Output buffer front-end.
1891 */
1892 ret = xmlAllocOutputBuffer(encoder);
1893 if (ret != NULL) {
1894 ret->context = context;
1895 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
1896 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
1897 }
1898 return(ret);
1899}
1900
1901/**
1902 * xmlParserInputBufferCreateFile:
1903 * @file: a FILE*
1904 * @enc: the charset encoding if known
1905 *
1906 * Create a buffered parser input for the progressive parsing of a FILE *
1907 * buffered C I/O
1908 *
1909 * Returns the new parser input or NULL
1910 */
1911xmlParserInputBufferPtr
1912xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
1913 xmlParserInputBufferPtr ret;
1914
1915 if (xmlInputCallbackInitialized == 0)
1916 xmlRegisterDefaultInputCallbacks();
1917
1918 if (file == NULL) return(NULL);
1919
1920 ret = xmlAllocParserInputBuffer(enc);
1921 if (ret != NULL) {
1922 ret->context = file;
1923 ret->readcallback = xmlFileRead;
1924 ret->closecallback = xmlFileFlush;
1925 }
1926
1927 return(ret);
1928}
1929
1930/**
1931 * xmlOutputBufferCreateFile:
1932 * @file: a FILE*
1933 * @encoder: the encoding converter or NULL
1934 *
1935 * Create a buffered output for the progressive saving to a FILE *
1936 * buffered C I/O
1937 *
1938 * Returns the new parser output or NULL
1939 */
1940xmlOutputBufferPtr
1941xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
1942 xmlOutputBufferPtr ret;
1943
1944 if (xmlOutputCallbackInitialized == 0)
1945 xmlRegisterDefaultOutputCallbacks();
1946
1947 if (file == NULL) return(NULL);
1948
1949 ret = xmlAllocOutputBuffer(encoder);
1950 if (ret != NULL) {
1951 ret->context = file;
1952 ret->writecallback = xmlFileWrite;
1953 ret->closecallback = xmlFileFlush;
1954 }
1955
1956 return(ret);
1957}
1958
1959/**
1960 * xmlParserInputBufferCreateFd:
1961 * @fd: a file descriptor number
1962 * @enc: the charset encoding if known
1963 *
1964 * Create a buffered parser input for the progressive parsing for the input
1965 * from a file descriptor
1966 *
1967 * Returns the new parser input or NULL
1968 */
1969xmlParserInputBufferPtr
1970xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
1971 xmlParserInputBufferPtr ret;
1972
1973 if (fd < 0) return(NULL);
1974
1975 ret = xmlAllocParserInputBuffer(enc);
1976 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00001977 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00001978 ret->readcallback = xmlFdRead;
1979 ret->closecallback = xmlFdClose;
1980 }
1981
1982 return(ret);
1983}
1984
1985/**
1986 * xmlParserInputBufferCreateMem:
1987 * @mem: the memory input
1988 * @size: the length of the memory block
1989 * @enc: the charset encoding if known
1990 *
1991 * Create a buffered parser input for the progressive parsing for the input
1992 * from a memory area.
1993 *
1994 * Returns the new parser input or NULL
1995 */
1996xmlParserInputBufferPtr
1997xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
1998 xmlParserInputBufferPtr ret;
1999
2000 if (size <= 0) return(NULL);
2001 if (mem == NULL) return(NULL);
2002
2003 ret = xmlAllocParserInputBuffer(enc);
2004 if (ret != NULL) {
2005 ret->context = (void *) mem;
2006 ret->readcallback = (xmlInputReadCallback) xmlNop;
2007 ret->closecallback = NULL;
2008 xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size);
2009 }
2010
2011 return(ret);
2012}
2013
2014/**
Daniel Veillard53350552003-09-18 13:35:51 +00002015 * xmlParserInputBufferCreateStatic:
2016 * @mem: the memory input
2017 * @size: the length of the memory block
2018 * @enc: the charset encoding if known
2019 *
2020 * Create a buffered parser input for the progressive parsing for the input
2021 * from an immutable memory area. This will not copy the memory area to
2022 * the buffer, but the memory is expected to be available until the end of
2023 * the parsing, this is useful for example when using mmap'ed file.
2024 *
2025 * Returns the new parser input or NULL
2026 */
2027xmlParserInputBufferPtr
2028xmlParserInputBufferCreateStatic(const char *mem, int size,
2029 xmlCharEncoding enc) {
2030 xmlParserInputBufferPtr ret;
2031
2032 if (size <= 0) return(NULL);
2033 if (mem == NULL) return(NULL);
2034
2035 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2036 if (ret == NULL) {
2037 xmlGenericError(xmlGenericErrorContext,
2038 "xmlParserInputBufferCreateStatic : out of memory!\n");
2039 return(NULL);
2040 }
2041 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillarde72c5082003-09-19 12:44:05 +00002042 ret->buffer = xmlBufferCreateStatic((void *)mem, (size_t) size);
Daniel Veillard53350552003-09-18 13:35:51 +00002043 if (ret->buffer == NULL) {
2044 xmlFree(ret);
2045 return(NULL);
2046 }
2047 ret->encoder = xmlGetCharEncodingHandler(enc);
2048 if (ret->encoder != NULL)
2049 ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
2050 else
2051 ret->raw = NULL;
2052 ret->compressed = -1;
2053 ret->context = (void *) mem;
2054 ret->readcallback = NULL;
2055 ret->closecallback = NULL;
2056
2057 return(ret);
2058}
2059
2060/**
Owen Taylor3473f882001-02-23 17:55:21 +00002061 * xmlOutputBufferCreateFd:
2062 * @fd: a file descriptor number
2063 * @encoder: the encoding converter or NULL
2064 *
2065 * Create a buffered output for the progressive saving
2066 * to a file descriptor
2067 *
2068 * Returns the new parser output or NULL
2069 */
2070xmlOutputBufferPtr
2071xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
2072 xmlOutputBufferPtr ret;
2073
2074 if (fd < 0) return(NULL);
2075
2076 ret = xmlAllocOutputBuffer(encoder);
2077 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002078 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002079 ret->writecallback = xmlFdWrite;
Daniel Veillard7db38712002-02-07 16:39:11 +00002080 ret->closecallback = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002081 }
2082
2083 return(ret);
2084}
2085
2086/**
2087 * xmlParserInputBufferCreateIO:
2088 * @ioread: an I/O read function
2089 * @ioclose: an I/O close function
2090 * @ioctx: an I/O handler
2091 * @enc: the charset encoding if known
2092 *
2093 * Create a buffered parser input for the progressive parsing for the input
2094 * from an I/O handler
2095 *
2096 * Returns the new parser input or NULL
2097 */
2098xmlParserInputBufferPtr
2099xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
2100 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
2101 xmlParserInputBufferPtr ret;
2102
2103 if (ioread == NULL) return(NULL);
2104
2105 ret = xmlAllocParserInputBuffer(enc);
2106 if (ret != NULL) {
2107 ret->context = (void *) ioctx;
2108 ret->readcallback = ioread;
2109 ret->closecallback = ioclose;
2110 }
2111
2112 return(ret);
2113}
2114
2115/**
2116 * xmlOutputBufferCreateIO:
2117 * @iowrite: an I/O write function
2118 * @ioclose: an I/O close function
2119 * @ioctx: an I/O handler
Daniel Veillard9d06d302002-01-22 18:15:52 +00002120 * @encoder: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002121 *
2122 * Create a buffered output for the progressive saving
2123 * to an I/O handler
2124 *
2125 * Returns the new parser output or NULL
2126 */
2127xmlOutputBufferPtr
2128xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
2129 xmlOutputCloseCallback ioclose, void *ioctx,
2130 xmlCharEncodingHandlerPtr encoder) {
2131 xmlOutputBufferPtr ret;
2132
2133 if (iowrite == NULL) return(NULL);
2134
2135 ret = xmlAllocOutputBuffer(encoder);
2136 if (ret != NULL) {
2137 ret->context = (void *) ioctx;
2138 ret->writecallback = iowrite;
2139 ret->closecallback = ioclose;
2140 }
2141
2142 return(ret);
2143}
2144
2145/**
2146 * xmlParserInputBufferPush:
2147 * @in: a buffered parser input
2148 * @len: the size in bytes of the array.
2149 * @buf: an char array
2150 *
2151 * Push the content of the arry in the input buffer
2152 * This routine handle the I18N transcoding to internal UTF-8
2153 * This is used when operating the parser in progressive (push) mode.
2154 *
2155 * Returns the number of chars read and stored in the buffer, or -1
2156 * in case of error.
2157 */
2158int
2159xmlParserInputBufferPush(xmlParserInputBufferPtr in,
2160 int len, const char *buf) {
2161 int nbchars = 0;
2162
2163 if (len < 0) return(0);
2164 if (in->encoder != NULL) {
2165 /*
2166 * Store the data in the incoming raw buffer
2167 */
2168 if (in->raw == NULL) {
2169 in->raw = xmlBufferCreate();
2170 }
2171 xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
2172
2173 /*
2174 * convert as much as possible to the parser reading buffer.
2175 */
2176 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2177 if (nbchars < 0) {
2178 xmlGenericError(xmlGenericErrorContext,
2179 "xmlParserInputBufferPush: encoder error\n");
2180 return(-1);
2181 }
2182 } else {
2183 nbchars = len;
2184 xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
2185 }
2186#ifdef DEBUG_INPUT
2187 xmlGenericError(xmlGenericErrorContext,
2188 "I/O: pushed %d chars, buffer %d/%d\n",
2189 nbchars, in->buffer->use, in->buffer->size);
2190#endif
2191 return(nbchars);
2192}
2193
2194/**
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002195 * endOfInput:
2196 *
2197 * When reading from an Input channel indicated end of file or error
2198 * don't reread from it again.
2199 */
2200static int
2201endOfInput (void * context ATTRIBUTE_UNUSED,
2202 char * buffer ATTRIBUTE_UNUSED,
2203 int len ATTRIBUTE_UNUSED) {
2204 return(0);
2205}
2206
2207/**
Owen Taylor3473f882001-02-23 17:55:21 +00002208 * xmlParserInputBufferGrow:
2209 * @in: a buffered parser input
2210 * @len: indicative value of the amount of chars to read
2211 *
2212 * Grow up the content of the input buffer, the old data are preserved
2213 * This routine handle the I18N transcoding to internal UTF-8
2214 * This routine is used when operating the parser in normal (pull) mode
2215 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002216 * TODO: one should be able to remove one extra copy by copying directly
Owen Taylor3473f882001-02-23 17:55:21 +00002217 * onto in->buffer or in->raw
2218 *
2219 * Returns the number of chars read and stored in the buffer, or -1
2220 * in case of error.
2221 */
2222int
2223xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
2224 char *buffer = NULL;
2225 int res = 0;
2226 int nbchars = 0;
2227 int buffree;
Daniel Veillard9e412302002-06-10 15:59:44 +00002228 unsigned int needSize;
Owen Taylor3473f882001-02-23 17:55:21 +00002229
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002230 if ((len <= MINLEN) && (len != 4))
Owen Taylor3473f882001-02-23 17:55:21 +00002231 len = MINLEN;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002232
Owen Taylor3473f882001-02-23 17:55:21 +00002233 buffree = in->buffer->size - in->buffer->use;
2234 if (buffree <= 0) {
2235 xmlGenericError(xmlGenericErrorContext,
2236 "xmlParserInputBufferGrow : buffer full !\n");
2237 return(0);
2238 }
Owen Taylor3473f882001-02-23 17:55:21 +00002239
Daniel Veillarde5354492002-05-16 08:43:22 +00002240 needSize = in->buffer->use + len + 1;
2241 if (needSize > in->buffer->size){
2242 if (!xmlBufferResize(in->buffer, needSize)){
2243 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard8caa9c22003-06-02 13:35:24 +00002244 "xmlParserInputBufferGrow : out of memory!\n");
Daniel Veillarde5354492002-05-16 08:43:22 +00002245 return(0);
2246 }
Owen Taylor3473f882001-02-23 17:55:21 +00002247 }
Daniel Veillarde5354492002-05-16 08:43:22 +00002248 buffer = (char *)&in->buffer->content[in->buffer->use];
Owen Taylor3473f882001-02-23 17:55:21 +00002249
2250 /*
2251 * Call the read method for this I/O type.
2252 */
2253 if (in->readcallback != NULL) {
2254 res = in->readcallback(in->context, &buffer[0], len);
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002255 if (res <= 0)
2256 in->readcallback = endOfInput;
Owen Taylor3473f882001-02-23 17:55:21 +00002257 } else {
2258 xmlGenericError(xmlGenericErrorContext,
2259 "xmlParserInputBufferGrow : no input !\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002260 return(-1);
2261 }
2262 if (res < 0) {
Owen Taylor3473f882001-02-23 17:55:21 +00002263 return(-1);
2264 }
2265 len = res;
2266 if (in->encoder != NULL) {
2267 /*
2268 * Store the data in the incoming raw buffer
2269 */
2270 if (in->raw == NULL) {
2271 in->raw = xmlBufferCreate();
2272 }
2273 xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
2274
2275 /*
2276 * convert as much as possible to the parser reading buffer.
2277 */
2278 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2279 if (nbchars < 0) {
2280 xmlGenericError(xmlGenericErrorContext,
2281 "xmlParserInputBufferGrow: encoder error\n");
2282 return(-1);
2283 }
2284 } else {
2285 nbchars = len;
Daniel Veillarde5354492002-05-16 08:43:22 +00002286 in->buffer->use += nbchars;
2287 buffer[nbchars] = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002288 }
2289#ifdef DEBUG_INPUT
2290 xmlGenericError(xmlGenericErrorContext,
2291 "I/O: read %d chars, buffer %d/%d\n",
2292 nbchars, in->buffer->use, in->buffer->size);
2293#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002294 return(nbchars);
2295}
2296
2297/**
2298 * xmlParserInputBufferRead:
2299 * @in: a buffered parser input
2300 * @len: indicative value of the amount of chars to read
2301 *
2302 * Refresh the content of the input buffer, the old data are considered
2303 * consumed
2304 * This routine handle the I18N transcoding to internal UTF-8
2305 *
2306 * Returns the number of chars read and stored in the buffer, or -1
2307 * in case of error.
2308 */
2309int
2310xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
2311 /* xmlBufferEmpty(in->buffer); */
2312 if (in->readcallback != NULL)
2313 return(xmlParserInputBufferGrow(in, len));
Daniel Veillard53350552003-09-18 13:35:51 +00002314 else if ((in->buffer != NULL) &&
2315 (in->buffer->alloc == XML_BUFFER_ALLOC_IMMUTABLE))
2316 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002317 else
2318 return(-1);
2319}
2320
2321/**
2322 * xmlOutputBufferWrite:
2323 * @out: a buffered parser output
2324 * @len: the size in bytes of the array.
2325 * @buf: an char array
2326 *
2327 * Write the content of the array in the output I/O buffer
2328 * This routine handle the I18N transcoding from internal UTF-8
2329 * The buffer is lossless, i.e. will store in case of partial
2330 * or delayed writes.
2331 *
2332 * Returns the number of chars immediately written, or -1
2333 * in case of error.
2334 */
2335int
2336xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
2337 int nbchars = 0; /* number of chars to output to I/O */
2338 int ret; /* return from function call */
2339 int written = 0; /* number of char written to I/O so far */
2340 int chunk; /* number of byte curreent processed from buf */
2341
2342 if (len < 0) return(0);
2343
2344 do {
2345 chunk = len;
2346 if (chunk > 4 * MINLEN)
2347 chunk = 4 * MINLEN;
2348
2349 /*
2350 * first handle encoding stuff.
2351 */
2352 if (out->encoder != NULL) {
2353 /*
2354 * Store the data in the incoming raw buffer
2355 */
2356 if (out->conv == NULL) {
2357 out->conv = xmlBufferCreate();
2358 }
2359 xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2360
2361 if ((out->buffer->use < MINLEN) && (chunk == len))
2362 goto done;
2363
2364 /*
2365 * convert as much as possible to the parser reading buffer.
2366 */
2367 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
Daniel Veillard809faa52003-02-10 15:43:53 +00002368 if ((ret < 0) && (ret != -3)) {
Owen Taylor3473f882001-02-23 17:55:21 +00002369 xmlGenericError(xmlGenericErrorContext,
2370 "xmlOutputBufferWrite: encoder error\n");
2371 return(-1);
2372 }
2373 nbchars = out->conv->use;
2374 } else {
2375 xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2376 nbchars = out->buffer->use;
2377 }
2378 buf += chunk;
2379 len -= chunk;
2380
2381 if ((nbchars < MINLEN) && (len <= 0))
2382 goto done;
2383
2384 if (out->writecallback) {
2385 /*
2386 * second write the stuff to the I/O channel
2387 */
2388 if (out->encoder != NULL) {
2389 ret = out->writecallback(out->context,
2390 (const char *)out->conv->content, nbchars);
2391 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002392 xmlBufferShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002393 } else {
2394 ret = out->writecallback(out->context,
2395 (const char *)out->buffer->content, nbchars);
2396 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002397 xmlBufferShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002398 }
2399 if (ret < 0) {
2400 xmlGenericError(xmlGenericErrorContext,
2401 "I/O: error %d writing %d bytes\n", ret, nbchars);
2402 return(ret);
2403 }
2404 out->written += ret;
2405 }
2406 written += nbchars;
2407 } while (len > 0);
2408
2409done:
2410#ifdef DEBUG_INPUT
2411 xmlGenericError(xmlGenericErrorContext,
2412 "I/O: wrote %d chars\n", written);
2413#endif
2414 return(written);
2415}
2416
2417/**
2418 * xmlOutputBufferWriteString:
2419 * @out: a buffered parser output
2420 * @str: a zero terminated C string
2421 *
2422 * Write the content of the string in the output I/O buffer
2423 * This routine handle the I18N transcoding from internal UTF-8
2424 * The buffer is lossless, i.e. will store in case of partial
2425 * or delayed writes.
2426 *
2427 * Returns the number of chars immediately written, or -1
2428 * in case of error.
2429 */
2430int
2431xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
2432 int len;
2433
2434 if (str == NULL)
2435 return(-1);
2436 len = strlen(str);
2437
2438 if (len > 0)
2439 return(xmlOutputBufferWrite(out, len, str));
2440 return(len);
2441}
2442
2443/**
2444 * xmlOutputBufferFlush:
2445 * @out: a buffered output
2446 *
2447 * flushes the output I/O channel
2448 *
2449 * Returns the number of byte written or -1 in case of error.
2450 */
2451int
2452xmlOutputBufferFlush(xmlOutputBufferPtr out) {
2453 int nbchars = 0, ret = 0;
2454
2455 /*
2456 * first handle encoding stuff.
2457 */
2458 if ((out->conv != NULL) && (out->encoder != NULL)) {
2459 /*
2460 * convert as much as possible to the parser reading buffer.
2461 */
2462 nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
2463 if (nbchars < 0) {
2464 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002465 "xmlOutputBufferFlush: encoder error\n");
Owen Taylor3473f882001-02-23 17:55:21 +00002466 return(-1);
2467 }
2468 }
2469
2470 /*
2471 * second flush the stuff to the I/O channel
2472 */
2473 if ((out->conv != NULL) && (out->encoder != NULL) &&
2474 (out->writecallback != NULL)) {
2475 ret = out->writecallback(out->context,
2476 (const char *)out->conv->content, out->conv->use);
2477 if (ret >= 0)
2478 xmlBufferShrink(out->conv, ret);
2479 } else if (out->writecallback != NULL) {
2480 ret = out->writecallback(out->context,
2481 (const char *)out->buffer->content, out->buffer->use);
2482 if (ret >= 0)
2483 xmlBufferShrink(out->buffer, ret);
2484 }
2485 if (ret < 0) {
2486 xmlGenericError(xmlGenericErrorContext,
2487 "I/O: error %d flushing %d bytes\n", ret, nbchars);
2488 return(ret);
2489 }
2490 out->written += ret;
2491
2492#ifdef DEBUG_INPUT
2493 xmlGenericError(xmlGenericErrorContext,
2494 "I/O: flushed %d chars\n", ret);
2495#endif
2496 return(ret);
2497}
2498
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002499/**
Owen Taylor3473f882001-02-23 17:55:21 +00002500 * xmlParserGetDirectory:
2501 * @filename: the path to a file
2502 *
2503 * lookup the directory for that file
2504 *
2505 * Returns a new allocated string containing the directory, or NULL.
2506 */
2507char *
2508xmlParserGetDirectory(const char *filename) {
2509 char *ret = NULL;
2510 char dir[1024];
2511 char *cur;
2512 char sep = '/';
2513
Igor Zlatkovic9181cc02002-09-29 17:51:06 +00002514#ifdef _WIN32_WCE /* easy way by now ... wince does not have dirs! */
2515 return NULL;
2516#endif
2517
Owen Taylor3473f882001-02-23 17:55:21 +00002518 if (xmlInputCallbackInitialized == 0)
2519 xmlRegisterDefaultInputCallbacks();
2520
2521 if (filename == NULL) return(NULL);
Daniel Veillard3c5ed912002-01-08 10:36:16 +00002522#if defined(WIN32) && !defined(__CYGWIN__)
Owen Taylor3473f882001-02-23 17:55:21 +00002523 sep = '\\';
2524#endif
2525
2526 strncpy(dir, filename, 1023);
2527 dir[1023] = 0;
2528 cur = &dir[strlen(dir)];
2529 while (cur > dir) {
2530 if (*cur == sep) break;
2531 cur --;
2532 }
2533 if (*cur == sep) {
2534 if (cur == dir) dir[1] = 0;
2535 else *cur = 0;
2536 ret = xmlMemStrdup(dir);
2537 } else {
2538 if (getcwd(dir, 1024) != NULL) {
2539 dir[1023] = 0;
2540 ret = xmlMemStrdup(dir);
2541 }
2542 }
2543 return(ret);
2544}
2545
2546/****************************************************************
2547 * *
2548 * External entities loading *
2549 * *
2550 ****************************************************************/
2551
Daniel Veillard561b7f82002-03-20 21:55:57 +00002552static int xmlSysIDExists(const char *URL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00002553#ifdef HAVE_STAT
2554 int ret;
2555 struct stat info;
2556 const char *path;
2557
2558 if (URL == NULL)
2559 return(0);
2560
Daniel Veillardf4862f02002-09-10 11:13:43 +00002561 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00002562#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00002563 path = &URL[17];
2564#else
Daniel Veillard6990bf32001-08-23 21:17:48 +00002565 path = &URL[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00002566#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002567 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00002568#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard6990bf32001-08-23 21:17:48 +00002569 path = &URL[8];
2570#else
2571 path = &URL[7];
2572#endif
2573 } else
2574 path = URL;
2575 ret = stat(path, &info);
Daniel Veillard561b7f82002-03-20 21:55:57 +00002576 if (ret == 0)
2577 return(1);
Daniel Veillard6990bf32001-08-23 21:17:48 +00002578#endif
Daniel Veillard561b7f82002-03-20 21:55:57 +00002579 return(0);
Daniel Veillard6990bf32001-08-23 21:17:48 +00002580}
Daniel Veillard6990bf32001-08-23 21:17:48 +00002581
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002582/**
Owen Taylor3473f882001-02-23 17:55:21 +00002583 * xmlDefaultExternalEntityLoader:
2584 * @URL: the URL for the entity to load
2585 * @ID: the System ID for the entity to load
2586 * @ctxt: the context in which the entity is called or NULL
2587 *
2588 * By default we don't load external entitites, yet.
2589 *
2590 * Returns a new allocated xmlParserInputPtr, or NULL.
2591 */
2592static
2593xmlParserInputPtr
2594xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
2595 xmlParserCtxtPtr ctxt) {
2596 xmlParserInputPtr ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002597 xmlChar *resource = NULL;
2598#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002599 xmlCatalogAllow pref;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002600#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002601
2602#ifdef DEBUG_EXTERNAL_ENTITIES
2603 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf012a642001-07-23 19:10:52 +00002604 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00002605#endif
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002606#ifdef LIBXML_CATALOG_ENABLED
2607 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002608 * If the resource doesn't exists as a file,
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002609 * try to load it from the resource pointed in the catalogs
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002610 */
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002611 pref = xmlCatalogGetDefaults();
2612
Daniel Veillard561b7f82002-03-20 21:55:57 +00002613 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlSysIDExists(URL))) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002614 /*
2615 * Do a local lookup
2616 */
2617 if ((ctxt->catalogs != NULL) &&
2618 ((pref == XML_CATA_ALLOW_ALL) ||
2619 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2620 resource = xmlCatalogLocalResolve(ctxt->catalogs,
2621 (const xmlChar *)ID,
2622 (const xmlChar *)URL);
2623 }
2624 /*
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002625 * Try a global lookup
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002626 */
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002627 if ((resource == NULL) &&
2628 ((pref == XML_CATA_ALLOW_ALL) ||
2629 (pref == XML_CATA_ALLOW_GLOBAL))) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002630 resource = xmlCatalogResolve((const xmlChar *)ID,
2631 (const xmlChar *)URL);
2632 }
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002633 if ((resource == NULL) && (URL != NULL))
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00002634 resource = xmlStrdup((const xmlChar *) URL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002635
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002636 /*
2637 * TODO: do an URI lookup on the reference
2638 */
Daniel Veillard561b7f82002-03-20 21:55:57 +00002639 if ((resource != NULL) && (!xmlSysIDExists((const char *)resource))) {
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002640 xmlChar *tmp = NULL;
2641
2642 if ((ctxt->catalogs != NULL) &&
2643 ((pref == XML_CATA_ALLOW_ALL) ||
2644 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2645 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
2646 }
2647 if ((tmp == NULL) &&
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00002648 ((pref == XML_CATA_ALLOW_ALL) ||
2649 (pref == XML_CATA_ALLOW_GLOBAL))) {
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002650 tmp = xmlCatalogResolveURI(resource);
2651 }
2652
2653 if (tmp != NULL) {
2654 xmlFree(resource);
2655 resource = tmp;
2656 }
2657 }
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002658 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002659#endif
2660
2661 if (resource == NULL)
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002662 resource = (xmlChar *) URL;
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002663
2664 if (resource == NULL) {
Daniel Veillardc6613042002-03-02 09:34:02 +00002665 if (ID == NULL)
2666 ID = "NULL";
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002667 if ((ctxt->validate) && (ctxt->sax != NULL) &&
2668 (ctxt->sax->error != NULL))
William M. Brack4811ba32003-09-06 18:02:53 +00002669 ctxt->sax->error(ctxt->userData,
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002670 "failed to load external entity \"%s\"\n", ID);
2671 else if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
William M. Brack4811ba32003-09-06 18:02:53 +00002672 ctxt->sax->warning(ctxt->userData,
Owen Taylor3473f882001-02-23 17:55:21 +00002673 "failed to load external entity \"%s\"\n", ID);
2674 return(NULL);
2675 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002676 ret = xmlNewInputFromFile(ctxt, (const char *)resource);
Owen Taylor3473f882001-02-23 17:55:21 +00002677 if (ret == NULL) {
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002678 if ((ctxt->validate) && (ctxt->sax != NULL) &&
2679 (ctxt->sax->error != NULL))
William M. Brack4811ba32003-09-06 18:02:53 +00002680 ctxt->sax->error(ctxt->userData,
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002681 "failed to load external entity \"%s\"\n", resource);
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002682 else if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
William M. Brack4811ba32003-09-06 18:02:53 +00002683 ctxt->sax->warning(ctxt->userData,
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002684 "failed to load external entity \"%s\"\n", resource);
Owen Taylor3473f882001-02-23 17:55:21 +00002685 }
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002686 if ((resource != NULL) && (resource != (xmlChar *) URL))
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002687 xmlFree(resource);
Owen Taylor3473f882001-02-23 17:55:21 +00002688 return(ret);
2689}
2690
2691static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
2692 xmlDefaultExternalEntityLoader;
2693
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002694/**
Owen Taylor3473f882001-02-23 17:55:21 +00002695 * xmlSetExternalEntityLoader:
2696 * @f: the new entity resolver function
2697 *
2698 * Changes the defaultexternal entity resolver function for the application
2699 */
2700void
2701xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
2702 xmlCurrentExternalEntityLoader = f;
2703}
2704
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002705/**
Owen Taylor3473f882001-02-23 17:55:21 +00002706 * xmlGetExternalEntityLoader:
2707 *
2708 * Get the default external entity resolver function for the application
2709 *
2710 * Returns the xmlExternalEntityLoader function pointer
2711 */
2712xmlExternalEntityLoader
2713xmlGetExternalEntityLoader(void) {
2714 return(xmlCurrentExternalEntityLoader);
2715}
2716
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002717/**
Owen Taylor3473f882001-02-23 17:55:21 +00002718 * xmlLoadExternalEntity:
2719 * @URL: the URL for the entity to load
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00002720 * @ID: the Public ID for the entity to load
Owen Taylor3473f882001-02-23 17:55:21 +00002721 * @ctxt: the context in which the entity is called or NULL
2722 *
2723 * Load an external entity, note that the use of this function for
2724 * unparsed entities may generate problems
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002725 * TODO: a more generic External entity API must be designed
Owen Taylor3473f882001-02-23 17:55:21 +00002726 *
2727 * Returns the xmlParserInputPtr or NULL
2728 */
2729xmlParserInputPtr
2730xmlLoadExternalEntity(const char *URL, const char *ID,
2731 xmlParserCtxtPtr ctxt) {
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00002732 if ((URL != NULL) && (xmlSysIDExists(URL) == 0)) {
2733 char *canonicFilename;
2734 xmlParserInputPtr ret;
2735
2736 canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL);
2737 if (canonicFilename == NULL) {
2738 if (xmlDefaultSAXHandler.error != NULL) {
2739 xmlDefaultSAXHandler.error(NULL, "out of memory\n");
2740 }
2741 return(NULL);
2742 }
2743
2744 ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt);
2745 xmlFree(canonicFilename);
2746 return(ret);
2747 }
Owen Taylor3473f882001-02-23 17:55:21 +00002748 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
2749}
2750
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00002751/************************************************************************
2752 * *
2753 * Disabling Network access *
2754 * *
2755 ************************************************************************/
2756
2757#ifdef LIBXML_CATALOG_ENABLED
2758static int
2759xmlNoNetExists(const char *URL)
2760{
2761#ifdef HAVE_STAT
2762 int ret;
2763 struct stat info;
2764 const char *path;
2765
2766 if (URL == NULL)
2767 return (0);
2768
Daniel Veillardf4862f02002-09-10 11:13:43 +00002769 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00002770#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00002771 path = &URL[17];
2772#else
2773 path = &URL[16];
2774#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002775 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00002776#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00002777 path = &URL[8];
2778#else
2779 path = &URL[7];
2780#endif
2781 } else
2782 path = URL;
2783 ret = stat(path, &info);
2784 if (ret == 0)
2785 return (1);
2786#endif
2787 return (0);
2788}
2789#endif
2790
2791/**
2792 * xmlNoNetExternalEntityLoader:
2793 * @URL: the URL for the entity to load
2794 * @ID: the System ID for the entity to load
2795 * @ctxt: the context in which the entity is called or NULL
2796 *
2797 * A specific entity loader disabling network accesses, though still
2798 * allowing local catalog accesses for resolution.
2799 *
2800 * Returns a new allocated xmlParserInputPtr, or NULL.
2801 */
2802xmlParserInputPtr
2803xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
2804 xmlParserCtxtPtr ctxt) {
2805 xmlParserInputPtr input = NULL;
2806 xmlChar *resource = NULL;
2807
2808#ifdef LIBXML_CATALOG_ENABLED
2809 xmlCatalogAllow pref;
2810
2811 /*
2812 * If the resource doesn't exists as a file,
2813 * try to load it from the resource pointed in the catalogs
2814 */
2815 pref = xmlCatalogGetDefaults();
2816
2817 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
2818 /*
2819 * Do a local lookup
2820 */
2821 if ((ctxt->catalogs != NULL) &&
2822 ((pref == XML_CATA_ALLOW_ALL) ||
2823 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2824 resource = xmlCatalogLocalResolve(ctxt->catalogs,
2825 (const xmlChar *)ID,
2826 (const xmlChar *)URL);
2827 }
2828 /*
2829 * Try a global lookup
2830 */
2831 if ((resource == NULL) &&
2832 ((pref == XML_CATA_ALLOW_ALL) ||
2833 (pref == XML_CATA_ALLOW_GLOBAL))) {
2834 resource = xmlCatalogResolve((const xmlChar *)ID,
2835 (const xmlChar *)URL);
2836 }
2837 if ((resource == NULL) && (URL != NULL))
2838 resource = xmlStrdup((const xmlChar *) URL);
2839
2840 /*
2841 * TODO: do an URI lookup on the reference
2842 */
2843 if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
2844 xmlChar *tmp = NULL;
2845
2846 if ((ctxt->catalogs != NULL) &&
2847 ((pref == XML_CATA_ALLOW_ALL) ||
2848 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2849 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
2850 }
2851 if ((tmp == NULL) &&
2852 ((pref == XML_CATA_ALLOW_ALL) ||
2853 (pref == XML_CATA_ALLOW_GLOBAL))) {
2854 tmp = xmlCatalogResolveURI(resource);
2855 }
2856
2857 if (tmp != NULL) {
2858 xmlFree(resource);
2859 resource = tmp;
2860 }
2861 }
2862 }
2863#endif
2864 if (resource == NULL)
2865 resource = (xmlChar *) URL;
2866
2867 if (resource != NULL) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002868 if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
2869 (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00002870 xmlGenericError(xmlGenericErrorContext,
2871 "Attempt to load network entity %s \n", resource);
2872
2873 if (resource != (xmlChar *) URL)
2874 xmlFree(resource);
2875 return(NULL);
2876 }
2877 }
2878 input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
2879 if (resource != (xmlChar *) URL)
2880 xmlFree(resource);
2881 return(input);
2882}
2883