blob: 5382e94afd271d0ddf635f346f002eb7cb53d691 [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[] = {
133 "Unknown IO error errno", /* UNKNOWN */
134 "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 Veillard05d987b2003-10-08 11:54:57 +0000676 if ((items == 0) && (ferror((FILE *) context)))
677 xmlIOErr(0, "fwrite()");
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000678
679 return(items * len);
Owen Taylor3473f882001-02-23 17:55:21 +0000680}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000681#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000682
683/**
684 * xmlFileClose:
685 * @context: the I/O context
686 *
687 * Close an I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000688 *
689 * Returns 0 or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +0000690 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000691int
Owen Taylor3473f882001-02-23 17:55:21 +0000692xmlFileClose (void * context) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000693 FILE *fil;
Daniel Veillard05d987b2003-10-08 11:54:57 +0000694 int ret;
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000695
696 fil = (FILE *) context;
697 if (fil == stdin)
698 return(0);
699 if (fil == stdout)
700 return(0);
Daniel Veillardcd337f02001-11-22 18:20:37 +0000701 if (fil == stderr)
702 return(0);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000703 ret = ( fclose((FILE *) context) == EOF ) ? -1 : 0;
704 if (ret < 0)
705 xmlIOErr(0, "fclose()");
706 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000707}
708
709/**
710 * xmlFileFlush:
711 * @context: the I/O context
712 *
713 * Flush an I/O channel
714 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000715static int
Owen Taylor3473f882001-02-23 17:55:21 +0000716xmlFileFlush (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000717 int ret;
718 ret = ( fflush((FILE *) context) == EOF ) ? -1 : 0;
719 if (ret < 0)
720 xmlIOErr(0, "fflush()");
721 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000722}
723
724#ifdef HAVE_ZLIB_H
725/************************************************************************
726 * *
727 * I/O for compressed file accesses *
728 * *
729 ************************************************************************/
730/**
731 * xmlGzfileMatch:
732 * @filename: the URI for matching
733 *
734 * input from compressed file test
735 *
736 * Returns 1 if matches, 0 otherwise
737 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000738static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000739xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000740 return(1);
741}
742
743/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000744 * xmlGzfileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +0000745 * @filename: the URI for matching
746 *
747 * input from compressed file open
748 * if @filename is " " then the standard input is used
749 *
750 * Returns an I/O context or NULL in case of error
751 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000752static void *
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000753xmlGzfileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +0000754 const char *path = NULL;
755 gzFile fd;
756
757 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000758 fd = gzdopen(dup(0), "rb");
Owen Taylor3473f882001-02-23 17:55:21 +0000759 return((void *) fd);
760 }
761
Daniel Veillardf4862f02002-09-10 11:13:43 +0000762 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000763#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000764 path = &filename[17];
765#else
Owen Taylor3473f882001-02-23 17:55:21 +0000766 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000767#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000768 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000769#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000770 path = &filename[8];
771#else
Owen Taylor3473f882001-02-23 17:55:21 +0000772 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000773#endif
774 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000775 path = filename;
776
777 if (path == NULL)
778 return(NULL);
779 if (!xmlCheckFilename(path))
780 return(NULL);
781
782 fd = gzopen(path, "rb");
783 return((void *) fd);
784}
785
786/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000787 * xmlGzfileOpen:
788 * @filename: the URI for matching
789 *
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +0000790 * Wrapper around xmlGzfileOpen if the open fais, it will
791 * try to unescape @filename
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000792 */
793static void *
794xmlGzfileOpen (const char *filename) {
795 char *unescaped;
796 void *retval;
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +0000797
798 retval = xmlGzfileOpen_real(filename);
799 if (retval == NULL) {
800 unescaped = xmlURIUnescapeString(filename, 0, NULL);
801 if (unescaped != NULL) {
802 retval = xmlGzfileOpen_real(unescaped);
803 }
804 xmlFree(unescaped);
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000805 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000806 return retval;
807}
808
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000809#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000810/**
Owen Taylor3473f882001-02-23 17:55:21 +0000811 * xmlGzfileOpenW:
812 * @filename: the URI for matching
813 * @compression: the compression factor (0 - 9 included)
814 *
815 * input from compressed file open
816 * if @filename is " " then the standard input is used
817 *
818 * Returns an I/O context or NULL in case of error
819 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000820static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000821xmlGzfileOpenW (const char *filename, int compression) {
822 const char *path = NULL;
823 char mode[15];
824 gzFile fd;
825
Aleksey Sanin49cc9752002-06-14 17:07:10 +0000826 snprintf(mode, sizeof(mode), "wb%d", compression);
Owen Taylor3473f882001-02-23 17:55:21 +0000827 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000828 fd = gzdopen(dup(1), mode);
Owen Taylor3473f882001-02-23 17:55:21 +0000829 return((void *) fd);
830 }
831
Daniel Veillardf4862f02002-09-10 11:13:43 +0000832 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000833#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000834 path = &filename[17];
835#else
Owen Taylor3473f882001-02-23 17:55:21 +0000836 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000837#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000838 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000839#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000840 path = &filename[8];
841#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000842 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000843#endif
844 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000845 path = filename;
846
847 if (path == NULL)
848 return(NULL);
849
850 fd = gzopen(path, mode);
851 return((void *) fd);
852}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000853#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000854
855/**
856 * xmlGzfileRead:
857 * @context: the I/O context
858 * @buffer: where to drop data
859 * @len: number of bytes to write
860 *
861 * Read @len bytes to @buffer from the compressed I/O channel.
862 *
863 * Returns the number of bytes written
864 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000865static int
Owen Taylor3473f882001-02-23 17:55:21 +0000866xmlGzfileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000867 int ret;
868
869 ret = gzread((gzFile) context, &buffer[0], len);
870 if (ret < 0) xmlIOErr(0, "gzread()");
871 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000872}
873
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000874#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000875/**
876 * xmlGzfileWrite:
877 * @context: the I/O context
878 * @buffer: where to drop data
879 * @len: number of bytes to write
880 *
881 * Write @len bytes from @buffer to the compressed I/O channel.
882 *
883 * Returns the number of bytes written
884 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000885static int
Owen Taylor3473f882001-02-23 17:55:21 +0000886xmlGzfileWrite (void * context, const char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000887 int ret;
888
889 ret = gzwrite((gzFile) context, (char *) &buffer[0], len);
890 if (ret < 0) xmlIOErr(0, "gzwrite()");
891 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000892}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000893#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000894
895/**
896 * xmlGzfileClose:
897 * @context: the I/O context
898 *
899 * Close a compressed I/O channel
900 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000901static int
Owen Taylor3473f882001-02-23 17:55:21 +0000902xmlGzfileClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000903 int ret;
904
905 ret = (gzclose((gzFile) context) == Z_OK ) ? 0 : -1;
906 if (ret < 0) xmlIOErr(0, "gzclose()");
907 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000908}
909#endif /* HAVE_ZLIB_H */
910
911#ifdef LIBXML_HTTP_ENABLED
912/************************************************************************
913 * *
914 * I/O for HTTP file accesses *
915 * *
916 ************************************************************************/
Daniel Veillardf012a642001-07-23 19:10:52 +0000917
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000918#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +0000919typedef struct xmlIOHTTPWriteCtxt_
920{
921 int compression;
922
923 char * uri;
924
925 void * doc_buff;
926
927} xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr;
928
929#ifdef HAVE_ZLIB_H
930
931#define DFLT_WBITS ( -15 )
932#define DFLT_MEM_LVL ( 8 )
933#define GZ_MAGIC1 ( 0x1f )
934#define GZ_MAGIC2 ( 0x8b )
935#define LXML_ZLIB_OS_CODE ( 0x03 )
936#define INIT_HTTP_BUFF_SIZE ( 32768 )
937#define DFLT_ZLIB_RATIO ( 5 )
938
939/*
940** Data structure and functions to work with sending compressed data
941** via HTTP.
942*/
943
944typedef struct xmlZMemBuff_
945{
946 unsigned long size;
947 unsigned long crc;
948
949 unsigned char * zbuff;
950 z_stream zctrl;
951
952} xmlZMemBuff, *xmlZMemBuffPtr;
953
954/**
955 * append_reverse_ulong
956 * @buff: Compressed memory buffer
957 * @data: Unsigned long to append
958 *
959 * Append a unsigned long in reverse byte order to the end of the
960 * memory buffer.
961 */
962static void
963append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) {
964
965 int idx;
966
967 if ( buff == NULL )
968 return;
969
970 /*
971 ** This is plagiarized from putLong in gzio.c (zlib source) where
972 ** the number "4" is hardcoded. If zlib is ever patched to
973 ** support 64 bit file sizes, this code would need to be patched
974 ** as well.
975 */
976
977 for ( idx = 0; idx < 4; idx++ ) {
978 *buff->zctrl.next_out = ( data & 0xff );
979 data >>= 8;
980 buff->zctrl.next_out++;
981 }
982
983 return;
984}
985
986/**
987 *
988 * xmlFreeZMemBuff
989 * @buff: The memory buffer context to clear
990 *
991 * Release all the resources associated with the compressed memory buffer.
992 */
993static void
994xmlFreeZMemBuff( xmlZMemBuffPtr buff ) {
William M. Brack78637da2003-07-31 14:47:38 +0000995
996#ifdef DEBUG_HTTP
Daniel Veillardf012a642001-07-23 19:10:52 +0000997 int z_err;
William M. Brack78637da2003-07-31 14:47:38 +0000998#endif
Daniel Veillardf012a642001-07-23 19:10:52 +0000999
1000 if ( buff == NULL )
1001 return;
1002
1003 xmlFree( buff->zbuff );
Daniel Veillardf012a642001-07-23 19:10:52 +00001004#ifdef DEBUG_HTTP
William M. Brack78637da2003-07-31 14:47:38 +00001005 z_err = deflateEnd( &buff->zctrl );
Daniel Veillardf012a642001-07-23 19:10:52 +00001006 if ( z_err != Z_OK )
1007 xmlGenericError( xmlGenericErrorContext,
1008 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
1009 z_err );
William M. Brack78637da2003-07-31 14:47:38 +00001010#else
1011 deflateEnd( &buff->zctrl );
William M. Brack779af002003-08-01 15:55:39 +00001012#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001013
1014 xmlFree( buff );
1015 return;
1016}
1017
1018/**
1019 * xmlCreateZMemBuff
1020 *@compression: Compression value to use
1021 *
1022 * Create a memory buffer to hold the compressed XML document. The
1023 * compressed document in memory will end up being identical to what
1024 * would be created if gzopen/gzwrite/gzclose were being used to
1025 * write the document to disk. The code for the header/trailer data to
1026 * the compression is plagiarized from the zlib source files.
1027 */
1028static void *
1029xmlCreateZMemBuff( int compression ) {
1030
1031 int z_err;
1032 int hdr_lgth;
1033 xmlZMemBuffPtr buff = NULL;
1034
1035 if ( ( compression < 1 ) || ( compression > 9 ) )
1036 return ( NULL );
1037
1038 /* Create the control and data areas */
1039
1040 buff = xmlMalloc( sizeof( xmlZMemBuff ) );
1041 if ( buff == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001042 xmlIOErrMemory("creating buffer context");
Daniel Veillardf012a642001-07-23 19:10:52 +00001043 return ( NULL );
1044 }
1045
1046 (void)memset( buff, 0, sizeof( xmlZMemBuff ) );
1047 buff->size = INIT_HTTP_BUFF_SIZE;
1048 buff->zbuff = xmlMalloc( buff->size );
1049 if ( buff->zbuff == NULL ) {
1050 xmlFreeZMemBuff( buff );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001051 xmlIOErrMemory("creating buffer");
Daniel Veillardf012a642001-07-23 19:10:52 +00001052 return ( NULL );
1053 }
1054
1055 z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
1056 DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
1057 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001058 xmlChar msg[500];
Daniel Veillardf012a642001-07-23 19:10:52 +00001059 xmlFreeZMemBuff( buff );
1060 buff = NULL;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001061 xmlStrPrintf(msg, 500,
1062 (const xmlChar *) "xmlCreateZMemBuff: %s %d\n",
1063 "Error initializing compression context. ZLIB error:",
1064 z_err );
1065 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001066 return ( NULL );
1067 }
1068
1069 /* Set the header data. The CRC will be needed for the trailer */
Daniel Veillardf012a642001-07-23 19:10:52 +00001070 buff->crc = crc32( 0L, Z_NULL, 0 );
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001071 hdr_lgth = snprintf( (char *)buff->zbuff, buff->size,
1072 "%c%c%c%c%c%c%c%c%c%c",
Daniel Veillardf012a642001-07-23 19:10:52 +00001073 GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED,
1074 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE );
1075 buff->zctrl.next_out = buff->zbuff + hdr_lgth;
1076 buff->zctrl.avail_out = buff->size - hdr_lgth;
1077
1078 return ( buff );
1079}
1080
1081/**
1082 * xmlZMemBuffExtend
1083 * @buff: Buffer used to compress and consolidate data.
1084 * @ext_amt: Number of bytes to extend the buffer.
1085 *
1086 * Extend the internal buffer used to store the compressed data by the
1087 * specified amount.
1088 *
1089 * Returns 0 on success or -1 on failure to extend the buffer. On failure
1090 * the original buffer still exists at the original size.
1091 */
1092static int
1093xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) {
1094
1095 int rc = -1;
1096 size_t new_size;
1097 size_t cur_used;
1098
1099 unsigned char * tmp_ptr = NULL;
1100
1101 if ( buff == NULL )
1102 return ( -1 );
1103
1104 else if ( ext_amt == 0 )
1105 return ( 0 );
1106
1107 cur_used = buff->zctrl.next_out - buff->zbuff;
1108 new_size = buff->size + ext_amt;
1109
1110#ifdef DEBUG_HTTP
1111 if ( cur_used > new_size )
1112 xmlGenericError( xmlGenericErrorContext,
1113 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
1114 "Buffer overwrite detected during compressed memory",
1115 "buffer extension. Overflowed by",
1116 (cur_used - new_size ) );
1117#endif
1118
1119 tmp_ptr = xmlRealloc( buff->zbuff, new_size );
1120 if ( tmp_ptr != NULL ) {
1121 rc = 0;
1122 buff->size = new_size;
1123 buff->zbuff = tmp_ptr;
1124 buff->zctrl.next_out = tmp_ptr + cur_used;
1125 buff->zctrl.avail_out = new_size - cur_used;
1126 }
1127 else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001128 xmlChar msg[500];
1129 xmlStrPrintf(msg, 500,
1130 (const xmlChar *) "xmlZMemBuffExtend: %s %lu bytes.\n",
1131 "Allocation failure extending output buffer to",
1132 new_size );
1133 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001134 }
1135
1136 return ( rc );
1137}
1138
1139/**
1140 * xmlZMemBuffAppend
1141 * @buff: Buffer used to compress and consolidate data
1142 * @src: Uncompressed source content to append to buffer
1143 * @len: Length of source data to append to buffer
1144 *
1145 * Compress and append data to the internal buffer. The data buffer
1146 * will be expanded if needed to store the additional data.
1147 *
1148 * Returns the number of bytes appended to the buffer or -1 on error.
1149 */
1150static int
1151xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) {
1152
1153 int z_err;
1154 size_t min_accept;
1155
1156 if ( ( buff == NULL ) || ( src == NULL ) )
1157 return ( -1 );
1158
1159 buff->zctrl.avail_in = len;
1160 buff->zctrl.next_in = (unsigned char *)src;
1161 while ( buff->zctrl.avail_in > 0 ) {
1162 /*
1163 ** Extend the buffer prior to deflate call if a reasonable amount
1164 ** of output buffer space is not available.
1165 */
1166 min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO;
1167 if ( buff->zctrl.avail_out <= min_accept ) {
1168 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1169 return ( -1 );
1170 }
1171
1172 z_err = deflate( &buff->zctrl, Z_NO_FLUSH );
1173 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001174 xmlChar msg[500];
1175 xmlStrPrintf(msg, 500,
1176 (const xmlChar *) "xmlZMemBuffAppend: %s %d %s - %d",
Daniel Veillardf012a642001-07-23 19:10:52 +00001177 "Compression error while appending",
1178 len, "bytes to buffer. ZLIB error", z_err );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001179 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001180 return ( -1 );
1181 }
1182 }
1183
1184 buff->crc = crc32( buff->crc, (unsigned char *)src, len );
1185
1186 return ( len );
1187}
1188
1189/**
1190 * xmlZMemBuffGetContent
1191 * @buff: Compressed memory content buffer
1192 * @data_ref: Pointer reference to point to compressed content
1193 *
1194 * Flushes the compression buffers, appends gzip file trailers and
1195 * returns the compressed content and length of the compressed data.
1196 * NOTE: The gzip trailer code here is plagiarized from zlib source.
1197 *
1198 * Returns the length of the compressed data or -1 on error.
1199 */
1200static int
1201xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) {
1202
1203 int zlgth = -1;
1204 int z_err;
1205
1206 if ( ( buff == NULL ) || ( data_ref == NULL ) )
1207 return ( -1 );
1208
1209 /* Need to loop until compression output buffers are flushed */
1210
1211 do
1212 {
1213 z_err = deflate( &buff->zctrl, Z_FINISH );
1214 if ( z_err == Z_OK ) {
1215 /* In this case Z_OK means more buffer space needed */
1216
1217 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1218 return ( -1 );
1219 }
1220 }
1221 while ( z_err == Z_OK );
1222
1223 /* If the compression state is not Z_STREAM_END, some error occurred */
1224
1225 if ( z_err == Z_STREAM_END ) {
1226
1227 /* Need to append the gzip data trailer */
1228
1229 if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) {
1230 if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 )
1231 return ( -1 );
1232 }
1233
1234 /*
1235 ** For whatever reason, the CRC and length data are pushed out
1236 ** in reverse byte order. So a memcpy can't be used here.
1237 */
1238
1239 append_reverse_ulong( buff, buff->crc );
1240 append_reverse_ulong( buff, buff->zctrl.total_in );
1241
1242 zlgth = buff->zctrl.next_out - buff->zbuff;
1243 *data_ref = (char *)buff->zbuff;
1244 }
1245
Daniel Veillard05d987b2003-10-08 11:54:57 +00001246 else {
1247 xmlChar msg[500];
1248 xmlStrPrintf(msg, 500,
1249 (const xmlChar *) "xmlZMemBuffGetContent: %s - %d\n",
1250 "Error flushing zlib buffers. Error code", z_err );
1251 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1252 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001253
1254 return ( zlgth );
1255}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001256#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001257#endif /* HAVE_ZLIB_H */
1258
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001259#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001260/**
1261 * xmlFreeHTTPWriteCtxt
1262 * @ctxt: Context to cleanup
1263 *
1264 * Free allocated memory and reclaim system resources.
1265 *
1266 * No return value.
1267 */
1268static void
1269xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt )
1270{
1271 if ( ctxt->uri != NULL )
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001272 xmlFree( ctxt->uri );
Daniel Veillardf012a642001-07-23 19:10:52 +00001273
1274 if ( ctxt->doc_buff != NULL ) {
1275
1276#ifdef HAVE_ZLIB_H
1277 if ( ctxt->compression > 0 ) {
1278 xmlFreeZMemBuff( ctxt->doc_buff );
1279 }
1280 else
1281#endif
1282 {
1283 xmlOutputBufferClose( ctxt->doc_buff );
1284 }
1285 }
1286
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001287 xmlFree( ctxt );
Daniel Veillardf012a642001-07-23 19:10:52 +00001288 return;
1289}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001290#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001291
1292
Owen Taylor3473f882001-02-23 17:55:21 +00001293/**
1294 * xmlIOHTTPMatch:
1295 * @filename: the URI for matching
1296 *
1297 * check if the URI matches an HTTP one
1298 *
1299 * Returns 1 if matches, 0 otherwise
1300 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001301int
Owen Taylor3473f882001-02-23 17:55:21 +00001302xmlIOHTTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001303 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "http://", 7))
Owen Taylor3473f882001-02-23 17:55:21 +00001304 return(1);
1305 return(0);
1306}
1307
1308/**
1309 * xmlIOHTTPOpen:
1310 * @filename: the URI for matching
1311 *
1312 * open an HTTP I/O channel
1313 *
1314 * Returns an I/O context or NULL in case of error
1315 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001316void *
Owen Taylor3473f882001-02-23 17:55:21 +00001317xmlIOHTTPOpen (const char *filename) {
1318 return(xmlNanoHTTPOpen(filename, NULL));
1319}
1320
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001321#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001322/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001323 * xmlIOHTTPOpenW:
Daniel Veillardf012a642001-07-23 19:10:52 +00001324 * @post_uri: The destination URI for the document
1325 * @compression: The compression desired for the document.
1326 *
1327 * Open a temporary buffer to collect the document for a subsequent HTTP POST
1328 * request. Non-static as is called from the output buffer creation routine.
1329 *
1330 * Returns an I/O context or NULL in case of error.
1331 */
1332
1333void *
Daniel Veillard572577e2002-01-18 16:23:55 +00001334xmlIOHTTPOpenW(const char *post_uri, int compression)
1335{
Daniel Veillardf012a642001-07-23 19:10:52 +00001336
Daniel Veillard572577e2002-01-18 16:23:55 +00001337 xmlIOHTTPWriteCtxtPtr ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001338
Daniel Veillard572577e2002-01-18 16:23:55 +00001339 if (post_uri == NULL)
1340 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001341
Daniel Veillard572577e2002-01-18 16:23:55 +00001342 ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt));
1343 if (ctxt == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001344 xmlIOErrMemory("creating HTTP output context");
Daniel Veillard572577e2002-01-18 16:23:55 +00001345 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001346 }
1347
Daniel Veillard572577e2002-01-18 16:23:55 +00001348 (void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt));
Daniel Veillardf012a642001-07-23 19:10:52 +00001349
Daniel Veillard572577e2002-01-18 16:23:55 +00001350 ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri);
1351 if (ctxt->uri == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001352 xmlIOErrMemory("copying URI");
Daniel Veillard572577e2002-01-18 16:23:55 +00001353 xmlFreeHTTPWriteCtxt(ctxt);
1354 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001355 }
1356
1357 /*
Daniel Veillard572577e2002-01-18 16:23:55 +00001358 * ** Since the document length is required for an HTTP post,
1359 * ** need to put the document into a buffer. A memory buffer
1360 * ** is being used to avoid pushing the data to disk and back.
1361 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001362
1363#ifdef HAVE_ZLIB_H
Daniel Veillard572577e2002-01-18 16:23:55 +00001364 if ((compression > 0) && (compression <= 9)) {
1365
1366 ctxt->compression = compression;
1367 ctxt->doc_buff = xmlCreateZMemBuff(compression);
1368 } else
Daniel Veillardf012a642001-07-23 19:10:52 +00001369#endif
1370 {
Daniel Veillard572577e2002-01-18 16:23:55 +00001371 /* Any character conversions should have been done before this */
Daniel Veillardf012a642001-07-23 19:10:52 +00001372
Daniel Veillard572577e2002-01-18 16:23:55 +00001373 ctxt->doc_buff = xmlAllocOutputBuffer(NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001374 }
1375
Daniel Veillard572577e2002-01-18 16:23:55 +00001376 if (ctxt->doc_buff == NULL) {
1377 xmlFreeHTTPWriteCtxt(ctxt);
1378 ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001379 }
1380
Daniel Veillard572577e2002-01-18 16:23:55 +00001381 return (ctxt);
Daniel Veillardf012a642001-07-23 19:10:52 +00001382}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001383#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001384
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001385#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001386/**
1387 * xmlIOHTTPDfltOpenW
1388 * @post_uri: The destination URI for this document.
1389 *
1390 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
1391 * HTTP post command. This function should generally not be used as
1392 * the open callback is short circuited in xmlOutputBufferCreateFile.
1393 *
1394 * Returns a pointer to the new IO context.
1395 */
1396static void *
1397xmlIOHTTPDfltOpenW( const char * post_uri ) {
1398 return ( xmlIOHTTPOpenW( post_uri, 0 ) );
1399}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001400#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001401
1402/**
Owen Taylor3473f882001-02-23 17:55:21 +00001403 * xmlIOHTTPRead:
1404 * @context: the I/O context
1405 * @buffer: where to drop data
1406 * @len: number of bytes to write
1407 *
1408 * Read @len bytes to @buffer from the I/O channel.
1409 *
1410 * Returns the number of bytes written
1411 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001412int
Owen Taylor3473f882001-02-23 17:55:21 +00001413xmlIOHTTPRead(void * context, char * buffer, int len) {
1414 return(xmlNanoHTTPRead(context, &buffer[0], len));
1415}
1416
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001417#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001418/**
Daniel Veillardf012a642001-07-23 19:10:52 +00001419 * xmlIOHTTPWrite
1420 * @context: previously opened writing context
1421 * @buffer: data to output to temporary buffer
1422 * @len: bytes to output
1423 *
1424 * Collect data from memory buffer into a temporary file for later
1425 * processing.
1426 *
1427 * Returns number of bytes written.
1428 */
1429
1430static int
1431xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
1432
1433 xmlIOHTTPWriteCtxtPtr ctxt = context;
1434
1435 if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
1436 return ( -1 );
1437
1438 if ( len > 0 ) {
1439
1440 /* Use gzwrite or fwrite as previously setup in the open call */
1441
1442#ifdef HAVE_ZLIB_H
1443 if ( ctxt->compression > 0 )
1444 len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len );
1445
1446 else
1447#endif
1448 len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
1449
1450 if ( len < 0 ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001451 xmlChar msg[500];
1452 xmlStrPrintf(msg, 500,
1453 (const xmlChar *) "xmlIOHTTPWrite: %s\n%s '%s'.\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001454 "Error appending to internal buffer.",
1455 "Error sending document to URI",
1456 ctxt->uri );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001457 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001458 }
1459 }
1460
1461 return ( len );
1462}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001463#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001464
1465
1466/**
Owen Taylor3473f882001-02-23 17:55:21 +00001467 * xmlIOHTTPClose:
1468 * @context: the I/O context
1469 *
1470 * Close an HTTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001471 *
1472 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00001473 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001474int
Owen Taylor3473f882001-02-23 17:55:21 +00001475xmlIOHTTPClose (void * context) {
1476 xmlNanoHTTPClose(context);
Daniel Veillardf012a642001-07-23 19:10:52 +00001477 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001478}
Daniel Veillardf012a642001-07-23 19:10:52 +00001479
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001480#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001481/**
1482 * xmlIOHTTCloseWrite
1483 * @context: The I/O context
1484 * @http_mthd: The HTTP method to be used when sending the data
1485 *
1486 * Close the transmit HTTP I/O channel and actually send the data.
1487 */
1488static int
1489xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
1490
1491 int close_rc = -1;
1492 int http_rtn = 0;
1493 int content_lgth = 0;
1494 xmlIOHTTPWriteCtxtPtr ctxt = context;
1495
1496 char * http_content = NULL;
1497 char * content_encoding = NULL;
1498 char * content_type = (char *) "text/xml";
1499 void * http_ctxt = NULL;
1500
1501 if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
1502 return ( -1 );
1503
1504 /* Retrieve the content from the appropriate buffer */
1505
1506#ifdef HAVE_ZLIB_H
1507
1508 if ( ctxt->compression > 0 ) {
1509 content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
1510 content_encoding = (char *) "Content-Encoding: gzip";
1511 }
1512 else
1513#endif
1514 {
1515 /* Pull the data out of the memory output buffer */
1516
1517 xmlOutputBufferPtr dctxt = ctxt->doc_buff;
1518 http_content = (char *)dctxt->buffer->content;
1519 content_lgth = dctxt->buffer->use;
1520 }
1521
1522 if ( http_content == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001523 xmlChar msg[500];
1524 xmlStrPrintf(msg, 500,
1525 (const xmlChar *) "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
1526 "Error retrieving content.\nUnable to",
1527 http_mthd, "data to URI", ctxt->uri );
1528 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001529 }
1530
1531 else {
1532
1533 http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
1534 &content_type, content_encoding,
1535 content_lgth );
1536
1537 if ( http_ctxt != NULL ) {
1538#ifdef DEBUG_HTTP
1539 /* If testing/debugging - dump reply with request content */
1540
1541 FILE * tst_file = NULL;
1542 char buffer[ 4096 ];
1543 char * dump_name = NULL;
1544 int avail;
1545
1546 xmlGenericError( xmlGenericErrorContext,
1547 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
1548 http_mthd, ctxt->uri,
1549 xmlNanoHTTPReturnCode( http_ctxt ) );
1550
1551 /*
1552 ** Since either content or reply may be gzipped,
1553 ** dump them to separate files instead of the
1554 ** standard error context.
1555 */
1556
1557 dump_name = tempnam( NULL, "lxml" );
1558 if ( dump_name != NULL ) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001559 (void)snprintf( buffer, sizeof(buffer), "%s.content", dump_name );
Daniel Veillardf012a642001-07-23 19:10:52 +00001560
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00001561 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00001562 if ( tst_file != NULL ) {
1563 xmlGenericError( xmlGenericErrorContext,
1564 "Transmitted content saved in file: %s\n", buffer );
1565
1566 fwrite( http_content, sizeof( char ),
1567 content_lgth, tst_file );
1568 fclose( tst_file );
1569 }
1570
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001571 (void)snprintf( buffer, sizeof(buffer), "%s.reply", dump_name );
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00001572 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00001573 if ( tst_file != NULL ) {
1574 xmlGenericError( xmlGenericErrorContext,
1575 "Reply content saved in file: %s\n", buffer );
1576
1577
1578 while ( (avail = xmlNanoHTTPRead( http_ctxt,
1579 buffer, sizeof( buffer ) )) > 0 ) {
1580
1581 fwrite( buffer, sizeof( char ), avail, tst_file );
1582 }
1583
1584 fclose( tst_file );
1585 }
1586
1587 free( dump_name );
1588 }
1589#endif /* DEBUG_HTTP */
1590
1591 http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
1592 if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
1593 close_rc = 0;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001594 else {
1595 xmlChar msg[500];
1596 xmlStrPrintf(msg, 500,
1597 (const xmlChar *) "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001598 http_mthd, content_lgth,
1599 "bytes to URI", ctxt->uri,
1600 "failed. HTTP return code:", http_rtn );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001601 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1602 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001603
1604 xmlNanoHTTPClose( http_ctxt );
1605 xmlFree( content_type );
1606 }
1607 }
1608
1609 /* Final cleanups */
1610
1611 xmlFreeHTTPWriteCtxt( ctxt );
1612
1613 return ( close_rc );
1614}
1615
1616/**
1617 * xmlIOHTTPClosePut
1618 *
1619 * @context: The I/O context
1620 *
1621 * Close the transmit HTTP I/O channel and actually send data using a PUT
1622 * HTTP method.
1623 */
1624static int
1625xmlIOHTTPClosePut( void * ctxt ) {
1626 return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
1627}
1628
1629
1630/**
1631 * xmlIOHTTPClosePost
1632 *
1633 * @context: The I/O context
1634 *
1635 * Close the transmit HTTP I/O channel and actually send data using a POST
1636 * HTTP method.
1637 */
1638static int
1639xmlIOHTTPClosePost( void * ctxt ) {
1640 return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
1641}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001642#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001643
Owen Taylor3473f882001-02-23 17:55:21 +00001644#endif /* LIBXML_HTTP_ENABLED */
1645
1646#ifdef LIBXML_FTP_ENABLED
1647/************************************************************************
1648 * *
1649 * I/O for FTP file accesses *
1650 * *
1651 ************************************************************************/
1652/**
1653 * xmlIOFTPMatch:
1654 * @filename: the URI for matching
1655 *
1656 * check if the URI matches an FTP one
1657 *
1658 * Returns 1 if matches, 0 otherwise
1659 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001660int
Owen Taylor3473f882001-02-23 17:55:21 +00001661xmlIOFTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001662 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "ftp://", 6))
Owen Taylor3473f882001-02-23 17:55:21 +00001663 return(1);
1664 return(0);
1665}
1666
1667/**
1668 * xmlIOFTPOpen:
1669 * @filename: the URI for matching
1670 *
1671 * open an FTP I/O channel
1672 *
1673 * Returns an I/O context or NULL in case of error
1674 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001675void *
Owen Taylor3473f882001-02-23 17:55:21 +00001676xmlIOFTPOpen (const char *filename) {
1677 return(xmlNanoFTPOpen(filename));
1678}
1679
1680/**
1681 * xmlIOFTPRead:
1682 * @context: the I/O context
1683 * @buffer: where to drop data
1684 * @len: number of bytes to write
1685 *
1686 * Read @len bytes to @buffer from the I/O channel.
1687 *
1688 * Returns the number of bytes written
1689 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001690int
Owen Taylor3473f882001-02-23 17:55:21 +00001691xmlIOFTPRead(void * context, char * buffer, int len) {
1692 return(xmlNanoFTPRead(context, &buffer[0], len));
1693}
1694
1695/**
1696 * xmlIOFTPClose:
1697 * @context: the I/O context
1698 *
1699 * Close an FTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001700 *
1701 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00001702 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001703int
Owen Taylor3473f882001-02-23 17:55:21 +00001704xmlIOFTPClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001705 return ( xmlNanoFTPClose(context) );
Owen Taylor3473f882001-02-23 17:55:21 +00001706}
1707#endif /* LIBXML_FTP_ENABLED */
1708
1709
1710/**
1711 * xmlRegisterInputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001712 * @matchFunc: the xmlInputMatchCallback
1713 * @openFunc: the xmlInputOpenCallback
1714 * @readFunc: the xmlInputReadCallback
1715 * @closeFunc: the xmlInputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001716 *
1717 * Register a new set of I/O callback for handling parser input.
1718 *
1719 * Returns the registered handler number or -1 in case of error
1720 */
1721int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001722xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
1723 xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
1724 xmlInputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001725 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
1726 return(-1);
1727 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001728 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
1729 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
1730 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
1731 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00001732 xmlInputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00001733 return(xmlInputCallbackNr++);
1734}
1735
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001736#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001737/**
1738 * xmlRegisterOutputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001739 * @matchFunc: the xmlOutputMatchCallback
1740 * @openFunc: the xmlOutputOpenCallback
1741 * @writeFunc: the xmlOutputWriteCallback
1742 * @closeFunc: the xmlOutputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001743 *
1744 * Register a new set of I/O callback for handling output.
1745 *
1746 * Returns the registered handler number or -1 in case of error
1747 */
1748int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001749xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
1750 xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
1751 xmlOutputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001752 if (xmlOutputCallbackNr >= MAX_INPUT_CALLBACK) {
1753 return(-1);
1754 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001755 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
1756 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
1757 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
1758 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00001759 xmlOutputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00001760 return(xmlOutputCallbackNr++);
1761}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001762#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001763
1764/**
1765 * xmlRegisterDefaultInputCallbacks:
1766 *
1767 * Registers the default compiled-in I/O handlers.
1768 */
1769void
Owen Taylor3473f882001-02-23 17:55:21 +00001770xmlRegisterDefaultInputCallbacks
Owen Taylor3473f882001-02-23 17:55:21 +00001771(void) {
1772 if (xmlInputCallbackInitialized)
1773 return;
1774
1775 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
1776 xmlFileRead, xmlFileClose);
1777#ifdef HAVE_ZLIB_H
1778 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1779 xmlGzfileRead, xmlGzfileClose);
1780#endif /* HAVE_ZLIB_H */
1781
1782#ifdef LIBXML_HTTP_ENABLED
1783 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
1784 xmlIOHTTPRead, xmlIOHTTPClose);
1785#endif /* LIBXML_HTTP_ENABLED */
1786
1787#ifdef LIBXML_FTP_ENABLED
1788 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1789 xmlIOFTPRead, xmlIOFTPClose);
1790#endif /* LIBXML_FTP_ENABLED */
1791 xmlInputCallbackInitialized = 1;
1792}
1793
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001794#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001795/**
1796 * xmlRegisterDefaultOutputCallbacks:
1797 *
1798 * Registers the default compiled-in I/O handlers.
1799 */
1800void
Owen Taylor3473f882001-02-23 17:55:21 +00001801xmlRegisterDefaultOutputCallbacks
Owen Taylor3473f882001-02-23 17:55:21 +00001802(void) {
1803 if (xmlOutputCallbackInitialized)
1804 return;
1805
1806 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
1807 xmlFileWrite, xmlFileClose);
Daniel Veillardf012a642001-07-23 19:10:52 +00001808
1809#ifdef LIBXML_HTTP_ENABLED
1810 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
1811 xmlIOHTTPWrite, xmlIOHTTPClosePut);
1812#endif
1813
Owen Taylor3473f882001-02-23 17:55:21 +00001814/*********************************
1815 No way a-priori to distinguish between gzipped files from
1816 uncompressed ones except opening if existing then closing
1817 and saving with same compression ratio ... a pain.
1818
1819#ifdef HAVE_ZLIB_H
1820 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1821 xmlGzfileWrite, xmlGzfileClose);
1822#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001823
1824 Nor FTP PUT ....
1825#ifdef LIBXML_FTP_ENABLED
1826 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1827 xmlIOFTPWrite, xmlIOFTPClose);
1828#endif
1829 **********************************/
1830 xmlOutputCallbackInitialized = 1;
1831}
1832
Daniel Veillardf012a642001-07-23 19:10:52 +00001833#ifdef LIBXML_HTTP_ENABLED
1834/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001835 * xmlRegisterHTTPPostCallbacks:
Daniel Veillardf012a642001-07-23 19:10:52 +00001836 *
1837 * By default, libxml submits HTTP output requests using the "PUT" method.
1838 * Calling this method changes the HTTP output method to use the "POST"
1839 * method instead.
1840 *
1841 */
1842void
1843xmlRegisterHTTPPostCallbacks( void ) {
1844
1845 /* Register defaults if not done previously */
1846
1847 if ( xmlOutputCallbackInitialized == 0 )
1848 xmlRegisterDefaultOutputCallbacks( );
1849
1850 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
1851 xmlIOHTTPWrite, xmlIOHTTPClosePost);
1852 return;
1853}
1854#endif
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001855#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001856
Owen Taylor3473f882001-02-23 17:55:21 +00001857/**
1858 * xmlAllocParserInputBuffer:
1859 * @enc: the charset encoding if known
1860 *
1861 * Create a buffered parser input for progressive parsing
1862 *
1863 * Returns the new parser input or NULL
1864 */
1865xmlParserInputBufferPtr
1866xmlAllocParserInputBuffer(xmlCharEncoding enc) {
1867 xmlParserInputBufferPtr ret;
1868
1869 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
1870 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001871 xmlIOErrMemory("creating input buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00001872 return(NULL);
1873 }
1874 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00001875 ret->buffer = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00001876 if (ret->buffer == NULL) {
1877 xmlFree(ret);
1878 return(NULL);
1879 }
1880 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
1881 ret->encoder = xmlGetCharEncodingHandler(enc);
1882 if (ret->encoder != NULL)
Daniel Veillard6155d8a2003-08-19 15:01:28 +00001883 ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00001884 else
1885 ret->raw = NULL;
1886 ret->readcallback = NULL;
1887 ret->closecallback = NULL;
1888 ret->context = NULL;
William M. Brackc07329e2003-09-08 01:57:30 +00001889 ret->compressed = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00001890
1891 return(ret);
1892}
1893
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001894#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001895/**
1896 * xmlAllocOutputBuffer:
1897 * @encoder: the encoding converter or NULL
1898 *
1899 * Create a buffered parser output
1900 *
1901 * Returns the new parser output or NULL
1902 */
1903xmlOutputBufferPtr
1904xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
1905 xmlOutputBufferPtr ret;
1906
1907 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
1908 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001909 xmlIOErrMemory("creating output buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00001910 return(NULL);
1911 }
1912 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
1913 ret->buffer = xmlBufferCreate();
1914 if (ret->buffer == NULL) {
1915 xmlFree(ret);
1916 return(NULL);
1917 }
1918 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
1919 ret->encoder = encoder;
1920 if (encoder != NULL) {
1921 ret->conv = xmlBufferCreateSize(4000);
1922 /*
1923 * This call is designed to initiate the encoder state
1924 */
1925 xmlCharEncOutFunc(encoder, ret->conv, NULL);
1926 } else
1927 ret->conv = NULL;
1928 ret->writecallback = NULL;
1929 ret->closecallback = NULL;
1930 ret->context = NULL;
1931 ret->written = 0;
1932
1933 return(ret);
1934}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001935#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001936
1937/**
1938 * xmlFreeParserInputBuffer:
1939 * @in: a buffered parser input
1940 *
1941 * Free up the memory used by a buffered parser input
1942 */
1943void
1944xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
Daniel Veillard8d8bf2c2003-09-17 19:36:25 +00001945 if (in == NULL) return;
1946
Owen Taylor3473f882001-02-23 17:55:21 +00001947 if (in->raw) {
1948 xmlBufferFree(in->raw);
1949 in->raw = NULL;
1950 }
1951 if (in->encoder != NULL) {
1952 xmlCharEncCloseFunc(in->encoder);
1953 }
1954 if (in->closecallback != NULL) {
1955 in->closecallback(in->context);
1956 }
1957 if (in->buffer != NULL) {
1958 xmlBufferFree(in->buffer);
1959 in->buffer = NULL;
1960 }
1961
Owen Taylor3473f882001-02-23 17:55:21 +00001962 xmlFree(in);
1963}
1964
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001965#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001966/**
1967 * xmlOutputBufferClose:
1968 * @out: a buffered output
1969 *
1970 * flushes and close the output I/O channel
1971 * and free up all the associated resources
1972 *
1973 * Returns the number of byte written or -1 in case of error.
1974 */
1975int
1976xmlOutputBufferClose(xmlOutputBufferPtr out) {
1977 int written;
Daniel Veillardf012a642001-07-23 19:10:52 +00001978 int err_rc = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001979
1980 if (out == NULL)
1981 return(-1);
1982 if (out->writecallback != NULL)
1983 xmlOutputBufferFlush(out);
1984 if (out->closecallback != NULL) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001985 err_rc = out->closecallback(out->context);
Owen Taylor3473f882001-02-23 17:55:21 +00001986 }
1987 written = out->written;
1988 if (out->conv) {
1989 xmlBufferFree(out->conv);
1990 out->conv = NULL;
1991 }
1992 if (out->encoder != NULL) {
1993 xmlCharEncCloseFunc(out->encoder);
1994 }
1995 if (out->buffer != NULL) {
1996 xmlBufferFree(out->buffer);
1997 out->buffer = NULL;
1998 }
1999
Owen Taylor3473f882001-02-23 17:55:21 +00002000 xmlFree(out);
Daniel Veillardf012a642001-07-23 19:10:52 +00002001 return( ( err_rc == 0 ) ? written : err_rc );
Owen Taylor3473f882001-02-23 17:55:21 +00002002}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002003#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002004
2005/**
2006 * xmlParserInputBufferCreateFilename:
2007 * @URI: a C string containing the URI or filename
2008 * @enc: the charset encoding if known
2009 *
2010 * Create a buffered parser input for the progressive parsing of a file
2011 * If filename is "-' then we use stdin as the input.
2012 * Automatic support for ZLIB/Compress compressed document is provided
2013 * by default if found at compile-time.
2014 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
2015 *
2016 * Returns the new parser input or NULL
2017 */
2018xmlParserInputBufferPtr
Daniel Veillard3e59fc52003-04-18 12:34:58 +00002019xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002020 xmlParserInputBufferPtr ret;
Daniel Veillard388236f2001-07-08 18:35:48 +00002021 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002022 void *context = NULL;
2023
2024 if (xmlInputCallbackInitialized == 0)
2025 xmlRegisterDefaultInputCallbacks();
2026
2027 if (URI == NULL) return(NULL);
2028
2029 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002030 * Try to find one of the input accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002031 * Go in reverse to give precedence to user defined handlers.
Daniel Veillard388236f2001-07-08 18:35:48 +00002032 */
2033 if (context == NULL) {
2034 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
2035 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
2036 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002037 context = xmlInputCallbackTable[i].opencallback(URI);
Daniel Veillard388236f2001-07-08 18:35:48 +00002038 if (context != NULL)
2039 break;
2040 }
Owen Taylor3473f882001-02-23 17:55:21 +00002041 }
2042 }
2043 if (context == NULL) {
2044 return(NULL);
2045 }
2046
2047 /*
2048 * Allocate the Input buffer front-end.
2049 */
2050 ret = xmlAllocParserInputBuffer(enc);
2051 if (ret != NULL) {
2052 ret->context = context;
2053 ret->readcallback = xmlInputCallbackTable[i].readcallback;
2054 ret->closecallback = xmlInputCallbackTable[i].closecallback;
William M. Brackc07329e2003-09-08 01:57:30 +00002055#ifdef HAVE_ZLIB_H
2056 if (xmlInputCallbackTable[i].opencallback == xmlGzfileOpen) {
2057 if (((z_stream *)context)->avail_in > 4) {
2058 char *cptr, buff4[4];
Daniel Veillard07cb8222003-09-10 10:51:05 +00002059 cptr = (char *) ((z_stream *)context)->next_in;
William M. Brackc07329e2003-09-08 01:57:30 +00002060 if (gzread(context, buff4, 4) == 4) {
2061 if (strncmp(buff4, cptr, 4) == 0)
2062 ret->compressed = 0;
2063 else
2064 ret->compressed = 1;
2065 gzrewind(context);
2066 }
2067 }
2068 }
2069#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002070 }
2071 return(ret);
2072}
2073
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002074#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002075/**
2076 * xmlOutputBufferCreateFilename:
2077 * @URI: a C string containing the URI or filename
2078 * @encoder: the encoding converter or NULL
2079 * @compression: the compression ration (0 none, 9 max).
2080 *
2081 * Create a buffered output for the progressive saving of a file
2082 * If filename is "-' then we use stdout as the output.
2083 * Automatic support for ZLIB/Compress compressed document is provided
2084 * by default if found at compile-time.
2085 * TODO: currently if compression is set, the library only support
2086 * writing to a local file.
2087 *
2088 * Returns the new output or NULL
2089 */
2090xmlOutputBufferPtr
2091xmlOutputBufferCreateFilename(const char *URI,
2092 xmlCharEncodingHandlerPtr encoder,
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002093 int compression ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00002094 xmlOutputBufferPtr ret;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002095 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002096 void *context = NULL;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002097 char *unescaped;
Owen Taylor3473f882001-02-23 17:55:21 +00002098
Daniel Veillard4432df22003-09-28 18:58:27 +00002099#ifdef LIBXML_HTTP_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00002100 int is_http_uri = 0; /* Can't change if HTTP disabled */
Daniel Veillard4432df22003-09-28 18:58:27 +00002101#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00002102
Owen Taylor3473f882001-02-23 17:55:21 +00002103 if (xmlOutputCallbackInitialized == 0)
2104 xmlRegisterDefaultOutputCallbacks();
2105
2106 if (URI == NULL) return(NULL);
2107
Daniel Veillardf012a642001-07-23 19:10:52 +00002108#ifdef LIBXML_HTTP_ENABLED
2109 /* Need to prevent HTTP URI's from falling into zlib short circuit */
2110
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002111 is_http_uri = xmlIOHTTPMatch( URI );
Daniel Veillardf012a642001-07-23 19:10:52 +00002112#endif
2113
Owen Taylor3473f882001-02-23 17:55:21 +00002114
2115 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002116 * Try to find one of the output accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002117 * Go in reverse to give precedence to user defined handlers.
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002118 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00002119 */
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002120 unescaped = xmlURIUnescapeString(URI, 0, NULL);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002121 if (unescaped != NULL) {
2122#ifdef HAVE_ZLIB_H
2123 if ((compression > 0) && (compression <= 9) && (is_http_uri == 0)) {
2124 context = xmlGzfileOpenW(unescaped, compression);
2125 if (context != NULL) {
2126 ret = xmlAllocOutputBuffer(encoder);
2127 if (ret != NULL) {
2128 ret->context = context;
2129 ret->writecallback = xmlGzfileWrite;
2130 ret->closecallback = xmlGzfileClose;
2131 }
2132 xmlFree(unescaped);
2133 return(ret);
2134 }
2135 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002136#endif
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002137 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2138 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
2139 (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
2140#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2141 /* Need to pass compression parameter into HTTP open calls */
2142 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2143 context = xmlIOHTTPOpenW(unescaped, compression);
2144 else
2145#endif
2146 context = xmlOutputCallbackTable[i].opencallback(unescaped);
2147 if (context != NULL)
2148 break;
2149 }
2150 }
2151 xmlFree(unescaped);
2152 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002153
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002154 /*
2155 * If this failed try with a non-escaped URI this may be a strange
2156 * filename
2157 */
2158 if (context == NULL) {
2159#ifdef HAVE_ZLIB_H
2160 if ((compression > 0) && (compression <= 9) && (is_http_uri == 0)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002161 context = xmlGzfileOpenW(URI, compression);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002162 if (context != NULL) {
2163 ret = xmlAllocOutputBuffer(encoder);
2164 if (ret != NULL) {
2165 ret->context = context;
2166 ret->writecallback = xmlGzfileWrite;
2167 ret->closecallback = xmlGzfileClose;
2168 }
2169 return(ret);
2170 }
2171 }
2172#endif
2173 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2174 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002175 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002176#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2177 /* Need to pass compression parameter into HTTP open calls */
2178 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2179 context = xmlIOHTTPOpenW(URI, compression);
2180 else
2181#endif
2182 context = xmlOutputCallbackTable[i].opencallback(URI);
2183 if (context != NULL)
2184 break;
2185 }
Owen Taylor3473f882001-02-23 17:55:21 +00002186 }
2187 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002188
Owen Taylor3473f882001-02-23 17:55:21 +00002189 if (context == NULL) {
2190 return(NULL);
2191 }
2192
2193 /*
2194 * Allocate the Output buffer front-end.
2195 */
2196 ret = xmlAllocOutputBuffer(encoder);
2197 if (ret != NULL) {
2198 ret->context = context;
2199 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
2200 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
2201 }
2202 return(ret);
2203}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002204#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002205
2206/**
2207 * xmlParserInputBufferCreateFile:
2208 * @file: a FILE*
2209 * @enc: the charset encoding if known
2210 *
2211 * Create a buffered parser input for the progressive parsing of a FILE *
2212 * buffered C I/O
2213 *
2214 * Returns the new parser input or NULL
2215 */
2216xmlParserInputBufferPtr
2217xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
2218 xmlParserInputBufferPtr ret;
2219
2220 if (xmlInputCallbackInitialized == 0)
2221 xmlRegisterDefaultInputCallbacks();
2222
2223 if (file == NULL) return(NULL);
2224
2225 ret = xmlAllocParserInputBuffer(enc);
2226 if (ret != NULL) {
2227 ret->context = file;
2228 ret->readcallback = xmlFileRead;
2229 ret->closecallback = xmlFileFlush;
2230 }
2231
2232 return(ret);
2233}
2234
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002235#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002236/**
2237 * xmlOutputBufferCreateFile:
2238 * @file: a FILE*
2239 * @encoder: the encoding converter or NULL
2240 *
2241 * Create a buffered output for the progressive saving to a FILE *
2242 * buffered C I/O
2243 *
2244 * Returns the new parser output or NULL
2245 */
2246xmlOutputBufferPtr
2247xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
2248 xmlOutputBufferPtr ret;
2249
2250 if (xmlOutputCallbackInitialized == 0)
2251 xmlRegisterDefaultOutputCallbacks();
2252
2253 if (file == NULL) return(NULL);
2254
2255 ret = xmlAllocOutputBuffer(encoder);
2256 if (ret != NULL) {
2257 ret->context = file;
2258 ret->writecallback = xmlFileWrite;
2259 ret->closecallback = xmlFileFlush;
2260 }
2261
2262 return(ret);
2263}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002264#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002265
2266/**
2267 * xmlParserInputBufferCreateFd:
2268 * @fd: a file descriptor number
2269 * @enc: the charset encoding if known
2270 *
2271 * Create a buffered parser input for the progressive parsing for the input
2272 * from a file descriptor
2273 *
2274 * Returns the new parser input or NULL
2275 */
2276xmlParserInputBufferPtr
2277xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
2278 xmlParserInputBufferPtr ret;
2279
2280 if (fd < 0) return(NULL);
2281
2282 ret = xmlAllocParserInputBuffer(enc);
2283 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002284 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002285 ret->readcallback = xmlFdRead;
2286 ret->closecallback = xmlFdClose;
2287 }
2288
2289 return(ret);
2290}
2291
2292/**
2293 * xmlParserInputBufferCreateMem:
2294 * @mem: the memory input
2295 * @size: the length of the memory block
2296 * @enc: the charset encoding if known
2297 *
2298 * Create a buffered parser input for the progressive parsing for the input
2299 * from a memory area.
2300 *
2301 * Returns the new parser input or NULL
2302 */
2303xmlParserInputBufferPtr
2304xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
2305 xmlParserInputBufferPtr ret;
2306
2307 if (size <= 0) return(NULL);
2308 if (mem == NULL) return(NULL);
2309
2310 ret = xmlAllocParserInputBuffer(enc);
2311 if (ret != NULL) {
2312 ret->context = (void *) mem;
2313 ret->readcallback = (xmlInputReadCallback) xmlNop;
2314 ret->closecallback = NULL;
2315 xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size);
2316 }
2317
2318 return(ret);
2319}
2320
2321/**
Daniel Veillard53350552003-09-18 13:35:51 +00002322 * xmlParserInputBufferCreateStatic:
2323 * @mem: the memory input
2324 * @size: the length of the memory block
2325 * @enc: the charset encoding if known
2326 *
2327 * Create a buffered parser input for the progressive parsing for the input
2328 * from an immutable memory area. This will not copy the memory area to
2329 * the buffer, but the memory is expected to be available until the end of
2330 * the parsing, this is useful for example when using mmap'ed file.
2331 *
2332 * Returns the new parser input or NULL
2333 */
2334xmlParserInputBufferPtr
2335xmlParserInputBufferCreateStatic(const char *mem, int size,
2336 xmlCharEncoding enc) {
2337 xmlParserInputBufferPtr ret;
2338
2339 if (size <= 0) return(NULL);
2340 if (mem == NULL) return(NULL);
2341
2342 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2343 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002344 xmlIOErrMemory("creating input buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00002345 return(NULL);
2346 }
2347 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillarde72c5082003-09-19 12:44:05 +00002348 ret->buffer = xmlBufferCreateStatic((void *)mem, (size_t) size);
Daniel Veillard53350552003-09-18 13:35:51 +00002349 if (ret->buffer == NULL) {
2350 xmlFree(ret);
2351 return(NULL);
2352 }
2353 ret->encoder = xmlGetCharEncodingHandler(enc);
2354 if (ret->encoder != NULL)
2355 ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
2356 else
2357 ret->raw = NULL;
2358 ret->compressed = -1;
2359 ret->context = (void *) mem;
2360 ret->readcallback = NULL;
2361 ret->closecallback = NULL;
2362
2363 return(ret);
2364}
2365
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002366#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard53350552003-09-18 13:35:51 +00002367/**
Owen Taylor3473f882001-02-23 17:55:21 +00002368 * xmlOutputBufferCreateFd:
2369 * @fd: a file descriptor number
2370 * @encoder: the encoding converter or NULL
2371 *
2372 * Create a buffered output for the progressive saving
2373 * to a file descriptor
2374 *
2375 * Returns the new parser output or NULL
2376 */
2377xmlOutputBufferPtr
2378xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
2379 xmlOutputBufferPtr ret;
2380
2381 if (fd < 0) return(NULL);
2382
2383 ret = xmlAllocOutputBuffer(encoder);
2384 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002385 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002386 ret->writecallback = xmlFdWrite;
Daniel Veillard7db38712002-02-07 16:39:11 +00002387 ret->closecallback = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002388 }
2389
2390 return(ret);
2391}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002392#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002393
2394/**
2395 * xmlParserInputBufferCreateIO:
2396 * @ioread: an I/O read function
2397 * @ioclose: an I/O close function
2398 * @ioctx: an I/O handler
2399 * @enc: the charset encoding if known
2400 *
2401 * Create a buffered parser input for the progressive parsing for the input
2402 * from an I/O handler
2403 *
2404 * Returns the new parser input or NULL
2405 */
2406xmlParserInputBufferPtr
2407xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
2408 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
2409 xmlParserInputBufferPtr ret;
2410
2411 if (ioread == NULL) return(NULL);
2412
2413 ret = xmlAllocParserInputBuffer(enc);
2414 if (ret != NULL) {
2415 ret->context = (void *) ioctx;
2416 ret->readcallback = ioread;
2417 ret->closecallback = ioclose;
2418 }
2419
2420 return(ret);
2421}
2422
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002423#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002424/**
2425 * xmlOutputBufferCreateIO:
2426 * @iowrite: an I/O write function
2427 * @ioclose: an I/O close function
2428 * @ioctx: an I/O handler
Daniel Veillard9d06d302002-01-22 18:15:52 +00002429 * @encoder: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002430 *
2431 * Create a buffered output for the progressive saving
2432 * to an I/O handler
2433 *
2434 * Returns the new parser output or NULL
2435 */
2436xmlOutputBufferPtr
2437xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
2438 xmlOutputCloseCallback ioclose, void *ioctx,
2439 xmlCharEncodingHandlerPtr encoder) {
2440 xmlOutputBufferPtr ret;
2441
2442 if (iowrite == NULL) return(NULL);
2443
2444 ret = xmlAllocOutputBuffer(encoder);
2445 if (ret != NULL) {
2446 ret->context = (void *) ioctx;
2447 ret->writecallback = iowrite;
2448 ret->closecallback = ioclose;
2449 }
2450
2451 return(ret);
2452}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002453#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002454
2455/**
2456 * xmlParserInputBufferPush:
2457 * @in: a buffered parser input
2458 * @len: the size in bytes of the array.
2459 * @buf: an char array
2460 *
2461 * Push the content of the arry in the input buffer
2462 * This routine handle the I18N transcoding to internal UTF-8
2463 * This is used when operating the parser in progressive (push) mode.
2464 *
2465 * Returns the number of chars read and stored in the buffer, or -1
2466 * in case of error.
2467 */
2468int
2469xmlParserInputBufferPush(xmlParserInputBufferPtr in,
2470 int len, const char *buf) {
2471 int nbchars = 0;
2472
2473 if (len < 0) return(0);
2474 if (in->encoder != NULL) {
2475 /*
2476 * Store the data in the incoming raw buffer
2477 */
2478 if (in->raw == NULL) {
2479 in->raw = xmlBufferCreate();
2480 }
2481 xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
2482
2483 /*
2484 * convert as much as possible to the parser reading buffer.
2485 */
2486 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2487 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002488 xmlIOErr(XML_IO_ENCODER, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002489 return(-1);
2490 }
2491 } else {
2492 nbchars = len;
2493 xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
2494 }
2495#ifdef DEBUG_INPUT
2496 xmlGenericError(xmlGenericErrorContext,
2497 "I/O: pushed %d chars, buffer %d/%d\n",
2498 nbchars, in->buffer->use, in->buffer->size);
2499#endif
2500 return(nbchars);
2501}
2502
2503/**
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002504 * endOfInput:
2505 *
2506 * When reading from an Input channel indicated end of file or error
2507 * don't reread from it again.
2508 */
2509static int
2510endOfInput (void * context ATTRIBUTE_UNUSED,
2511 char * buffer ATTRIBUTE_UNUSED,
2512 int len ATTRIBUTE_UNUSED) {
2513 return(0);
2514}
2515
2516/**
Owen Taylor3473f882001-02-23 17:55:21 +00002517 * xmlParserInputBufferGrow:
2518 * @in: a buffered parser input
2519 * @len: indicative value of the amount of chars to read
2520 *
2521 * Grow up the content of the input buffer, the old data are preserved
2522 * This routine handle the I18N transcoding to internal UTF-8
2523 * This routine is used when operating the parser in normal (pull) mode
2524 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002525 * TODO: one should be able to remove one extra copy by copying directly
Owen Taylor3473f882001-02-23 17:55:21 +00002526 * onto in->buffer or in->raw
2527 *
2528 * Returns the number of chars read and stored in the buffer, or -1
2529 * in case of error.
2530 */
2531int
2532xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
2533 char *buffer = NULL;
2534 int res = 0;
2535 int nbchars = 0;
2536 int buffree;
Daniel Veillard9e412302002-06-10 15:59:44 +00002537 unsigned int needSize;
Owen Taylor3473f882001-02-23 17:55:21 +00002538
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002539 if ((len <= MINLEN) && (len != 4))
Owen Taylor3473f882001-02-23 17:55:21 +00002540 len = MINLEN;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002541
Owen Taylor3473f882001-02-23 17:55:21 +00002542 buffree = in->buffer->size - in->buffer->use;
2543 if (buffree <= 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002544 xmlIOErr(XML_IO_BUFFER_FULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002545 return(0);
2546 }
Owen Taylor3473f882001-02-23 17:55:21 +00002547
Daniel Veillarde5354492002-05-16 08:43:22 +00002548 needSize = in->buffer->use + len + 1;
2549 if (needSize > in->buffer->size){
2550 if (!xmlBufferResize(in->buffer, needSize)){
Daniel Veillard05d987b2003-10-08 11:54:57 +00002551 xmlIOErrMemory("growing input buffer");
Daniel Veillarde5354492002-05-16 08:43:22 +00002552 return(0);
2553 }
Owen Taylor3473f882001-02-23 17:55:21 +00002554 }
Daniel Veillarde5354492002-05-16 08:43:22 +00002555 buffer = (char *)&in->buffer->content[in->buffer->use];
Owen Taylor3473f882001-02-23 17:55:21 +00002556
2557 /*
2558 * Call the read method for this I/O type.
2559 */
2560 if (in->readcallback != NULL) {
2561 res = in->readcallback(in->context, &buffer[0], len);
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002562 if (res <= 0)
2563 in->readcallback = endOfInput;
Owen Taylor3473f882001-02-23 17:55:21 +00002564 } else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002565 xmlIOErr(XML_IO_NO_INPUT, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002566 return(-1);
2567 }
2568 if (res < 0) {
Owen Taylor3473f882001-02-23 17:55:21 +00002569 return(-1);
2570 }
2571 len = res;
2572 if (in->encoder != NULL) {
2573 /*
2574 * Store the data in the incoming raw buffer
2575 */
2576 if (in->raw == NULL) {
2577 in->raw = xmlBufferCreate();
2578 }
2579 xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
2580
2581 /*
2582 * convert as much as possible to the parser reading buffer.
2583 */
2584 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2585 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002586 xmlIOErr(XML_IO_ENCODER, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002587 return(-1);
2588 }
2589 } else {
2590 nbchars = len;
Daniel Veillarde5354492002-05-16 08:43:22 +00002591 in->buffer->use += nbchars;
2592 buffer[nbchars] = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002593 }
2594#ifdef DEBUG_INPUT
2595 xmlGenericError(xmlGenericErrorContext,
2596 "I/O: read %d chars, buffer %d/%d\n",
2597 nbchars, in->buffer->use, in->buffer->size);
2598#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002599 return(nbchars);
2600}
2601
2602/**
2603 * xmlParserInputBufferRead:
2604 * @in: a buffered parser input
2605 * @len: indicative value of the amount of chars to read
2606 *
2607 * Refresh the content of the input buffer, the old data are considered
2608 * consumed
2609 * This routine handle the I18N transcoding to internal UTF-8
2610 *
2611 * Returns the number of chars read and stored in the buffer, or -1
2612 * in case of error.
2613 */
2614int
2615xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
2616 /* xmlBufferEmpty(in->buffer); */
2617 if (in->readcallback != NULL)
2618 return(xmlParserInputBufferGrow(in, len));
Daniel Veillard53350552003-09-18 13:35:51 +00002619 else if ((in->buffer != NULL) &&
2620 (in->buffer->alloc == XML_BUFFER_ALLOC_IMMUTABLE))
2621 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002622 else
2623 return(-1);
2624}
2625
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002626#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002627/**
2628 * xmlOutputBufferWrite:
2629 * @out: a buffered parser output
2630 * @len: the size in bytes of the array.
2631 * @buf: an char array
2632 *
2633 * Write the content of the array in the output I/O buffer
2634 * This routine handle the I18N transcoding from internal UTF-8
2635 * The buffer is lossless, i.e. will store in case of partial
2636 * or delayed writes.
2637 *
2638 * Returns the number of chars immediately written, or -1
2639 * in case of error.
2640 */
2641int
2642xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
2643 int nbchars = 0; /* number of chars to output to I/O */
2644 int ret; /* return from function call */
2645 int written = 0; /* number of char written to I/O so far */
2646 int chunk; /* number of byte curreent processed from buf */
2647
2648 if (len < 0) return(0);
2649
2650 do {
2651 chunk = len;
2652 if (chunk > 4 * MINLEN)
2653 chunk = 4 * MINLEN;
2654
2655 /*
2656 * first handle encoding stuff.
2657 */
2658 if (out->encoder != NULL) {
2659 /*
2660 * Store the data in the incoming raw buffer
2661 */
2662 if (out->conv == NULL) {
2663 out->conv = xmlBufferCreate();
2664 }
2665 xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2666
2667 if ((out->buffer->use < MINLEN) && (chunk == len))
2668 goto done;
2669
2670 /*
2671 * convert as much as possible to the parser reading buffer.
2672 */
2673 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
Daniel Veillard809faa52003-02-10 15:43:53 +00002674 if ((ret < 0) && (ret != -3)) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002675 xmlIOErr(XML_IO_ENCODER, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002676 return(-1);
2677 }
2678 nbchars = out->conv->use;
2679 } else {
2680 xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2681 nbchars = out->buffer->use;
2682 }
2683 buf += chunk;
2684 len -= chunk;
2685
2686 if ((nbchars < MINLEN) && (len <= 0))
2687 goto done;
2688
2689 if (out->writecallback) {
2690 /*
2691 * second write the stuff to the I/O channel
2692 */
2693 if (out->encoder != NULL) {
2694 ret = out->writecallback(out->context,
2695 (const char *)out->conv->content, nbchars);
2696 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002697 xmlBufferShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002698 } else {
2699 ret = out->writecallback(out->context,
2700 (const char *)out->buffer->content, nbchars);
2701 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002702 xmlBufferShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002703 }
2704 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002705 xmlIOErr(XML_IO_WRITE, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002706 return(ret);
2707 }
2708 out->written += ret;
2709 }
2710 written += nbchars;
2711 } while (len > 0);
2712
2713done:
2714#ifdef DEBUG_INPUT
2715 xmlGenericError(xmlGenericErrorContext,
2716 "I/O: wrote %d chars\n", written);
2717#endif
2718 return(written);
2719}
2720
2721/**
2722 * xmlOutputBufferWriteString:
2723 * @out: a buffered parser output
2724 * @str: a zero terminated C string
2725 *
2726 * Write the content of the string in the output I/O buffer
2727 * This routine handle the I18N transcoding from internal UTF-8
2728 * The buffer is lossless, i.e. will store in case of partial
2729 * or delayed writes.
2730 *
2731 * Returns the number of chars immediately written, or -1
2732 * in case of error.
2733 */
2734int
2735xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
2736 int len;
2737
2738 if (str == NULL)
2739 return(-1);
2740 len = strlen(str);
2741
2742 if (len > 0)
2743 return(xmlOutputBufferWrite(out, len, str));
2744 return(len);
2745}
2746
2747/**
2748 * xmlOutputBufferFlush:
2749 * @out: a buffered output
2750 *
2751 * flushes the output I/O channel
2752 *
2753 * Returns the number of byte written or -1 in case of error.
2754 */
2755int
2756xmlOutputBufferFlush(xmlOutputBufferPtr out) {
2757 int nbchars = 0, ret = 0;
2758
2759 /*
2760 * first handle encoding stuff.
2761 */
2762 if ((out->conv != NULL) && (out->encoder != NULL)) {
2763 /*
2764 * convert as much as possible to the parser reading buffer.
2765 */
2766 nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
2767 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002768 xmlIOErr(XML_IO_ENCODER, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002769 return(-1);
2770 }
2771 }
2772
2773 /*
2774 * second flush the stuff to the I/O channel
2775 */
2776 if ((out->conv != NULL) && (out->encoder != NULL) &&
2777 (out->writecallback != NULL)) {
2778 ret = out->writecallback(out->context,
2779 (const char *)out->conv->content, out->conv->use);
2780 if (ret >= 0)
2781 xmlBufferShrink(out->conv, ret);
2782 } else if (out->writecallback != NULL) {
2783 ret = out->writecallback(out->context,
2784 (const char *)out->buffer->content, out->buffer->use);
2785 if (ret >= 0)
2786 xmlBufferShrink(out->buffer, ret);
2787 }
2788 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002789 xmlIOErr(XML_IO_FLUSH, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002790 return(ret);
2791 }
2792 out->written += ret;
2793
2794#ifdef DEBUG_INPUT
2795 xmlGenericError(xmlGenericErrorContext,
2796 "I/O: flushed %d chars\n", ret);
2797#endif
2798 return(ret);
2799}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002800#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002801
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002802/**
Owen Taylor3473f882001-02-23 17:55:21 +00002803 * xmlParserGetDirectory:
2804 * @filename: the path to a file
2805 *
2806 * lookup the directory for that file
2807 *
2808 * Returns a new allocated string containing the directory, or NULL.
2809 */
2810char *
2811xmlParserGetDirectory(const char *filename) {
2812 char *ret = NULL;
2813 char dir[1024];
2814 char *cur;
2815 char sep = '/';
2816
Igor Zlatkovic9181cc02002-09-29 17:51:06 +00002817#ifdef _WIN32_WCE /* easy way by now ... wince does not have dirs! */
2818 return NULL;
2819#endif
2820
Owen Taylor3473f882001-02-23 17:55:21 +00002821 if (xmlInputCallbackInitialized == 0)
2822 xmlRegisterDefaultInputCallbacks();
2823
2824 if (filename == NULL) return(NULL);
Daniel Veillard3c5ed912002-01-08 10:36:16 +00002825#if defined(WIN32) && !defined(__CYGWIN__)
Owen Taylor3473f882001-02-23 17:55:21 +00002826 sep = '\\';
2827#endif
2828
2829 strncpy(dir, filename, 1023);
2830 dir[1023] = 0;
2831 cur = &dir[strlen(dir)];
2832 while (cur > dir) {
2833 if (*cur == sep) break;
2834 cur --;
2835 }
2836 if (*cur == sep) {
2837 if (cur == dir) dir[1] = 0;
2838 else *cur = 0;
2839 ret = xmlMemStrdup(dir);
2840 } else {
2841 if (getcwd(dir, 1024) != NULL) {
2842 dir[1023] = 0;
2843 ret = xmlMemStrdup(dir);
2844 }
2845 }
2846 return(ret);
2847}
2848
2849/****************************************************************
2850 * *
2851 * External entities loading *
2852 * *
2853 ****************************************************************/
2854
Daniel Veillard561b7f82002-03-20 21:55:57 +00002855static int xmlSysIDExists(const char *URL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00002856#ifdef HAVE_STAT
2857 int ret;
2858 struct stat info;
2859 const char *path;
2860
2861 if (URL == NULL)
2862 return(0);
2863
Daniel Veillardf4862f02002-09-10 11:13:43 +00002864 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00002865#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00002866 path = &URL[17];
2867#else
Daniel Veillard6990bf32001-08-23 21:17:48 +00002868 path = &URL[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00002869#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002870 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00002871#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard6990bf32001-08-23 21:17:48 +00002872 path = &URL[8];
2873#else
2874 path = &URL[7];
2875#endif
2876 } else
2877 path = URL;
2878 ret = stat(path, &info);
Daniel Veillard561b7f82002-03-20 21:55:57 +00002879 if (ret == 0)
2880 return(1);
Daniel Veillard6990bf32001-08-23 21:17:48 +00002881#endif
Daniel Veillard561b7f82002-03-20 21:55:57 +00002882 return(0);
Daniel Veillard6990bf32001-08-23 21:17:48 +00002883}
Daniel Veillard6990bf32001-08-23 21:17:48 +00002884
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002885/**
Owen Taylor3473f882001-02-23 17:55:21 +00002886 * xmlDefaultExternalEntityLoader:
2887 * @URL: the URL for the entity to load
2888 * @ID: the System ID for the entity to load
2889 * @ctxt: the context in which the entity is called or NULL
2890 *
2891 * By default we don't load external entitites, yet.
2892 *
2893 * Returns a new allocated xmlParserInputPtr, or NULL.
2894 */
2895static
2896xmlParserInputPtr
2897xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
2898 xmlParserCtxtPtr ctxt) {
2899 xmlParserInputPtr ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002900 xmlChar *resource = NULL;
2901#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002902 xmlCatalogAllow pref;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002903#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002904
2905#ifdef DEBUG_EXTERNAL_ENTITIES
2906 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardf012a642001-07-23 19:10:52 +00002907 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00002908#endif
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002909#ifdef LIBXML_CATALOG_ENABLED
2910 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002911 * If the resource doesn't exists as a file,
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002912 * try to load it from the resource pointed in the catalogs
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002913 */
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002914 pref = xmlCatalogGetDefaults();
2915
Daniel Veillard561b7f82002-03-20 21:55:57 +00002916 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlSysIDExists(URL))) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002917 /*
2918 * Do a local lookup
2919 */
2920 if ((ctxt->catalogs != NULL) &&
2921 ((pref == XML_CATA_ALLOW_ALL) ||
2922 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2923 resource = xmlCatalogLocalResolve(ctxt->catalogs,
2924 (const xmlChar *)ID,
2925 (const xmlChar *)URL);
2926 }
2927 /*
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002928 * Try a global lookup
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002929 */
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002930 if ((resource == NULL) &&
2931 ((pref == XML_CATA_ALLOW_ALL) ||
2932 (pref == XML_CATA_ALLOW_GLOBAL))) {
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002933 resource = xmlCatalogResolve((const xmlChar *)ID,
2934 (const xmlChar *)URL);
2935 }
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002936 if ((resource == NULL) && (URL != NULL))
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00002937 resource = xmlStrdup((const xmlChar *) URL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002938
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002939 /*
2940 * TODO: do an URI lookup on the reference
2941 */
Daniel Veillard561b7f82002-03-20 21:55:57 +00002942 if ((resource != NULL) && (!xmlSysIDExists((const char *)resource))) {
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002943 xmlChar *tmp = NULL;
2944
2945 if ((ctxt->catalogs != NULL) &&
2946 ((pref == XML_CATA_ALLOW_ALL) ||
2947 (pref == XML_CATA_ALLOW_DOCUMENT))) {
2948 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
2949 }
2950 if ((tmp == NULL) &&
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00002951 ((pref == XML_CATA_ALLOW_ALL) ||
2952 (pref == XML_CATA_ALLOW_GLOBAL))) {
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002953 tmp = xmlCatalogResolveURI(resource);
2954 }
2955
2956 if (tmp != NULL) {
2957 xmlFree(resource);
2958 resource = tmp;
2959 }
2960 }
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00002961 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002962#endif
2963
2964 if (resource == NULL)
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002965 resource = (xmlChar *) URL;
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002966
2967 if (resource == NULL) {
Daniel Veillardc6613042002-03-02 09:34:02 +00002968 if (ID == NULL)
2969 ID = "NULL";
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002970 if ((ctxt->validate) && (ctxt->sax != NULL) &&
2971 (ctxt->sax->error != NULL))
William M. Brack4811ba32003-09-06 18:02:53 +00002972 ctxt->sax->error(ctxt->userData,
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002973 "failed to load external entity \"%s\"\n", ID);
2974 else if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
William M. Brack4811ba32003-09-06 18:02:53 +00002975 ctxt->sax->warning(ctxt->userData,
Owen Taylor3473f882001-02-23 17:55:21 +00002976 "failed to load external entity \"%s\"\n", ID);
2977 return(NULL);
2978 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002979 ret = xmlNewInputFromFile(ctxt, (const char *)resource);
Owen Taylor3473f882001-02-23 17:55:21 +00002980 if (ret == NULL) {
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002981 if ((ctxt->validate) && (ctxt->sax != NULL) &&
2982 (ctxt->sax->error != NULL))
William M. Brack4811ba32003-09-06 18:02:53 +00002983 ctxt->sax->error(ctxt->userData,
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002984 "failed to load external entity \"%s\"\n", resource);
Daniel Veillard34b1b3a2001-04-21 14:16:10 +00002985 else if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
William M. Brack4811ba32003-09-06 18:02:53 +00002986 ctxt->sax->warning(ctxt->userData,
Daniel Veillard7d6fd212001-05-10 15:34:11 +00002987 "failed to load external entity \"%s\"\n", resource);
Owen Taylor3473f882001-02-23 17:55:21 +00002988 }
Daniel Veillarddc2cee22001-08-22 16:30:37 +00002989 if ((resource != NULL) && (resource != (xmlChar *) URL))
Daniel Veillarde2940dd2001-08-22 00:06:49 +00002990 xmlFree(resource);
Owen Taylor3473f882001-02-23 17:55:21 +00002991 return(ret);
2992}
2993
2994static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
2995 xmlDefaultExternalEntityLoader;
2996
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002997/**
Owen Taylor3473f882001-02-23 17:55:21 +00002998 * xmlSetExternalEntityLoader:
2999 * @f: the new entity resolver function
3000 *
3001 * Changes the defaultexternal entity resolver function for the application
3002 */
3003void
3004xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
3005 xmlCurrentExternalEntityLoader = f;
3006}
3007
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003008/**
Owen Taylor3473f882001-02-23 17:55:21 +00003009 * xmlGetExternalEntityLoader:
3010 *
3011 * Get the default external entity resolver function for the application
3012 *
3013 * Returns the xmlExternalEntityLoader function pointer
3014 */
3015xmlExternalEntityLoader
3016xmlGetExternalEntityLoader(void) {
3017 return(xmlCurrentExternalEntityLoader);
3018}
3019
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003020/**
Owen Taylor3473f882001-02-23 17:55:21 +00003021 * xmlLoadExternalEntity:
3022 * @URL: the URL for the entity to load
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00003023 * @ID: the Public ID for the entity to load
Owen Taylor3473f882001-02-23 17:55:21 +00003024 * @ctxt: the context in which the entity is called or NULL
3025 *
3026 * Load an external entity, note that the use of this function for
3027 * unparsed entities may generate problems
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003028 * TODO: a more generic External entity API must be designed
Owen Taylor3473f882001-02-23 17:55:21 +00003029 *
3030 * Returns the xmlParserInputPtr or NULL
3031 */
3032xmlParserInputPtr
3033xmlLoadExternalEntity(const char *URL, const char *ID,
3034 xmlParserCtxtPtr ctxt) {
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00003035 if ((URL != NULL) && (xmlSysIDExists(URL) == 0)) {
3036 char *canonicFilename;
3037 xmlParserInputPtr ret;
3038
3039 canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL);
3040 if (canonicFilename == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003041 xmlIOErrMemory("building canonical path\n");
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00003042 return(NULL);
3043 }
3044
3045 ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt);
3046 xmlFree(canonicFilename);
3047 return(ret);
3048 }
Owen Taylor3473f882001-02-23 17:55:21 +00003049 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
3050}
3051
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003052/************************************************************************
3053 * *
3054 * Disabling Network access *
3055 * *
3056 ************************************************************************/
3057
3058#ifdef LIBXML_CATALOG_ENABLED
3059static int
3060xmlNoNetExists(const char *URL)
3061{
3062#ifdef HAVE_STAT
3063 int ret;
3064 struct stat info;
3065 const char *path;
3066
3067 if (URL == NULL)
3068 return (0);
3069
Daniel Veillardf4862f02002-09-10 11:13:43 +00003070 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003071#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00003072 path = &URL[17];
3073#else
3074 path = &URL[16];
3075#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003076 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003077#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003078 path = &URL[8];
3079#else
3080 path = &URL[7];
3081#endif
3082 } else
3083 path = URL;
3084 ret = stat(path, &info);
3085 if (ret == 0)
3086 return (1);
3087#endif
3088 return (0);
3089}
3090#endif
3091
3092/**
3093 * xmlNoNetExternalEntityLoader:
3094 * @URL: the URL for the entity to load
3095 * @ID: the System ID for the entity to load
3096 * @ctxt: the context in which the entity is called or NULL
3097 *
3098 * A specific entity loader disabling network accesses, though still
3099 * allowing local catalog accesses for resolution.
3100 *
3101 * Returns a new allocated xmlParserInputPtr, or NULL.
3102 */
3103xmlParserInputPtr
3104xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
3105 xmlParserCtxtPtr ctxt) {
3106 xmlParserInputPtr input = NULL;
3107 xmlChar *resource = NULL;
3108
3109#ifdef LIBXML_CATALOG_ENABLED
3110 xmlCatalogAllow pref;
3111
3112 /*
3113 * If the resource doesn't exists as a file,
3114 * try to load it from the resource pointed in the catalogs
3115 */
3116 pref = xmlCatalogGetDefaults();
3117
3118 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
3119 /*
3120 * Do a local lookup
3121 */
3122 if ((ctxt->catalogs != NULL) &&
3123 ((pref == XML_CATA_ALLOW_ALL) ||
3124 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3125 resource = xmlCatalogLocalResolve(ctxt->catalogs,
3126 (const xmlChar *)ID,
3127 (const xmlChar *)URL);
3128 }
3129 /*
3130 * Try a global lookup
3131 */
3132 if ((resource == NULL) &&
3133 ((pref == XML_CATA_ALLOW_ALL) ||
3134 (pref == XML_CATA_ALLOW_GLOBAL))) {
3135 resource = xmlCatalogResolve((const xmlChar *)ID,
3136 (const xmlChar *)URL);
3137 }
3138 if ((resource == NULL) && (URL != NULL))
3139 resource = xmlStrdup((const xmlChar *) URL);
3140
3141 /*
3142 * TODO: do an URI lookup on the reference
3143 */
3144 if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
3145 xmlChar *tmp = NULL;
3146
3147 if ((ctxt->catalogs != NULL) &&
3148 ((pref == XML_CATA_ALLOW_ALL) ||
3149 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3150 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
3151 }
3152 if ((tmp == NULL) &&
3153 ((pref == XML_CATA_ALLOW_ALL) ||
3154 (pref == XML_CATA_ALLOW_GLOBAL))) {
3155 tmp = xmlCatalogResolveURI(resource);
3156 }
3157
3158 if (tmp != NULL) {
3159 xmlFree(resource);
3160 resource = tmp;
3161 }
3162 }
3163 }
3164#endif
3165 if (resource == NULL)
3166 resource = (xmlChar *) URL;
3167
3168 if (resource != NULL) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003169 if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
3170 (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003171 xmlIOErr(XML_IO_NETWORK_ATTEMPT, (const char *) resource);
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003172 if (resource != (xmlChar *) URL)
3173 xmlFree(resource);
3174 return(NULL);
3175 }
3176 }
3177 input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
3178 if (resource != (xmlChar *) URL)
3179 xmlFree(resource);
3180 return(input);
3181}
3182