blob: 0698d0497f13bea5199e25b893ead906b62110b7 [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
2 * xmlIO.c : implementation of the I/O interfaces used by the parser
3 *
4 * See Copyright for the status of this software.
5 *
Daniel Veillard344cee72001-08-20 00:08:40 +00006 * daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +00007 *
8 * 14 Nov 2000 ht - for VMS, truncated name of long functions to under 32 char
9 */
10
Daniel Veillard34ce8be2002-03-18 19:37:11 +000011#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000012#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000013
Owen Taylor3473f882001-02-23 17:55:21 +000014#include <string.h>
Daniel Veillard92727042002-09-17 17:59:20 +000015#ifdef HAVE_ERRNO_H
Owen Taylor3473f882001-02-23 17:55:21 +000016#include <errno.h>
Daniel Veillard92727042002-09-17 17:59:20 +000017#endif
18
Owen Taylor3473f882001-02-23 17:55:21 +000019
20#ifdef HAVE_SYS_TYPES_H
21#include <sys/types.h>
22#endif
23#ifdef HAVE_SYS_STAT_H
24#include <sys/stat.h>
25#endif
26#ifdef HAVE_FCNTL_H
27#include <fcntl.h>
28#endif
29#ifdef HAVE_UNISTD_H
30#include <unistd.h>
31#endif
32#ifdef HAVE_STDLIB_H
33#include <stdlib.h>
34#endif
35#ifdef HAVE_ZLIB_H
36#include <zlib.h>
37#endif
38
39/* Figure a portable way to know if a file is a directory. */
40#ifndef HAVE_STAT
41# ifdef HAVE__STAT
Daniel Veillard50f34372001-08-03 12:06:36 +000042 /* MS C library seems to define stat and _stat. The definition
43 is identical. Still, mapping them to each other causes a warning. */
44# ifndef _MSC_VER
45# define stat(x,y) _stat(x,y)
46# endif
Owen Taylor3473f882001-02-23 17:55:21 +000047# define HAVE_STAT
48# endif
49#endif
50#ifdef HAVE_STAT
51# ifndef S_ISDIR
52# ifdef _S_ISDIR
53# define S_ISDIR(x) _S_ISDIR(x)
54# else
55# ifdef S_IFDIR
56# ifndef S_IFMT
57# ifdef _S_IFMT
58# define S_IFMT _S_IFMT
59# endif
60# endif
61# ifdef S_IFMT
62# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
63# endif
64# endif
65# endif
66# endif
67#endif
68
69#include <libxml/xmlmemory.h>
70#include <libxml/parser.h>
71#include <libxml/parserInternals.h>
72#include <libxml/xmlIO.h>
Daniel Veillard388236f2001-07-08 18:35:48 +000073#include <libxml/uri.h>
Owen Taylor3473f882001-02-23 17:55:21 +000074#include <libxml/nanohttp.h>
75#include <libxml/nanoftp.h>
76#include <libxml/xmlerror.h>
Daniel Veillard7d6fd212001-05-10 15:34:11 +000077#ifdef LIBXML_CATALOG_ENABLED
78#include <libxml/catalog.h>
79#endif
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000080#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000081
Daniel Veillardf012a642001-07-23 19:10:52 +000082/* #define VERBOSE_FAILURE */
Daniel Veillard1fd36d22001-07-04 22:54:28 +000083/* #define DEBUG_EXTERNAL_ENTITIES */
Owen Taylor3473f882001-02-23 17:55:21 +000084/* #define DEBUG_INPUT */
85
86#ifdef DEBUG_INPUT
87#define MINLEN 40
88#else
89#define MINLEN 4000
90#endif
91
92/*
93 * Input I/O callback sets
94 */
95typedef struct _xmlInputCallback {
96 xmlInputMatchCallback matchcallback;
97 xmlInputOpenCallback opencallback;
98 xmlInputReadCallback readcallback;
99 xmlInputCloseCallback closecallback;
100} xmlInputCallback;
101
102#define MAX_INPUT_CALLBACK 15
103
Daniel Veillard22090732001-07-16 00:06:07 +0000104static xmlInputCallback xmlInputCallbackTable[MAX_INPUT_CALLBACK];
105static int xmlInputCallbackNr = 0;
106static int xmlInputCallbackInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000107
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000108#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000109/*
110 * Output I/O callback sets
111 */
112typedef struct _xmlOutputCallback {
113 xmlOutputMatchCallback matchcallback;
114 xmlOutputOpenCallback opencallback;
115 xmlOutputWriteCallback writecallback;
116 xmlOutputCloseCallback closecallback;
117} xmlOutputCallback;
118
119#define MAX_OUTPUT_CALLBACK 15
120
Daniel Veillard22090732001-07-16 00:06:07 +0000121static xmlOutputCallback xmlOutputCallbackTable[MAX_OUTPUT_CALLBACK];
122static int xmlOutputCallbackNr = 0;
123static int xmlOutputCallbackInitialized = 0;
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000124#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000125
Daniel Veillard05d987b2003-10-08 11:54:57 +0000126/************************************************************************
127 * *
128 * Tree memory error handler *
129 * *
130 ************************************************************************/
Daniel Veillardf4862f02002-09-10 11:13:43 +0000131
Daniel Veillard05d987b2003-10-08 11:54:57 +0000132static const char *IOerr[] = {
Daniel Veillarda8856222003-10-08 19:26:03 +0000133 "Unknown IO error", /* UNKNOWN */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000134 "Permission denied", /* EACCES */
135 "Resource temporarily unavailable",/* EAGAIN */
136 "Bad file descriptor", /* EBADF */
137 "Bad message", /* EBADMSG */
138 "Resource busy", /* EBUSY */
139 "Operation canceled", /* ECANCELED */
140 "No child processes", /* ECHILD */
141 "Resource deadlock avoided",/* EDEADLK */
142 "Domain error", /* EDOM */
143 "File exists", /* EEXIST */
144 "Bad address", /* EFAULT */
145 "File too large", /* EFBIG */
146 "Operation in progress", /* EINPROGRESS */
147 "Interrupted function call",/* EINTR */
148 "Invalid argument", /* EINVAL */
149 "Input/output error", /* EIO */
150 "Is a directory", /* EISDIR */
151 "Too many open files", /* EMFILE */
152 "Too many links", /* EMLINK */
153 "Inappropriate message buffer length",/* EMSGSIZE */
154 "Filename too long", /* ENAMETOOLONG */
155 "Too many open files in system",/* ENFILE */
156 "No such device", /* ENODEV */
157 "No such file or directory",/* ENOENT */
158 "Exec format error", /* ENOEXEC */
159 "No locks available", /* ENOLCK */
160 "Not enough space", /* ENOMEM */
161 "No space left on device", /* ENOSPC */
162 "Function not implemented", /* ENOSYS */
163 "Not a directory", /* ENOTDIR */
164 "Directory not empty", /* ENOTEMPTY */
165 "Not supported", /* ENOTSUP */
166 "Inappropriate I/O control operation",/* ENOTTY */
167 "No such device or address",/* ENXIO */
168 "Operation not permitted", /* EPERM */
169 "Broken pipe", /* EPIPE */
170 "Result too large", /* ERANGE */
171 "Read-only file system", /* EROFS */
172 "Invalid seek", /* ESPIPE */
173 "No such process", /* ESRCH */
174 "Operation timed out", /* ETIMEDOUT */
175 "Improper link", /* EXDEV */
176 "Attempt to load network entity %s" /* XML_IO_NETWORK_ATTEMPT */
177 "encoder error", /* XML_IO_ENCODER */
178};
179
180/**
181 * xmlIOErrMemory:
182 * @extra: extra informations
183 *
184 * Handle an out of memory condition
185 */
186static void
187xmlIOErrMemory(const char *extra)
188{
189 __xmlSimpleError(XML_FROM_IO, XML_ERR_NO_MEMORY, NULL, NULL, extra);
190}
191
192/**
193 * xmlIOErr:
194 * @code: the error number
195 * @extra: extra informations
196 *
197 * Handle an out of memory condition
198 */
199static void
200xmlIOErr(int code, const char *extra)
201{
202 unsigned int idx;
203
204 if (code == 0) {
205#ifdef HAVE_ERRNO_H
206 if (errno == 0) code = 0;
207#ifdef EACCES
208 else if (errno == EACCES) code = XML_IO_EACCES;
209#endif
210#ifdef EAGAIN
211 else if (errno == EAGAIN) code = XML_IO_EAGAIN;
212#endif
213#ifdef EBADF
214 else if (errno == EBADF) code = XML_IO_EBADF;
215#endif
216#ifdef EBADMSG
217 else if (errno == EBADMSG) code = XML_IO_EBADMSG;
218#endif
219#ifdef EBUSY
220 else if (errno == EBUSY) code = XML_IO_EBUSY;
221#endif
222#ifdef ECANCELED
223 else if (errno == ECANCELED) code = XML_IO_ECANCELED;
224#endif
225#ifdef ECHILD
226 else if (errno == ECHILD) code = XML_IO_ECHILD;
227#endif
228#ifdef EDEADLK
229 else if (errno == EDEADLK) code = XML_IO_EDEADLK;
230#endif
231#ifdef EDOM
232 else if (errno == EDOM) code = XML_IO_EDOM;
233#endif
234#ifdef EEXIST
235 else if (errno == EEXIST) code = XML_IO_EEXIST;
236#endif
237#ifdef EFAULT
238 else if (errno == EFAULT) code = XML_IO_EFAULT;
239#endif
240#ifdef EFBIG
241 else if (errno == EFBIG) code = XML_IO_EFBIG;
242#endif
243#ifdef EINPROGRESS
244 else if (errno == EINPROGRESS) code = XML_IO_EINPROGRESS;
245#endif
246#ifdef EINTR
247 else if (errno == EINTR) code = XML_IO_EINTR;
248#endif
249#ifdef EINVAL
250 else if (errno == EINVAL) code = XML_IO_EINVAL;
251#endif
252#ifdef EIO
253 else if (errno == EIO) code = XML_IO_EIO;
254#endif
255#ifdef EISDIR
256 else if (errno == EISDIR) code = XML_IO_EISDIR;
257#endif
258#ifdef EMFILE
259 else if (errno == EMFILE) code = XML_IO_EMFILE;
260#endif
261#ifdef EMLINK
262 else if (errno == EMLINK) code = XML_IO_EMLINK;
263#endif
264#ifdef EMSGSIZE
265 else if (errno == EMSGSIZE) code = XML_IO_EMSGSIZE;
266#endif
267#ifdef ENAMETOOLONG
268 else if (errno == ENAMETOOLONG) code = XML_IO_ENAMETOOLONG;
269#endif
270#ifdef ENFILE
271 else if (errno == ENFILE) code = XML_IO_ENFILE;
272#endif
273#ifdef ENODEV
274 else if (errno == ENODEV) code = XML_IO_ENODEV;
275#endif
276#ifdef ENOENT
277 else if (errno == ENOENT) code = XML_IO_ENOENT;
278#endif
279#ifdef ENOEXEC
280 else if (errno == ENOEXEC) code = XML_IO_ENOEXEC;
281#endif
282#ifdef ENOLCK
283 else if (errno == ENOLCK) code = XML_IO_ENOLCK;
284#endif
285#ifdef ENOMEM
286 else if (errno == ENOMEM) code = XML_IO_ENOMEM;
287#endif
288#ifdef ENOSPC
289 else if (errno == ENOSPC) code = XML_IO_ENOSPC;
290#endif
291#ifdef ENOSYS
292 else if (errno == ENOSYS) code = XML_IO_ENOSYS;
293#endif
294#ifdef ENOTDIR
295 else if (errno == ENOTDIR) code = XML_IO_ENOTDIR;
296#endif
297#ifdef ENOTEMPTY
298 else if (errno == ENOTEMPTY) code = XML_IO_ENOTEMPTY;
299#endif
300#ifdef ENOTSUP
301 else if (errno == ENOTSUP) code = XML_IO_ENOTSUP;
302#endif
303#ifdef ENOTTY
304 else if (errno == ENOTTY) code = XML_IO_ENOTTY;
305#endif
306#ifdef ENXIO
307 else if (errno == ENXIO) code = XML_IO_ENXIO;
308#endif
309#ifdef EPERM
310 else if (errno == EPERM) code = XML_IO_EPERM;
311#endif
312#ifdef EPIPE
313 else if (errno == EPIPE) code = XML_IO_EPIPE;
314#endif
315#ifdef ERANGE
316 else if (errno == ERANGE) code = XML_IO_ERANGE;
317#endif
318#ifdef EROFS
319 else if (errno == EROFS) code = XML_IO_EROFS;
320#endif
321#ifdef ESPIPE
322 else if (errno == ESPIPE) code = XML_IO_ESPIPE;
323#endif
324#ifdef ESRCH
325 else if (errno == ESRCH) code = XML_IO_ESRCH;
326#endif
327#ifdef ETIMEDOUT
328 else if (errno == ETIMEDOUT) code = XML_IO_ETIMEDOUT;
329#endif
330#ifdef EXDEV
331 else if (errno == EXDEV) code = XML_IO_EXDEV;
332#endif
333 else code = XML_IO_UNKNOWN;
334#endif /* HAVE_ERRNO_H */
335 }
336 idx = 0;
337 if (code >= XML_IO_UNKNOWN) idx = code - XML_IO_UNKNOWN;
338 if (idx >= (sizeof(IOerr) / sizeof(IOerr[0]))) idx = 0;
339
340 __xmlSimpleError(XML_FROM_IO, code, NULL, IOerr[idx], extra);
341}
342
343/************************************************************************
344 * *
345 * Tree memory error handler *
346 * *
347 ************************************************************************/
Daniel Veillardf4862f02002-09-10 11:13:43 +0000348/**
Daniel Veillard01c13b52002-12-10 15:19:08 +0000349 * xmlNormalizeWindowsPath:
Daniel Veillard33300b42003-04-17 09:09:19 +0000350 * @path: the input file path
Daniel Veillardf4862f02002-09-10 11:13:43 +0000351 *
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +0000352 * This function is obsolete. Please see xmlURIFromPath in uri.c for
353 * a better solution.
Daniel Veillard33300b42003-04-17 09:09:19 +0000354 *
355 * Returns a canonicalized version of the path
Daniel Veillardf4862f02002-09-10 11:13:43 +0000356 */
357xmlChar *
358xmlNormalizeWindowsPath(const xmlChar *path)
359{
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +0000360 return xmlCanonicPath(path);
Daniel Veillardf4862f02002-09-10 11:13:43 +0000361}
362
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000363/**
364 * xmlCleanupInputCallbacks:
365 *
366 * clears the entire input callback table. this includes the
367 * compiled-in I/O.
368 */
369void
370xmlCleanupInputCallbacks(void)
371{
372 int i;
373
374 if (!xmlInputCallbackInitialized)
375 return;
376
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000377 for (i = xmlInputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000378 xmlInputCallbackTable[i].matchcallback = NULL;
379 xmlInputCallbackTable[i].opencallback = NULL;
380 xmlInputCallbackTable[i].readcallback = NULL;
381 xmlInputCallbackTable[i].closecallback = NULL;
382 }
383
384 xmlInputCallbackNr = 0;
Aleksey Sanin9c45ba82002-06-06 21:46:13 +0000385 xmlInputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000386}
387
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000388#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000389/**
390 * xmlCleanupOutputCallbacks:
391 *
392 * clears the entire output callback table. this includes the
393 * compiled-in I/O callbacks.
394 */
395void
396xmlCleanupOutputCallbacks(void)
397{
398 int i;
399
400 if (!xmlOutputCallbackInitialized)
401 return;
402
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000403 for (i = xmlOutputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000404 xmlOutputCallbackTable[i].matchcallback = NULL;
405 xmlOutputCallbackTable[i].opencallback = NULL;
406 xmlOutputCallbackTable[i].writecallback = NULL;
407 xmlOutputCallbackTable[i].closecallback = NULL;
408 }
409
410 xmlOutputCallbackNr = 0;
Aleksey Sanin9c45ba82002-06-06 21:46:13 +0000411 xmlOutputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000412}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000413#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000414
Owen Taylor3473f882001-02-23 17:55:21 +0000415/************************************************************************
416 * *
417 * Standard I/O for file accesses *
418 * *
419 ************************************************************************/
420
421/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000422 * xmlCheckFilename:
Owen Taylor3473f882001-02-23 17:55:21 +0000423 * @path: the path to check
424 *
425 * function checks to see if @path is a valid source
426 * (file, socket...) for XML.
427 *
428 * if stat is not available on the target machine,
429 * returns 1. if stat fails, returns 0 (if calling
430 * stat on the filename fails, it can't be right).
431 * if stat succeeds and the file is a directory,
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000432 * returns 2. otherwise returns 1.
Owen Taylor3473f882001-02-23 17:55:21 +0000433 */
434
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000435int
Owen Taylor3473f882001-02-23 17:55:21 +0000436xmlCheckFilename (const char *path)
437{
438#ifdef HAVE_STAT
Owen Taylor3473f882001-02-23 17:55:21 +0000439 struct stat stat_buffer;
440
441 if (stat(path, &stat_buffer) == -1)
442 return 0;
443
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000444#ifdef S_ISDIR
Owen Taylor3473f882001-02-23 17:55:21 +0000445 if (S_ISDIR(stat_buffer.st_mode)) {
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000446 return 2;
Owen Taylor3473f882001-02-23 17:55:21 +0000447 }
Owen Taylor3473f882001-02-23 17:55:21 +0000448#endif
449#endif
450 return 1;
451}
452
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000453static int
Owen Taylor3473f882001-02-23 17:55:21 +0000454xmlNop(void) {
455 return(0);
456}
457
458/**
Owen Taylor3473f882001-02-23 17:55:21 +0000459 * xmlFdRead:
460 * @context: the I/O context
461 * @buffer: where to drop data
462 * @len: number of bytes to read
463 *
464 * Read @len bytes to @buffer from the I/O channel.
465 *
466 * Returns the number of bytes written
467 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000468static int
Owen Taylor3473f882001-02-23 17:55:21 +0000469xmlFdRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000470 int ret;
471
472 ret = read((int) (long) context, &buffer[0], len);
473 if (ret < 0) xmlIOErr(0, "read()");
474 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000475}
476
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000477#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000478/**
479 * xmlFdWrite:
480 * @context: the I/O context
481 * @buffer: where to get data
482 * @len: number of bytes to write
483 *
484 * Write @len bytes from @buffer to the I/O channel.
485 *
486 * Returns the number of bytes written
487 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000488static int
Owen Taylor3473f882001-02-23 17:55:21 +0000489xmlFdWrite (void * context, const char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000490 int ret;
491
492 ret = write((int) (long) context, &buffer[0], len);
493 if (ret < 0) xmlIOErr(0, "write()");
494 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000495}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000496#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000497
498/**
499 * xmlFdClose:
500 * @context: the I/O context
501 *
502 * Close an I/O channel
Daniel Veillardf012a642001-07-23 19:10:52 +0000503 *
504 * Returns 0 in case of success and error code otherwise
Owen Taylor3473f882001-02-23 17:55:21 +0000505 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000506static int
Owen Taylor3473f882001-02-23 17:55:21 +0000507xmlFdClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000508 int ret;
509 ret = close((int) (long) context);
510 if (ret < 0) xmlIOErr(0, "close()");
511 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000512}
513
514/**
515 * xmlFileMatch:
516 * @filename: the URI for matching
517 *
518 * input from FILE *
519 *
520 * Returns 1 if matches, 0 otherwise
521 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000522int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000523xmlFileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000524 return(1);
525}
526
527/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000528 * xmlFileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +0000529 * @filename: the URI for matching
530 *
531 * input from FILE *, supports compressed input
532 * if @filename is " " then the standard input is used
533 *
534 * Returns an I/O context or NULL in case of error
535 */
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000536static void *
537xmlFileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +0000538 const char *path = NULL;
539 FILE *fd;
540
541 if (!strcmp(filename, "-")) {
542 fd = stdin;
543 return((void *) fd);
544 }
545
Daniel Veillardf4862f02002-09-10 11:13:43 +0000546 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000547#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000548 path = &filename[17];
549#else
Owen Taylor3473f882001-02-23 17:55:21 +0000550 path = &filename[16];
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000551#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000552 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000553#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000554 path = &filename[8];
555#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000556 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000557#endif
558 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000559 path = filename;
560
561 if (path == NULL)
562 return(NULL);
563 if (!xmlCheckFilename(path))
564 return(NULL);
565
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000566#if defined(WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
Owen Taylor3473f882001-02-23 17:55:21 +0000567 fd = fopen(path, "rb");
568#else
569 fd = fopen(path, "r");
570#endif /* WIN32 */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000571 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +0000572 return((void *) fd);
573}
574
575/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000576 * xmlFileOpen:
577 * @filename: the URI for matching
578 *
579 * Wrapper around xmlFileOpen_real that try it with an unescaped
580 * version of @filename, if this fails fallback to @filename
Daniel Veillard71531f32003-02-05 13:19:53 +0000581 *
582 * Returns a handler or NULL in case or failure
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000583 */
584void *
585xmlFileOpen (const char *filename) {
586 char *unescaped;
587 void *retval;
588 unescaped = xmlURIUnescapeString(filename, 0, NULL);
589 if (unescaped != NULL) {
590 retval = xmlFileOpen_real(unescaped);
591 } else {
592 retval = xmlFileOpen_real(filename);
593 }
594 xmlFree(unescaped);
595 return retval;
596}
597
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000598#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000599/**
Owen Taylor3473f882001-02-23 17:55:21 +0000600 * xmlFileOpenW:
601 * @filename: the URI for matching
602 *
603 * output to from FILE *,
604 * if @filename is "-" then the standard output is used
605 *
606 * Returns an I/O context or NULL in case of error
607 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000608static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000609xmlFileOpenW (const char *filename) {
610 const char *path = NULL;
611 FILE *fd;
612
613 if (!strcmp(filename, "-")) {
614 fd = stdout;
615 return((void *) fd);
616 }
617
Daniel Veillardf4862f02002-09-10 11:13:43 +0000618 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000619#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000620 path = &filename[17];
621#else
Owen Taylor3473f882001-02-23 17:55:21 +0000622 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000623#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000624 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000625#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000626 path = &filename[8];
627#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000628 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000629#endif
630 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000631 path = filename;
632
633 if (path == NULL)
634 return(NULL);
635
Daniel Veillardcbbd78d2003-07-20 15:21:30 +0000636 fd = fopen(path, "wb");
Daniel Veillard05d987b2003-10-08 11:54:57 +0000637 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +0000638 return((void *) fd);
639}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000640#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000641
642/**
643 * xmlFileRead:
644 * @context: the I/O context
645 * @buffer: where to drop data
646 * @len: number of bytes to write
647 *
648 * Read @len bytes to @buffer from the I/O channel.
649 *
650 * Returns the number of bytes written
651 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000652int
Owen Taylor3473f882001-02-23 17:55:21 +0000653xmlFileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000654 int ret;
655 ret = fread(&buffer[0], 1, len, (FILE *) context);
656 if (ret < 0) xmlIOErr(0, "fread()");
657 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000658}
659
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000660#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000661/**
662 * xmlFileWrite:
663 * @context: the I/O context
664 * @buffer: where to drop data
665 * @len: number of bytes to write
666 *
667 * Write @len bytes from @buffer to the I/O channel.
668 *
669 * Returns the number of bytes written
670 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000671static int
Owen Taylor3473f882001-02-23 17:55:21 +0000672xmlFileWrite (void * context, const char * buffer, int len) {
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000673 int items;
674
675 items = fwrite(&buffer[0], len, 1, (FILE *) context);
Daniel Veillard97bf4d02003-10-08 18:58:28 +0000676 if ((items == 0) && (ferror((FILE *) context))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000677 xmlIOErr(0, "fwrite()");
Daniel Veillard97bf4d02003-10-08 18:58:28 +0000678 return(-1);
679 }
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000680 return(items * len);
Owen Taylor3473f882001-02-23 17:55:21 +0000681}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000682#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000683
684/**
685 * xmlFileClose:
686 * @context: the I/O context
687 *
688 * Close an I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000689 *
690 * Returns 0 or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +0000691 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000692int
Owen Taylor3473f882001-02-23 17:55:21 +0000693xmlFileClose (void * context) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000694 FILE *fil;
Daniel Veillard05d987b2003-10-08 11:54:57 +0000695 int ret;
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000696
697 fil = (FILE *) context;
698 if (fil == stdin)
699 return(0);
700 if (fil == stdout)
701 return(0);
Daniel Veillardcd337f02001-11-22 18:20:37 +0000702 if (fil == stderr)
703 return(0);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000704 ret = ( fclose((FILE *) context) == EOF ) ? -1 : 0;
705 if (ret < 0)
706 xmlIOErr(0, "fclose()");
707 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000708}
709
710/**
711 * xmlFileFlush:
712 * @context: the I/O context
713 *
714 * Flush an I/O channel
715 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000716static int
Owen Taylor3473f882001-02-23 17:55:21 +0000717xmlFileFlush (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000718 int ret;
719 ret = ( fflush((FILE *) context) == EOF ) ? -1 : 0;
720 if (ret < 0)
721 xmlIOErr(0, "fflush()");
722 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000723}
724
725#ifdef HAVE_ZLIB_H
726/************************************************************************
727 * *
728 * I/O for compressed file accesses *
729 * *
730 ************************************************************************/
731/**
732 * xmlGzfileMatch:
733 * @filename: the URI for matching
734 *
735 * input from compressed file test
736 *
737 * Returns 1 if matches, 0 otherwise
738 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000739static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000740xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000741 return(1);
742}
743
744/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000745 * xmlGzfileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +0000746 * @filename: the URI for matching
747 *
748 * input from compressed file open
749 * if @filename is " " then the standard input is used
750 *
751 * Returns an I/O context or NULL in case of error
752 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000753static void *
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000754xmlGzfileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +0000755 const char *path = NULL;
756 gzFile fd;
757
758 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000759 fd = gzdopen(dup(0), "rb");
Owen Taylor3473f882001-02-23 17:55:21 +0000760 return((void *) fd);
761 }
762
Daniel Veillardf4862f02002-09-10 11:13:43 +0000763 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000764#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000765 path = &filename[17];
766#else
Owen Taylor3473f882001-02-23 17:55:21 +0000767 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000768#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000769 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000770#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000771 path = &filename[8];
772#else
Owen Taylor3473f882001-02-23 17:55:21 +0000773 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000774#endif
775 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000776 path = filename;
777
778 if (path == NULL)
779 return(NULL);
780 if (!xmlCheckFilename(path))
781 return(NULL);
782
783 fd = gzopen(path, "rb");
784 return((void *) fd);
785}
786
787/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000788 * xmlGzfileOpen:
789 * @filename: the URI for matching
790 *
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +0000791 * Wrapper around xmlGzfileOpen if the open fais, it will
792 * try to unescape @filename
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000793 */
794static void *
795xmlGzfileOpen (const char *filename) {
796 char *unescaped;
797 void *retval;
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +0000798
799 retval = xmlGzfileOpen_real(filename);
800 if (retval == NULL) {
801 unescaped = xmlURIUnescapeString(filename, 0, NULL);
802 if (unescaped != NULL) {
803 retval = xmlGzfileOpen_real(unescaped);
804 }
805 xmlFree(unescaped);
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000806 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000807 return retval;
808}
809
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000810#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000811/**
Owen Taylor3473f882001-02-23 17:55:21 +0000812 * xmlGzfileOpenW:
813 * @filename: the URI for matching
814 * @compression: the compression factor (0 - 9 included)
815 *
816 * input from compressed file open
817 * if @filename is " " then the standard input is used
818 *
819 * Returns an I/O context or NULL in case of error
820 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000821static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000822xmlGzfileOpenW (const char *filename, int compression) {
823 const char *path = NULL;
824 char mode[15];
825 gzFile fd;
826
Aleksey Sanin49cc9752002-06-14 17:07:10 +0000827 snprintf(mode, sizeof(mode), "wb%d", compression);
Owen Taylor3473f882001-02-23 17:55:21 +0000828 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000829 fd = gzdopen(dup(1), mode);
Owen Taylor3473f882001-02-23 17:55:21 +0000830 return((void *) fd);
831 }
832
Daniel Veillardf4862f02002-09-10 11:13:43 +0000833 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000834#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000835 path = &filename[17];
836#else
Owen Taylor3473f882001-02-23 17:55:21 +0000837 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000838#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000839 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000840#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000841 path = &filename[8];
842#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000843 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000844#endif
845 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000846 path = filename;
847
848 if (path == NULL)
849 return(NULL);
850
851 fd = gzopen(path, mode);
852 return((void *) fd);
853}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000854#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000855
856/**
857 * xmlGzfileRead:
858 * @context: the I/O context
859 * @buffer: where to drop data
860 * @len: number of bytes to write
861 *
862 * Read @len bytes to @buffer from the compressed I/O channel.
863 *
864 * Returns the number of bytes written
865 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000866static int
Owen Taylor3473f882001-02-23 17:55:21 +0000867xmlGzfileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000868 int ret;
869
870 ret = gzread((gzFile) context, &buffer[0], len);
871 if (ret < 0) xmlIOErr(0, "gzread()");
872 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000873}
874
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000875#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000876/**
877 * xmlGzfileWrite:
878 * @context: the I/O context
879 * @buffer: where to drop data
880 * @len: number of bytes to write
881 *
882 * Write @len bytes from @buffer to the compressed I/O channel.
883 *
884 * Returns the number of bytes written
885 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000886static int
Owen Taylor3473f882001-02-23 17:55:21 +0000887xmlGzfileWrite (void * context, const char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000888 int ret;
889
890 ret = gzwrite((gzFile) context, (char *) &buffer[0], len);
891 if (ret < 0) xmlIOErr(0, "gzwrite()");
892 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000893}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000894#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000895
896/**
897 * xmlGzfileClose:
898 * @context: the I/O context
899 *
900 * Close a compressed I/O channel
901 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000902static int
Owen Taylor3473f882001-02-23 17:55:21 +0000903xmlGzfileClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000904 int ret;
905
906 ret = (gzclose((gzFile) context) == Z_OK ) ? 0 : -1;
907 if (ret < 0) xmlIOErr(0, "gzclose()");
908 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000909}
910#endif /* HAVE_ZLIB_H */
911
912#ifdef LIBXML_HTTP_ENABLED
913/************************************************************************
914 * *
915 * I/O for HTTP file accesses *
916 * *
917 ************************************************************************/
Daniel Veillardf012a642001-07-23 19:10:52 +0000918
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000919#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +0000920typedef struct xmlIOHTTPWriteCtxt_
921{
922 int compression;
923
924 char * uri;
925
926 void * doc_buff;
927
928} xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr;
929
930#ifdef HAVE_ZLIB_H
931
932#define DFLT_WBITS ( -15 )
933#define DFLT_MEM_LVL ( 8 )
934#define GZ_MAGIC1 ( 0x1f )
935#define GZ_MAGIC2 ( 0x8b )
936#define LXML_ZLIB_OS_CODE ( 0x03 )
937#define INIT_HTTP_BUFF_SIZE ( 32768 )
938#define DFLT_ZLIB_RATIO ( 5 )
939
940/*
941** Data structure and functions to work with sending compressed data
942** via HTTP.
943*/
944
945typedef struct xmlZMemBuff_
946{
947 unsigned long size;
948 unsigned long crc;
949
950 unsigned char * zbuff;
951 z_stream zctrl;
952
953} xmlZMemBuff, *xmlZMemBuffPtr;
954
955/**
956 * append_reverse_ulong
957 * @buff: Compressed memory buffer
958 * @data: Unsigned long to append
959 *
960 * Append a unsigned long in reverse byte order to the end of the
961 * memory buffer.
962 */
963static void
964append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) {
965
966 int idx;
967
968 if ( buff == NULL )
969 return;
970
971 /*
972 ** This is plagiarized from putLong in gzio.c (zlib source) where
973 ** the number "4" is hardcoded. If zlib is ever patched to
974 ** support 64 bit file sizes, this code would need to be patched
975 ** as well.
976 */
977
978 for ( idx = 0; idx < 4; idx++ ) {
979 *buff->zctrl.next_out = ( data & 0xff );
980 data >>= 8;
981 buff->zctrl.next_out++;
982 }
983
984 return;
985}
986
987/**
988 *
989 * xmlFreeZMemBuff
990 * @buff: The memory buffer context to clear
991 *
992 * Release all the resources associated with the compressed memory buffer.
993 */
994static void
995xmlFreeZMemBuff( xmlZMemBuffPtr buff ) {
William M. Brack78637da2003-07-31 14:47:38 +0000996
997#ifdef DEBUG_HTTP
Daniel Veillardf012a642001-07-23 19:10:52 +0000998 int z_err;
William M. Brack78637da2003-07-31 14:47:38 +0000999#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001000
1001 if ( buff == NULL )
1002 return;
1003
1004 xmlFree( buff->zbuff );
Daniel Veillardf012a642001-07-23 19:10:52 +00001005#ifdef DEBUG_HTTP
William M. Brack78637da2003-07-31 14:47:38 +00001006 z_err = deflateEnd( &buff->zctrl );
Daniel Veillardf012a642001-07-23 19:10:52 +00001007 if ( z_err != Z_OK )
1008 xmlGenericError( xmlGenericErrorContext,
1009 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
1010 z_err );
William M. Brack78637da2003-07-31 14:47:38 +00001011#else
1012 deflateEnd( &buff->zctrl );
William M. Brack779af002003-08-01 15:55:39 +00001013#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001014
1015 xmlFree( buff );
1016 return;
1017}
1018
1019/**
1020 * xmlCreateZMemBuff
1021 *@compression: Compression value to use
1022 *
1023 * Create a memory buffer to hold the compressed XML document. The
1024 * compressed document in memory will end up being identical to what
1025 * would be created if gzopen/gzwrite/gzclose were being used to
1026 * write the document to disk. The code for the header/trailer data to
1027 * the compression is plagiarized from the zlib source files.
1028 */
1029static void *
1030xmlCreateZMemBuff( int compression ) {
1031
1032 int z_err;
1033 int hdr_lgth;
1034 xmlZMemBuffPtr buff = NULL;
1035
1036 if ( ( compression < 1 ) || ( compression > 9 ) )
1037 return ( NULL );
1038
1039 /* Create the control and data areas */
1040
1041 buff = xmlMalloc( sizeof( xmlZMemBuff ) );
1042 if ( buff == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001043 xmlIOErrMemory("creating buffer context");
Daniel Veillardf012a642001-07-23 19:10:52 +00001044 return ( NULL );
1045 }
1046
1047 (void)memset( buff, 0, sizeof( xmlZMemBuff ) );
1048 buff->size = INIT_HTTP_BUFF_SIZE;
1049 buff->zbuff = xmlMalloc( buff->size );
1050 if ( buff->zbuff == NULL ) {
1051 xmlFreeZMemBuff( buff );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001052 xmlIOErrMemory("creating buffer");
Daniel Veillardf012a642001-07-23 19:10:52 +00001053 return ( NULL );
1054 }
1055
1056 z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
1057 DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
1058 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001059 xmlChar msg[500];
Daniel Veillardf012a642001-07-23 19:10:52 +00001060 xmlFreeZMemBuff( buff );
1061 buff = NULL;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001062 xmlStrPrintf(msg, 500,
1063 (const xmlChar *) "xmlCreateZMemBuff: %s %d\n",
1064 "Error initializing compression context. ZLIB error:",
1065 z_err );
1066 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001067 return ( NULL );
1068 }
1069
1070 /* Set the header data. The CRC will be needed for the trailer */
Daniel Veillardf012a642001-07-23 19:10:52 +00001071 buff->crc = crc32( 0L, Z_NULL, 0 );
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001072 hdr_lgth = snprintf( (char *)buff->zbuff, buff->size,
1073 "%c%c%c%c%c%c%c%c%c%c",
Daniel Veillardf012a642001-07-23 19:10:52 +00001074 GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED,
1075 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE );
1076 buff->zctrl.next_out = buff->zbuff + hdr_lgth;
1077 buff->zctrl.avail_out = buff->size - hdr_lgth;
1078
1079 return ( buff );
1080}
1081
1082/**
1083 * xmlZMemBuffExtend
1084 * @buff: Buffer used to compress and consolidate data.
1085 * @ext_amt: Number of bytes to extend the buffer.
1086 *
1087 * Extend the internal buffer used to store the compressed data by the
1088 * specified amount.
1089 *
1090 * Returns 0 on success or -1 on failure to extend the buffer. On failure
1091 * the original buffer still exists at the original size.
1092 */
1093static int
1094xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) {
1095
1096 int rc = -1;
1097 size_t new_size;
1098 size_t cur_used;
1099
1100 unsigned char * tmp_ptr = NULL;
1101
1102 if ( buff == NULL )
1103 return ( -1 );
1104
1105 else if ( ext_amt == 0 )
1106 return ( 0 );
1107
1108 cur_used = buff->zctrl.next_out - buff->zbuff;
1109 new_size = buff->size + ext_amt;
1110
1111#ifdef DEBUG_HTTP
1112 if ( cur_used > new_size )
1113 xmlGenericError( xmlGenericErrorContext,
1114 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
1115 "Buffer overwrite detected during compressed memory",
1116 "buffer extension. Overflowed by",
1117 (cur_used - new_size ) );
1118#endif
1119
1120 tmp_ptr = xmlRealloc( buff->zbuff, new_size );
1121 if ( tmp_ptr != NULL ) {
1122 rc = 0;
1123 buff->size = new_size;
1124 buff->zbuff = tmp_ptr;
1125 buff->zctrl.next_out = tmp_ptr + cur_used;
1126 buff->zctrl.avail_out = new_size - cur_used;
1127 }
1128 else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001129 xmlChar msg[500];
1130 xmlStrPrintf(msg, 500,
1131 (const xmlChar *) "xmlZMemBuffExtend: %s %lu bytes.\n",
1132 "Allocation failure extending output buffer to",
1133 new_size );
1134 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001135 }
1136
1137 return ( rc );
1138}
1139
1140/**
1141 * xmlZMemBuffAppend
1142 * @buff: Buffer used to compress and consolidate data
1143 * @src: Uncompressed source content to append to buffer
1144 * @len: Length of source data to append to buffer
1145 *
1146 * Compress and append data to the internal buffer. The data buffer
1147 * will be expanded if needed to store the additional data.
1148 *
1149 * Returns the number of bytes appended to the buffer or -1 on error.
1150 */
1151static int
1152xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) {
1153
1154 int z_err;
1155 size_t min_accept;
1156
1157 if ( ( buff == NULL ) || ( src == NULL ) )
1158 return ( -1 );
1159
1160 buff->zctrl.avail_in = len;
1161 buff->zctrl.next_in = (unsigned char *)src;
1162 while ( buff->zctrl.avail_in > 0 ) {
1163 /*
1164 ** Extend the buffer prior to deflate call if a reasonable amount
1165 ** of output buffer space is not available.
1166 */
1167 min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO;
1168 if ( buff->zctrl.avail_out <= min_accept ) {
1169 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1170 return ( -1 );
1171 }
1172
1173 z_err = deflate( &buff->zctrl, Z_NO_FLUSH );
1174 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001175 xmlChar msg[500];
1176 xmlStrPrintf(msg, 500,
1177 (const xmlChar *) "xmlZMemBuffAppend: %s %d %s - %d",
Daniel Veillardf012a642001-07-23 19:10:52 +00001178 "Compression error while appending",
1179 len, "bytes to buffer. ZLIB error", z_err );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001180 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001181 return ( -1 );
1182 }
1183 }
1184
1185 buff->crc = crc32( buff->crc, (unsigned char *)src, len );
1186
1187 return ( len );
1188}
1189
1190/**
1191 * xmlZMemBuffGetContent
1192 * @buff: Compressed memory content buffer
1193 * @data_ref: Pointer reference to point to compressed content
1194 *
1195 * Flushes the compression buffers, appends gzip file trailers and
1196 * returns the compressed content and length of the compressed data.
1197 * NOTE: The gzip trailer code here is plagiarized from zlib source.
1198 *
1199 * Returns the length of the compressed data or -1 on error.
1200 */
1201static int
1202xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) {
1203
1204 int zlgth = -1;
1205 int z_err;
1206
1207 if ( ( buff == NULL ) || ( data_ref == NULL ) )
1208 return ( -1 );
1209
1210 /* Need to loop until compression output buffers are flushed */
1211
1212 do
1213 {
1214 z_err = deflate( &buff->zctrl, Z_FINISH );
1215 if ( z_err == Z_OK ) {
1216 /* In this case Z_OK means more buffer space needed */
1217
1218 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1219 return ( -1 );
1220 }
1221 }
1222 while ( z_err == Z_OK );
1223
1224 /* If the compression state is not Z_STREAM_END, some error occurred */
1225
1226 if ( z_err == Z_STREAM_END ) {
1227
1228 /* Need to append the gzip data trailer */
1229
1230 if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) {
1231 if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 )
1232 return ( -1 );
1233 }
1234
1235 /*
1236 ** For whatever reason, the CRC and length data are pushed out
1237 ** in reverse byte order. So a memcpy can't be used here.
1238 */
1239
1240 append_reverse_ulong( buff, buff->crc );
1241 append_reverse_ulong( buff, buff->zctrl.total_in );
1242
1243 zlgth = buff->zctrl.next_out - buff->zbuff;
1244 *data_ref = (char *)buff->zbuff;
1245 }
1246
Daniel Veillard05d987b2003-10-08 11:54:57 +00001247 else {
1248 xmlChar msg[500];
1249 xmlStrPrintf(msg, 500,
1250 (const xmlChar *) "xmlZMemBuffGetContent: %s - %d\n",
1251 "Error flushing zlib buffers. Error code", z_err );
1252 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1253 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001254
1255 return ( zlgth );
1256}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001257#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001258#endif /* HAVE_ZLIB_H */
1259
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001260#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001261/**
1262 * xmlFreeHTTPWriteCtxt
1263 * @ctxt: Context to cleanup
1264 *
1265 * Free allocated memory and reclaim system resources.
1266 *
1267 * No return value.
1268 */
1269static void
1270xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt )
1271{
1272 if ( ctxt->uri != NULL )
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001273 xmlFree( ctxt->uri );
Daniel Veillardf012a642001-07-23 19:10:52 +00001274
1275 if ( ctxt->doc_buff != NULL ) {
1276
1277#ifdef HAVE_ZLIB_H
1278 if ( ctxt->compression > 0 ) {
1279 xmlFreeZMemBuff( ctxt->doc_buff );
1280 }
1281 else
1282#endif
1283 {
1284 xmlOutputBufferClose( ctxt->doc_buff );
1285 }
1286 }
1287
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001288 xmlFree( ctxt );
Daniel Veillardf012a642001-07-23 19:10:52 +00001289 return;
1290}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001291#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001292
1293
Owen Taylor3473f882001-02-23 17:55:21 +00001294/**
1295 * xmlIOHTTPMatch:
1296 * @filename: the URI for matching
1297 *
1298 * check if the URI matches an HTTP one
1299 *
1300 * Returns 1 if matches, 0 otherwise
1301 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001302int
Owen Taylor3473f882001-02-23 17:55:21 +00001303xmlIOHTTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001304 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "http://", 7))
Owen Taylor3473f882001-02-23 17:55:21 +00001305 return(1);
1306 return(0);
1307}
1308
1309/**
1310 * xmlIOHTTPOpen:
1311 * @filename: the URI for matching
1312 *
1313 * open an HTTP I/O channel
1314 *
1315 * Returns an I/O context or NULL in case of error
1316 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001317void *
Owen Taylor3473f882001-02-23 17:55:21 +00001318xmlIOHTTPOpen (const char *filename) {
1319 return(xmlNanoHTTPOpen(filename, NULL));
1320}
1321
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001322#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001323/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001324 * xmlIOHTTPOpenW:
Daniel Veillardf012a642001-07-23 19:10:52 +00001325 * @post_uri: The destination URI for the document
1326 * @compression: The compression desired for the document.
1327 *
1328 * Open a temporary buffer to collect the document for a subsequent HTTP POST
1329 * request. Non-static as is called from the output buffer creation routine.
1330 *
1331 * Returns an I/O context or NULL in case of error.
1332 */
1333
1334void *
Daniel Veillard572577e2002-01-18 16:23:55 +00001335xmlIOHTTPOpenW(const char *post_uri, int compression)
1336{
Daniel Veillardf012a642001-07-23 19:10:52 +00001337
Daniel Veillard572577e2002-01-18 16:23:55 +00001338 xmlIOHTTPWriteCtxtPtr ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001339
Daniel Veillard572577e2002-01-18 16:23:55 +00001340 if (post_uri == NULL)
1341 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001342
Daniel Veillard572577e2002-01-18 16:23:55 +00001343 ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt));
1344 if (ctxt == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001345 xmlIOErrMemory("creating HTTP output context");
Daniel Veillard572577e2002-01-18 16:23:55 +00001346 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001347 }
1348
Daniel Veillard572577e2002-01-18 16:23:55 +00001349 (void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt));
Daniel Veillardf012a642001-07-23 19:10:52 +00001350
Daniel Veillard572577e2002-01-18 16:23:55 +00001351 ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri);
1352 if (ctxt->uri == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001353 xmlIOErrMemory("copying URI");
Daniel Veillard572577e2002-01-18 16:23:55 +00001354 xmlFreeHTTPWriteCtxt(ctxt);
1355 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001356 }
1357
1358 /*
Daniel Veillard572577e2002-01-18 16:23:55 +00001359 * ** Since the document length is required for an HTTP post,
1360 * ** need to put the document into a buffer. A memory buffer
1361 * ** is being used to avoid pushing the data to disk and back.
1362 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001363
1364#ifdef HAVE_ZLIB_H
Daniel Veillard572577e2002-01-18 16:23:55 +00001365 if ((compression > 0) && (compression <= 9)) {
1366
1367 ctxt->compression = compression;
1368 ctxt->doc_buff = xmlCreateZMemBuff(compression);
1369 } else
Daniel Veillardf012a642001-07-23 19:10:52 +00001370#endif
1371 {
Daniel Veillard572577e2002-01-18 16:23:55 +00001372 /* Any character conversions should have been done before this */
Daniel Veillardf012a642001-07-23 19:10:52 +00001373
Daniel Veillard572577e2002-01-18 16:23:55 +00001374 ctxt->doc_buff = xmlAllocOutputBuffer(NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001375 }
1376
Daniel Veillard572577e2002-01-18 16:23:55 +00001377 if (ctxt->doc_buff == NULL) {
1378 xmlFreeHTTPWriteCtxt(ctxt);
1379 ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001380 }
1381
Daniel Veillard572577e2002-01-18 16:23:55 +00001382 return (ctxt);
Daniel Veillardf012a642001-07-23 19:10:52 +00001383}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001384#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001385
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001386#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001387/**
1388 * xmlIOHTTPDfltOpenW
1389 * @post_uri: The destination URI for this document.
1390 *
1391 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
1392 * HTTP post command. This function should generally not be used as
1393 * the open callback is short circuited in xmlOutputBufferCreateFile.
1394 *
1395 * Returns a pointer to the new IO context.
1396 */
1397static void *
1398xmlIOHTTPDfltOpenW( const char * post_uri ) {
1399 return ( xmlIOHTTPOpenW( post_uri, 0 ) );
1400}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001401#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001402
1403/**
Owen Taylor3473f882001-02-23 17:55:21 +00001404 * xmlIOHTTPRead:
1405 * @context: the I/O context
1406 * @buffer: where to drop data
1407 * @len: number of bytes to write
1408 *
1409 * Read @len bytes to @buffer from the I/O channel.
1410 *
1411 * Returns the number of bytes written
1412 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001413int
Owen Taylor3473f882001-02-23 17:55:21 +00001414xmlIOHTTPRead(void * context, char * buffer, int len) {
1415 return(xmlNanoHTTPRead(context, &buffer[0], len));
1416}
1417
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001418#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001419/**
Daniel Veillardf012a642001-07-23 19:10:52 +00001420 * xmlIOHTTPWrite
1421 * @context: previously opened writing context
1422 * @buffer: data to output to temporary buffer
1423 * @len: bytes to output
1424 *
1425 * Collect data from memory buffer into a temporary file for later
1426 * processing.
1427 *
1428 * Returns number of bytes written.
1429 */
1430
1431static int
1432xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
1433
1434 xmlIOHTTPWriteCtxtPtr ctxt = context;
1435
1436 if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
1437 return ( -1 );
1438
1439 if ( len > 0 ) {
1440
1441 /* Use gzwrite or fwrite as previously setup in the open call */
1442
1443#ifdef HAVE_ZLIB_H
1444 if ( ctxt->compression > 0 )
1445 len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len );
1446
1447 else
1448#endif
1449 len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
1450
1451 if ( len < 0 ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001452 xmlChar msg[500];
1453 xmlStrPrintf(msg, 500,
1454 (const xmlChar *) "xmlIOHTTPWrite: %s\n%s '%s'.\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001455 "Error appending to internal buffer.",
1456 "Error sending document to URI",
1457 ctxt->uri );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001458 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001459 }
1460 }
1461
1462 return ( len );
1463}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001464#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001465
1466
1467/**
Owen Taylor3473f882001-02-23 17:55:21 +00001468 * xmlIOHTTPClose:
1469 * @context: the I/O context
1470 *
1471 * Close an HTTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001472 *
1473 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00001474 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001475int
Owen Taylor3473f882001-02-23 17:55:21 +00001476xmlIOHTTPClose (void * context) {
1477 xmlNanoHTTPClose(context);
Daniel Veillardf012a642001-07-23 19:10:52 +00001478 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001479}
Daniel Veillardf012a642001-07-23 19:10:52 +00001480
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001481#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001482/**
1483 * xmlIOHTTCloseWrite
1484 * @context: The I/O context
1485 * @http_mthd: The HTTP method to be used when sending the data
1486 *
1487 * Close the transmit HTTP I/O channel and actually send the data.
1488 */
1489static int
1490xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
1491
1492 int close_rc = -1;
1493 int http_rtn = 0;
1494 int content_lgth = 0;
1495 xmlIOHTTPWriteCtxtPtr ctxt = context;
1496
1497 char * http_content = NULL;
1498 char * content_encoding = NULL;
1499 char * content_type = (char *) "text/xml";
1500 void * http_ctxt = NULL;
1501
1502 if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
1503 return ( -1 );
1504
1505 /* Retrieve the content from the appropriate buffer */
1506
1507#ifdef HAVE_ZLIB_H
1508
1509 if ( ctxt->compression > 0 ) {
1510 content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
1511 content_encoding = (char *) "Content-Encoding: gzip";
1512 }
1513 else
1514#endif
1515 {
1516 /* Pull the data out of the memory output buffer */
1517
1518 xmlOutputBufferPtr dctxt = ctxt->doc_buff;
1519 http_content = (char *)dctxt->buffer->content;
1520 content_lgth = dctxt->buffer->use;
1521 }
1522
1523 if ( http_content == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001524 xmlChar msg[500];
1525 xmlStrPrintf(msg, 500,
1526 (const xmlChar *) "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
1527 "Error retrieving content.\nUnable to",
1528 http_mthd, "data to URI", ctxt->uri );
1529 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001530 }
1531
1532 else {
1533
1534 http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
1535 &content_type, content_encoding,
1536 content_lgth );
1537
1538 if ( http_ctxt != NULL ) {
1539#ifdef DEBUG_HTTP
1540 /* If testing/debugging - dump reply with request content */
1541
1542 FILE * tst_file = NULL;
1543 char buffer[ 4096 ];
1544 char * dump_name = NULL;
1545 int avail;
1546
1547 xmlGenericError( xmlGenericErrorContext,
1548 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
1549 http_mthd, ctxt->uri,
1550 xmlNanoHTTPReturnCode( http_ctxt ) );
1551
1552 /*
1553 ** Since either content or reply may be gzipped,
1554 ** dump them to separate files instead of the
1555 ** standard error context.
1556 */
1557
1558 dump_name = tempnam( NULL, "lxml" );
1559 if ( dump_name != NULL ) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001560 (void)snprintf( buffer, sizeof(buffer), "%s.content", dump_name );
Daniel Veillardf012a642001-07-23 19:10:52 +00001561
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00001562 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00001563 if ( tst_file != NULL ) {
1564 xmlGenericError( xmlGenericErrorContext,
1565 "Transmitted content saved in file: %s\n", buffer );
1566
1567 fwrite( http_content, sizeof( char ),
1568 content_lgth, tst_file );
1569 fclose( tst_file );
1570 }
1571
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001572 (void)snprintf( buffer, sizeof(buffer), "%s.reply", dump_name );
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00001573 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00001574 if ( tst_file != NULL ) {
1575 xmlGenericError( xmlGenericErrorContext,
1576 "Reply content saved in file: %s\n", buffer );
1577
1578
1579 while ( (avail = xmlNanoHTTPRead( http_ctxt,
1580 buffer, sizeof( buffer ) )) > 0 ) {
1581
1582 fwrite( buffer, sizeof( char ), avail, tst_file );
1583 }
1584
1585 fclose( tst_file );
1586 }
1587
1588 free( dump_name );
1589 }
1590#endif /* DEBUG_HTTP */
1591
1592 http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
1593 if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
1594 close_rc = 0;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001595 else {
1596 xmlChar msg[500];
1597 xmlStrPrintf(msg, 500,
1598 (const xmlChar *) "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001599 http_mthd, content_lgth,
1600 "bytes to URI", ctxt->uri,
1601 "failed. HTTP return code:", http_rtn );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001602 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1603 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001604
1605 xmlNanoHTTPClose( http_ctxt );
1606 xmlFree( content_type );
1607 }
1608 }
1609
1610 /* Final cleanups */
1611
1612 xmlFreeHTTPWriteCtxt( ctxt );
1613
1614 return ( close_rc );
1615}
1616
1617/**
1618 * xmlIOHTTPClosePut
1619 *
1620 * @context: The I/O context
1621 *
1622 * Close the transmit HTTP I/O channel and actually send data using a PUT
1623 * HTTP method.
1624 */
1625static int
1626xmlIOHTTPClosePut( void * ctxt ) {
1627 return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
1628}
1629
1630
1631/**
1632 * xmlIOHTTPClosePost
1633 *
1634 * @context: The I/O context
1635 *
1636 * Close the transmit HTTP I/O channel and actually send data using a POST
1637 * HTTP method.
1638 */
1639static int
1640xmlIOHTTPClosePost( void * ctxt ) {
1641 return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
1642}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001643#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001644
Owen Taylor3473f882001-02-23 17:55:21 +00001645#endif /* LIBXML_HTTP_ENABLED */
1646
1647#ifdef LIBXML_FTP_ENABLED
1648/************************************************************************
1649 * *
1650 * I/O for FTP file accesses *
1651 * *
1652 ************************************************************************/
1653/**
1654 * xmlIOFTPMatch:
1655 * @filename: the URI for matching
1656 *
1657 * check if the URI matches an FTP one
1658 *
1659 * Returns 1 if matches, 0 otherwise
1660 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001661int
Owen Taylor3473f882001-02-23 17:55:21 +00001662xmlIOFTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001663 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "ftp://", 6))
Owen Taylor3473f882001-02-23 17:55:21 +00001664 return(1);
1665 return(0);
1666}
1667
1668/**
1669 * xmlIOFTPOpen:
1670 * @filename: the URI for matching
1671 *
1672 * open an FTP I/O channel
1673 *
1674 * Returns an I/O context or NULL in case of error
1675 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001676void *
Owen Taylor3473f882001-02-23 17:55:21 +00001677xmlIOFTPOpen (const char *filename) {
1678 return(xmlNanoFTPOpen(filename));
1679}
1680
1681/**
1682 * xmlIOFTPRead:
1683 * @context: the I/O context
1684 * @buffer: where to drop data
1685 * @len: number of bytes to write
1686 *
1687 * Read @len bytes to @buffer from the I/O channel.
1688 *
1689 * Returns the number of bytes written
1690 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001691int
Owen Taylor3473f882001-02-23 17:55:21 +00001692xmlIOFTPRead(void * context, char * buffer, int len) {
1693 return(xmlNanoFTPRead(context, &buffer[0], len));
1694}
1695
1696/**
1697 * xmlIOFTPClose:
1698 * @context: the I/O context
1699 *
1700 * Close an FTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001701 *
1702 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00001703 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001704int
Owen Taylor3473f882001-02-23 17:55:21 +00001705xmlIOFTPClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001706 return ( xmlNanoFTPClose(context) );
Owen Taylor3473f882001-02-23 17:55:21 +00001707}
1708#endif /* LIBXML_FTP_ENABLED */
1709
1710
1711/**
1712 * xmlRegisterInputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001713 * @matchFunc: the xmlInputMatchCallback
1714 * @openFunc: the xmlInputOpenCallback
1715 * @readFunc: the xmlInputReadCallback
1716 * @closeFunc: the xmlInputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001717 *
1718 * Register a new set of I/O callback for handling parser input.
1719 *
1720 * Returns the registered handler number or -1 in case of error
1721 */
1722int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001723xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
1724 xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
1725 xmlInputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001726 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
1727 return(-1);
1728 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001729 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
1730 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
1731 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
1732 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00001733 xmlInputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00001734 return(xmlInputCallbackNr++);
1735}
1736
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001737#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001738/**
1739 * xmlRegisterOutputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001740 * @matchFunc: the xmlOutputMatchCallback
1741 * @openFunc: the xmlOutputOpenCallback
1742 * @writeFunc: the xmlOutputWriteCallback
1743 * @closeFunc: the xmlOutputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001744 *
1745 * Register a new set of I/O callback for handling output.
1746 *
1747 * Returns the registered handler number or -1 in case of error
1748 */
1749int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001750xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
1751 xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
1752 xmlOutputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001753 if (xmlOutputCallbackNr >= MAX_INPUT_CALLBACK) {
1754 return(-1);
1755 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001756 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
1757 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
1758 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
1759 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00001760 xmlOutputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00001761 return(xmlOutputCallbackNr++);
1762}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001763#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001764
1765/**
1766 * xmlRegisterDefaultInputCallbacks:
1767 *
1768 * Registers the default compiled-in I/O handlers.
1769 */
1770void
Owen Taylor3473f882001-02-23 17:55:21 +00001771xmlRegisterDefaultInputCallbacks
Owen Taylor3473f882001-02-23 17:55:21 +00001772(void) {
1773 if (xmlInputCallbackInitialized)
1774 return;
1775
1776 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
1777 xmlFileRead, xmlFileClose);
1778#ifdef HAVE_ZLIB_H
1779 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1780 xmlGzfileRead, xmlGzfileClose);
1781#endif /* HAVE_ZLIB_H */
1782
1783#ifdef LIBXML_HTTP_ENABLED
1784 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
1785 xmlIOHTTPRead, xmlIOHTTPClose);
1786#endif /* LIBXML_HTTP_ENABLED */
1787
1788#ifdef LIBXML_FTP_ENABLED
1789 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1790 xmlIOFTPRead, xmlIOFTPClose);
1791#endif /* LIBXML_FTP_ENABLED */
1792 xmlInputCallbackInitialized = 1;
1793}
1794
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001795#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001796/**
1797 * xmlRegisterDefaultOutputCallbacks:
1798 *
1799 * Registers the default compiled-in I/O handlers.
1800 */
1801void
Owen Taylor3473f882001-02-23 17:55:21 +00001802xmlRegisterDefaultOutputCallbacks
Owen Taylor3473f882001-02-23 17:55:21 +00001803(void) {
1804 if (xmlOutputCallbackInitialized)
1805 return;
1806
1807 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
1808 xmlFileWrite, xmlFileClose);
Daniel Veillardf012a642001-07-23 19:10:52 +00001809
1810#ifdef LIBXML_HTTP_ENABLED
1811 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
1812 xmlIOHTTPWrite, xmlIOHTTPClosePut);
1813#endif
1814
Owen Taylor3473f882001-02-23 17:55:21 +00001815/*********************************
1816 No way a-priori to distinguish between gzipped files from
1817 uncompressed ones except opening if existing then closing
1818 and saving with same compression ratio ... a pain.
1819
1820#ifdef HAVE_ZLIB_H
1821 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1822 xmlGzfileWrite, xmlGzfileClose);
1823#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001824
1825 Nor FTP PUT ....
1826#ifdef LIBXML_FTP_ENABLED
1827 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1828 xmlIOFTPWrite, xmlIOFTPClose);
1829#endif
1830 **********************************/
1831 xmlOutputCallbackInitialized = 1;
1832}
1833
Daniel Veillardf012a642001-07-23 19:10:52 +00001834#ifdef LIBXML_HTTP_ENABLED
1835/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001836 * xmlRegisterHTTPPostCallbacks:
Daniel Veillardf012a642001-07-23 19:10:52 +00001837 *
1838 * By default, libxml submits HTTP output requests using the "PUT" method.
1839 * Calling this method changes the HTTP output method to use the "POST"
1840 * method instead.
1841 *
1842 */
1843void
1844xmlRegisterHTTPPostCallbacks( void ) {
1845
1846 /* Register defaults if not done previously */
1847
1848 if ( xmlOutputCallbackInitialized == 0 )
1849 xmlRegisterDefaultOutputCallbacks( );
1850
1851 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
1852 xmlIOHTTPWrite, xmlIOHTTPClosePost);
1853 return;
1854}
1855#endif
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001856#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001857
Owen Taylor3473f882001-02-23 17:55:21 +00001858/**
1859 * xmlAllocParserInputBuffer:
1860 * @enc: the charset encoding if known
1861 *
1862 * Create a buffered parser input for progressive parsing
1863 *
1864 * Returns the new parser input or NULL
1865 */
1866xmlParserInputBufferPtr
1867xmlAllocParserInputBuffer(xmlCharEncoding enc) {
1868 xmlParserInputBufferPtr ret;
1869
1870 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
1871 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001872 xmlIOErrMemory("creating input buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00001873 return(NULL);
1874 }
1875 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00001876 ret->buffer = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00001877 if (ret->buffer == NULL) {
1878 xmlFree(ret);
1879 return(NULL);
1880 }
1881 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
1882 ret->encoder = xmlGetCharEncodingHandler(enc);
1883 if (ret->encoder != NULL)
Daniel Veillard6155d8a2003-08-19 15:01:28 +00001884 ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00001885 else
1886 ret->raw = NULL;
1887 ret->readcallback = NULL;
1888 ret->closecallback = NULL;
1889 ret->context = NULL;
William M. Brackc07329e2003-09-08 01:57:30 +00001890 ret->compressed = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00001891
1892 return(ret);
1893}
1894
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001895#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001896/**
1897 * xmlAllocOutputBuffer:
1898 * @encoder: the encoding converter or NULL
1899 *
1900 * Create a buffered parser output
1901 *
1902 * Returns the new parser output or NULL
1903 */
1904xmlOutputBufferPtr
1905xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
1906 xmlOutputBufferPtr ret;
1907
1908 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
1909 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001910 xmlIOErrMemory("creating output buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00001911 return(NULL);
1912 }
1913 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
1914 ret->buffer = xmlBufferCreate();
1915 if (ret->buffer == NULL) {
1916 xmlFree(ret);
1917 return(NULL);
1918 }
1919 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
1920 ret->encoder = encoder;
1921 if (encoder != NULL) {
1922 ret->conv = xmlBufferCreateSize(4000);
1923 /*
1924 * This call is designed to initiate the encoder state
1925 */
1926 xmlCharEncOutFunc(encoder, ret->conv, NULL);
1927 } else
1928 ret->conv = NULL;
1929 ret->writecallback = NULL;
1930 ret->closecallback = NULL;
1931 ret->context = NULL;
1932 ret->written = 0;
1933
1934 return(ret);
1935}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001936#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001937
1938/**
1939 * xmlFreeParserInputBuffer:
1940 * @in: a buffered parser input
1941 *
1942 * Free up the memory used by a buffered parser input
1943 */
1944void
1945xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
Daniel Veillard8d8bf2c2003-09-17 19:36:25 +00001946 if (in == NULL) return;
1947
Owen Taylor3473f882001-02-23 17:55:21 +00001948 if (in->raw) {
1949 xmlBufferFree(in->raw);
1950 in->raw = NULL;
1951 }
1952 if (in->encoder != NULL) {
1953 xmlCharEncCloseFunc(in->encoder);
1954 }
1955 if (in->closecallback != NULL) {
1956 in->closecallback(in->context);
1957 }
1958 if (in->buffer != NULL) {
1959 xmlBufferFree(in->buffer);
1960 in->buffer = NULL;
1961 }
1962
Owen Taylor3473f882001-02-23 17:55:21 +00001963 xmlFree(in);
1964}
1965
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001966#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001967/**
1968 * xmlOutputBufferClose:
1969 * @out: a buffered output
1970 *
1971 * flushes and close the output I/O channel
1972 * and free up all the associated resources
1973 *
1974 * Returns the number of byte written or -1 in case of error.
1975 */
1976int
Daniel Veillard828ce832003-10-08 19:19:10 +00001977xmlOutputBufferClose(xmlOutputBufferPtr out)
1978{
Owen Taylor3473f882001-02-23 17:55:21 +00001979 int written;
Daniel Veillardf012a642001-07-23 19:10:52 +00001980 int err_rc = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001981
1982 if (out == NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00001983 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001984 if (out->writecallback != NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00001985 xmlOutputBufferFlush(out);
Owen Taylor3473f882001-02-23 17:55:21 +00001986 if (out->closecallback != NULL) {
Daniel Veillard828ce832003-10-08 19:19:10 +00001987 err_rc = out->closecallback(out->context);
Owen Taylor3473f882001-02-23 17:55:21 +00001988 }
1989 written = out->written;
1990 if (out->conv) {
1991 xmlBufferFree(out->conv);
Daniel Veillard828ce832003-10-08 19:19:10 +00001992 out->conv = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00001993 }
1994 if (out->encoder != NULL) {
1995 xmlCharEncCloseFunc(out->encoder);
1996 }
1997 if (out->buffer != NULL) {
1998 xmlBufferFree(out->buffer);
Daniel Veillard828ce832003-10-08 19:19:10 +00001999 out->buffer = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002000 }
2001
Daniel Veillard828ce832003-10-08 19:19:10 +00002002 if (out->error)
2003 err_rc = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00002004 xmlFree(out);
Daniel Veillard828ce832003-10-08 19:19:10 +00002005 return ((err_rc == 0) ? written : err_rc);
Owen Taylor3473f882001-02-23 17:55:21 +00002006}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002007#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002008
2009/**
2010 * xmlParserInputBufferCreateFilename:
2011 * @URI: a C string containing the URI or filename
2012 * @enc: the charset encoding if known
2013 *
2014 * Create a buffered parser input for the progressive parsing of a file
2015 * If filename is "-' then we use stdin as the input.
2016 * Automatic support for ZLIB/Compress compressed document is provided
2017 * by default if found at compile-time.
2018 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
2019 *
2020 * Returns the new parser input or NULL
2021 */
2022xmlParserInputBufferPtr
Daniel Veillard3e59fc52003-04-18 12:34:58 +00002023xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002024 xmlParserInputBufferPtr ret;
Daniel Veillard388236f2001-07-08 18:35:48 +00002025 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002026 void *context = NULL;
2027
2028 if (xmlInputCallbackInitialized == 0)
2029 xmlRegisterDefaultInputCallbacks();
2030
2031 if (URI == NULL) return(NULL);
2032
2033 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002034 * Try to find one of the input accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002035 * Go in reverse to give precedence to user defined handlers.
Daniel Veillard388236f2001-07-08 18:35:48 +00002036 */
2037 if (context == NULL) {
2038 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
2039 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
2040 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002041 context = xmlInputCallbackTable[i].opencallback(URI);
Daniel Veillard388236f2001-07-08 18:35:48 +00002042 if (context != NULL)
2043 break;
2044 }
Owen Taylor3473f882001-02-23 17:55:21 +00002045 }
2046 }
2047 if (context == NULL) {
2048 return(NULL);
2049 }
2050
2051 /*
2052 * Allocate the Input buffer front-end.
2053 */
2054 ret = xmlAllocParserInputBuffer(enc);
2055 if (ret != NULL) {
2056 ret->context = context;
2057 ret->readcallback = xmlInputCallbackTable[i].readcallback;
2058 ret->closecallback = xmlInputCallbackTable[i].closecallback;
William M. Brackc07329e2003-09-08 01:57:30 +00002059#ifdef HAVE_ZLIB_H
2060 if (xmlInputCallbackTable[i].opencallback == xmlGzfileOpen) {
2061 if (((z_stream *)context)->avail_in > 4) {
2062 char *cptr, buff4[4];
Daniel Veillard07cb8222003-09-10 10:51:05 +00002063 cptr = (char *) ((z_stream *)context)->next_in;
William M. Brackc07329e2003-09-08 01:57:30 +00002064 if (gzread(context, buff4, 4) == 4) {
2065 if (strncmp(buff4, cptr, 4) == 0)
2066 ret->compressed = 0;
2067 else
2068 ret->compressed = 1;
2069 gzrewind(context);
2070 }
2071 }
2072 }
2073#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002074 }
2075 return(ret);
2076}
2077
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002078#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002079/**
2080 * xmlOutputBufferCreateFilename:
2081 * @URI: a C string containing the URI or filename
2082 * @encoder: the encoding converter or NULL
2083 * @compression: the compression ration (0 none, 9 max).
2084 *
2085 * Create a buffered output for the progressive saving of a file
2086 * If filename is "-' then we use stdout as the output.
2087 * Automatic support for ZLIB/Compress compressed document is provided
2088 * by default if found at compile-time.
2089 * TODO: currently if compression is set, the library only support
2090 * writing to a local file.
2091 *
2092 * Returns the new output or NULL
2093 */
2094xmlOutputBufferPtr
2095xmlOutputBufferCreateFilename(const char *URI,
2096 xmlCharEncodingHandlerPtr encoder,
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002097 int compression ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00002098 xmlOutputBufferPtr ret;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002099 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002100 void *context = NULL;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002101 char *unescaped;
Owen Taylor3473f882001-02-23 17:55:21 +00002102
Daniel Veillard4432df22003-09-28 18:58:27 +00002103#ifdef LIBXML_HTTP_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00002104 int is_http_uri = 0; /* Can't change if HTTP disabled */
Daniel Veillard4432df22003-09-28 18:58:27 +00002105#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00002106
Owen Taylor3473f882001-02-23 17:55:21 +00002107 if (xmlOutputCallbackInitialized == 0)
2108 xmlRegisterDefaultOutputCallbacks();
2109
2110 if (URI == NULL) return(NULL);
2111
Daniel Veillardf012a642001-07-23 19:10:52 +00002112#ifdef LIBXML_HTTP_ENABLED
2113 /* Need to prevent HTTP URI's from falling into zlib short circuit */
2114
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002115 is_http_uri = xmlIOHTTPMatch( URI );
Daniel Veillardf012a642001-07-23 19:10:52 +00002116#endif
2117
Owen Taylor3473f882001-02-23 17:55:21 +00002118
2119 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002120 * Try to find one of the output accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002121 * Go in reverse to give precedence to user defined handlers.
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002122 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00002123 */
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002124 unescaped = xmlURIUnescapeString(URI, 0, NULL);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002125 if (unescaped != NULL) {
2126#ifdef HAVE_ZLIB_H
2127 if ((compression > 0) && (compression <= 9) && (is_http_uri == 0)) {
2128 context = xmlGzfileOpenW(unescaped, compression);
2129 if (context != NULL) {
2130 ret = xmlAllocOutputBuffer(encoder);
2131 if (ret != NULL) {
2132 ret->context = context;
2133 ret->writecallback = xmlGzfileWrite;
2134 ret->closecallback = xmlGzfileClose;
2135 }
2136 xmlFree(unescaped);
2137 return(ret);
2138 }
2139 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002140#endif
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002141 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2142 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
2143 (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
2144#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2145 /* Need to pass compression parameter into HTTP open calls */
2146 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2147 context = xmlIOHTTPOpenW(unescaped, compression);
2148 else
2149#endif
2150 context = xmlOutputCallbackTable[i].opencallback(unescaped);
2151 if (context != NULL)
2152 break;
2153 }
2154 }
2155 xmlFree(unescaped);
2156 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002157
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002158 /*
2159 * If this failed try with a non-escaped URI this may be a strange
2160 * filename
2161 */
2162 if (context == NULL) {
2163#ifdef HAVE_ZLIB_H
2164 if ((compression > 0) && (compression <= 9) && (is_http_uri == 0)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002165 context = xmlGzfileOpenW(URI, compression);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002166 if (context != NULL) {
2167 ret = xmlAllocOutputBuffer(encoder);
2168 if (ret != NULL) {
2169 ret->context = context;
2170 ret->writecallback = xmlGzfileWrite;
2171 ret->closecallback = xmlGzfileClose;
2172 }
2173 return(ret);
2174 }
2175 }
2176#endif
2177 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2178 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002179 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002180#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2181 /* Need to pass compression parameter into HTTP open calls */
2182 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2183 context = xmlIOHTTPOpenW(URI, compression);
2184 else
2185#endif
2186 context = xmlOutputCallbackTable[i].opencallback(URI);
2187 if (context != NULL)
2188 break;
2189 }
Owen Taylor3473f882001-02-23 17:55:21 +00002190 }
2191 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002192
Owen Taylor3473f882001-02-23 17:55:21 +00002193 if (context == NULL) {
2194 return(NULL);
2195 }
2196
2197 /*
2198 * Allocate the Output buffer front-end.
2199 */
2200 ret = xmlAllocOutputBuffer(encoder);
2201 if (ret != NULL) {
2202 ret->context = context;
2203 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
2204 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
2205 }
2206 return(ret);
2207}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002208#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002209
2210/**
2211 * xmlParserInputBufferCreateFile:
2212 * @file: a FILE*
2213 * @enc: the charset encoding if known
2214 *
2215 * Create a buffered parser input for the progressive parsing of a FILE *
2216 * buffered C I/O
2217 *
2218 * Returns the new parser input or NULL
2219 */
2220xmlParserInputBufferPtr
2221xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
2222 xmlParserInputBufferPtr ret;
2223
2224 if (xmlInputCallbackInitialized == 0)
2225 xmlRegisterDefaultInputCallbacks();
2226
2227 if (file == NULL) return(NULL);
2228
2229 ret = xmlAllocParserInputBuffer(enc);
2230 if (ret != NULL) {
2231 ret->context = file;
2232 ret->readcallback = xmlFileRead;
2233 ret->closecallback = xmlFileFlush;
2234 }
2235
2236 return(ret);
2237}
2238
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002239#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002240/**
2241 * xmlOutputBufferCreateFile:
2242 * @file: a FILE*
2243 * @encoder: the encoding converter or NULL
2244 *
2245 * Create a buffered output for the progressive saving to a FILE *
2246 * buffered C I/O
2247 *
2248 * Returns the new parser output or NULL
2249 */
2250xmlOutputBufferPtr
2251xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
2252 xmlOutputBufferPtr ret;
2253
2254 if (xmlOutputCallbackInitialized == 0)
2255 xmlRegisterDefaultOutputCallbacks();
2256
2257 if (file == NULL) return(NULL);
2258
2259 ret = xmlAllocOutputBuffer(encoder);
2260 if (ret != NULL) {
2261 ret->context = file;
2262 ret->writecallback = xmlFileWrite;
2263 ret->closecallback = xmlFileFlush;
2264 }
2265
2266 return(ret);
2267}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002268#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002269
2270/**
2271 * xmlParserInputBufferCreateFd:
2272 * @fd: a file descriptor number
2273 * @enc: the charset encoding if known
2274 *
2275 * Create a buffered parser input for the progressive parsing for the input
2276 * from a file descriptor
2277 *
2278 * Returns the new parser input or NULL
2279 */
2280xmlParserInputBufferPtr
2281xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
2282 xmlParserInputBufferPtr ret;
2283
2284 if (fd < 0) return(NULL);
2285
2286 ret = xmlAllocParserInputBuffer(enc);
2287 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002288 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002289 ret->readcallback = xmlFdRead;
2290 ret->closecallback = xmlFdClose;
2291 }
2292
2293 return(ret);
2294}
2295
2296/**
2297 * xmlParserInputBufferCreateMem:
2298 * @mem: the memory input
2299 * @size: the length of the memory block
2300 * @enc: the charset encoding if known
2301 *
2302 * Create a buffered parser input for the progressive parsing for the input
2303 * from a memory area.
2304 *
2305 * Returns the new parser input or NULL
2306 */
2307xmlParserInputBufferPtr
2308xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
2309 xmlParserInputBufferPtr ret;
2310
2311 if (size <= 0) return(NULL);
2312 if (mem == NULL) return(NULL);
2313
2314 ret = xmlAllocParserInputBuffer(enc);
2315 if (ret != NULL) {
2316 ret->context = (void *) mem;
2317 ret->readcallback = (xmlInputReadCallback) xmlNop;
2318 ret->closecallback = NULL;
2319 xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size);
2320 }
2321
2322 return(ret);
2323}
2324
2325/**
Daniel Veillard53350552003-09-18 13:35:51 +00002326 * xmlParserInputBufferCreateStatic:
2327 * @mem: the memory input
2328 * @size: the length of the memory block
2329 * @enc: the charset encoding if known
2330 *
2331 * Create a buffered parser input for the progressive parsing for the input
2332 * from an immutable memory area. This will not copy the memory area to
2333 * the buffer, but the memory is expected to be available until the end of
2334 * the parsing, this is useful for example when using mmap'ed file.
2335 *
2336 * Returns the new parser input or NULL
2337 */
2338xmlParserInputBufferPtr
2339xmlParserInputBufferCreateStatic(const char *mem, int size,
2340 xmlCharEncoding enc) {
2341 xmlParserInputBufferPtr ret;
2342
2343 if (size <= 0) return(NULL);
2344 if (mem == NULL) return(NULL);
2345
2346 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2347 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002348 xmlIOErrMemory("creating input buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00002349 return(NULL);
2350 }
2351 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillarde72c5082003-09-19 12:44:05 +00002352 ret->buffer = xmlBufferCreateStatic((void *)mem, (size_t) size);
Daniel Veillard53350552003-09-18 13:35:51 +00002353 if (ret->buffer == NULL) {
2354 xmlFree(ret);
2355 return(NULL);
2356 }
2357 ret->encoder = xmlGetCharEncodingHandler(enc);
2358 if (ret->encoder != NULL)
2359 ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
2360 else
2361 ret->raw = NULL;
2362 ret->compressed = -1;
2363 ret->context = (void *) mem;
2364 ret->readcallback = NULL;
2365 ret->closecallback = NULL;
2366
2367 return(ret);
2368}
2369
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002370#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard53350552003-09-18 13:35:51 +00002371/**
Owen Taylor3473f882001-02-23 17:55:21 +00002372 * xmlOutputBufferCreateFd:
2373 * @fd: a file descriptor number
2374 * @encoder: the encoding converter or NULL
2375 *
2376 * Create a buffered output for the progressive saving
2377 * to a file descriptor
2378 *
2379 * Returns the new parser output or NULL
2380 */
2381xmlOutputBufferPtr
2382xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
2383 xmlOutputBufferPtr ret;
2384
2385 if (fd < 0) return(NULL);
2386
2387 ret = xmlAllocOutputBuffer(encoder);
2388 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002389 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002390 ret->writecallback = xmlFdWrite;
Daniel Veillard7db38712002-02-07 16:39:11 +00002391 ret->closecallback = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002392 }
2393
2394 return(ret);
2395}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002396#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002397
2398/**
2399 * xmlParserInputBufferCreateIO:
2400 * @ioread: an I/O read function
2401 * @ioclose: an I/O close function
2402 * @ioctx: an I/O handler
2403 * @enc: the charset encoding if known
2404 *
2405 * Create a buffered parser input for the progressive parsing for the input
2406 * from an I/O handler
2407 *
2408 * Returns the new parser input or NULL
2409 */
2410xmlParserInputBufferPtr
2411xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
2412 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
2413 xmlParserInputBufferPtr ret;
2414
2415 if (ioread == NULL) return(NULL);
2416
2417 ret = xmlAllocParserInputBuffer(enc);
2418 if (ret != NULL) {
2419 ret->context = (void *) ioctx;
2420 ret->readcallback = ioread;
2421 ret->closecallback = ioclose;
2422 }
2423
2424 return(ret);
2425}
2426
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002427#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002428/**
2429 * xmlOutputBufferCreateIO:
2430 * @iowrite: an I/O write function
2431 * @ioclose: an I/O close function
2432 * @ioctx: an I/O handler
Daniel Veillard9d06d302002-01-22 18:15:52 +00002433 * @encoder: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002434 *
2435 * Create a buffered output for the progressive saving
2436 * to an I/O handler
2437 *
2438 * Returns the new parser output or NULL
2439 */
2440xmlOutputBufferPtr
2441xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
2442 xmlOutputCloseCallback ioclose, void *ioctx,
2443 xmlCharEncodingHandlerPtr encoder) {
2444 xmlOutputBufferPtr ret;
2445
2446 if (iowrite == NULL) return(NULL);
2447
2448 ret = xmlAllocOutputBuffer(encoder);
2449 if (ret != NULL) {
2450 ret->context = (void *) ioctx;
2451 ret->writecallback = iowrite;
2452 ret->closecallback = ioclose;
2453 }
2454
2455 return(ret);
2456}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002457#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002458
2459/**
2460 * xmlParserInputBufferPush:
2461 * @in: a buffered parser input
2462 * @len: the size in bytes of the array.
2463 * @buf: an char array
2464 *
2465 * Push the content of the arry in the input buffer
2466 * This routine handle the I18N transcoding to internal UTF-8
2467 * This is used when operating the parser in progressive (push) mode.
2468 *
2469 * Returns the number of chars read and stored in the buffer, or -1
2470 * in case of error.
2471 */
2472int
2473xmlParserInputBufferPush(xmlParserInputBufferPtr in,
2474 int len, const char *buf) {
2475 int nbchars = 0;
2476
2477 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002478 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002479 if (in->encoder != NULL) {
2480 /*
2481 * Store the data in the incoming raw buffer
2482 */
2483 if (in->raw == NULL) {
2484 in->raw = xmlBufferCreate();
2485 }
2486 xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
2487
2488 /*
2489 * convert as much as possible to the parser reading buffer.
2490 */
2491 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2492 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002493 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002494 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002495 return(-1);
2496 }
2497 } else {
2498 nbchars = len;
2499 xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
2500 }
2501#ifdef DEBUG_INPUT
2502 xmlGenericError(xmlGenericErrorContext,
2503 "I/O: pushed %d chars, buffer %d/%d\n",
2504 nbchars, in->buffer->use, in->buffer->size);
2505#endif
2506 return(nbchars);
2507}
2508
2509/**
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002510 * endOfInput:
2511 *
2512 * When reading from an Input channel indicated end of file or error
2513 * don't reread from it again.
2514 */
2515static int
2516endOfInput (void * context ATTRIBUTE_UNUSED,
2517 char * buffer ATTRIBUTE_UNUSED,
2518 int len ATTRIBUTE_UNUSED) {
2519 return(0);
2520}
2521
2522/**
Owen Taylor3473f882001-02-23 17:55:21 +00002523 * xmlParserInputBufferGrow:
2524 * @in: a buffered parser input
2525 * @len: indicative value of the amount of chars to read
2526 *
2527 * Grow up the content of the input buffer, the old data are preserved
2528 * This routine handle the I18N transcoding to internal UTF-8
2529 * This routine is used when operating the parser in normal (pull) mode
2530 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002531 * TODO: one should be able to remove one extra copy by copying directly
Owen Taylor3473f882001-02-23 17:55:21 +00002532 * onto in->buffer or in->raw
2533 *
2534 * Returns the number of chars read and stored in the buffer, or -1
2535 * in case of error.
2536 */
2537int
2538xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
2539 char *buffer = NULL;
2540 int res = 0;
2541 int nbchars = 0;
2542 int buffree;
Daniel Veillard9e412302002-06-10 15:59:44 +00002543 unsigned int needSize;
Owen Taylor3473f882001-02-23 17:55:21 +00002544
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002545 if ((in == NULL) || (in->error)) return(-1);
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002546 if ((len <= MINLEN) && (len != 4))
Owen Taylor3473f882001-02-23 17:55:21 +00002547 len = MINLEN;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002548
Owen Taylor3473f882001-02-23 17:55:21 +00002549 buffree = in->buffer->size - in->buffer->use;
2550 if (buffree <= 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002551 xmlIOErr(XML_IO_BUFFER_FULL, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002552 in->error = XML_IO_BUFFER_FULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002553 return(0);
2554 }
Owen Taylor3473f882001-02-23 17:55:21 +00002555
Daniel Veillarde5354492002-05-16 08:43:22 +00002556 needSize = in->buffer->use + len + 1;
2557 if (needSize > in->buffer->size){
2558 if (!xmlBufferResize(in->buffer, needSize)){
Daniel Veillard05d987b2003-10-08 11:54:57 +00002559 xmlIOErrMemory("growing input buffer");
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002560 in->error = XML_ERR_NO_MEMORY;
Daniel Veillarde5354492002-05-16 08:43:22 +00002561 return(0);
2562 }
Owen Taylor3473f882001-02-23 17:55:21 +00002563 }
Daniel Veillarde5354492002-05-16 08:43:22 +00002564 buffer = (char *)&in->buffer->content[in->buffer->use];
Owen Taylor3473f882001-02-23 17:55:21 +00002565
2566 /*
2567 * Call the read method for this I/O type.
2568 */
2569 if (in->readcallback != NULL) {
2570 res = in->readcallback(in->context, &buffer[0], len);
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002571 if (res <= 0)
2572 in->readcallback = endOfInput;
Owen Taylor3473f882001-02-23 17:55:21 +00002573 } else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002574 xmlIOErr(XML_IO_NO_INPUT, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002575 in->error = XML_IO_NO_INPUT;
Owen Taylor3473f882001-02-23 17:55:21 +00002576 return(-1);
2577 }
2578 if (res < 0) {
Owen Taylor3473f882001-02-23 17:55:21 +00002579 return(-1);
2580 }
2581 len = res;
2582 if (in->encoder != NULL) {
2583 /*
2584 * Store the data in the incoming raw buffer
2585 */
2586 if (in->raw == NULL) {
2587 in->raw = xmlBufferCreate();
2588 }
2589 xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
2590
2591 /*
2592 * convert as much as possible to the parser reading buffer.
2593 */
2594 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2595 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002596 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002597 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002598 return(-1);
2599 }
2600 } else {
2601 nbchars = len;
Daniel Veillarde5354492002-05-16 08:43:22 +00002602 in->buffer->use += nbchars;
2603 buffer[nbchars] = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002604 }
2605#ifdef DEBUG_INPUT
2606 xmlGenericError(xmlGenericErrorContext,
2607 "I/O: read %d chars, buffer %d/%d\n",
2608 nbchars, in->buffer->use, in->buffer->size);
2609#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002610 return(nbchars);
2611}
2612
2613/**
2614 * xmlParserInputBufferRead:
2615 * @in: a buffered parser input
2616 * @len: indicative value of the amount of chars to read
2617 *
2618 * Refresh the content of the input buffer, the old data are considered
2619 * consumed
2620 * This routine handle the I18N transcoding to internal UTF-8
2621 *
2622 * Returns the number of chars read and stored in the buffer, or -1
2623 * in case of error.
2624 */
2625int
2626xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002627 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002628 if (in->readcallback != NULL)
2629 return(xmlParserInputBufferGrow(in, len));
Daniel Veillard53350552003-09-18 13:35:51 +00002630 else if ((in->buffer != NULL) &&
2631 (in->buffer->alloc == XML_BUFFER_ALLOC_IMMUTABLE))
2632 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002633 else
2634 return(-1);
2635}
2636
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002637#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002638/**
2639 * xmlOutputBufferWrite:
2640 * @out: a buffered parser output
2641 * @len: the size in bytes of the array.
2642 * @buf: an char array
2643 *
2644 * Write the content of the array in the output I/O buffer
2645 * This routine handle the I18N transcoding from internal UTF-8
2646 * The buffer is lossless, i.e. will store in case of partial
2647 * or delayed writes.
2648 *
2649 * Returns the number of chars immediately written, or -1
2650 * in case of error.
2651 */
2652int
2653xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
2654 int nbchars = 0; /* number of chars to output to I/O */
2655 int ret; /* return from function call */
2656 int written = 0; /* number of char written to I/O so far */
2657 int chunk; /* number of byte curreent processed from buf */
2658
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002659 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002660 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002661 if (out->error) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002662
2663 do {
2664 chunk = len;
2665 if (chunk > 4 * MINLEN)
2666 chunk = 4 * MINLEN;
2667
2668 /*
2669 * first handle encoding stuff.
2670 */
2671 if (out->encoder != NULL) {
2672 /*
2673 * Store the data in the incoming raw buffer
2674 */
2675 if (out->conv == NULL) {
2676 out->conv = xmlBufferCreate();
2677 }
2678 xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2679
2680 if ((out->buffer->use < MINLEN) && (chunk == len))
2681 goto done;
2682
2683 /*
2684 * convert as much as possible to the parser reading buffer.
2685 */
2686 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
Daniel Veillard809faa52003-02-10 15:43:53 +00002687 if ((ret < 0) && (ret != -3)) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002688 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002689 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002690 return(-1);
2691 }
2692 nbchars = out->conv->use;
2693 } else {
2694 xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2695 nbchars = out->buffer->use;
2696 }
2697 buf += chunk;
2698 len -= chunk;
2699
2700 if ((nbchars < MINLEN) && (len <= 0))
2701 goto done;
2702
2703 if (out->writecallback) {
2704 /*
2705 * second write the stuff to the I/O channel
2706 */
2707 if (out->encoder != NULL) {
2708 ret = out->writecallback(out->context,
2709 (const char *)out->conv->content, nbchars);
2710 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002711 xmlBufferShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002712 } else {
2713 ret = out->writecallback(out->context,
2714 (const char *)out->buffer->content, nbchars);
2715 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002716 xmlBufferShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002717 }
2718 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002719 xmlIOErr(XML_IO_WRITE, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002720 out->error = XML_IO_WRITE;
Owen Taylor3473f882001-02-23 17:55:21 +00002721 return(ret);
2722 }
2723 out->written += ret;
2724 }
2725 written += nbchars;
2726 } while (len > 0);
2727
2728done:
2729#ifdef DEBUG_INPUT
2730 xmlGenericError(xmlGenericErrorContext,
2731 "I/O: wrote %d chars\n", written);
2732#endif
2733 return(written);
2734}
2735
2736/**
2737 * xmlOutputBufferWriteString:
2738 * @out: a buffered parser output
2739 * @str: a zero terminated C string
2740 *
2741 * Write the content of the string in the output I/O buffer
2742 * This routine handle the I18N transcoding from internal UTF-8
2743 * The buffer is lossless, i.e. will store in case of partial
2744 * or delayed writes.
2745 *
2746 * Returns the number of chars immediately written, or -1
2747 * in case of error.
2748 */
2749int
2750xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
2751 int len;
2752
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002753 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002754 if (str == NULL)
2755 return(-1);
2756 len = strlen(str);
2757
2758 if (len > 0)
2759 return(xmlOutputBufferWrite(out, len, str));
2760 return(len);
2761}
2762
2763/**
2764 * xmlOutputBufferFlush:
2765 * @out: a buffered output
2766 *
2767 * flushes the output I/O channel
2768 *
2769 * Returns the number of byte written or -1 in case of error.
2770 */
2771int
2772xmlOutputBufferFlush(xmlOutputBufferPtr out) {
2773 int nbchars = 0, ret = 0;
2774
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002775 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002776 /*
2777 * first handle encoding stuff.
2778 */
2779 if ((out->conv != NULL) && (out->encoder != NULL)) {
2780 /*
2781 * convert as much as possible to the parser reading buffer.
2782 */
2783 nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
2784 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002785 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002786 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002787 return(-1);
2788 }
2789 }
2790
2791 /*
2792 * second flush the stuff to the I/O channel
2793 */
2794 if ((out->conv != NULL) && (out->encoder != NULL) &&
2795 (out->writecallback != NULL)) {
2796 ret = out->writecallback(out->context,
2797 (const char *)out->conv->content, out->conv->use);
2798 if (ret >= 0)
2799 xmlBufferShrink(out->conv, ret);
2800 } else if (out->writecallback != NULL) {
2801 ret = out->writecallback(out->context,
2802 (const char *)out->buffer->content, out->buffer->use);
2803 if (ret >= 0)
2804 xmlBufferShrink(out->buffer, ret);
2805 }
2806 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002807 xmlIOErr(XML_IO_FLUSH, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002808 out->error = XML_IO_FLUSH;
Owen Taylor3473f882001-02-23 17:55:21 +00002809 return(ret);
2810 }
2811 out->written += ret;
2812
2813#ifdef DEBUG_INPUT
2814 xmlGenericError(xmlGenericErrorContext,
2815 "I/O: flushed %d chars\n", ret);
2816#endif
2817 return(ret);
2818}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002819#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002820
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002821/**
Owen Taylor3473f882001-02-23 17:55:21 +00002822 * xmlParserGetDirectory:
2823 * @filename: the path to a file
2824 *
2825 * lookup the directory for that file
2826 *
2827 * Returns a new allocated string containing the directory, or NULL.
2828 */
2829char *
2830xmlParserGetDirectory(const char *filename) {
2831 char *ret = NULL;
2832 char dir[1024];
2833 char *cur;
2834 char sep = '/';
2835
Igor Zlatkovic9181cc02002-09-29 17:51:06 +00002836#ifdef _WIN32_WCE /* easy way by now ... wince does not have dirs! */
2837 return NULL;
2838#endif
2839
Owen Taylor3473f882001-02-23 17:55:21 +00002840 if (xmlInputCallbackInitialized == 0)
2841 xmlRegisterDefaultInputCallbacks();
2842
2843 if (filename == NULL) return(NULL);
Daniel Veillard3c5ed912002-01-08 10:36:16 +00002844#if defined(WIN32) && !defined(__CYGWIN__)
Owen Taylor3473f882001-02-23 17:55:21 +00002845 sep = '\\';
2846#endif
2847
2848 strncpy(dir, filename, 1023);
2849 dir[1023] = 0;
2850 cur = &dir[strlen(dir)];
2851 while (cur > dir) {
2852 if (*cur == sep) break;
2853 cur --;
2854 }
2855 if (*cur == sep) {
2856 if (cur == dir) dir[1] = 0;
2857 else *cur = 0;
2858 ret = xmlMemStrdup(dir);
2859 } else {
2860 if (getcwd(dir, 1024) != NULL) {
2861 dir[1023] = 0;
2862 ret = xmlMemStrdup(dir);
2863 }
2864 }
2865 return(ret);
2866}
2867
2868/****************************************************************
2869 * *
2870 * External entities loading *
2871 * *
2872 ****************************************************************/
2873
Daniel Veillard561b7f82002-03-20 21:55:57 +00002874static int xmlSysIDExists(const char *URL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00002875#ifdef HAVE_STAT
2876 int ret;
2877 struct stat info;
2878 const char *path;
2879
2880 if (URL == NULL)
2881 return(0);
2882
Daniel Veillardf4862f02002-09-10 11:13:43 +00002883 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00002884#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00002885 path = &URL[17];
2886#else
Daniel Veillard6990bf32001-08-23 21:17:48 +00002887 path = &URL[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00002888#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002889 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00002890#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard6990bf32001-08-23 21:17:48 +00002891 path = &URL[8];
2892#else
2893 path = &URL[7];
2894#endif
2895 } else
2896 path = URL;
2897 ret = stat(path, &info);
Daniel Veillard561b7f82002-03-20 21:55:57 +00002898 if (ret == 0)
2899 return(1);
Daniel Veillard6990bf32001-08-23 21:17:48 +00002900#endif
Daniel Veillard561b7f82002-03-20 21:55:57 +00002901 return(0);
Daniel Veillard6990bf32001-08-23 21:17:48 +00002902}
Daniel Veillard6990bf32001-08-23 21:17:48 +00002903
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002904/**
Owen Taylor3473f882001-02-23 17:55:21 +00002905 * xmlDefaultExternalEntityLoader:
2906 * @URL: the URL for the entity to load
2907 * @ID: the System ID for the entity to load
2908 * @ctxt: the context in which the entity is called or NULL
2909 *
2910 * By default we don't load external entitites, yet.
2911 *
2912 * Returns a new allocated xmlParserInputPtr, or NULL.
2913 */
2914static
2915xmlParserInputPtr
2916xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
2917 xmlParserCtxtPtr ctxt) {
2918 xmlParserInputPtr ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002919 xmlChar *resource = NULL;
2920#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002921 xmlCatalogAllow pref;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002922#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002923
2924#ifdef DEBUG_EXTERNAL_ENTITIES
2925 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf012a642001-07-23 19:10:52 +00002926 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00002927#endif
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002928#ifdef LIBXML_CATALOG_ENABLED
2929 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002930 * If the resource doesn't exists as a file,
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002931 * try to load it from the resource pointed in the catalogs
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002932 */
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002933 pref = xmlCatalogGetDefaults();
2934
Daniel Veillard561b7f82002-03-20 21:55:57 +00002935 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlSysIDExists(URL))) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002936 /*
2937 * Do a local lookup
2938 */
2939 if ((ctxt->catalogs != NULL) &&
2940 ((pref == XML_CATA_ALLOW_ALL) ||
2941 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2942 resource = xmlCatalogLocalResolve(ctxt->catalogs,
2943 (const xmlChar *)ID,
2944 (const xmlChar *)URL);
2945 }
2946 /*
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002947 * Try a global lookup
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002948 */
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002949 if ((resource == NULL) &&
2950 ((pref == XML_CATA_ALLOW_ALL) ||
2951 (pref == XML_CATA_ALLOW_GLOBAL))) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002952 resource = xmlCatalogResolve((const xmlChar *)ID,
2953 (const xmlChar *)URL);
2954 }
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002955 if ((resource == NULL) && (URL != NULL))
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00002956 resource = xmlStrdup((const xmlChar *) URL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002957
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002958 /*
2959 * TODO: do an URI lookup on the reference
2960 */
Daniel Veillard561b7f82002-03-20 21:55:57 +00002961 if ((resource != NULL) && (!xmlSysIDExists((const char *)resource))) {
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002962 xmlChar *tmp = NULL;
2963
2964 if ((ctxt->catalogs != NULL) &&
2965 ((pref == XML_CATA_ALLOW_ALL) ||
2966 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2967 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
2968 }
2969 if ((tmp == NULL) &&
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00002970 ((pref == XML_CATA_ALLOW_ALL) ||
2971 (pref == XML_CATA_ALLOW_GLOBAL))) {
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002972 tmp = xmlCatalogResolveURI(resource);
2973 }
2974
2975 if (tmp != NULL) {
2976 xmlFree(resource);
2977 resource = tmp;
2978 }
2979 }
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002980 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002981#endif
2982
2983 if (resource == NULL)
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002984 resource = (xmlChar *) URL;
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002985
2986 if (resource == NULL) {
Daniel Veillardc6613042002-03-02 09:34:02 +00002987 if (ID == NULL)
2988 ID = "NULL";
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002989 if ((ctxt->validate) && (ctxt->sax != NULL) &&
2990 (ctxt->sax->error != NULL))
William M. Brack4811ba32003-09-06 18:02:53 +00002991 ctxt->sax->error(ctxt->userData,
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002992 "failed to load external entity \"%s\"\n", ID);
2993 else if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
William M. Brack4811ba32003-09-06 18:02:53 +00002994 ctxt->sax->warning(ctxt->userData,
Owen Taylor3473f882001-02-23 17:55:21 +00002995 "failed to load external entity \"%s\"\n", ID);
2996 return(NULL);
2997 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002998 ret = xmlNewInputFromFile(ctxt, (const char *)resource);
Owen Taylor3473f882001-02-23 17:55:21 +00002999 if (ret == NULL) {
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00003000 if ((ctxt->validate) && (ctxt->sax != NULL) &&
3001 (ctxt->sax->error != NULL))
William M. Brack4811ba32003-09-06 18:02:53 +00003002 ctxt->sax->error(ctxt->userData,
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003003 "failed to load external entity \"%s\"\n", resource);
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00003004 else if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
William M. Brack4811ba32003-09-06 18:02:53 +00003005 ctxt->sax->warning(ctxt->userData,
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003006 "failed to load external entity \"%s\"\n", resource);
Owen Taylor3473f882001-02-23 17:55:21 +00003007 }
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003008 if ((resource != NULL) && (resource != (xmlChar *) URL))
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003009 xmlFree(resource);
Owen Taylor3473f882001-02-23 17:55:21 +00003010 return(ret);
3011}
3012
3013static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
3014 xmlDefaultExternalEntityLoader;
3015
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003016/**
Owen Taylor3473f882001-02-23 17:55:21 +00003017 * xmlSetExternalEntityLoader:
3018 * @f: the new entity resolver function
3019 *
3020 * Changes the defaultexternal entity resolver function for the application
3021 */
3022void
3023xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
3024 xmlCurrentExternalEntityLoader = f;
3025}
3026
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003027/**
Owen Taylor3473f882001-02-23 17:55:21 +00003028 * xmlGetExternalEntityLoader:
3029 *
3030 * Get the default external entity resolver function for the application
3031 *
3032 * Returns the xmlExternalEntityLoader function pointer
3033 */
3034xmlExternalEntityLoader
3035xmlGetExternalEntityLoader(void) {
3036 return(xmlCurrentExternalEntityLoader);
3037}
3038
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003039/**
Owen Taylor3473f882001-02-23 17:55:21 +00003040 * xmlLoadExternalEntity:
3041 * @URL: the URL for the entity to load
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00003042 * @ID: the Public ID for the entity to load
Owen Taylor3473f882001-02-23 17:55:21 +00003043 * @ctxt: the context in which the entity is called or NULL
3044 *
3045 * Load an external entity, note that the use of this function for
3046 * unparsed entities may generate problems
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003047 * TODO: a more generic External entity API must be designed
Owen Taylor3473f882001-02-23 17:55:21 +00003048 *
3049 * Returns the xmlParserInputPtr or NULL
3050 */
3051xmlParserInputPtr
3052xmlLoadExternalEntity(const char *URL, const char *ID,
3053 xmlParserCtxtPtr ctxt) {
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00003054 if ((URL != NULL) && (xmlSysIDExists(URL) == 0)) {
3055 char *canonicFilename;
3056 xmlParserInputPtr ret;
3057
3058 canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL);
3059 if (canonicFilename == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003060 xmlIOErrMemory("building canonical path\n");
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00003061 return(NULL);
3062 }
3063
3064 ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt);
3065 xmlFree(canonicFilename);
3066 return(ret);
3067 }
Owen Taylor3473f882001-02-23 17:55:21 +00003068 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
3069}
3070
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003071/************************************************************************
3072 * *
3073 * Disabling Network access *
3074 * *
3075 ************************************************************************/
3076
3077#ifdef LIBXML_CATALOG_ENABLED
3078static int
3079xmlNoNetExists(const char *URL)
3080{
3081#ifdef HAVE_STAT
3082 int ret;
3083 struct stat info;
3084 const char *path;
3085
3086 if (URL == NULL)
3087 return (0);
3088
Daniel Veillardf4862f02002-09-10 11:13:43 +00003089 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003090#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00003091 path = &URL[17];
3092#else
3093 path = &URL[16];
3094#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003095 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003096#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003097 path = &URL[8];
3098#else
3099 path = &URL[7];
3100#endif
3101 } else
3102 path = URL;
3103 ret = stat(path, &info);
3104 if (ret == 0)
3105 return (1);
3106#endif
3107 return (0);
3108}
3109#endif
3110
3111/**
3112 * xmlNoNetExternalEntityLoader:
3113 * @URL: the URL for the entity to load
3114 * @ID: the System ID for the entity to load
3115 * @ctxt: the context in which the entity is called or NULL
3116 *
3117 * A specific entity loader disabling network accesses, though still
3118 * allowing local catalog accesses for resolution.
3119 *
3120 * Returns a new allocated xmlParserInputPtr, or NULL.
3121 */
3122xmlParserInputPtr
3123xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
3124 xmlParserCtxtPtr ctxt) {
3125 xmlParserInputPtr input = NULL;
3126 xmlChar *resource = NULL;
3127
3128#ifdef LIBXML_CATALOG_ENABLED
3129 xmlCatalogAllow pref;
3130
3131 /*
3132 * If the resource doesn't exists as a file,
3133 * try to load it from the resource pointed in the catalogs
3134 */
3135 pref = xmlCatalogGetDefaults();
3136
3137 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
3138 /*
3139 * Do a local lookup
3140 */
3141 if ((ctxt->catalogs != NULL) &&
3142 ((pref == XML_CATA_ALLOW_ALL) ||
3143 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3144 resource = xmlCatalogLocalResolve(ctxt->catalogs,
3145 (const xmlChar *)ID,
3146 (const xmlChar *)URL);
3147 }
3148 /*
3149 * Try a global lookup
3150 */
3151 if ((resource == NULL) &&
3152 ((pref == XML_CATA_ALLOW_ALL) ||
3153 (pref == XML_CATA_ALLOW_GLOBAL))) {
3154 resource = xmlCatalogResolve((const xmlChar *)ID,
3155 (const xmlChar *)URL);
3156 }
3157 if ((resource == NULL) && (URL != NULL))
3158 resource = xmlStrdup((const xmlChar *) URL);
3159
3160 /*
3161 * TODO: do an URI lookup on the reference
3162 */
3163 if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
3164 xmlChar *tmp = NULL;
3165
3166 if ((ctxt->catalogs != NULL) &&
3167 ((pref == XML_CATA_ALLOW_ALL) ||
3168 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3169 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
3170 }
3171 if ((tmp == NULL) &&
3172 ((pref == XML_CATA_ALLOW_ALL) ||
3173 (pref == XML_CATA_ALLOW_GLOBAL))) {
3174 tmp = xmlCatalogResolveURI(resource);
3175 }
3176
3177 if (tmp != NULL) {
3178 xmlFree(resource);
3179 resource = tmp;
3180 }
3181 }
3182 }
3183#endif
3184 if (resource == NULL)
3185 resource = (xmlChar *) URL;
3186
3187 if (resource != NULL) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003188 if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
3189 (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003190 xmlIOErr(XML_IO_NETWORK_ATTEMPT, (const char *) resource);
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003191 if (resource != (xmlChar *) URL)
3192 xmlFree(resource);
3193 return(NULL);
3194 }
3195 }
3196 input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
3197 if (resource != (xmlChar *) URL)
3198 xmlFree(resource);
3199 return(input);
3200}
3201