blob: ce0c2646934de06f3bb8c46960b9a57ef23d47a1 [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
2 * xmlIO.c : implementation of the I/O interfaces used by the parser
3 *
4 * See Copyright for the status of this software.
5 *
Daniel Veillard344cee72001-08-20 00:08:40 +00006 * daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +00007 *
8 * 14 Nov 2000 ht - for VMS, truncated name of long functions to under 32 char
9 */
10
Daniel Veillard34ce8be2002-03-18 19:37:11 +000011#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000012#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000013
Owen Taylor3473f882001-02-23 17:55:21 +000014#include <string.h>
Daniel Veillard92727042002-09-17 17:59:20 +000015#ifdef HAVE_ERRNO_H
Owen Taylor3473f882001-02-23 17:55:21 +000016#include <errno.h>
Daniel Veillard92727042002-09-17 17:59:20 +000017#endif
18
Owen Taylor3473f882001-02-23 17:55:21 +000019
20#ifdef HAVE_SYS_TYPES_H
21#include <sys/types.h>
22#endif
23#ifdef HAVE_SYS_STAT_H
24#include <sys/stat.h>
25#endif
26#ifdef HAVE_FCNTL_H
27#include <fcntl.h>
28#endif
29#ifdef HAVE_UNISTD_H
30#include <unistd.h>
31#endif
32#ifdef HAVE_STDLIB_H
33#include <stdlib.h>
34#endif
35#ifdef HAVE_ZLIB_H
36#include <zlib.h>
37#endif
38
39/* Figure a portable way to know if a file is a directory. */
40#ifndef HAVE_STAT
41# ifdef HAVE__STAT
Daniel Veillard50f34372001-08-03 12:06:36 +000042 /* MS C library seems to define stat and _stat. The definition
43 is identical. Still, mapping them to each other causes a warning. */
44# ifndef _MSC_VER
45# define stat(x,y) _stat(x,y)
46# endif
Owen Taylor3473f882001-02-23 17:55:21 +000047# define HAVE_STAT
48# endif
49#endif
50#ifdef HAVE_STAT
51# ifndef S_ISDIR
52# ifdef _S_ISDIR
53# define S_ISDIR(x) _S_ISDIR(x)
54# else
55# ifdef S_IFDIR
56# ifndef S_IFMT
57# ifdef _S_IFMT
58# define S_IFMT _S_IFMT
59# endif
60# endif
61# ifdef S_IFMT
62# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
63# endif
64# endif
65# endif
66# endif
67#endif
68
69#include <libxml/xmlmemory.h>
70#include <libxml/parser.h>
71#include <libxml/parserInternals.h>
72#include <libxml/xmlIO.h>
Daniel Veillard388236f2001-07-08 18:35:48 +000073#include <libxml/uri.h>
Owen Taylor3473f882001-02-23 17:55:21 +000074#include <libxml/nanohttp.h>
75#include <libxml/nanoftp.h>
76#include <libxml/xmlerror.h>
Daniel Veillard7d6fd212001-05-10 15:34:11 +000077#ifdef LIBXML_CATALOG_ENABLED
78#include <libxml/catalog.h>
79#endif
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000080#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000081
Daniel Veillardf012a642001-07-23 19:10:52 +000082/* #define VERBOSE_FAILURE */
Daniel Veillard1fd36d22001-07-04 22:54:28 +000083/* #define DEBUG_EXTERNAL_ENTITIES */
Owen Taylor3473f882001-02-23 17:55:21 +000084/* #define DEBUG_INPUT */
85
86#ifdef DEBUG_INPUT
87#define MINLEN 40
88#else
89#define MINLEN 4000
90#endif
91
92/*
93 * Input I/O callback sets
94 */
95typedef struct _xmlInputCallback {
96 xmlInputMatchCallback matchcallback;
97 xmlInputOpenCallback opencallback;
98 xmlInputReadCallback readcallback;
99 xmlInputCloseCallback closecallback;
100} xmlInputCallback;
101
102#define MAX_INPUT_CALLBACK 15
103
Daniel Veillard22090732001-07-16 00:06:07 +0000104static xmlInputCallback xmlInputCallbackTable[MAX_INPUT_CALLBACK];
105static int xmlInputCallbackNr = 0;
106static int xmlInputCallbackInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000107
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000108#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000109/*
110 * Output I/O callback sets
111 */
112typedef struct _xmlOutputCallback {
113 xmlOutputMatchCallback matchcallback;
114 xmlOutputOpenCallback opencallback;
115 xmlOutputWriteCallback writecallback;
116 xmlOutputCloseCallback closecallback;
117} xmlOutputCallback;
118
119#define MAX_OUTPUT_CALLBACK 15
120
Daniel Veillard22090732001-07-16 00:06:07 +0000121static xmlOutputCallback xmlOutputCallbackTable[MAX_OUTPUT_CALLBACK];
122static int xmlOutputCallbackNr = 0;
123static int xmlOutputCallbackInitialized = 0;
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000124#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000125
Daniel Veillard05d987b2003-10-08 11:54:57 +0000126/************************************************************************
127 * *
128 * Tree memory error handler *
129 * *
130 ************************************************************************/
Daniel Veillardf4862f02002-09-10 11:13:43 +0000131
Daniel Veillard05d987b2003-10-08 11:54:57 +0000132static const char *IOerr[] = {
Daniel Veillarda8856222003-10-08 19:26:03 +0000133 "Unknown IO error", /* UNKNOWN */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000134 "Permission denied", /* EACCES */
135 "Resource temporarily unavailable",/* EAGAIN */
136 "Bad file descriptor", /* EBADF */
137 "Bad message", /* EBADMSG */
138 "Resource busy", /* EBUSY */
139 "Operation canceled", /* ECANCELED */
140 "No child processes", /* ECHILD */
141 "Resource deadlock avoided",/* EDEADLK */
142 "Domain error", /* EDOM */
143 "File exists", /* EEXIST */
144 "Bad address", /* EFAULT */
145 "File too large", /* EFBIG */
146 "Operation in progress", /* EINPROGRESS */
147 "Interrupted function call",/* EINTR */
148 "Invalid argument", /* EINVAL */
149 "Input/output error", /* EIO */
150 "Is a directory", /* EISDIR */
151 "Too many open files", /* EMFILE */
152 "Too many links", /* EMLINK */
153 "Inappropriate message buffer length",/* EMSGSIZE */
154 "Filename too long", /* ENAMETOOLONG */
155 "Too many open files in system",/* ENFILE */
156 "No such device", /* ENODEV */
157 "No such file or directory",/* ENOENT */
158 "Exec format error", /* ENOEXEC */
159 "No locks available", /* ENOLCK */
160 "Not enough space", /* ENOMEM */
161 "No space left on device", /* ENOSPC */
162 "Function not implemented", /* ENOSYS */
163 "Not a directory", /* ENOTDIR */
164 "Directory not empty", /* ENOTEMPTY */
165 "Not supported", /* ENOTSUP */
166 "Inappropriate I/O control operation",/* ENOTTY */
167 "No such device or address",/* ENXIO */
168 "Operation not permitted", /* EPERM */
169 "Broken pipe", /* EPIPE */
170 "Result too large", /* ERANGE */
171 "Read-only file system", /* EROFS */
172 "Invalid seek", /* ESPIPE */
173 "No such process", /* ESRCH */
174 "Operation timed out", /* ETIMEDOUT */
175 "Improper link", /* EXDEV */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000176 "Attempt to load network entity %s", /* XML_IO_NETWORK_ATTEMPT */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000177 "encoder error", /* XML_IO_ENCODER */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000178 "flush error",
179 "write error",
180 "no input",
181 "buffer full",
182 "loading error",
183 "not a socket", /* ENOTSOCK */
184 "already connected", /* EISCONN */
185 "connection refuxed", /* ECONNREFUSED */
186 "unreachable network", /* ENETUNREACH */
187 "adddress in use", /* EADDRINUSE */
188 "already in use", /* EALREADY */
189 "unknown address familly", /* EAFNOSUPPORT */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000190};
191
192/**
193 * xmlIOErrMemory:
194 * @extra: extra informations
195 *
196 * Handle an out of memory condition
197 */
198static void
199xmlIOErrMemory(const char *extra)
200{
201 __xmlSimpleError(XML_FROM_IO, XML_ERR_NO_MEMORY, NULL, NULL, extra);
202}
203
204/**
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000205 * __xmlIOErr:
Daniel Veillard05d987b2003-10-08 11:54:57 +0000206 * @code: the error number
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000207 * @
Daniel Veillard05d987b2003-10-08 11:54:57 +0000208 * @extra: extra informations
209 *
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000210 * Handle an I/O error
Daniel Veillard05d987b2003-10-08 11:54:57 +0000211 */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000212void
213__xmlIOErr(int domain, int code, const char *extra)
Daniel Veillard05d987b2003-10-08 11:54:57 +0000214{
215 unsigned int idx;
216
217 if (code == 0) {
218#ifdef HAVE_ERRNO_H
219 if (errno == 0) code = 0;
220#ifdef EACCES
221 else if (errno == EACCES) code = XML_IO_EACCES;
222#endif
223#ifdef EAGAIN
224 else if (errno == EAGAIN) code = XML_IO_EAGAIN;
225#endif
226#ifdef EBADF
227 else if (errno == EBADF) code = XML_IO_EBADF;
228#endif
229#ifdef EBADMSG
230 else if (errno == EBADMSG) code = XML_IO_EBADMSG;
231#endif
232#ifdef EBUSY
233 else if (errno == EBUSY) code = XML_IO_EBUSY;
234#endif
235#ifdef ECANCELED
236 else if (errno == ECANCELED) code = XML_IO_ECANCELED;
237#endif
238#ifdef ECHILD
239 else if (errno == ECHILD) code = XML_IO_ECHILD;
240#endif
241#ifdef EDEADLK
242 else if (errno == EDEADLK) code = XML_IO_EDEADLK;
243#endif
244#ifdef EDOM
245 else if (errno == EDOM) code = XML_IO_EDOM;
246#endif
247#ifdef EEXIST
248 else if (errno == EEXIST) code = XML_IO_EEXIST;
249#endif
250#ifdef EFAULT
251 else if (errno == EFAULT) code = XML_IO_EFAULT;
252#endif
253#ifdef EFBIG
254 else if (errno == EFBIG) code = XML_IO_EFBIG;
255#endif
256#ifdef EINPROGRESS
257 else if (errno == EINPROGRESS) code = XML_IO_EINPROGRESS;
258#endif
259#ifdef EINTR
260 else if (errno == EINTR) code = XML_IO_EINTR;
261#endif
262#ifdef EINVAL
263 else if (errno == EINVAL) code = XML_IO_EINVAL;
264#endif
265#ifdef EIO
266 else if (errno == EIO) code = XML_IO_EIO;
267#endif
268#ifdef EISDIR
269 else if (errno == EISDIR) code = XML_IO_EISDIR;
270#endif
271#ifdef EMFILE
272 else if (errno == EMFILE) code = XML_IO_EMFILE;
273#endif
274#ifdef EMLINK
275 else if (errno == EMLINK) code = XML_IO_EMLINK;
276#endif
277#ifdef EMSGSIZE
278 else if (errno == EMSGSIZE) code = XML_IO_EMSGSIZE;
279#endif
280#ifdef ENAMETOOLONG
281 else if (errno == ENAMETOOLONG) code = XML_IO_ENAMETOOLONG;
282#endif
283#ifdef ENFILE
284 else if (errno == ENFILE) code = XML_IO_ENFILE;
285#endif
286#ifdef ENODEV
287 else if (errno == ENODEV) code = XML_IO_ENODEV;
288#endif
289#ifdef ENOENT
290 else if (errno == ENOENT) code = XML_IO_ENOENT;
291#endif
292#ifdef ENOEXEC
293 else if (errno == ENOEXEC) code = XML_IO_ENOEXEC;
294#endif
295#ifdef ENOLCK
296 else if (errno == ENOLCK) code = XML_IO_ENOLCK;
297#endif
298#ifdef ENOMEM
299 else if (errno == ENOMEM) code = XML_IO_ENOMEM;
300#endif
301#ifdef ENOSPC
302 else if (errno == ENOSPC) code = XML_IO_ENOSPC;
303#endif
304#ifdef ENOSYS
305 else if (errno == ENOSYS) code = XML_IO_ENOSYS;
306#endif
307#ifdef ENOTDIR
308 else if (errno == ENOTDIR) code = XML_IO_ENOTDIR;
309#endif
310#ifdef ENOTEMPTY
311 else if (errno == ENOTEMPTY) code = XML_IO_ENOTEMPTY;
312#endif
313#ifdef ENOTSUP
314 else if (errno == ENOTSUP) code = XML_IO_ENOTSUP;
315#endif
316#ifdef ENOTTY
317 else if (errno == ENOTTY) code = XML_IO_ENOTTY;
318#endif
319#ifdef ENXIO
320 else if (errno == ENXIO) code = XML_IO_ENXIO;
321#endif
322#ifdef EPERM
323 else if (errno == EPERM) code = XML_IO_EPERM;
324#endif
325#ifdef EPIPE
326 else if (errno == EPIPE) code = XML_IO_EPIPE;
327#endif
328#ifdef ERANGE
329 else if (errno == ERANGE) code = XML_IO_ERANGE;
330#endif
331#ifdef EROFS
332 else if (errno == EROFS) code = XML_IO_EROFS;
333#endif
334#ifdef ESPIPE
335 else if (errno == ESPIPE) code = XML_IO_ESPIPE;
336#endif
337#ifdef ESRCH
338 else if (errno == ESRCH) code = XML_IO_ESRCH;
339#endif
340#ifdef ETIMEDOUT
341 else if (errno == ETIMEDOUT) code = XML_IO_ETIMEDOUT;
342#endif
343#ifdef EXDEV
344 else if (errno == EXDEV) code = XML_IO_EXDEV;
345#endif
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000346#ifdef ENOTSOCK
347 else if (errno == ENOTSOCK) code = XML_IO_ENOTSOCK;
348#endif
349#ifdef EISCONN
350 else if (errno == EISCONN) code = XML_IO_EISCONN;
351#endif
352#ifdef ECONNREFUSED
353 else if (errno == ECONNREFUSED) code = XML_IO_ECONNREFUSED;
354#endif
355#ifdef ETIMEDOUT
356 else if (errno == ETIMEDOUT) code = XML_IO_ETIMEDOUT;
357#endif
358#ifdef ENETUNREACH
359 else if (errno == ENETUNREACH) code = XML_IO_ENETUNREACH;
360#endif
361#ifdef EADDRINUSE
362 else if (errno == EADDRINUSE) code = XML_IO_EADDRINUSE;
363#endif
364#ifdef EINPROGRESS
365 else if (errno == EINPROGRESS) code = XML_IO_EINPROGRESS;
366#endif
367#ifdef EALREADY
368 else if (errno == EALREADY) code = XML_IO_EALREADY;
369#endif
370#ifdef EAFNOSUPPORT
371 else if (errno == EAFNOSUPPORT) code = XML_IO_EAFNOSUPPORT;
372#endif
Daniel Veillard05d987b2003-10-08 11:54:57 +0000373 else code = XML_IO_UNKNOWN;
374#endif /* HAVE_ERRNO_H */
375 }
376 idx = 0;
377 if (code >= XML_IO_UNKNOWN) idx = code - XML_IO_UNKNOWN;
378 if (idx >= (sizeof(IOerr) / sizeof(IOerr[0]))) idx = 0;
379
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000380 __xmlSimpleError(domain, code, NULL, IOerr[idx], extra);
381}
382
383/**
384 * xmlIOErr:
385 * @code: the error number
386 * @extra: extra informations
387 *
388 * Handle an I/O error
389 */
390static void
391xmlIOErr(int code, const char *extra)
392{
393 __xmlIOErr(XML_FROM_IO, code, extra);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000394}
395
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000396/**
397 * xmlLoaderErr:
398 * @ctxt: the parser context
399 * @extra: extra informations
400 *
401 * Handle a resource access error
402 */
403static void
404xmlLoaderErr(xmlParserCtxtPtr ctxt, const char *msg, const char *filename)
405{
Daniel Veillard659e71e2003-10-10 14:10:40 +0000406 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000407 xmlGenericErrorFunc channel = NULL;
408 void *data = NULL;
409 xmlErrorLevel level = XML_ERR_ERROR;
410
411 if ((ctxt != NULL) && (ctxt->sax != NULL)) {
412 if (ctxt->validate) {
413 channel = ctxt->sax->error;
414 level = XML_ERR_ERROR;
415 } else {
416 channel = ctxt->sax->warning;
417 level = XML_ERR_WARNING;
418 }
Daniel Veillard659e71e2003-10-10 14:10:40 +0000419 schannel = ctxt->sax->serror;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000420 data = ctxt->userData;
421 }
Daniel Veillard659e71e2003-10-10 14:10:40 +0000422 __xmlRaiseError(schannel, channel, data, ctxt, NULL, XML_FROM_IO,
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000423 XML_IO_LOAD_ERROR, level, NULL, 0,
424 filename, NULL, NULL, 0, 0,
425 msg, filename);
426
427}
428
Daniel Veillard05d987b2003-10-08 11:54:57 +0000429/************************************************************************
430 * *
431 * Tree memory error handler *
432 * *
433 ************************************************************************/
Daniel Veillardf4862f02002-09-10 11:13:43 +0000434/**
Daniel Veillard01c13b52002-12-10 15:19:08 +0000435 * xmlNormalizeWindowsPath:
Daniel Veillard33300b42003-04-17 09:09:19 +0000436 * @path: the input file path
Daniel Veillardf4862f02002-09-10 11:13:43 +0000437 *
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +0000438 * This function is obsolete. Please see xmlURIFromPath in uri.c for
439 * a better solution.
Daniel Veillard33300b42003-04-17 09:09:19 +0000440 *
441 * Returns a canonicalized version of the path
Daniel Veillardf4862f02002-09-10 11:13:43 +0000442 */
443xmlChar *
444xmlNormalizeWindowsPath(const xmlChar *path)
445{
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +0000446 return xmlCanonicPath(path);
Daniel Veillardf4862f02002-09-10 11:13:43 +0000447}
448
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000449/**
450 * xmlCleanupInputCallbacks:
451 *
452 * clears the entire input callback table. this includes the
453 * compiled-in I/O.
454 */
455void
456xmlCleanupInputCallbacks(void)
457{
458 int i;
459
460 if (!xmlInputCallbackInitialized)
461 return;
462
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000463 for (i = xmlInputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000464 xmlInputCallbackTable[i].matchcallback = NULL;
465 xmlInputCallbackTable[i].opencallback = NULL;
466 xmlInputCallbackTable[i].readcallback = NULL;
467 xmlInputCallbackTable[i].closecallback = NULL;
468 }
469
470 xmlInputCallbackNr = 0;
Aleksey Sanin9c45ba82002-06-06 21:46:13 +0000471 xmlInputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000472}
473
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000474#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000475/**
476 * xmlCleanupOutputCallbacks:
477 *
478 * clears the entire output callback table. this includes the
479 * compiled-in I/O callbacks.
480 */
481void
482xmlCleanupOutputCallbacks(void)
483{
484 int i;
485
486 if (!xmlOutputCallbackInitialized)
487 return;
488
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000489 for (i = xmlOutputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000490 xmlOutputCallbackTable[i].matchcallback = NULL;
491 xmlOutputCallbackTable[i].opencallback = NULL;
492 xmlOutputCallbackTable[i].writecallback = NULL;
493 xmlOutputCallbackTable[i].closecallback = NULL;
494 }
495
496 xmlOutputCallbackNr = 0;
Aleksey Sanin9c45ba82002-06-06 21:46:13 +0000497 xmlOutputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000498}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000499#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000500
Owen Taylor3473f882001-02-23 17:55:21 +0000501/************************************************************************
502 * *
503 * Standard I/O for file accesses *
504 * *
505 ************************************************************************/
506
507/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000508 * xmlCheckFilename:
Owen Taylor3473f882001-02-23 17:55:21 +0000509 * @path: the path to check
510 *
511 * function checks to see if @path is a valid source
512 * (file, socket...) for XML.
513 *
514 * if stat is not available on the target machine,
515 * returns 1. if stat fails, returns 0 (if calling
516 * stat on the filename fails, it can't be right).
517 * if stat succeeds and the file is a directory,
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000518 * returns 2. otherwise returns 1.
Owen Taylor3473f882001-02-23 17:55:21 +0000519 */
520
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000521int
Owen Taylor3473f882001-02-23 17:55:21 +0000522xmlCheckFilename (const char *path)
523{
524#ifdef HAVE_STAT
Owen Taylor3473f882001-02-23 17:55:21 +0000525 struct stat stat_buffer;
526
527 if (stat(path, &stat_buffer) == -1)
528 return 0;
529
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000530#ifdef S_ISDIR
Owen Taylor3473f882001-02-23 17:55:21 +0000531 if (S_ISDIR(stat_buffer.st_mode)) {
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000532 return 2;
Owen Taylor3473f882001-02-23 17:55:21 +0000533 }
Owen Taylor3473f882001-02-23 17:55:21 +0000534#endif
535#endif
536 return 1;
537}
538
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000539static int
Owen Taylor3473f882001-02-23 17:55:21 +0000540xmlNop(void) {
541 return(0);
542}
543
544/**
Owen Taylor3473f882001-02-23 17:55:21 +0000545 * xmlFdRead:
546 * @context: the I/O context
547 * @buffer: where to drop data
548 * @len: number of bytes to read
549 *
550 * Read @len bytes to @buffer from the I/O channel.
551 *
552 * Returns the number of bytes written
553 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000554static int
Owen Taylor3473f882001-02-23 17:55:21 +0000555xmlFdRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000556 int ret;
557
558 ret = read((int) (long) context, &buffer[0], len);
559 if (ret < 0) xmlIOErr(0, "read()");
560 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000561}
562
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000563#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000564/**
565 * xmlFdWrite:
566 * @context: the I/O context
567 * @buffer: where to get data
568 * @len: number of bytes to write
569 *
570 * Write @len bytes from @buffer to the I/O channel.
571 *
572 * Returns the number of bytes written
573 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000574static int
Owen Taylor3473f882001-02-23 17:55:21 +0000575xmlFdWrite (void * context, const char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000576 int ret;
577
578 ret = write((int) (long) context, &buffer[0], len);
579 if (ret < 0) xmlIOErr(0, "write()");
580 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000581}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000582#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000583
584/**
585 * xmlFdClose:
586 * @context: the I/O context
587 *
588 * Close an I/O channel
Daniel Veillardf012a642001-07-23 19:10:52 +0000589 *
590 * Returns 0 in case of success and error code otherwise
Owen Taylor3473f882001-02-23 17:55:21 +0000591 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000592static int
Owen Taylor3473f882001-02-23 17:55:21 +0000593xmlFdClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000594 int ret;
595 ret = close((int) (long) context);
596 if (ret < 0) xmlIOErr(0, "close()");
597 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000598}
599
600/**
601 * xmlFileMatch:
602 * @filename: the URI for matching
603 *
604 * input from FILE *
605 *
606 * Returns 1 if matches, 0 otherwise
607 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000608int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000609xmlFileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000610 return(1);
611}
612
613/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000614 * xmlFileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +0000615 * @filename: the URI for matching
616 *
617 * input from FILE *, supports compressed input
618 * if @filename is " " then the standard input is used
619 *
620 * Returns an I/O context or NULL in case of error
621 */
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000622static void *
623xmlFileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +0000624 const char *path = NULL;
625 FILE *fd;
626
627 if (!strcmp(filename, "-")) {
628 fd = stdin;
629 return((void *) fd);
630 }
631
Daniel Veillardf4862f02002-09-10 11:13:43 +0000632 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000633#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000634 path = &filename[17];
635#else
Owen Taylor3473f882001-02-23 17:55:21 +0000636 path = &filename[16];
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000637#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000638 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000639#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000640 path = &filename[8];
641#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000642 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000643#endif
644 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000645 path = filename;
646
647 if (path == NULL)
648 return(NULL);
649 if (!xmlCheckFilename(path))
650 return(NULL);
651
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000652#if defined(WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
Owen Taylor3473f882001-02-23 17:55:21 +0000653 fd = fopen(path, "rb");
654#else
655 fd = fopen(path, "r");
656#endif /* WIN32 */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000657 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +0000658 return((void *) fd);
659}
660
661/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000662 * xmlFileOpen:
663 * @filename: the URI for matching
664 *
665 * Wrapper around xmlFileOpen_real that try it with an unescaped
666 * version of @filename, if this fails fallback to @filename
Daniel Veillard71531f32003-02-05 13:19:53 +0000667 *
668 * Returns a handler or NULL in case or failure
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000669 */
670void *
671xmlFileOpen (const char *filename) {
672 char *unescaped;
673 void *retval;
674 unescaped = xmlURIUnescapeString(filename, 0, NULL);
675 if (unescaped != NULL) {
676 retval = xmlFileOpen_real(unescaped);
677 } else {
678 retval = xmlFileOpen_real(filename);
679 }
680 xmlFree(unescaped);
681 return retval;
682}
683
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000684#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000685/**
Owen Taylor3473f882001-02-23 17:55:21 +0000686 * xmlFileOpenW:
687 * @filename: the URI for matching
688 *
689 * output to from FILE *,
690 * if @filename is "-" then the standard output is used
691 *
692 * Returns an I/O context or NULL in case of error
693 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000694static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000695xmlFileOpenW (const char *filename) {
696 const char *path = NULL;
697 FILE *fd;
698
699 if (!strcmp(filename, "-")) {
700 fd = stdout;
701 return((void *) fd);
702 }
703
Daniel Veillardf4862f02002-09-10 11:13:43 +0000704 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000705#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000706 path = &filename[17];
707#else
Owen Taylor3473f882001-02-23 17:55:21 +0000708 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000709#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000710 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000711#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000712 path = &filename[8];
713#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000714 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000715#endif
716 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000717 path = filename;
718
719 if (path == NULL)
720 return(NULL);
721
Daniel Veillardcbbd78d2003-07-20 15:21:30 +0000722 fd = fopen(path, "wb");
Daniel Veillard05d987b2003-10-08 11:54:57 +0000723 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +0000724 return((void *) fd);
725}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000726#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000727
728/**
729 * xmlFileRead:
730 * @context: the I/O context
731 * @buffer: where to drop data
732 * @len: number of bytes to write
733 *
734 * Read @len bytes to @buffer from the I/O channel.
735 *
736 * Returns the number of bytes written
737 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000738int
Owen Taylor3473f882001-02-23 17:55:21 +0000739xmlFileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000740 int ret;
741 ret = fread(&buffer[0], 1, len, (FILE *) context);
742 if (ret < 0) xmlIOErr(0, "fread()");
743 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000744}
745
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000746#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000747/**
748 * xmlFileWrite:
749 * @context: the I/O context
750 * @buffer: where to drop data
751 * @len: number of bytes to write
752 *
753 * Write @len bytes from @buffer to the I/O channel.
754 *
755 * Returns the number of bytes written
756 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000757static int
Owen Taylor3473f882001-02-23 17:55:21 +0000758xmlFileWrite (void * context, const char * buffer, int len) {
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000759 int items;
760
761 items = fwrite(&buffer[0], len, 1, (FILE *) context);
Daniel Veillard97bf4d02003-10-08 18:58:28 +0000762 if ((items == 0) && (ferror((FILE *) context))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000763 xmlIOErr(0, "fwrite()");
Daniel Veillard97bf4d02003-10-08 18:58:28 +0000764 return(-1);
765 }
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000766 return(items * len);
Owen Taylor3473f882001-02-23 17:55:21 +0000767}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000768#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000769
770/**
771 * xmlFileClose:
772 * @context: the I/O context
773 *
774 * Close an I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000775 *
776 * Returns 0 or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +0000777 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000778int
Owen Taylor3473f882001-02-23 17:55:21 +0000779xmlFileClose (void * context) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000780 FILE *fil;
Daniel Veillard05d987b2003-10-08 11:54:57 +0000781 int ret;
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000782
783 fil = (FILE *) context;
784 if (fil == stdin)
785 return(0);
786 if (fil == stdout)
787 return(0);
Daniel Veillardcd337f02001-11-22 18:20:37 +0000788 if (fil == stderr)
789 return(0);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000790 ret = ( fclose((FILE *) context) == EOF ) ? -1 : 0;
791 if (ret < 0)
792 xmlIOErr(0, "fclose()");
793 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000794}
795
796/**
797 * xmlFileFlush:
798 * @context: the I/O context
799 *
800 * Flush an I/O channel
801 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000802static int
Owen Taylor3473f882001-02-23 17:55:21 +0000803xmlFileFlush (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000804 int ret;
805 ret = ( fflush((FILE *) context) == EOF ) ? -1 : 0;
806 if (ret < 0)
807 xmlIOErr(0, "fflush()");
808 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000809}
810
811#ifdef HAVE_ZLIB_H
812/************************************************************************
813 * *
814 * I/O for compressed file accesses *
815 * *
816 ************************************************************************/
817/**
818 * xmlGzfileMatch:
819 * @filename: the URI for matching
820 *
821 * input from compressed file test
822 *
823 * Returns 1 if matches, 0 otherwise
824 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000825static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000826xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000827 return(1);
828}
829
830/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000831 * xmlGzfileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +0000832 * @filename: the URI for matching
833 *
834 * input from compressed file open
835 * if @filename is " " then the standard input is used
836 *
837 * Returns an I/O context or NULL in case of error
838 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000839static void *
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000840xmlGzfileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +0000841 const char *path = NULL;
842 gzFile fd;
843
844 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000845 fd = gzdopen(dup(0), "rb");
Owen Taylor3473f882001-02-23 17:55:21 +0000846 return((void *) fd);
847 }
848
Daniel Veillardf4862f02002-09-10 11:13:43 +0000849 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000850#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000851 path = &filename[17];
852#else
Owen Taylor3473f882001-02-23 17:55:21 +0000853 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000854#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000855 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000856#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000857 path = &filename[8];
858#else
Owen Taylor3473f882001-02-23 17:55:21 +0000859 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000860#endif
861 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000862 path = filename;
863
864 if (path == NULL)
865 return(NULL);
866 if (!xmlCheckFilename(path))
867 return(NULL);
868
869 fd = gzopen(path, "rb");
870 return((void *) fd);
871}
872
873/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000874 * xmlGzfileOpen:
875 * @filename: the URI for matching
876 *
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +0000877 * Wrapper around xmlGzfileOpen if the open fais, it will
878 * try to unescape @filename
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000879 */
880static void *
881xmlGzfileOpen (const char *filename) {
882 char *unescaped;
883 void *retval;
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +0000884
885 retval = xmlGzfileOpen_real(filename);
886 if (retval == NULL) {
887 unescaped = xmlURIUnescapeString(filename, 0, NULL);
888 if (unescaped != NULL) {
889 retval = xmlGzfileOpen_real(unescaped);
890 }
891 xmlFree(unescaped);
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000892 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000893 return retval;
894}
895
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000896#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000897/**
Owen Taylor3473f882001-02-23 17:55:21 +0000898 * xmlGzfileOpenW:
899 * @filename: the URI for matching
900 * @compression: the compression factor (0 - 9 included)
901 *
902 * input from compressed file open
903 * if @filename is " " then the standard input is used
904 *
905 * Returns an I/O context or NULL in case of error
906 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000907static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000908xmlGzfileOpenW (const char *filename, int compression) {
909 const char *path = NULL;
910 char mode[15];
911 gzFile fd;
912
Aleksey Sanin49cc9752002-06-14 17:07:10 +0000913 snprintf(mode, sizeof(mode), "wb%d", compression);
Owen Taylor3473f882001-02-23 17:55:21 +0000914 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000915 fd = gzdopen(dup(1), mode);
Owen Taylor3473f882001-02-23 17:55:21 +0000916 return((void *) fd);
917 }
918
Daniel Veillardf4862f02002-09-10 11:13:43 +0000919 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000920#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000921 path = &filename[17];
922#else
Owen Taylor3473f882001-02-23 17:55:21 +0000923 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000924#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000925 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000926#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000927 path = &filename[8];
928#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000929 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000930#endif
931 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000932 path = filename;
933
934 if (path == NULL)
935 return(NULL);
936
937 fd = gzopen(path, mode);
938 return((void *) fd);
939}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000940#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000941
942/**
943 * xmlGzfileRead:
944 * @context: the I/O context
945 * @buffer: where to drop data
946 * @len: number of bytes to write
947 *
948 * Read @len bytes to @buffer from the compressed I/O channel.
949 *
950 * Returns the number of bytes written
951 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000952static int
Owen Taylor3473f882001-02-23 17:55:21 +0000953xmlGzfileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000954 int ret;
955
956 ret = gzread((gzFile) context, &buffer[0], len);
957 if (ret < 0) xmlIOErr(0, "gzread()");
958 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000959}
960
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000961#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000962/**
963 * xmlGzfileWrite:
964 * @context: the I/O context
965 * @buffer: where to drop data
966 * @len: number of bytes to write
967 *
968 * Write @len bytes from @buffer to the compressed I/O channel.
969 *
970 * Returns the number of bytes written
971 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000972static int
Owen Taylor3473f882001-02-23 17:55:21 +0000973xmlGzfileWrite (void * context, const char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000974 int ret;
975
976 ret = gzwrite((gzFile) context, (char *) &buffer[0], len);
977 if (ret < 0) xmlIOErr(0, "gzwrite()");
978 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000979}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000980#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000981
982/**
983 * xmlGzfileClose:
984 * @context: the I/O context
985 *
986 * Close a compressed I/O channel
987 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000988static int
Owen Taylor3473f882001-02-23 17:55:21 +0000989xmlGzfileClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000990 int ret;
991
992 ret = (gzclose((gzFile) context) == Z_OK ) ? 0 : -1;
993 if (ret < 0) xmlIOErr(0, "gzclose()");
994 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000995}
996#endif /* HAVE_ZLIB_H */
997
998#ifdef LIBXML_HTTP_ENABLED
999/************************************************************************
1000 * *
1001 * I/O for HTTP file accesses *
1002 * *
1003 ************************************************************************/
Daniel Veillardf012a642001-07-23 19:10:52 +00001004
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001005#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001006typedef struct xmlIOHTTPWriteCtxt_
1007{
1008 int compression;
1009
1010 char * uri;
1011
1012 void * doc_buff;
1013
1014} xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr;
1015
1016#ifdef HAVE_ZLIB_H
1017
1018#define DFLT_WBITS ( -15 )
1019#define DFLT_MEM_LVL ( 8 )
1020#define GZ_MAGIC1 ( 0x1f )
1021#define GZ_MAGIC2 ( 0x8b )
1022#define LXML_ZLIB_OS_CODE ( 0x03 )
1023#define INIT_HTTP_BUFF_SIZE ( 32768 )
1024#define DFLT_ZLIB_RATIO ( 5 )
1025
1026/*
1027** Data structure and functions to work with sending compressed data
1028** via HTTP.
1029*/
1030
1031typedef struct xmlZMemBuff_
1032{
1033 unsigned long size;
1034 unsigned long crc;
1035
1036 unsigned char * zbuff;
1037 z_stream zctrl;
1038
1039} xmlZMemBuff, *xmlZMemBuffPtr;
1040
1041/**
1042 * append_reverse_ulong
1043 * @buff: Compressed memory buffer
1044 * @data: Unsigned long to append
1045 *
1046 * Append a unsigned long in reverse byte order to the end of the
1047 * memory buffer.
1048 */
1049static void
1050append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) {
1051
1052 int idx;
1053
1054 if ( buff == NULL )
1055 return;
1056
1057 /*
1058 ** This is plagiarized from putLong in gzio.c (zlib source) where
1059 ** the number "4" is hardcoded. If zlib is ever patched to
1060 ** support 64 bit file sizes, this code would need to be patched
1061 ** as well.
1062 */
1063
1064 for ( idx = 0; idx < 4; idx++ ) {
1065 *buff->zctrl.next_out = ( data & 0xff );
1066 data >>= 8;
1067 buff->zctrl.next_out++;
1068 }
1069
1070 return;
1071}
1072
1073/**
1074 *
1075 * xmlFreeZMemBuff
1076 * @buff: The memory buffer context to clear
1077 *
1078 * Release all the resources associated with the compressed memory buffer.
1079 */
1080static void
1081xmlFreeZMemBuff( xmlZMemBuffPtr buff ) {
William M. Brack78637da2003-07-31 14:47:38 +00001082
1083#ifdef DEBUG_HTTP
Daniel Veillardf012a642001-07-23 19:10:52 +00001084 int z_err;
William M. Brack78637da2003-07-31 14:47:38 +00001085#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001086
1087 if ( buff == NULL )
1088 return;
1089
1090 xmlFree( buff->zbuff );
Daniel Veillardf012a642001-07-23 19:10:52 +00001091#ifdef DEBUG_HTTP
William M. Brack78637da2003-07-31 14:47:38 +00001092 z_err = deflateEnd( &buff->zctrl );
Daniel Veillardf012a642001-07-23 19:10:52 +00001093 if ( z_err != Z_OK )
1094 xmlGenericError( xmlGenericErrorContext,
1095 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
1096 z_err );
William M. Brack78637da2003-07-31 14:47:38 +00001097#else
1098 deflateEnd( &buff->zctrl );
William M. Brack779af002003-08-01 15:55:39 +00001099#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001100
1101 xmlFree( buff );
1102 return;
1103}
1104
1105/**
1106 * xmlCreateZMemBuff
1107 *@compression: Compression value to use
1108 *
1109 * Create a memory buffer to hold the compressed XML document. The
1110 * compressed document in memory will end up being identical to what
1111 * would be created if gzopen/gzwrite/gzclose were being used to
1112 * write the document to disk. The code for the header/trailer data to
1113 * the compression is plagiarized from the zlib source files.
1114 */
1115static void *
1116xmlCreateZMemBuff( int compression ) {
1117
1118 int z_err;
1119 int hdr_lgth;
1120 xmlZMemBuffPtr buff = NULL;
1121
1122 if ( ( compression < 1 ) || ( compression > 9 ) )
1123 return ( NULL );
1124
1125 /* Create the control and data areas */
1126
1127 buff = xmlMalloc( sizeof( xmlZMemBuff ) );
1128 if ( buff == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001129 xmlIOErrMemory("creating buffer context");
Daniel Veillardf012a642001-07-23 19:10:52 +00001130 return ( NULL );
1131 }
1132
1133 (void)memset( buff, 0, sizeof( xmlZMemBuff ) );
1134 buff->size = INIT_HTTP_BUFF_SIZE;
1135 buff->zbuff = xmlMalloc( buff->size );
1136 if ( buff->zbuff == NULL ) {
1137 xmlFreeZMemBuff( buff );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001138 xmlIOErrMemory("creating buffer");
Daniel Veillardf012a642001-07-23 19:10:52 +00001139 return ( NULL );
1140 }
1141
1142 z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
1143 DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
1144 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001145 xmlChar msg[500];
Daniel Veillardf012a642001-07-23 19:10:52 +00001146 xmlFreeZMemBuff( buff );
1147 buff = NULL;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001148 xmlStrPrintf(msg, 500,
1149 (const xmlChar *) "xmlCreateZMemBuff: %s %d\n",
1150 "Error initializing compression context. ZLIB error:",
1151 z_err );
1152 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001153 return ( NULL );
1154 }
1155
1156 /* Set the header data. The CRC will be needed for the trailer */
Daniel Veillardf012a642001-07-23 19:10:52 +00001157 buff->crc = crc32( 0L, Z_NULL, 0 );
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001158 hdr_lgth = snprintf( (char *)buff->zbuff, buff->size,
1159 "%c%c%c%c%c%c%c%c%c%c",
Daniel Veillardf012a642001-07-23 19:10:52 +00001160 GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED,
1161 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE );
1162 buff->zctrl.next_out = buff->zbuff + hdr_lgth;
1163 buff->zctrl.avail_out = buff->size - hdr_lgth;
1164
1165 return ( buff );
1166}
1167
1168/**
1169 * xmlZMemBuffExtend
1170 * @buff: Buffer used to compress and consolidate data.
1171 * @ext_amt: Number of bytes to extend the buffer.
1172 *
1173 * Extend the internal buffer used to store the compressed data by the
1174 * specified amount.
1175 *
1176 * Returns 0 on success or -1 on failure to extend the buffer. On failure
1177 * the original buffer still exists at the original size.
1178 */
1179static int
1180xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) {
1181
1182 int rc = -1;
1183 size_t new_size;
1184 size_t cur_used;
1185
1186 unsigned char * tmp_ptr = NULL;
1187
1188 if ( buff == NULL )
1189 return ( -1 );
1190
1191 else if ( ext_amt == 0 )
1192 return ( 0 );
1193
1194 cur_used = buff->zctrl.next_out - buff->zbuff;
1195 new_size = buff->size + ext_amt;
1196
1197#ifdef DEBUG_HTTP
1198 if ( cur_used > new_size )
1199 xmlGenericError( xmlGenericErrorContext,
1200 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
1201 "Buffer overwrite detected during compressed memory",
1202 "buffer extension. Overflowed by",
1203 (cur_used - new_size ) );
1204#endif
1205
1206 tmp_ptr = xmlRealloc( buff->zbuff, new_size );
1207 if ( tmp_ptr != NULL ) {
1208 rc = 0;
1209 buff->size = new_size;
1210 buff->zbuff = tmp_ptr;
1211 buff->zctrl.next_out = tmp_ptr + cur_used;
1212 buff->zctrl.avail_out = new_size - cur_used;
1213 }
1214 else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001215 xmlChar msg[500];
1216 xmlStrPrintf(msg, 500,
1217 (const xmlChar *) "xmlZMemBuffExtend: %s %lu bytes.\n",
1218 "Allocation failure extending output buffer to",
1219 new_size );
1220 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001221 }
1222
1223 return ( rc );
1224}
1225
1226/**
1227 * xmlZMemBuffAppend
1228 * @buff: Buffer used to compress and consolidate data
1229 * @src: Uncompressed source content to append to buffer
1230 * @len: Length of source data to append to buffer
1231 *
1232 * Compress and append data to the internal buffer. The data buffer
1233 * will be expanded if needed to store the additional data.
1234 *
1235 * Returns the number of bytes appended to the buffer or -1 on error.
1236 */
1237static int
1238xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) {
1239
1240 int z_err;
1241 size_t min_accept;
1242
1243 if ( ( buff == NULL ) || ( src == NULL ) )
1244 return ( -1 );
1245
1246 buff->zctrl.avail_in = len;
1247 buff->zctrl.next_in = (unsigned char *)src;
1248 while ( buff->zctrl.avail_in > 0 ) {
1249 /*
1250 ** Extend the buffer prior to deflate call if a reasonable amount
1251 ** of output buffer space is not available.
1252 */
1253 min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO;
1254 if ( buff->zctrl.avail_out <= min_accept ) {
1255 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1256 return ( -1 );
1257 }
1258
1259 z_err = deflate( &buff->zctrl, Z_NO_FLUSH );
1260 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001261 xmlChar msg[500];
1262 xmlStrPrintf(msg, 500,
1263 (const xmlChar *) "xmlZMemBuffAppend: %s %d %s - %d",
Daniel Veillardf012a642001-07-23 19:10:52 +00001264 "Compression error while appending",
1265 len, "bytes to buffer. ZLIB error", z_err );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001266 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001267 return ( -1 );
1268 }
1269 }
1270
1271 buff->crc = crc32( buff->crc, (unsigned char *)src, len );
1272
1273 return ( len );
1274}
1275
1276/**
1277 * xmlZMemBuffGetContent
1278 * @buff: Compressed memory content buffer
1279 * @data_ref: Pointer reference to point to compressed content
1280 *
1281 * Flushes the compression buffers, appends gzip file trailers and
1282 * returns the compressed content and length of the compressed data.
1283 * NOTE: The gzip trailer code here is plagiarized from zlib source.
1284 *
1285 * Returns the length of the compressed data or -1 on error.
1286 */
1287static int
1288xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) {
1289
1290 int zlgth = -1;
1291 int z_err;
1292
1293 if ( ( buff == NULL ) || ( data_ref == NULL ) )
1294 return ( -1 );
1295
1296 /* Need to loop until compression output buffers are flushed */
1297
1298 do
1299 {
1300 z_err = deflate( &buff->zctrl, Z_FINISH );
1301 if ( z_err == Z_OK ) {
1302 /* In this case Z_OK means more buffer space needed */
1303
1304 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1305 return ( -1 );
1306 }
1307 }
1308 while ( z_err == Z_OK );
1309
1310 /* If the compression state is not Z_STREAM_END, some error occurred */
1311
1312 if ( z_err == Z_STREAM_END ) {
1313
1314 /* Need to append the gzip data trailer */
1315
1316 if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) {
1317 if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 )
1318 return ( -1 );
1319 }
1320
1321 /*
1322 ** For whatever reason, the CRC and length data are pushed out
1323 ** in reverse byte order. So a memcpy can't be used here.
1324 */
1325
1326 append_reverse_ulong( buff, buff->crc );
1327 append_reverse_ulong( buff, buff->zctrl.total_in );
1328
1329 zlgth = buff->zctrl.next_out - buff->zbuff;
1330 *data_ref = (char *)buff->zbuff;
1331 }
1332
Daniel Veillard05d987b2003-10-08 11:54:57 +00001333 else {
1334 xmlChar msg[500];
1335 xmlStrPrintf(msg, 500,
1336 (const xmlChar *) "xmlZMemBuffGetContent: %s - %d\n",
1337 "Error flushing zlib buffers. Error code", z_err );
1338 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1339 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001340
1341 return ( zlgth );
1342}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001343#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001344#endif /* HAVE_ZLIB_H */
1345
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001346#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001347/**
1348 * xmlFreeHTTPWriteCtxt
1349 * @ctxt: Context to cleanup
1350 *
1351 * Free allocated memory and reclaim system resources.
1352 *
1353 * No return value.
1354 */
1355static void
1356xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt )
1357{
1358 if ( ctxt->uri != NULL )
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001359 xmlFree( ctxt->uri );
Daniel Veillardf012a642001-07-23 19:10:52 +00001360
1361 if ( ctxt->doc_buff != NULL ) {
1362
1363#ifdef HAVE_ZLIB_H
1364 if ( ctxt->compression > 0 ) {
1365 xmlFreeZMemBuff( ctxt->doc_buff );
1366 }
1367 else
1368#endif
1369 {
1370 xmlOutputBufferClose( ctxt->doc_buff );
1371 }
1372 }
1373
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001374 xmlFree( ctxt );
Daniel Veillardf012a642001-07-23 19:10:52 +00001375 return;
1376}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001377#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001378
1379
Owen Taylor3473f882001-02-23 17:55:21 +00001380/**
1381 * xmlIOHTTPMatch:
1382 * @filename: the URI for matching
1383 *
1384 * check if the URI matches an HTTP one
1385 *
1386 * Returns 1 if matches, 0 otherwise
1387 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001388int
Owen Taylor3473f882001-02-23 17:55:21 +00001389xmlIOHTTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001390 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "http://", 7))
Owen Taylor3473f882001-02-23 17:55:21 +00001391 return(1);
1392 return(0);
1393}
1394
1395/**
1396 * xmlIOHTTPOpen:
1397 * @filename: the URI for matching
1398 *
1399 * open an HTTP I/O channel
1400 *
1401 * Returns an I/O context or NULL in case of error
1402 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001403void *
Owen Taylor3473f882001-02-23 17:55:21 +00001404xmlIOHTTPOpen (const char *filename) {
1405 return(xmlNanoHTTPOpen(filename, NULL));
1406}
1407
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001408#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001409/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001410 * xmlIOHTTPOpenW:
Daniel Veillardf012a642001-07-23 19:10:52 +00001411 * @post_uri: The destination URI for the document
1412 * @compression: The compression desired for the document.
1413 *
1414 * Open a temporary buffer to collect the document for a subsequent HTTP POST
1415 * request. Non-static as is called from the output buffer creation routine.
1416 *
1417 * Returns an I/O context or NULL in case of error.
1418 */
1419
1420void *
Daniel Veillard572577e2002-01-18 16:23:55 +00001421xmlIOHTTPOpenW(const char *post_uri, int compression)
1422{
Daniel Veillardf012a642001-07-23 19:10:52 +00001423
Daniel Veillard572577e2002-01-18 16:23:55 +00001424 xmlIOHTTPWriteCtxtPtr ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001425
Daniel Veillard572577e2002-01-18 16:23:55 +00001426 if (post_uri == NULL)
1427 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001428
Daniel Veillard572577e2002-01-18 16:23:55 +00001429 ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt));
1430 if (ctxt == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001431 xmlIOErrMemory("creating HTTP output context");
Daniel Veillard572577e2002-01-18 16:23:55 +00001432 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001433 }
1434
Daniel Veillard572577e2002-01-18 16:23:55 +00001435 (void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt));
Daniel Veillardf012a642001-07-23 19:10:52 +00001436
Daniel Veillard572577e2002-01-18 16:23:55 +00001437 ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri);
1438 if (ctxt->uri == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001439 xmlIOErrMemory("copying URI");
Daniel Veillard572577e2002-01-18 16:23:55 +00001440 xmlFreeHTTPWriteCtxt(ctxt);
1441 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001442 }
1443
1444 /*
Daniel Veillard572577e2002-01-18 16:23:55 +00001445 * ** Since the document length is required for an HTTP post,
1446 * ** need to put the document into a buffer. A memory buffer
1447 * ** is being used to avoid pushing the data to disk and back.
1448 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001449
1450#ifdef HAVE_ZLIB_H
Daniel Veillard572577e2002-01-18 16:23:55 +00001451 if ((compression > 0) && (compression <= 9)) {
1452
1453 ctxt->compression = compression;
1454 ctxt->doc_buff = xmlCreateZMemBuff(compression);
1455 } else
Daniel Veillardf012a642001-07-23 19:10:52 +00001456#endif
1457 {
Daniel Veillard572577e2002-01-18 16:23:55 +00001458 /* Any character conversions should have been done before this */
Daniel Veillardf012a642001-07-23 19:10:52 +00001459
Daniel Veillard572577e2002-01-18 16:23:55 +00001460 ctxt->doc_buff = xmlAllocOutputBuffer(NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001461 }
1462
Daniel Veillard572577e2002-01-18 16:23:55 +00001463 if (ctxt->doc_buff == NULL) {
1464 xmlFreeHTTPWriteCtxt(ctxt);
1465 ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001466 }
1467
Daniel Veillard572577e2002-01-18 16:23:55 +00001468 return (ctxt);
Daniel Veillardf012a642001-07-23 19:10:52 +00001469}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001470#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001471
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001472#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001473/**
1474 * xmlIOHTTPDfltOpenW
1475 * @post_uri: The destination URI for this document.
1476 *
1477 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
1478 * HTTP post command. This function should generally not be used as
1479 * the open callback is short circuited in xmlOutputBufferCreateFile.
1480 *
1481 * Returns a pointer to the new IO context.
1482 */
1483static void *
1484xmlIOHTTPDfltOpenW( const char * post_uri ) {
1485 return ( xmlIOHTTPOpenW( post_uri, 0 ) );
1486}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001487#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001488
1489/**
Owen Taylor3473f882001-02-23 17:55:21 +00001490 * xmlIOHTTPRead:
1491 * @context: the I/O context
1492 * @buffer: where to drop data
1493 * @len: number of bytes to write
1494 *
1495 * Read @len bytes to @buffer from the I/O channel.
1496 *
1497 * Returns the number of bytes written
1498 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001499int
Owen Taylor3473f882001-02-23 17:55:21 +00001500xmlIOHTTPRead(void * context, char * buffer, int len) {
1501 return(xmlNanoHTTPRead(context, &buffer[0], len));
1502}
1503
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001504#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001505/**
Daniel Veillardf012a642001-07-23 19:10:52 +00001506 * xmlIOHTTPWrite
1507 * @context: previously opened writing context
1508 * @buffer: data to output to temporary buffer
1509 * @len: bytes to output
1510 *
1511 * Collect data from memory buffer into a temporary file for later
1512 * processing.
1513 *
1514 * Returns number of bytes written.
1515 */
1516
1517static int
1518xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
1519
1520 xmlIOHTTPWriteCtxtPtr ctxt = context;
1521
1522 if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
1523 return ( -1 );
1524
1525 if ( len > 0 ) {
1526
1527 /* Use gzwrite or fwrite as previously setup in the open call */
1528
1529#ifdef HAVE_ZLIB_H
1530 if ( ctxt->compression > 0 )
1531 len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len );
1532
1533 else
1534#endif
1535 len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
1536
1537 if ( len < 0 ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001538 xmlChar msg[500];
1539 xmlStrPrintf(msg, 500,
1540 (const xmlChar *) "xmlIOHTTPWrite: %s\n%s '%s'.\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001541 "Error appending to internal buffer.",
1542 "Error sending document to URI",
1543 ctxt->uri );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001544 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001545 }
1546 }
1547
1548 return ( len );
1549}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001550#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001551
1552
1553/**
Owen Taylor3473f882001-02-23 17:55:21 +00001554 * xmlIOHTTPClose:
1555 * @context: the I/O context
1556 *
1557 * Close an HTTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001558 *
1559 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00001560 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001561int
Owen Taylor3473f882001-02-23 17:55:21 +00001562xmlIOHTTPClose (void * context) {
1563 xmlNanoHTTPClose(context);
Daniel Veillardf012a642001-07-23 19:10:52 +00001564 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001565}
Daniel Veillardf012a642001-07-23 19:10:52 +00001566
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001567#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001568/**
1569 * xmlIOHTTCloseWrite
1570 * @context: The I/O context
1571 * @http_mthd: The HTTP method to be used when sending the data
1572 *
1573 * Close the transmit HTTP I/O channel and actually send the data.
1574 */
1575static int
1576xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
1577
1578 int close_rc = -1;
1579 int http_rtn = 0;
1580 int content_lgth = 0;
1581 xmlIOHTTPWriteCtxtPtr ctxt = context;
1582
1583 char * http_content = NULL;
1584 char * content_encoding = NULL;
1585 char * content_type = (char *) "text/xml";
1586 void * http_ctxt = NULL;
1587
1588 if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
1589 return ( -1 );
1590
1591 /* Retrieve the content from the appropriate buffer */
1592
1593#ifdef HAVE_ZLIB_H
1594
1595 if ( ctxt->compression > 0 ) {
1596 content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
1597 content_encoding = (char *) "Content-Encoding: gzip";
1598 }
1599 else
1600#endif
1601 {
1602 /* Pull the data out of the memory output buffer */
1603
1604 xmlOutputBufferPtr dctxt = ctxt->doc_buff;
1605 http_content = (char *)dctxt->buffer->content;
1606 content_lgth = dctxt->buffer->use;
1607 }
1608
1609 if ( http_content == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001610 xmlChar msg[500];
1611 xmlStrPrintf(msg, 500,
1612 (const xmlChar *) "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
1613 "Error retrieving content.\nUnable to",
1614 http_mthd, "data to URI", ctxt->uri );
1615 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001616 }
1617
1618 else {
1619
1620 http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
1621 &content_type, content_encoding,
1622 content_lgth );
1623
1624 if ( http_ctxt != NULL ) {
1625#ifdef DEBUG_HTTP
1626 /* If testing/debugging - dump reply with request content */
1627
1628 FILE * tst_file = NULL;
1629 char buffer[ 4096 ];
1630 char * dump_name = NULL;
1631 int avail;
1632
1633 xmlGenericError( xmlGenericErrorContext,
1634 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
1635 http_mthd, ctxt->uri,
1636 xmlNanoHTTPReturnCode( http_ctxt ) );
1637
1638 /*
1639 ** Since either content or reply may be gzipped,
1640 ** dump them to separate files instead of the
1641 ** standard error context.
1642 */
1643
1644 dump_name = tempnam( NULL, "lxml" );
1645 if ( dump_name != NULL ) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001646 (void)snprintf( buffer, sizeof(buffer), "%s.content", dump_name );
Daniel Veillardf012a642001-07-23 19:10:52 +00001647
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00001648 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00001649 if ( tst_file != NULL ) {
1650 xmlGenericError( xmlGenericErrorContext,
1651 "Transmitted content saved in file: %s\n", buffer );
1652
1653 fwrite( http_content, sizeof( char ),
1654 content_lgth, tst_file );
1655 fclose( tst_file );
1656 }
1657
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001658 (void)snprintf( buffer, sizeof(buffer), "%s.reply", dump_name );
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00001659 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00001660 if ( tst_file != NULL ) {
1661 xmlGenericError( xmlGenericErrorContext,
1662 "Reply content saved in file: %s\n", buffer );
1663
1664
1665 while ( (avail = xmlNanoHTTPRead( http_ctxt,
1666 buffer, sizeof( buffer ) )) > 0 ) {
1667
1668 fwrite( buffer, sizeof( char ), avail, tst_file );
1669 }
1670
1671 fclose( tst_file );
1672 }
1673
1674 free( dump_name );
1675 }
1676#endif /* DEBUG_HTTP */
1677
1678 http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
1679 if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
1680 close_rc = 0;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001681 else {
1682 xmlChar msg[500];
1683 xmlStrPrintf(msg, 500,
1684 (const xmlChar *) "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001685 http_mthd, content_lgth,
1686 "bytes to URI", ctxt->uri,
1687 "failed. HTTP return code:", http_rtn );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001688 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1689 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001690
1691 xmlNanoHTTPClose( http_ctxt );
1692 xmlFree( content_type );
1693 }
1694 }
1695
1696 /* Final cleanups */
1697
1698 xmlFreeHTTPWriteCtxt( ctxt );
1699
1700 return ( close_rc );
1701}
1702
1703/**
1704 * xmlIOHTTPClosePut
1705 *
1706 * @context: The I/O context
1707 *
1708 * Close the transmit HTTP I/O channel and actually send data using a PUT
1709 * HTTP method.
1710 */
1711static int
1712xmlIOHTTPClosePut( void * ctxt ) {
1713 return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
1714}
1715
1716
1717/**
1718 * xmlIOHTTPClosePost
1719 *
1720 * @context: The I/O context
1721 *
1722 * Close the transmit HTTP I/O channel and actually send data using a POST
1723 * HTTP method.
1724 */
1725static int
1726xmlIOHTTPClosePost( void * ctxt ) {
1727 return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
1728}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001729#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001730
Owen Taylor3473f882001-02-23 17:55:21 +00001731#endif /* LIBXML_HTTP_ENABLED */
1732
1733#ifdef LIBXML_FTP_ENABLED
1734/************************************************************************
1735 * *
1736 * I/O for FTP file accesses *
1737 * *
1738 ************************************************************************/
1739/**
1740 * xmlIOFTPMatch:
1741 * @filename: the URI for matching
1742 *
1743 * check if the URI matches an FTP one
1744 *
1745 * Returns 1 if matches, 0 otherwise
1746 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001747int
Owen Taylor3473f882001-02-23 17:55:21 +00001748xmlIOFTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001749 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "ftp://", 6))
Owen Taylor3473f882001-02-23 17:55:21 +00001750 return(1);
1751 return(0);
1752}
1753
1754/**
1755 * xmlIOFTPOpen:
1756 * @filename: the URI for matching
1757 *
1758 * open an FTP I/O channel
1759 *
1760 * Returns an I/O context or NULL in case of error
1761 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001762void *
Owen Taylor3473f882001-02-23 17:55:21 +00001763xmlIOFTPOpen (const char *filename) {
1764 return(xmlNanoFTPOpen(filename));
1765}
1766
1767/**
1768 * xmlIOFTPRead:
1769 * @context: the I/O context
1770 * @buffer: where to drop data
1771 * @len: number of bytes to write
1772 *
1773 * Read @len bytes to @buffer from the I/O channel.
1774 *
1775 * Returns the number of bytes written
1776 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001777int
Owen Taylor3473f882001-02-23 17:55:21 +00001778xmlIOFTPRead(void * context, char * buffer, int len) {
1779 return(xmlNanoFTPRead(context, &buffer[0], len));
1780}
1781
1782/**
1783 * xmlIOFTPClose:
1784 * @context: the I/O context
1785 *
1786 * Close an FTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001787 *
1788 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00001789 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001790int
Owen Taylor3473f882001-02-23 17:55:21 +00001791xmlIOFTPClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001792 return ( xmlNanoFTPClose(context) );
Owen Taylor3473f882001-02-23 17:55:21 +00001793}
1794#endif /* LIBXML_FTP_ENABLED */
1795
1796
1797/**
1798 * xmlRegisterInputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001799 * @matchFunc: the xmlInputMatchCallback
1800 * @openFunc: the xmlInputOpenCallback
1801 * @readFunc: the xmlInputReadCallback
1802 * @closeFunc: the xmlInputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001803 *
1804 * Register a new set of I/O callback for handling parser input.
1805 *
1806 * Returns the registered handler number or -1 in case of error
1807 */
1808int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001809xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
1810 xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
1811 xmlInputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001812 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
1813 return(-1);
1814 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001815 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
1816 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
1817 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
1818 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00001819 xmlInputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00001820 return(xmlInputCallbackNr++);
1821}
1822
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001823#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001824/**
1825 * xmlRegisterOutputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001826 * @matchFunc: the xmlOutputMatchCallback
1827 * @openFunc: the xmlOutputOpenCallback
1828 * @writeFunc: the xmlOutputWriteCallback
1829 * @closeFunc: the xmlOutputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001830 *
1831 * Register a new set of I/O callback for handling output.
1832 *
1833 * Returns the registered handler number or -1 in case of error
1834 */
1835int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001836xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
1837 xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
1838 xmlOutputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001839 if (xmlOutputCallbackNr >= MAX_INPUT_CALLBACK) {
1840 return(-1);
1841 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001842 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
1843 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
1844 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
1845 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00001846 xmlOutputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00001847 return(xmlOutputCallbackNr++);
1848}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001849#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001850
1851/**
1852 * xmlRegisterDefaultInputCallbacks:
1853 *
1854 * Registers the default compiled-in I/O handlers.
1855 */
1856void
Owen Taylor3473f882001-02-23 17:55:21 +00001857xmlRegisterDefaultInputCallbacks
Owen Taylor3473f882001-02-23 17:55:21 +00001858(void) {
1859 if (xmlInputCallbackInitialized)
1860 return;
1861
1862 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
1863 xmlFileRead, xmlFileClose);
1864#ifdef HAVE_ZLIB_H
1865 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1866 xmlGzfileRead, xmlGzfileClose);
1867#endif /* HAVE_ZLIB_H */
1868
1869#ifdef LIBXML_HTTP_ENABLED
1870 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
1871 xmlIOHTTPRead, xmlIOHTTPClose);
1872#endif /* LIBXML_HTTP_ENABLED */
1873
1874#ifdef LIBXML_FTP_ENABLED
1875 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1876 xmlIOFTPRead, xmlIOFTPClose);
1877#endif /* LIBXML_FTP_ENABLED */
1878 xmlInputCallbackInitialized = 1;
1879}
1880
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001881#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001882/**
1883 * xmlRegisterDefaultOutputCallbacks:
1884 *
1885 * Registers the default compiled-in I/O handlers.
1886 */
1887void
Owen Taylor3473f882001-02-23 17:55:21 +00001888xmlRegisterDefaultOutputCallbacks
Owen Taylor3473f882001-02-23 17:55:21 +00001889(void) {
1890 if (xmlOutputCallbackInitialized)
1891 return;
1892
1893 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
1894 xmlFileWrite, xmlFileClose);
Daniel Veillardf012a642001-07-23 19:10:52 +00001895
1896#ifdef LIBXML_HTTP_ENABLED
1897 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
1898 xmlIOHTTPWrite, xmlIOHTTPClosePut);
1899#endif
1900
Owen Taylor3473f882001-02-23 17:55:21 +00001901/*********************************
1902 No way a-priori to distinguish between gzipped files from
1903 uncompressed ones except opening if existing then closing
1904 and saving with same compression ratio ... a pain.
1905
1906#ifdef HAVE_ZLIB_H
1907 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1908 xmlGzfileWrite, xmlGzfileClose);
1909#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001910
1911 Nor FTP PUT ....
1912#ifdef LIBXML_FTP_ENABLED
1913 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1914 xmlIOFTPWrite, xmlIOFTPClose);
1915#endif
1916 **********************************/
1917 xmlOutputCallbackInitialized = 1;
1918}
1919
Daniel Veillardf012a642001-07-23 19:10:52 +00001920#ifdef LIBXML_HTTP_ENABLED
1921/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001922 * xmlRegisterHTTPPostCallbacks:
Daniel Veillardf012a642001-07-23 19:10:52 +00001923 *
1924 * By default, libxml submits HTTP output requests using the "PUT" method.
1925 * Calling this method changes the HTTP output method to use the "POST"
1926 * method instead.
1927 *
1928 */
1929void
1930xmlRegisterHTTPPostCallbacks( void ) {
1931
1932 /* Register defaults if not done previously */
1933
1934 if ( xmlOutputCallbackInitialized == 0 )
1935 xmlRegisterDefaultOutputCallbacks( );
1936
1937 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
1938 xmlIOHTTPWrite, xmlIOHTTPClosePost);
1939 return;
1940}
1941#endif
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001942#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001943
Owen Taylor3473f882001-02-23 17:55:21 +00001944/**
1945 * xmlAllocParserInputBuffer:
1946 * @enc: the charset encoding if known
1947 *
1948 * Create a buffered parser input for progressive parsing
1949 *
1950 * Returns the new parser input or NULL
1951 */
1952xmlParserInputBufferPtr
1953xmlAllocParserInputBuffer(xmlCharEncoding enc) {
1954 xmlParserInputBufferPtr ret;
1955
1956 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
1957 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001958 xmlIOErrMemory("creating input buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00001959 return(NULL);
1960 }
1961 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00001962 ret->buffer = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00001963 if (ret->buffer == NULL) {
1964 xmlFree(ret);
1965 return(NULL);
1966 }
1967 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
1968 ret->encoder = xmlGetCharEncodingHandler(enc);
1969 if (ret->encoder != NULL)
Daniel Veillard6155d8a2003-08-19 15:01:28 +00001970 ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00001971 else
1972 ret->raw = NULL;
1973 ret->readcallback = NULL;
1974 ret->closecallback = NULL;
1975 ret->context = NULL;
William M. Brackc07329e2003-09-08 01:57:30 +00001976 ret->compressed = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00001977
1978 return(ret);
1979}
1980
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001981#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001982/**
1983 * xmlAllocOutputBuffer:
1984 * @encoder: the encoding converter or NULL
1985 *
1986 * Create a buffered parser output
1987 *
1988 * Returns the new parser output or NULL
1989 */
1990xmlOutputBufferPtr
1991xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
1992 xmlOutputBufferPtr ret;
1993
1994 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
1995 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001996 xmlIOErrMemory("creating output buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00001997 return(NULL);
1998 }
1999 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
2000 ret->buffer = xmlBufferCreate();
2001 if (ret->buffer == NULL) {
2002 xmlFree(ret);
2003 return(NULL);
2004 }
2005 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
2006 ret->encoder = encoder;
2007 if (encoder != NULL) {
2008 ret->conv = xmlBufferCreateSize(4000);
2009 /*
2010 * This call is designed to initiate the encoder state
2011 */
2012 xmlCharEncOutFunc(encoder, ret->conv, NULL);
2013 } else
2014 ret->conv = NULL;
2015 ret->writecallback = NULL;
2016 ret->closecallback = NULL;
2017 ret->context = NULL;
2018 ret->written = 0;
2019
2020 return(ret);
2021}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002022#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002023
2024/**
2025 * xmlFreeParserInputBuffer:
2026 * @in: a buffered parser input
2027 *
2028 * Free up the memory used by a buffered parser input
2029 */
2030void
2031xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
Daniel Veillard8d8bf2c2003-09-17 19:36:25 +00002032 if (in == NULL) return;
2033
Owen Taylor3473f882001-02-23 17:55:21 +00002034 if (in->raw) {
2035 xmlBufferFree(in->raw);
2036 in->raw = NULL;
2037 }
2038 if (in->encoder != NULL) {
2039 xmlCharEncCloseFunc(in->encoder);
2040 }
2041 if (in->closecallback != NULL) {
2042 in->closecallback(in->context);
2043 }
2044 if (in->buffer != NULL) {
2045 xmlBufferFree(in->buffer);
2046 in->buffer = NULL;
2047 }
2048
Owen Taylor3473f882001-02-23 17:55:21 +00002049 xmlFree(in);
2050}
2051
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002052#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002053/**
2054 * xmlOutputBufferClose:
2055 * @out: a buffered output
2056 *
2057 * flushes and close the output I/O channel
2058 * and free up all the associated resources
2059 *
2060 * Returns the number of byte written or -1 in case of error.
2061 */
2062int
Daniel Veillard828ce832003-10-08 19:19:10 +00002063xmlOutputBufferClose(xmlOutputBufferPtr out)
2064{
Owen Taylor3473f882001-02-23 17:55:21 +00002065 int written;
Daniel Veillardf012a642001-07-23 19:10:52 +00002066 int err_rc = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002067
2068 if (out == NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002069 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002070 if (out->writecallback != NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002071 xmlOutputBufferFlush(out);
Owen Taylor3473f882001-02-23 17:55:21 +00002072 if (out->closecallback != NULL) {
Daniel Veillard828ce832003-10-08 19:19:10 +00002073 err_rc = out->closecallback(out->context);
Owen Taylor3473f882001-02-23 17:55:21 +00002074 }
2075 written = out->written;
2076 if (out->conv) {
2077 xmlBufferFree(out->conv);
Daniel Veillard828ce832003-10-08 19:19:10 +00002078 out->conv = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002079 }
2080 if (out->encoder != NULL) {
2081 xmlCharEncCloseFunc(out->encoder);
2082 }
2083 if (out->buffer != NULL) {
2084 xmlBufferFree(out->buffer);
Daniel Veillard828ce832003-10-08 19:19:10 +00002085 out->buffer = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002086 }
2087
Daniel Veillard828ce832003-10-08 19:19:10 +00002088 if (out->error)
2089 err_rc = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00002090 xmlFree(out);
Daniel Veillard828ce832003-10-08 19:19:10 +00002091 return ((err_rc == 0) ? written : err_rc);
Owen Taylor3473f882001-02-23 17:55:21 +00002092}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002093#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002094
2095/**
2096 * xmlParserInputBufferCreateFilename:
2097 * @URI: a C string containing the URI or filename
2098 * @enc: the charset encoding if known
2099 *
2100 * Create a buffered parser input for the progressive parsing of a file
2101 * If filename is "-' then we use stdin as the input.
2102 * Automatic support for ZLIB/Compress compressed document is provided
2103 * by default if found at compile-time.
2104 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
2105 *
2106 * Returns the new parser input or NULL
2107 */
2108xmlParserInputBufferPtr
Daniel Veillard3e59fc52003-04-18 12:34:58 +00002109xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002110 xmlParserInputBufferPtr ret;
Daniel Veillard847332a2003-10-18 11:29:40 +00002111 int is_http = 0;
Daniel Veillard388236f2001-07-08 18:35:48 +00002112 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002113 void *context = NULL;
2114
2115 if (xmlInputCallbackInitialized == 0)
2116 xmlRegisterDefaultInputCallbacks();
2117
2118 if (URI == NULL) return(NULL);
2119
2120 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002121 * Try to find one of the input accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002122 * Go in reverse to give precedence to user defined handlers.
Daniel Veillard388236f2001-07-08 18:35:48 +00002123 */
2124 if (context == NULL) {
2125 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
2126 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
2127 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002128 context = xmlInputCallbackTable[i].opencallback(URI);
Daniel Veillard847332a2003-10-18 11:29:40 +00002129 if (context != NULL) {
2130 if (xmlInputCallbackTable[i].opencallback == xmlIOHTTPOpen)
2131 is_http = 1;
Daniel Veillard388236f2001-07-08 18:35:48 +00002132 break;
Daniel Veillard847332a2003-10-18 11:29:40 +00002133 }
Daniel Veillard388236f2001-07-08 18:35:48 +00002134 }
Owen Taylor3473f882001-02-23 17:55:21 +00002135 }
2136 }
2137 if (context == NULL) {
2138 return(NULL);
2139 }
2140
2141 /*
2142 * Allocate the Input buffer front-end.
2143 */
2144 ret = xmlAllocParserInputBuffer(enc);
2145 if (ret != NULL) {
2146 ret->context = context;
2147 ret->readcallback = xmlInputCallbackTable[i].readcallback;
2148 ret->closecallback = xmlInputCallbackTable[i].closecallback;
William M. Brackc07329e2003-09-08 01:57:30 +00002149#ifdef HAVE_ZLIB_H
2150 if (xmlInputCallbackTable[i].opencallback == xmlGzfileOpen) {
2151 if (((z_stream *)context)->avail_in > 4) {
2152 char *cptr, buff4[4];
Daniel Veillard07cb8222003-09-10 10:51:05 +00002153 cptr = (char *) ((z_stream *)context)->next_in;
William M. Brackc07329e2003-09-08 01:57:30 +00002154 if (gzread(context, buff4, 4) == 4) {
2155 if (strncmp(buff4, cptr, 4) == 0)
2156 ret->compressed = 0;
2157 else
2158 ret->compressed = 1;
2159 gzrewind(context);
2160 }
2161 }
2162 }
2163#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002164 }
2165 return(ret);
2166}
2167
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002168#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002169/**
2170 * xmlOutputBufferCreateFilename:
2171 * @URI: a C string containing the URI or filename
2172 * @encoder: the encoding converter or NULL
2173 * @compression: the compression ration (0 none, 9 max).
2174 *
2175 * Create a buffered output for the progressive saving of a file
2176 * If filename is "-' then we use stdout as the output.
2177 * Automatic support for ZLIB/Compress compressed document is provided
2178 * by default if found at compile-time.
2179 * TODO: currently if compression is set, the library only support
2180 * writing to a local file.
2181 *
2182 * Returns the new output or NULL
2183 */
2184xmlOutputBufferPtr
2185xmlOutputBufferCreateFilename(const char *URI,
2186 xmlCharEncodingHandlerPtr encoder,
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002187 int compression ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00002188 xmlOutputBufferPtr ret;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002189 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002190 void *context = NULL;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002191 char *unescaped;
Owen Taylor3473f882001-02-23 17:55:21 +00002192
Daniel Veillard4432df22003-09-28 18:58:27 +00002193#ifdef LIBXML_HTTP_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00002194 int is_http_uri = 0; /* Can't change if HTTP disabled */
Daniel Veillard4432df22003-09-28 18:58:27 +00002195#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00002196
Owen Taylor3473f882001-02-23 17:55:21 +00002197 if (xmlOutputCallbackInitialized == 0)
2198 xmlRegisterDefaultOutputCallbacks();
2199
2200 if (URI == NULL) return(NULL);
2201
Daniel Veillardf012a642001-07-23 19:10:52 +00002202#ifdef LIBXML_HTTP_ENABLED
2203 /* Need to prevent HTTP URI's from falling into zlib short circuit */
2204
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002205 is_http_uri = xmlIOHTTPMatch( URI );
Daniel Veillardf012a642001-07-23 19:10:52 +00002206#endif
2207
Owen Taylor3473f882001-02-23 17:55:21 +00002208
2209 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002210 * Try to find one of the output accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002211 * Go in reverse to give precedence to user defined handlers.
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002212 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00002213 */
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002214 unescaped = xmlURIUnescapeString(URI, 0, NULL);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002215 if (unescaped != NULL) {
2216#ifdef HAVE_ZLIB_H
2217 if ((compression > 0) && (compression <= 9) && (is_http_uri == 0)) {
2218 context = xmlGzfileOpenW(unescaped, compression);
2219 if (context != NULL) {
2220 ret = xmlAllocOutputBuffer(encoder);
2221 if (ret != NULL) {
2222 ret->context = context;
2223 ret->writecallback = xmlGzfileWrite;
2224 ret->closecallback = xmlGzfileClose;
2225 }
2226 xmlFree(unescaped);
2227 return(ret);
2228 }
2229 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002230#endif
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002231 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2232 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
2233 (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
2234#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2235 /* Need to pass compression parameter into HTTP open calls */
2236 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2237 context = xmlIOHTTPOpenW(unescaped, compression);
2238 else
2239#endif
2240 context = xmlOutputCallbackTable[i].opencallback(unescaped);
2241 if (context != NULL)
2242 break;
2243 }
2244 }
2245 xmlFree(unescaped);
2246 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002247
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002248 /*
2249 * If this failed try with a non-escaped URI this may be a strange
2250 * filename
2251 */
2252 if (context == NULL) {
2253#ifdef HAVE_ZLIB_H
2254 if ((compression > 0) && (compression <= 9) && (is_http_uri == 0)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002255 context = xmlGzfileOpenW(URI, compression);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002256 if (context != NULL) {
2257 ret = xmlAllocOutputBuffer(encoder);
2258 if (ret != NULL) {
2259 ret->context = context;
2260 ret->writecallback = xmlGzfileWrite;
2261 ret->closecallback = xmlGzfileClose;
2262 }
2263 return(ret);
2264 }
2265 }
2266#endif
2267 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2268 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002269 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002270#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2271 /* Need to pass compression parameter into HTTP open calls */
2272 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2273 context = xmlIOHTTPOpenW(URI, compression);
2274 else
2275#endif
2276 context = xmlOutputCallbackTable[i].opencallback(URI);
2277 if (context != NULL)
2278 break;
2279 }
Owen Taylor3473f882001-02-23 17:55:21 +00002280 }
2281 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002282
Owen Taylor3473f882001-02-23 17:55:21 +00002283 if (context == NULL) {
2284 return(NULL);
2285 }
2286
2287 /*
2288 * Allocate the Output buffer front-end.
2289 */
2290 ret = xmlAllocOutputBuffer(encoder);
2291 if (ret != NULL) {
2292 ret->context = context;
2293 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
2294 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
2295 }
2296 return(ret);
2297}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002298#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002299
2300/**
2301 * xmlParserInputBufferCreateFile:
2302 * @file: a FILE*
2303 * @enc: the charset encoding if known
2304 *
2305 * Create a buffered parser input for the progressive parsing of a FILE *
2306 * buffered C I/O
2307 *
2308 * Returns the new parser input or NULL
2309 */
2310xmlParserInputBufferPtr
2311xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
2312 xmlParserInputBufferPtr ret;
2313
2314 if (xmlInputCallbackInitialized == 0)
2315 xmlRegisterDefaultInputCallbacks();
2316
2317 if (file == NULL) return(NULL);
2318
2319 ret = xmlAllocParserInputBuffer(enc);
2320 if (ret != NULL) {
2321 ret->context = file;
2322 ret->readcallback = xmlFileRead;
2323 ret->closecallback = xmlFileFlush;
2324 }
2325
2326 return(ret);
2327}
2328
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002329#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002330/**
2331 * xmlOutputBufferCreateFile:
2332 * @file: a FILE*
2333 * @encoder: the encoding converter or NULL
2334 *
2335 * Create a buffered output for the progressive saving to a FILE *
2336 * buffered C I/O
2337 *
2338 * Returns the new parser output or NULL
2339 */
2340xmlOutputBufferPtr
2341xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
2342 xmlOutputBufferPtr ret;
2343
2344 if (xmlOutputCallbackInitialized == 0)
2345 xmlRegisterDefaultOutputCallbacks();
2346
2347 if (file == NULL) return(NULL);
2348
2349 ret = xmlAllocOutputBuffer(encoder);
2350 if (ret != NULL) {
2351 ret->context = file;
2352 ret->writecallback = xmlFileWrite;
2353 ret->closecallback = xmlFileFlush;
2354 }
2355
2356 return(ret);
2357}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002358#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002359
2360/**
2361 * xmlParserInputBufferCreateFd:
2362 * @fd: a file descriptor number
2363 * @enc: the charset encoding if known
2364 *
2365 * Create a buffered parser input for the progressive parsing for the input
2366 * from a file descriptor
2367 *
2368 * Returns the new parser input or NULL
2369 */
2370xmlParserInputBufferPtr
2371xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
2372 xmlParserInputBufferPtr ret;
2373
2374 if (fd < 0) return(NULL);
2375
2376 ret = xmlAllocParserInputBuffer(enc);
2377 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002378 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002379 ret->readcallback = xmlFdRead;
2380 ret->closecallback = xmlFdClose;
2381 }
2382
2383 return(ret);
2384}
2385
2386/**
2387 * xmlParserInputBufferCreateMem:
2388 * @mem: the memory input
2389 * @size: the length of the memory block
2390 * @enc: the charset encoding if known
2391 *
2392 * Create a buffered parser input for the progressive parsing for the input
2393 * from a memory area.
2394 *
2395 * Returns the new parser input or NULL
2396 */
2397xmlParserInputBufferPtr
2398xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
2399 xmlParserInputBufferPtr ret;
2400
2401 if (size <= 0) return(NULL);
2402 if (mem == NULL) return(NULL);
2403
2404 ret = xmlAllocParserInputBuffer(enc);
2405 if (ret != NULL) {
2406 ret->context = (void *) mem;
2407 ret->readcallback = (xmlInputReadCallback) xmlNop;
2408 ret->closecallback = NULL;
2409 xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size);
2410 }
2411
2412 return(ret);
2413}
2414
2415/**
Daniel Veillard53350552003-09-18 13:35:51 +00002416 * xmlParserInputBufferCreateStatic:
2417 * @mem: the memory input
2418 * @size: the length of the memory block
2419 * @enc: the charset encoding if known
2420 *
2421 * Create a buffered parser input for the progressive parsing for the input
2422 * from an immutable memory area. This will not copy the memory area to
2423 * the buffer, but the memory is expected to be available until the end of
2424 * the parsing, this is useful for example when using mmap'ed file.
2425 *
2426 * Returns the new parser input or NULL
2427 */
2428xmlParserInputBufferPtr
2429xmlParserInputBufferCreateStatic(const char *mem, int size,
2430 xmlCharEncoding enc) {
2431 xmlParserInputBufferPtr ret;
2432
2433 if (size <= 0) return(NULL);
2434 if (mem == NULL) return(NULL);
2435
2436 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2437 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002438 xmlIOErrMemory("creating input buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00002439 return(NULL);
2440 }
2441 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillarde72c5082003-09-19 12:44:05 +00002442 ret->buffer = xmlBufferCreateStatic((void *)mem, (size_t) size);
Daniel Veillard53350552003-09-18 13:35:51 +00002443 if (ret->buffer == NULL) {
2444 xmlFree(ret);
2445 return(NULL);
2446 }
2447 ret->encoder = xmlGetCharEncodingHandler(enc);
2448 if (ret->encoder != NULL)
2449 ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
2450 else
2451 ret->raw = NULL;
2452 ret->compressed = -1;
2453 ret->context = (void *) mem;
2454 ret->readcallback = NULL;
2455 ret->closecallback = NULL;
2456
2457 return(ret);
2458}
2459
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002460#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard53350552003-09-18 13:35:51 +00002461/**
Owen Taylor3473f882001-02-23 17:55:21 +00002462 * xmlOutputBufferCreateFd:
2463 * @fd: a file descriptor number
2464 * @encoder: the encoding converter or NULL
2465 *
2466 * Create a buffered output for the progressive saving
2467 * to a file descriptor
2468 *
2469 * Returns the new parser output or NULL
2470 */
2471xmlOutputBufferPtr
2472xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
2473 xmlOutputBufferPtr ret;
2474
2475 if (fd < 0) return(NULL);
2476
2477 ret = xmlAllocOutputBuffer(encoder);
2478 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002479 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002480 ret->writecallback = xmlFdWrite;
Daniel Veillard7db38712002-02-07 16:39:11 +00002481 ret->closecallback = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002482 }
2483
2484 return(ret);
2485}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002486#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002487
2488/**
2489 * xmlParserInputBufferCreateIO:
2490 * @ioread: an I/O read function
2491 * @ioclose: an I/O close function
2492 * @ioctx: an I/O handler
2493 * @enc: the charset encoding if known
2494 *
2495 * Create a buffered parser input for the progressive parsing for the input
2496 * from an I/O handler
2497 *
2498 * Returns the new parser input or NULL
2499 */
2500xmlParserInputBufferPtr
2501xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
2502 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
2503 xmlParserInputBufferPtr ret;
2504
2505 if (ioread == NULL) return(NULL);
2506
2507 ret = xmlAllocParserInputBuffer(enc);
2508 if (ret != NULL) {
2509 ret->context = (void *) ioctx;
2510 ret->readcallback = ioread;
2511 ret->closecallback = ioclose;
2512 }
2513
2514 return(ret);
2515}
2516
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002517#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002518/**
2519 * xmlOutputBufferCreateIO:
2520 * @iowrite: an I/O write function
2521 * @ioclose: an I/O close function
2522 * @ioctx: an I/O handler
Daniel Veillard9d06d302002-01-22 18:15:52 +00002523 * @encoder: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002524 *
2525 * Create a buffered output for the progressive saving
2526 * to an I/O handler
2527 *
2528 * Returns the new parser output or NULL
2529 */
2530xmlOutputBufferPtr
2531xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
2532 xmlOutputCloseCallback ioclose, void *ioctx,
2533 xmlCharEncodingHandlerPtr encoder) {
2534 xmlOutputBufferPtr ret;
2535
2536 if (iowrite == NULL) return(NULL);
2537
2538 ret = xmlAllocOutputBuffer(encoder);
2539 if (ret != NULL) {
2540 ret->context = (void *) ioctx;
2541 ret->writecallback = iowrite;
2542 ret->closecallback = ioclose;
2543 }
2544
2545 return(ret);
2546}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002547#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002548
2549/**
2550 * xmlParserInputBufferPush:
2551 * @in: a buffered parser input
2552 * @len: the size in bytes of the array.
2553 * @buf: an char array
2554 *
2555 * Push the content of the arry in the input buffer
2556 * This routine handle the I18N transcoding to internal UTF-8
2557 * This is used when operating the parser in progressive (push) mode.
2558 *
2559 * Returns the number of chars read and stored in the buffer, or -1
2560 * in case of error.
2561 */
2562int
2563xmlParserInputBufferPush(xmlParserInputBufferPtr in,
2564 int len, const char *buf) {
2565 int nbchars = 0;
2566
2567 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002568 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002569 if (in->encoder != NULL) {
2570 /*
2571 * Store the data in the incoming raw buffer
2572 */
2573 if (in->raw == NULL) {
2574 in->raw = xmlBufferCreate();
2575 }
2576 xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
2577
2578 /*
2579 * convert as much as possible to the parser reading buffer.
2580 */
2581 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2582 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002583 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002584 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002585 return(-1);
2586 }
2587 } else {
2588 nbchars = len;
2589 xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
2590 }
2591#ifdef DEBUG_INPUT
2592 xmlGenericError(xmlGenericErrorContext,
2593 "I/O: pushed %d chars, buffer %d/%d\n",
2594 nbchars, in->buffer->use, in->buffer->size);
2595#endif
2596 return(nbchars);
2597}
2598
2599/**
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002600 * endOfInput:
2601 *
2602 * When reading from an Input channel indicated end of file or error
2603 * don't reread from it again.
2604 */
2605static int
2606endOfInput (void * context ATTRIBUTE_UNUSED,
2607 char * buffer ATTRIBUTE_UNUSED,
2608 int len ATTRIBUTE_UNUSED) {
2609 return(0);
2610}
2611
2612/**
Owen Taylor3473f882001-02-23 17:55:21 +00002613 * xmlParserInputBufferGrow:
2614 * @in: a buffered parser input
2615 * @len: indicative value of the amount of chars to read
2616 *
2617 * Grow up the content of the input buffer, the old data are preserved
2618 * This routine handle the I18N transcoding to internal UTF-8
2619 * This routine is used when operating the parser in normal (pull) mode
2620 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002621 * TODO: one should be able to remove one extra copy by copying directly
Owen Taylor3473f882001-02-23 17:55:21 +00002622 * onto in->buffer or in->raw
2623 *
2624 * Returns the number of chars read and stored in the buffer, or -1
2625 * in case of error.
2626 */
2627int
2628xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
2629 char *buffer = NULL;
2630 int res = 0;
2631 int nbchars = 0;
2632 int buffree;
Daniel Veillard9e412302002-06-10 15:59:44 +00002633 unsigned int needSize;
Owen Taylor3473f882001-02-23 17:55:21 +00002634
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002635 if ((in == NULL) || (in->error)) return(-1);
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002636 if ((len <= MINLEN) && (len != 4))
Owen Taylor3473f882001-02-23 17:55:21 +00002637 len = MINLEN;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002638
Owen Taylor3473f882001-02-23 17:55:21 +00002639 buffree = in->buffer->size - in->buffer->use;
2640 if (buffree <= 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002641 xmlIOErr(XML_IO_BUFFER_FULL, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002642 in->error = XML_IO_BUFFER_FULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002643 return(0);
2644 }
Owen Taylor3473f882001-02-23 17:55:21 +00002645
Daniel Veillarde5354492002-05-16 08:43:22 +00002646 needSize = in->buffer->use + len + 1;
2647 if (needSize > in->buffer->size){
2648 if (!xmlBufferResize(in->buffer, needSize)){
Daniel Veillard05d987b2003-10-08 11:54:57 +00002649 xmlIOErrMemory("growing input buffer");
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002650 in->error = XML_ERR_NO_MEMORY;
Daniel Veillarde5354492002-05-16 08:43:22 +00002651 return(0);
2652 }
Owen Taylor3473f882001-02-23 17:55:21 +00002653 }
Daniel Veillarde5354492002-05-16 08:43:22 +00002654 buffer = (char *)&in->buffer->content[in->buffer->use];
Owen Taylor3473f882001-02-23 17:55:21 +00002655
2656 /*
2657 * Call the read method for this I/O type.
2658 */
2659 if (in->readcallback != NULL) {
2660 res = in->readcallback(in->context, &buffer[0], len);
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002661 if (res <= 0)
2662 in->readcallback = endOfInput;
Owen Taylor3473f882001-02-23 17:55:21 +00002663 } else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002664 xmlIOErr(XML_IO_NO_INPUT, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002665 in->error = XML_IO_NO_INPUT;
Owen Taylor3473f882001-02-23 17:55:21 +00002666 return(-1);
2667 }
2668 if (res < 0) {
Owen Taylor3473f882001-02-23 17:55:21 +00002669 return(-1);
2670 }
2671 len = res;
2672 if (in->encoder != NULL) {
2673 /*
2674 * Store the data in the incoming raw buffer
2675 */
2676 if (in->raw == NULL) {
2677 in->raw = xmlBufferCreate();
2678 }
2679 xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
2680
2681 /*
2682 * convert as much as possible to the parser reading buffer.
2683 */
2684 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2685 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002686 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002687 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002688 return(-1);
2689 }
2690 } else {
2691 nbchars = len;
Daniel Veillarde5354492002-05-16 08:43:22 +00002692 in->buffer->use += nbchars;
2693 buffer[nbchars] = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002694 }
2695#ifdef DEBUG_INPUT
2696 xmlGenericError(xmlGenericErrorContext,
2697 "I/O: read %d chars, buffer %d/%d\n",
2698 nbchars, in->buffer->use, in->buffer->size);
2699#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002700 return(nbchars);
2701}
2702
2703/**
2704 * xmlParserInputBufferRead:
2705 * @in: a buffered parser input
2706 * @len: indicative value of the amount of chars to read
2707 *
2708 * Refresh the content of the input buffer, the old data are considered
2709 * consumed
2710 * This routine handle the I18N transcoding to internal UTF-8
2711 *
2712 * Returns the number of chars read and stored in the buffer, or -1
2713 * in case of error.
2714 */
2715int
2716xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002717 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002718 if (in->readcallback != NULL)
2719 return(xmlParserInputBufferGrow(in, len));
Daniel Veillard53350552003-09-18 13:35:51 +00002720 else if ((in->buffer != NULL) &&
2721 (in->buffer->alloc == XML_BUFFER_ALLOC_IMMUTABLE))
2722 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002723 else
2724 return(-1);
2725}
2726
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002727#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002728/**
2729 * xmlOutputBufferWrite:
2730 * @out: a buffered parser output
2731 * @len: the size in bytes of the array.
2732 * @buf: an char array
2733 *
2734 * Write the content of the array in the output I/O buffer
2735 * This routine handle the I18N transcoding from internal UTF-8
2736 * The buffer is lossless, i.e. will store in case of partial
2737 * or delayed writes.
2738 *
2739 * Returns the number of chars immediately written, or -1
2740 * in case of error.
2741 */
2742int
2743xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
2744 int nbchars = 0; /* number of chars to output to I/O */
2745 int ret; /* return from function call */
2746 int written = 0; /* number of char written to I/O so far */
2747 int chunk; /* number of byte curreent processed from buf */
2748
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002749 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002750 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002751 if (out->error) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002752
2753 do {
2754 chunk = len;
2755 if (chunk > 4 * MINLEN)
2756 chunk = 4 * MINLEN;
2757
2758 /*
2759 * first handle encoding stuff.
2760 */
2761 if (out->encoder != NULL) {
2762 /*
2763 * Store the data in the incoming raw buffer
2764 */
2765 if (out->conv == NULL) {
2766 out->conv = xmlBufferCreate();
2767 }
2768 xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2769
2770 if ((out->buffer->use < MINLEN) && (chunk == len))
2771 goto done;
2772
2773 /*
2774 * convert as much as possible to the parser reading buffer.
2775 */
2776 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
Daniel Veillard809faa52003-02-10 15:43:53 +00002777 if ((ret < 0) && (ret != -3)) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002778 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002779 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002780 return(-1);
2781 }
2782 nbchars = out->conv->use;
2783 } else {
2784 xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2785 nbchars = out->buffer->use;
2786 }
2787 buf += chunk;
2788 len -= chunk;
2789
2790 if ((nbchars < MINLEN) && (len <= 0))
2791 goto done;
2792
2793 if (out->writecallback) {
2794 /*
2795 * second write the stuff to the I/O channel
2796 */
2797 if (out->encoder != NULL) {
2798 ret = out->writecallback(out->context,
2799 (const char *)out->conv->content, nbchars);
2800 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002801 xmlBufferShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002802 } else {
2803 ret = out->writecallback(out->context,
2804 (const char *)out->buffer->content, nbchars);
2805 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002806 xmlBufferShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002807 }
2808 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002809 xmlIOErr(XML_IO_WRITE, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002810 out->error = XML_IO_WRITE;
Owen Taylor3473f882001-02-23 17:55:21 +00002811 return(ret);
2812 }
2813 out->written += ret;
2814 }
2815 written += nbchars;
2816 } while (len > 0);
2817
2818done:
2819#ifdef DEBUG_INPUT
2820 xmlGenericError(xmlGenericErrorContext,
2821 "I/O: wrote %d chars\n", written);
2822#endif
2823 return(written);
2824}
2825
2826/**
2827 * xmlOutputBufferWriteString:
2828 * @out: a buffered parser output
2829 * @str: a zero terminated C string
2830 *
2831 * Write the content of the string in the output I/O buffer
2832 * This routine handle the I18N transcoding from internal UTF-8
2833 * The buffer is lossless, i.e. will store in case of partial
2834 * or delayed writes.
2835 *
2836 * Returns the number of chars immediately written, or -1
2837 * in case of error.
2838 */
2839int
2840xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
2841 int len;
2842
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002843 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002844 if (str == NULL)
2845 return(-1);
2846 len = strlen(str);
2847
2848 if (len > 0)
2849 return(xmlOutputBufferWrite(out, len, str));
2850 return(len);
2851}
2852
2853/**
2854 * xmlOutputBufferFlush:
2855 * @out: a buffered output
2856 *
2857 * flushes the output I/O channel
2858 *
2859 * Returns the number of byte written or -1 in case of error.
2860 */
2861int
2862xmlOutputBufferFlush(xmlOutputBufferPtr out) {
2863 int nbchars = 0, ret = 0;
2864
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002865 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002866 /*
2867 * first handle encoding stuff.
2868 */
2869 if ((out->conv != NULL) && (out->encoder != NULL)) {
2870 /*
2871 * convert as much as possible to the parser reading buffer.
2872 */
2873 nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
2874 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002875 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002876 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002877 return(-1);
2878 }
2879 }
2880
2881 /*
2882 * second flush the stuff to the I/O channel
2883 */
2884 if ((out->conv != NULL) && (out->encoder != NULL) &&
2885 (out->writecallback != NULL)) {
2886 ret = out->writecallback(out->context,
2887 (const char *)out->conv->content, out->conv->use);
2888 if (ret >= 0)
2889 xmlBufferShrink(out->conv, ret);
2890 } else if (out->writecallback != NULL) {
2891 ret = out->writecallback(out->context,
2892 (const char *)out->buffer->content, out->buffer->use);
2893 if (ret >= 0)
2894 xmlBufferShrink(out->buffer, ret);
2895 }
2896 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002897 xmlIOErr(XML_IO_FLUSH, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002898 out->error = XML_IO_FLUSH;
Owen Taylor3473f882001-02-23 17:55:21 +00002899 return(ret);
2900 }
2901 out->written += ret;
2902
2903#ifdef DEBUG_INPUT
2904 xmlGenericError(xmlGenericErrorContext,
2905 "I/O: flushed %d chars\n", ret);
2906#endif
2907 return(ret);
2908}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002909#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002910
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002911/**
Owen Taylor3473f882001-02-23 17:55:21 +00002912 * xmlParserGetDirectory:
2913 * @filename: the path to a file
2914 *
2915 * lookup the directory for that file
2916 *
2917 * Returns a new allocated string containing the directory, or NULL.
2918 */
2919char *
2920xmlParserGetDirectory(const char *filename) {
2921 char *ret = NULL;
2922 char dir[1024];
2923 char *cur;
2924 char sep = '/';
2925
Igor Zlatkovic9181cc02002-09-29 17:51:06 +00002926#ifdef _WIN32_WCE /* easy way by now ... wince does not have dirs! */
2927 return NULL;
2928#endif
2929
Owen Taylor3473f882001-02-23 17:55:21 +00002930 if (xmlInputCallbackInitialized == 0)
2931 xmlRegisterDefaultInputCallbacks();
2932
2933 if (filename == NULL) return(NULL);
Daniel Veillard3c5ed912002-01-08 10:36:16 +00002934#if defined(WIN32) && !defined(__CYGWIN__)
Owen Taylor3473f882001-02-23 17:55:21 +00002935 sep = '\\';
2936#endif
2937
2938 strncpy(dir, filename, 1023);
2939 dir[1023] = 0;
2940 cur = &dir[strlen(dir)];
2941 while (cur > dir) {
2942 if (*cur == sep) break;
2943 cur --;
2944 }
2945 if (*cur == sep) {
2946 if (cur == dir) dir[1] = 0;
2947 else *cur = 0;
2948 ret = xmlMemStrdup(dir);
2949 } else {
2950 if (getcwd(dir, 1024) != NULL) {
2951 dir[1023] = 0;
2952 ret = xmlMemStrdup(dir);
2953 }
2954 }
2955 return(ret);
2956}
2957
2958/****************************************************************
2959 * *
2960 * External entities loading *
2961 * *
2962 ****************************************************************/
2963
Daniel Veillarda840b692003-10-19 13:35:37 +00002964/**
2965 * xmlCheckHTTPInput:
2966 * @ctxt: an XML parser context
2967 * @ret: an XML parser input
2968 *
2969 * Check an input in case it was created from an HTTP stream, in that
2970 * case it will handle encoding and update of the base URL in case of
2971 * redirection. It also checks for HTTP errors in which case the input
2972 * is cleanly freed up and an appropriate error is raised in context
2973 *
2974 * Returns the input or NULL in case of HTTP error.
2975 */
2976xmlParserInputPtr
2977xmlCheckHTTPInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr ret) {
2978#ifdef LIBXML_HTTP_ENABLED
2979 if ((ret != NULL) && (ret->buf != NULL) &&
2980 (ret->buf->readcallback == xmlIOHTTPRead) &&
2981 (ret->buf->context != NULL)) {
2982 const char *encoding;
2983 const char *redir;
2984 const char *mime;
2985 int code;
2986
2987 code = xmlNanoHTTPReturnCode(ret->buf->context);
2988 if (code >= 400) {
2989 /* fatal error */
2990 if (ret->filename != NULL)
2991 xmlLoaderErr(ctxt, "failed to load HTTP resource \"%s\"\n",
2992 (const char *) ret->filename);
2993 else
2994 xmlLoaderErr(ctxt, "failed to load HTTP resource\n", NULL);
2995 xmlFreeInputStream(ret);
2996 ret = NULL;
2997 } else {
2998
2999 mime = xmlNanoHTTPMimeType(ret->buf->context);
3000 if ((xmlStrstr(BAD_CAST mime, BAD_CAST "/xml")) ||
3001 (xmlStrstr(BAD_CAST mime, BAD_CAST "+xml"))) {
3002 encoding = xmlNanoHTTPEncoding(ret->buf->context);
3003 if (encoding != NULL) {
3004 xmlCharEncodingHandlerPtr handler;
3005
3006 handler = xmlFindCharEncodingHandler(encoding);
3007 if (handler != NULL) {
3008 xmlSwitchInputEncoding(ctxt, ret, handler);
3009 } else {
3010 __xmlErrEncoding(ctxt, XML_ERR_UNKNOWN_ENCODING,
3011 "Unknown encoding %s",
3012 BAD_CAST encoding, NULL);
3013 }
3014 if (ret->encoding == NULL)
3015 ret->encoding = xmlStrdup(BAD_CAST encoding);
3016 }
3017#if 0
3018 } else if (xmlStrstr(BAD_CAST mime, BAD_CAST "html")) {
3019#endif
3020 }
3021 redir = xmlNanoHTTPRedir(ret->buf->context);
3022 if (redir != NULL) {
3023 if (ret->filename != NULL)
3024 xmlFree((xmlChar *) ret->filename);
3025 if (ret->directory != NULL) {
3026 xmlFree((xmlChar *) ret->directory);
3027 ret->directory = NULL;
3028 }
3029 ret->filename =
3030 (char *) xmlStrdup((const xmlChar *) redir);
3031 }
3032 }
3033 }
3034#endif
3035 return(ret);
3036}
3037
Daniel Veillard561b7f82002-03-20 21:55:57 +00003038static int xmlSysIDExists(const char *URL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003039#ifdef HAVE_STAT
3040 int ret;
3041 struct stat info;
3042 const char *path;
3043
3044 if (URL == NULL)
3045 return(0);
3046
Daniel Veillardf4862f02002-09-10 11:13:43 +00003047 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003048#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00003049 path = &URL[17];
3050#else
Daniel Veillard6990bf32001-08-23 21:17:48 +00003051 path = &URL[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00003052#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003053 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003054#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard6990bf32001-08-23 21:17:48 +00003055 path = &URL[8];
3056#else
3057 path = &URL[7];
3058#endif
3059 } else
3060 path = URL;
3061 ret = stat(path, &info);
Daniel Veillard561b7f82002-03-20 21:55:57 +00003062 if (ret == 0)
3063 return(1);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003064#endif
Daniel Veillard561b7f82002-03-20 21:55:57 +00003065 return(0);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003066}
Daniel Veillard6990bf32001-08-23 21:17:48 +00003067
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003068/**
Owen Taylor3473f882001-02-23 17:55:21 +00003069 * xmlDefaultExternalEntityLoader:
3070 * @URL: the URL for the entity to load
3071 * @ID: the System ID for the entity to load
3072 * @ctxt: the context in which the entity is called or NULL
3073 *
3074 * By default we don't load external entitites, yet.
3075 *
3076 * Returns a new allocated xmlParserInputPtr, or NULL.
3077 */
Daniel Veillarda840b692003-10-19 13:35:37 +00003078static xmlParserInputPtr
Owen Taylor3473f882001-02-23 17:55:21 +00003079xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
Daniel Veillarda840b692003-10-19 13:35:37 +00003080 xmlParserCtxtPtr ctxt)
3081{
Owen Taylor3473f882001-02-23 17:55:21 +00003082 xmlParserInputPtr ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003083 xmlChar *resource = NULL;
Daniel Veillarda840b692003-10-19 13:35:37 +00003084
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003085#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003086 xmlCatalogAllow pref;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003087#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003088
3089#ifdef DEBUG_EXTERNAL_ENTITIES
3090 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda840b692003-10-19 13:35:37 +00003091 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00003092#endif
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003093#ifdef LIBXML_CATALOG_ENABLED
3094 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003095 * If the resource doesn't exists as a file,
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003096 * try to load it from the resource pointed in the catalogs
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003097 */
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003098 pref = xmlCatalogGetDefaults();
3099
Daniel Veillard561b7f82002-03-20 21:55:57 +00003100 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlSysIDExists(URL))) {
Daniel Veillarda840b692003-10-19 13:35:37 +00003101 /*
3102 * Do a local lookup
3103 */
3104 if ((ctxt->catalogs != NULL) &&
3105 ((pref == XML_CATA_ALLOW_ALL) ||
3106 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3107 resource = xmlCatalogLocalResolve(ctxt->catalogs,
3108 (const xmlChar *) ID,
3109 (const xmlChar *) URL);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003110 }
Daniel Veillarda840b692003-10-19 13:35:37 +00003111 /*
3112 * Try a global lookup
3113 */
3114 if ((resource == NULL) &&
3115 ((pref == XML_CATA_ALLOW_ALL) ||
3116 (pref == XML_CATA_ALLOW_GLOBAL))) {
3117 resource = xmlCatalogResolve((const xmlChar *) ID,
3118 (const xmlChar *) URL);
3119 }
3120 if ((resource == NULL) && (URL != NULL))
3121 resource = xmlStrdup((const xmlChar *) URL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003122
Daniel Veillarda840b692003-10-19 13:35:37 +00003123 /*
3124 * TODO: do an URI lookup on the reference
3125 */
3126 if ((resource != NULL)
3127 && (!xmlSysIDExists((const char *) resource))) {
3128 xmlChar *tmp = NULL;
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003129
Daniel Veillarda840b692003-10-19 13:35:37 +00003130 if ((ctxt->catalogs != NULL) &&
3131 ((pref == XML_CATA_ALLOW_ALL) ||
3132 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3133 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
3134 }
3135 if ((tmp == NULL) &&
3136 ((pref == XML_CATA_ALLOW_ALL) ||
3137 (pref == XML_CATA_ALLOW_GLOBAL))) {
3138 tmp = xmlCatalogResolveURI(resource);
3139 }
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003140
Daniel Veillarda840b692003-10-19 13:35:37 +00003141 if (tmp != NULL) {
3142 xmlFree(resource);
3143 resource = tmp;
3144 }
3145 }
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003146 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003147#endif
3148
3149 if (resource == NULL)
Daniel Veillarda840b692003-10-19 13:35:37 +00003150 resource = (xmlChar *) URL;
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003151
3152 if (resource == NULL) {
Daniel Veillarda840b692003-10-19 13:35:37 +00003153 if (ID == NULL)
3154 ID = "NULL";
3155 xmlLoaderErr(ctxt, "failed to load external entity \"%s\"\n", ID);
3156 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003157 }
Daniel Veillarda840b692003-10-19 13:35:37 +00003158 ret = xmlNewInputFromFile(ctxt, (const char *) resource);
Owen Taylor3473f882001-02-23 17:55:21 +00003159 if (ret == NULL) {
Daniel Veillarda840b692003-10-19 13:35:37 +00003160 xmlLoaderErr(ctxt, "failed to load external entity \"%s\"\n",
3161 (const char *) resource);
Daniel Veillard847332a2003-10-18 11:29:40 +00003162 }
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003163 if ((resource != NULL) && (resource != (xmlChar *) URL))
Daniel Veillarda840b692003-10-19 13:35:37 +00003164 xmlFree(resource);
3165 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003166}
3167
3168static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
3169 xmlDefaultExternalEntityLoader;
3170
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003171/**
Owen Taylor3473f882001-02-23 17:55:21 +00003172 * xmlSetExternalEntityLoader:
3173 * @f: the new entity resolver function
3174 *
3175 * Changes the defaultexternal entity resolver function for the application
3176 */
3177void
3178xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
3179 xmlCurrentExternalEntityLoader = f;
3180}
3181
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003182/**
Owen Taylor3473f882001-02-23 17:55:21 +00003183 * xmlGetExternalEntityLoader:
3184 *
3185 * Get the default external entity resolver function for the application
3186 *
3187 * Returns the xmlExternalEntityLoader function pointer
3188 */
3189xmlExternalEntityLoader
3190xmlGetExternalEntityLoader(void) {
3191 return(xmlCurrentExternalEntityLoader);
3192}
3193
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003194/**
Owen Taylor3473f882001-02-23 17:55:21 +00003195 * xmlLoadExternalEntity:
3196 * @URL: the URL for the entity to load
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00003197 * @ID: the Public ID for the entity to load
Owen Taylor3473f882001-02-23 17:55:21 +00003198 * @ctxt: the context in which the entity is called or NULL
3199 *
3200 * Load an external entity, note that the use of this function for
3201 * unparsed entities may generate problems
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003202 * TODO: a more generic External entity API must be designed
Owen Taylor3473f882001-02-23 17:55:21 +00003203 *
3204 * Returns the xmlParserInputPtr or NULL
3205 */
3206xmlParserInputPtr
3207xmlLoadExternalEntity(const char *URL, const char *ID,
3208 xmlParserCtxtPtr ctxt) {
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00003209 if ((URL != NULL) && (xmlSysIDExists(URL) == 0)) {
3210 char *canonicFilename;
3211 xmlParserInputPtr ret;
3212
3213 canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL);
3214 if (canonicFilename == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003215 xmlIOErrMemory("building canonical path\n");
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00003216 return(NULL);
3217 }
3218
3219 ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt);
3220 xmlFree(canonicFilename);
3221 return(ret);
3222 }
Owen Taylor3473f882001-02-23 17:55:21 +00003223 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
3224}
3225
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003226/************************************************************************
3227 * *
3228 * Disabling Network access *
3229 * *
3230 ************************************************************************/
3231
3232#ifdef LIBXML_CATALOG_ENABLED
3233static int
3234xmlNoNetExists(const char *URL)
3235{
3236#ifdef HAVE_STAT
3237 int ret;
3238 struct stat info;
3239 const char *path;
3240
3241 if (URL == NULL)
3242 return (0);
3243
Daniel Veillardf4862f02002-09-10 11:13:43 +00003244 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003245#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00003246 path = &URL[17];
3247#else
3248 path = &URL[16];
3249#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003250 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003251#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003252 path = &URL[8];
3253#else
3254 path = &URL[7];
3255#endif
3256 } else
3257 path = URL;
3258 ret = stat(path, &info);
3259 if (ret == 0)
3260 return (1);
3261#endif
3262 return (0);
3263}
3264#endif
3265
3266/**
3267 * xmlNoNetExternalEntityLoader:
3268 * @URL: the URL for the entity to load
3269 * @ID: the System ID for the entity to load
3270 * @ctxt: the context in which the entity is called or NULL
3271 *
3272 * A specific entity loader disabling network accesses, though still
3273 * allowing local catalog accesses for resolution.
3274 *
3275 * Returns a new allocated xmlParserInputPtr, or NULL.
3276 */
3277xmlParserInputPtr
3278xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
3279 xmlParserCtxtPtr ctxt) {
3280 xmlParserInputPtr input = NULL;
3281 xmlChar *resource = NULL;
3282
3283#ifdef LIBXML_CATALOG_ENABLED
3284 xmlCatalogAllow pref;
3285
3286 /*
3287 * If the resource doesn't exists as a file,
3288 * try to load it from the resource pointed in the catalogs
3289 */
3290 pref = xmlCatalogGetDefaults();
3291
3292 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
3293 /*
3294 * Do a local lookup
3295 */
3296 if ((ctxt->catalogs != NULL) &&
3297 ((pref == XML_CATA_ALLOW_ALL) ||
3298 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3299 resource = xmlCatalogLocalResolve(ctxt->catalogs,
3300 (const xmlChar *)ID,
3301 (const xmlChar *)URL);
3302 }
3303 /*
3304 * Try a global lookup
3305 */
3306 if ((resource == NULL) &&
3307 ((pref == XML_CATA_ALLOW_ALL) ||
3308 (pref == XML_CATA_ALLOW_GLOBAL))) {
3309 resource = xmlCatalogResolve((const xmlChar *)ID,
3310 (const xmlChar *)URL);
3311 }
3312 if ((resource == NULL) && (URL != NULL))
3313 resource = xmlStrdup((const xmlChar *) URL);
3314
3315 /*
3316 * TODO: do an URI lookup on the reference
3317 */
3318 if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
3319 xmlChar *tmp = NULL;
3320
3321 if ((ctxt->catalogs != NULL) &&
3322 ((pref == XML_CATA_ALLOW_ALL) ||
3323 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3324 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
3325 }
3326 if ((tmp == NULL) &&
3327 ((pref == XML_CATA_ALLOW_ALL) ||
3328 (pref == XML_CATA_ALLOW_GLOBAL))) {
3329 tmp = xmlCatalogResolveURI(resource);
3330 }
3331
3332 if (tmp != NULL) {
3333 xmlFree(resource);
3334 resource = tmp;
3335 }
3336 }
3337 }
3338#endif
3339 if (resource == NULL)
3340 resource = (xmlChar *) URL;
3341
3342 if (resource != NULL) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003343 if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
3344 (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003345 xmlIOErr(XML_IO_NETWORK_ATTEMPT, (const char *) resource);
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003346 if (resource != (xmlChar *) URL)
3347 xmlFree(resource);
3348 return(NULL);
3349 }
3350 }
3351 input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
3352 if (resource != (xmlChar *) URL)
3353 xmlFree(resource);
3354 return(input);
3355}
3356