blob: 9f2fecb164f5a7b0afedf5fe926c2f22a0d3f800 [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/**
Daniel Veillarde8039df2003-10-27 11:25:13 +0000397 * __xmlLoaderErr:
398 * @ctx: the parser context
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000399 * @extra: extra informations
400 *
401 * Handle a resource access error
402 */
Daniel Veillarde8039df2003-10-27 11:25:13 +0000403void
404__xmlLoaderErr(void *ctx, const char *msg, const char *filename)
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000405{
Daniel Veillarde8039df2003-10-27 11:25:13 +0000406 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000407 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000408 xmlGenericErrorFunc channel = NULL;
409 void *data = NULL;
410 xmlErrorLevel level = XML_ERR_ERROR;
411
412 if ((ctxt != NULL) && (ctxt->sax != NULL)) {
413 if (ctxt->validate) {
414 channel = ctxt->sax->error;
415 level = XML_ERR_ERROR;
416 } else {
417 channel = ctxt->sax->warning;
418 level = XML_ERR_WARNING;
419 }
Daniel Veillard659e71e2003-10-10 14:10:40 +0000420 schannel = ctxt->sax->serror;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000421 data = ctxt->userData;
422 }
Daniel Veillard659e71e2003-10-10 14:10:40 +0000423 __xmlRaiseError(schannel, channel, data, ctxt, NULL, XML_FROM_IO,
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000424 XML_IO_LOAD_ERROR, level, NULL, 0,
425 filename, NULL, NULL, 0, 0,
426 msg, filename);
427
428}
429
Daniel Veillard05d987b2003-10-08 11:54:57 +0000430/************************************************************************
431 * *
432 * Tree memory error handler *
433 * *
434 ************************************************************************/
Daniel Veillardf4862f02002-09-10 11:13:43 +0000435/**
Daniel Veillard01c13b52002-12-10 15:19:08 +0000436 * xmlNormalizeWindowsPath:
Daniel Veillard33300b42003-04-17 09:09:19 +0000437 * @path: the input file path
Daniel Veillardf4862f02002-09-10 11:13:43 +0000438 *
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +0000439 * This function is obsolete. Please see xmlURIFromPath in uri.c for
440 * a better solution.
Daniel Veillard33300b42003-04-17 09:09:19 +0000441 *
442 * Returns a canonicalized version of the path
Daniel Veillardf4862f02002-09-10 11:13:43 +0000443 */
444xmlChar *
445xmlNormalizeWindowsPath(const xmlChar *path)
446{
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +0000447 return xmlCanonicPath(path);
Daniel Veillardf4862f02002-09-10 11:13:43 +0000448}
449
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000450/**
451 * xmlCleanupInputCallbacks:
452 *
453 * clears the entire input callback table. this includes the
454 * compiled-in I/O.
455 */
456void
457xmlCleanupInputCallbacks(void)
458{
459 int i;
460
461 if (!xmlInputCallbackInitialized)
462 return;
463
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000464 for (i = xmlInputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000465 xmlInputCallbackTable[i].matchcallback = NULL;
466 xmlInputCallbackTable[i].opencallback = NULL;
467 xmlInputCallbackTable[i].readcallback = NULL;
468 xmlInputCallbackTable[i].closecallback = NULL;
469 }
470
471 xmlInputCallbackNr = 0;
Aleksey Sanin9c45ba82002-06-06 21:46:13 +0000472 xmlInputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000473}
474
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000475#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000476/**
477 * xmlCleanupOutputCallbacks:
478 *
479 * clears the entire output callback table. this includes the
480 * compiled-in I/O callbacks.
481 */
482void
483xmlCleanupOutputCallbacks(void)
484{
485 int i;
486
487 if (!xmlOutputCallbackInitialized)
488 return;
489
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000490 for (i = xmlOutputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000491 xmlOutputCallbackTable[i].matchcallback = NULL;
492 xmlOutputCallbackTable[i].opencallback = NULL;
493 xmlOutputCallbackTable[i].writecallback = NULL;
494 xmlOutputCallbackTable[i].closecallback = NULL;
495 }
496
497 xmlOutputCallbackNr = 0;
Aleksey Sanin9c45ba82002-06-06 21:46:13 +0000498 xmlOutputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000499}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000500#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000501
Owen Taylor3473f882001-02-23 17:55:21 +0000502/************************************************************************
503 * *
504 * Standard I/O for file accesses *
505 * *
506 ************************************************************************/
507
508/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000509 * xmlCheckFilename:
Owen Taylor3473f882001-02-23 17:55:21 +0000510 * @path: the path to check
511 *
512 * function checks to see if @path is a valid source
513 * (file, socket...) for XML.
514 *
515 * if stat is not available on the target machine,
516 * returns 1. if stat fails, returns 0 (if calling
517 * stat on the filename fails, it can't be right).
518 * if stat succeeds and the file is a directory,
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000519 * returns 2. otherwise returns 1.
Owen Taylor3473f882001-02-23 17:55:21 +0000520 */
521
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000522int
Owen Taylor3473f882001-02-23 17:55:21 +0000523xmlCheckFilename (const char *path)
524{
525#ifdef HAVE_STAT
Owen Taylor3473f882001-02-23 17:55:21 +0000526 struct stat stat_buffer;
527
528 if (stat(path, &stat_buffer) == -1)
529 return 0;
530
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000531#ifdef S_ISDIR
Owen Taylor3473f882001-02-23 17:55:21 +0000532 if (S_ISDIR(stat_buffer.st_mode)) {
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000533 return 2;
Owen Taylor3473f882001-02-23 17:55:21 +0000534 }
Owen Taylor3473f882001-02-23 17:55:21 +0000535#endif
536#endif
537 return 1;
538}
539
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000540static int
Owen Taylor3473f882001-02-23 17:55:21 +0000541xmlNop(void) {
542 return(0);
543}
544
545/**
Owen Taylor3473f882001-02-23 17:55:21 +0000546 * xmlFdRead:
547 * @context: the I/O context
548 * @buffer: where to drop data
549 * @len: number of bytes to read
550 *
551 * Read @len bytes to @buffer from the I/O channel.
552 *
553 * Returns the number of bytes written
554 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000555static int
Owen Taylor3473f882001-02-23 17:55:21 +0000556xmlFdRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000557 int ret;
558
559 ret = read((int) (long) context, &buffer[0], len);
560 if (ret < 0) xmlIOErr(0, "read()");
561 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000562}
563
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000564#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000565/**
566 * xmlFdWrite:
567 * @context: the I/O context
568 * @buffer: where to get data
569 * @len: number of bytes to write
570 *
571 * Write @len bytes from @buffer to the I/O channel.
572 *
573 * Returns the number of bytes written
574 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000575static int
Owen Taylor3473f882001-02-23 17:55:21 +0000576xmlFdWrite (void * context, const char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000577 int ret;
578
579 ret = write((int) (long) context, &buffer[0], len);
580 if (ret < 0) xmlIOErr(0, "write()");
581 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000582}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000583#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000584
585/**
586 * xmlFdClose:
587 * @context: the I/O context
588 *
589 * Close an I/O channel
Daniel Veillardf012a642001-07-23 19:10:52 +0000590 *
591 * Returns 0 in case of success and error code otherwise
Owen Taylor3473f882001-02-23 17:55:21 +0000592 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000593static int
Owen Taylor3473f882001-02-23 17:55:21 +0000594xmlFdClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000595 int ret;
596 ret = close((int) (long) context);
597 if (ret < 0) xmlIOErr(0, "close()");
598 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000599}
600
601/**
602 * xmlFileMatch:
603 * @filename: the URI for matching
604 *
605 * input from FILE *
606 *
607 * Returns 1 if matches, 0 otherwise
608 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000609int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000610xmlFileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000611 return(1);
612}
613
614/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000615 * xmlFileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +0000616 * @filename: the URI for matching
617 *
618 * input from FILE *, supports compressed input
619 * if @filename is " " then the standard input is used
620 *
621 * Returns an I/O context or NULL in case of error
622 */
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000623static void *
624xmlFileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +0000625 const char *path = NULL;
626 FILE *fd;
627
628 if (!strcmp(filename, "-")) {
629 fd = stdin;
630 return((void *) fd);
631 }
632
Daniel Veillardf4862f02002-09-10 11:13:43 +0000633 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000634#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000635 path = &filename[17];
636#else
Owen Taylor3473f882001-02-23 17:55:21 +0000637 path = &filename[16];
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000638#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000639 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000640#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000641 path = &filename[8];
642#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000643 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000644#endif
645 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000646 path = filename;
647
648 if (path == NULL)
649 return(NULL);
650 if (!xmlCheckFilename(path))
651 return(NULL);
652
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000653#if defined(WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
Owen Taylor3473f882001-02-23 17:55:21 +0000654 fd = fopen(path, "rb");
655#else
656 fd = fopen(path, "r");
657#endif /* WIN32 */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000658 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +0000659 return((void *) fd);
660}
661
662/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000663 * xmlFileOpen:
664 * @filename: the URI for matching
665 *
666 * Wrapper around xmlFileOpen_real that try it with an unescaped
667 * version of @filename, if this fails fallback to @filename
Daniel Veillard71531f32003-02-05 13:19:53 +0000668 *
669 * Returns a handler or NULL in case or failure
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000670 */
671void *
672xmlFileOpen (const char *filename) {
673 char *unescaped;
674 void *retval;
675 unescaped = xmlURIUnescapeString(filename, 0, NULL);
676 if (unescaped != NULL) {
677 retval = xmlFileOpen_real(unescaped);
678 } else {
679 retval = xmlFileOpen_real(filename);
680 }
681 xmlFree(unescaped);
682 return retval;
683}
684
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000685#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000686/**
Owen Taylor3473f882001-02-23 17:55:21 +0000687 * xmlFileOpenW:
688 * @filename: the URI for matching
689 *
690 * output to from FILE *,
691 * if @filename is "-" then the standard output is used
692 *
693 * Returns an I/O context or NULL in case of error
694 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000695static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000696xmlFileOpenW (const char *filename) {
697 const char *path = NULL;
698 FILE *fd;
699
700 if (!strcmp(filename, "-")) {
701 fd = stdout;
702 return((void *) fd);
703 }
704
Daniel Veillardf4862f02002-09-10 11:13:43 +0000705 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000706#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000707 path = &filename[17];
708#else
Owen Taylor3473f882001-02-23 17:55:21 +0000709 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000710#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000711 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000712#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000713 path = &filename[8];
714#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000715 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000716#endif
717 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000718 path = filename;
719
720 if (path == NULL)
721 return(NULL);
722
Daniel Veillardcbbd78d2003-07-20 15:21:30 +0000723 fd = fopen(path, "wb");
Daniel Veillard05d987b2003-10-08 11:54:57 +0000724 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +0000725 return((void *) fd);
726}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000727#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000728
729/**
730 * xmlFileRead:
731 * @context: the I/O context
732 * @buffer: where to drop data
733 * @len: number of bytes to write
734 *
735 * Read @len bytes to @buffer from the I/O channel.
736 *
737 * Returns the number of bytes written
738 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000739int
Owen Taylor3473f882001-02-23 17:55:21 +0000740xmlFileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000741 int ret;
742 ret = fread(&buffer[0], 1, len, (FILE *) context);
743 if (ret < 0) xmlIOErr(0, "fread()");
744 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000745}
746
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000747#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000748/**
749 * xmlFileWrite:
750 * @context: the I/O context
751 * @buffer: where to drop data
752 * @len: number of bytes to write
753 *
754 * Write @len bytes from @buffer to the I/O channel.
755 *
756 * Returns the number of bytes written
757 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000758static int
Owen Taylor3473f882001-02-23 17:55:21 +0000759xmlFileWrite (void * context, const char * buffer, int len) {
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000760 int items;
761
762 items = fwrite(&buffer[0], len, 1, (FILE *) context);
Daniel Veillard97bf4d02003-10-08 18:58:28 +0000763 if ((items == 0) && (ferror((FILE *) context))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000764 xmlIOErr(0, "fwrite()");
Daniel Veillard97bf4d02003-10-08 18:58:28 +0000765 return(-1);
766 }
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000767 return(items * len);
Owen Taylor3473f882001-02-23 17:55:21 +0000768}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000769#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000770
771/**
772 * xmlFileClose:
773 * @context: the I/O context
774 *
775 * Close an I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000776 *
777 * Returns 0 or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +0000778 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000779int
Owen Taylor3473f882001-02-23 17:55:21 +0000780xmlFileClose (void * context) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000781 FILE *fil;
Daniel Veillard05d987b2003-10-08 11:54:57 +0000782 int ret;
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000783
784 fil = (FILE *) context;
785 if (fil == stdin)
786 return(0);
787 if (fil == stdout)
788 return(0);
Daniel Veillardcd337f02001-11-22 18:20:37 +0000789 if (fil == stderr)
790 return(0);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000791 ret = ( fclose((FILE *) context) == EOF ) ? -1 : 0;
792 if (ret < 0)
793 xmlIOErr(0, "fclose()");
794 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000795}
796
797/**
798 * xmlFileFlush:
799 * @context: the I/O context
800 *
801 * Flush an I/O channel
802 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000803static int
Owen Taylor3473f882001-02-23 17:55:21 +0000804xmlFileFlush (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000805 int ret;
806 ret = ( fflush((FILE *) context) == EOF ) ? -1 : 0;
807 if (ret < 0)
808 xmlIOErr(0, "fflush()");
809 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000810}
811
812#ifdef HAVE_ZLIB_H
813/************************************************************************
814 * *
815 * I/O for compressed file accesses *
816 * *
817 ************************************************************************/
818/**
819 * xmlGzfileMatch:
820 * @filename: the URI for matching
821 *
822 * input from compressed file test
823 *
824 * Returns 1 if matches, 0 otherwise
825 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000826static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000827xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000828 return(1);
829}
830
831/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000832 * xmlGzfileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +0000833 * @filename: the URI for matching
834 *
835 * input from compressed file open
836 * if @filename is " " then the standard input is used
837 *
838 * Returns an I/O context or NULL in case of error
839 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000840static void *
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000841xmlGzfileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +0000842 const char *path = NULL;
843 gzFile fd;
844
845 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000846 fd = gzdopen(dup(0), "rb");
Owen Taylor3473f882001-02-23 17:55:21 +0000847 return((void *) fd);
848 }
849
Daniel Veillardf4862f02002-09-10 11:13:43 +0000850 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000851#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000852 path = &filename[17];
853#else
Owen Taylor3473f882001-02-23 17:55:21 +0000854 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000855#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000856 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000857#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000858 path = &filename[8];
859#else
Owen Taylor3473f882001-02-23 17:55:21 +0000860 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000861#endif
862 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000863 path = filename;
864
865 if (path == NULL)
866 return(NULL);
867 if (!xmlCheckFilename(path))
868 return(NULL);
869
870 fd = gzopen(path, "rb");
871 return((void *) fd);
872}
873
874/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000875 * xmlGzfileOpen:
876 * @filename: the URI for matching
877 *
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +0000878 * Wrapper around xmlGzfileOpen if the open fais, it will
879 * try to unescape @filename
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000880 */
881static void *
882xmlGzfileOpen (const char *filename) {
883 char *unescaped;
884 void *retval;
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +0000885
886 retval = xmlGzfileOpen_real(filename);
887 if (retval == NULL) {
888 unescaped = xmlURIUnescapeString(filename, 0, NULL);
889 if (unescaped != NULL) {
890 retval = xmlGzfileOpen_real(unescaped);
891 }
892 xmlFree(unescaped);
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000893 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000894 return retval;
895}
896
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000897#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000898/**
Owen Taylor3473f882001-02-23 17:55:21 +0000899 * xmlGzfileOpenW:
900 * @filename: the URI for matching
901 * @compression: the compression factor (0 - 9 included)
902 *
903 * input from compressed file open
904 * if @filename is " " then the standard input is used
905 *
906 * Returns an I/O context or NULL in case of error
907 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000908static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000909xmlGzfileOpenW (const char *filename, int compression) {
910 const char *path = NULL;
911 char mode[15];
912 gzFile fd;
913
Aleksey Sanin49cc9752002-06-14 17:07:10 +0000914 snprintf(mode, sizeof(mode), "wb%d", compression);
Owen Taylor3473f882001-02-23 17:55:21 +0000915 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000916 fd = gzdopen(dup(1), mode);
Owen Taylor3473f882001-02-23 17:55:21 +0000917 return((void *) fd);
918 }
919
Daniel Veillardf4862f02002-09-10 11:13:43 +0000920 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000921#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000922 path = &filename[17];
923#else
Owen Taylor3473f882001-02-23 17:55:21 +0000924 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000925#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000926 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000927#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000928 path = &filename[8];
929#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000930 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000931#endif
932 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000933 path = filename;
934
935 if (path == NULL)
936 return(NULL);
937
938 fd = gzopen(path, mode);
939 return((void *) fd);
940}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000941#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000942
943/**
944 * xmlGzfileRead:
945 * @context: the I/O context
946 * @buffer: where to drop data
947 * @len: number of bytes to write
948 *
949 * Read @len bytes to @buffer from the compressed I/O channel.
950 *
951 * Returns the number of bytes written
952 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000953static int
Owen Taylor3473f882001-02-23 17:55:21 +0000954xmlGzfileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000955 int ret;
956
957 ret = gzread((gzFile) context, &buffer[0], len);
958 if (ret < 0) xmlIOErr(0, "gzread()");
959 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000960}
961
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000962#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000963/**
964 * xmlGzfileWrite:
965 * @context: the I/O context
966 * @buffer: where to drop data
967 * @len: number of bytes to write
968 *
969 * Write @len bytes from @buffer to the compressed I/O channel.
970 *
971 * Returns the number of bytes written
972 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000973static int
Owen Taylor3473f882001-02-23 17:55:21 +0000974xmlGzfileWrite (void * context, const char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000975 int ret;
976
977 ret = gzwrite((gzFile) context, (char *) &buffer[0], len);
978 if (ret < 0) xmlIOErr(0, "gzwrite()");
979 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000980}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000981#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000982
983/**
984 * xmlGzfileClose:
985 * @context: the I/O context
986 *
987 * Close a compressed I/O channel
988 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000989static int
Owen Taylor3473f882001-02-23 17:55:21 +0000990xmlGzfileClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000991 int ret;
992
993 ret = (gzclose((gzFile) context) == Z_OK ) ? 0 : -1;
994 if (ret < 0) xmlIOErr(0, "gzclose()");
995 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000996}
997#endif /* HAVE_ZLIB_H */
998
999#ifdef LIBXML_HTTP_ENABLED
1000/************************************************************************
1001 * *
1002 * I/O for HTTP file accesses *
1003 * *
1004 ************************************************************************/
Daniel Veillardf012a642001-07-23 19:10:52 +00001005
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001006#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001007typedef struct xmlIOHTTPWriteCtxt_
1008{
1009 int compression;
1010
1011 char * uri;
1012
1013 void * doc_buff;
1014
1015} xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr;
1016
1017#ifdef HAVE_ZLIB_H
1018
1019#define DFLT_WBITS ( -15 )
1020#define DFLT_MEM_LVL ( 8 )
1021#define GZ_MAGIC1 ( 0x1f )
1022#define GZ_MAGIC2 ( 0x8b )
1023#define LXML_ZLIB_OS_CODE ( 0x03 )
1024#define INIT_HTTP_BUFF_SIZE ( 32768 )
1025#define DFLT_ZLIB_RATIO ( 5 )
1026
1027/*
1028** Data structure and functions to work with sending compressed data
1029** via HTTP.
1030*/
1031
1032typedef struct xmlZMemBuff_
1033{
1034 unsigned long size;
1035 unsigned long crc;
1036
1037 unsigned char * zbuff;
1038 z_stream zctrl;
1039
1040} xmlZMemBuff, *xmlZMemBuffPtr;
1041
1042/**
1043 * append_reverse_ulong
1044 * @buff: Compressed memory buffer
1045 * @data: Unsigned long to append
1046 *
1047 * Append a unsigned long in reverse byte order to the end of the
1048 * memory buffer.
1049 */
1050static void
1051append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) {
1052
1053 int idx;
1054
1055 if ( buff == NULL )
1056 return;
1057
1058 /*
1059 ** This is plagiarized from putLong in gzio.c (zlib source) where
1060 ** the number "4" is hardcoded. If zlib is ever patched to
1061 ** support 64 bit file sizes, this code would need to be patched
1062 ** as well.
1063 */
1064
1065 for ( idx = 0; idx < 4; idx++ ) {
1066 *buff->zctrl.next_out = ( data & 0xff );
1067 data >>= 8;
1068 buff->zctrl.next_out++;
1069 }
1070
1071 return;
1072}
1073
1074/**
1075 *
1076 * xmlFreeZMemBuff
1077 * @buff: The memory buffer context to clear
1078 *
1079 * Release all the resources associated with the compressed memory buffer.
1080 */
1081static void
1082xmlFreeZMemBuff( xmlZMemBuffPtr buff ) {
William M. Brack78637da2003-07-31 14:47:38 +00001083
1084#ifdef DEBUG_HTTP
Daniel Veillardf012a642001-07-23 19:10:52 +00001085 int z_err;
William M. Brack78637da2003-07-31 14:47:38 +00001086#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001087
1088 if ( buff == NULL )
1089 return;
1090
1091 xmlFree( buff->zbuff );
Daniel Veillardf012a642001-07-23 19:10:52 +00001092#ifdef DEBUG_HTTP
William M. Brack78637da2003-07-31 14:47:38 +00001093 z_err = deflateEnd( &buff->zctrl );
Daniel Veillardf012a642001-07-23 19:10:52 +00001094 if ( z_err != Z_OK )
1095 xmlGenericError( xmlGenericErrorContext,
1096 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
1097 z_err );
William M. Brack78637da2003-07-31 14:47:38 +00001098#else
1099 deflateEnd( &buff->zctrl );
William M. Brack779af002003-08-01 15:55:39 +00001100#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001101
1102 xmlFree( buff );
1103 return;
1104}
1105
1106/**
1107 * xmlCreateZMemBuff
1108 *@compression: Compression value to use
1109 *
1110 * Create a memory buffer to hold the compressed XML document. The
1111 * compressed document in memory will end up being identical to what
1112 * would be created if gzopen/gzwrite/gzclose were being used to
1113 * write the document to disk. The code for the header/trailer data to
1114 * the compression is plagiarized from the zlib source files.
1115 */
1116static void *
1117xmlCreateZMemBuff( int compression ) {
1118
1119 int z_err;
1120 int hdr_lgth;
1121 xmlZMemBuffPtr buff = NULL;
1122
1123 if ( ( compression < 1 ) || ( compression > 9 ) )
1124 return ( NULL );
1125
1126 /* Create the control and data areas */
1127
1128 buff = xmlMalloc( sizeof( xmlZMemBuff ) );
1129 if ( buff == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001130 xmlIOErrMemory("creating buffer context");
Daniel Veillardf012a642001-07-23 19:10:52 +00001131 return ( NULL );
1132 }
1133
1134 (void)memset( buff, 0, sizeof( xmlZMemBuff ) );
1135 buff->size = INIT_HTTP_BUFF_SIZE;
1136 buff->zbuff = xmlMalloc( buff->size );
1137 if ( buff->zbuff == NULL ) {
1138 xmlFreeZMemBuff( buff );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001139 xmlIOErrMemory("creating buffer");
Daniel Veillardf012a642001-07-23 19:10:52 +00001140 return ( NULL );
1141 }
1142
1143 z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
1144 DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
1145 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001146 xmlChar msg[500];
Daniel Veillardf012a642001-07-23 19:10:52 +00001147 xmlFreeZMemBuff( buff );
1148 buff = NULL;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001149 xmlStrPrintf(msg, 500,
1150 (const xmlChar *) "xmlCreateZMemBuff: %s %d\n",
1151 "Error initializing compression context. ZLIB error:",
1152 z_err );
1153 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001154 return ( NULL );
1155 }
1156
1157 /* Set the header data. The CRC will be needed for the trailer */
Daniel Veillardf012a642001-07-23 19:10:52 +00001158 buff->crc = crc32( 0L, Z_NULL, 0 );
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001159 hdr_lgth = snprintf( (char *)buff->zbuff, buff->size,
1160 "%c%c%c%c%c%c%c%c%c%c",
Daniel Veillardf012a642001-07-23 19:10:52 +00001161 GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED,
1162 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE );
1163 buff->zctrl.next_out = buff->zbuff + hdr_lgth;
1164 buff->zctrl.avail_out = buff->size - hdr_lgth;
1165
1166 return ( buff );
1167}
1168
1169/**
1170 * xmlZMemBuffExtend
1171 * @buff: Buffer used to compress and consolidate data.
1172 * @ext_amt: Number of bytes to extend the buffer.
1173 *
1174 * Extend the internal buffer used to store the compressed data by the
1175 * specified amount.
1176 *
1177 * Returns 0 on success or -1 on failure to extend the buffer. On failure
1178 * the original buffer still exists at the original size.
1179 */
1180static int
1181xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) {
1182
1183 int rc = -1;
1184 size_t new_size;
1185 size_t cur_used;
1186
1187 unsigned char * tmp_ptr = NULL;
1188
1189 if ( buff == NULL )
1190 return ( -1 );
1191
1192 else if ( ext_amt == 0 )
1193 return ( 0 );
1194
1195 cur_used = buff->zctrl.next_out - buff->zbuff;
1196 new_size = buff->size + ext_amt;
1197
1198#ifdef DEBUG_HTTP
1199 if ( cur_used > new_size )
1200 xmlGenericError( xmlGenericErrorContext,
1201 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
1202 "Buffer overwrite detected during compressed memory",
1203 "buffer extension. Overflowed by",
1204 (cur_used - new_size ) );
1205#endif
1206
1207 tmp_ptr = xmlRealloc( buff->zbuff, new_size );
1208 if ( tmp_ptr != NULL ) {
1209 rc = 0;
1210 buff->size = new_size;
1211 buff->zbuff = tmp_ptr;
1212 buff->zctrl.next_out = tmp_ptr + cur_used;
1213 buff->zctrl.avail_out = new_size - cur_used;
1214 }
1215 else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001216 xmlChar msg[500];
1217 xmlStrPrintf(msg, 500,
1218 (const xmlChar *) "xmlZMemBuffExtend: %s %lu bytes.\n",
1219 "Allocation failure extending output buffer to",
1220 new_size );
1221 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001222 }
1223
1224 return ( rc );
1225}
1226
1227/**
1228 * xmlZMemBuffAppend
1229 * @buff: Buffer used to compress and consolidate data
1230 * @src: Uncompressed source content to append to buffer
1231 * @len: Length of source data to append to buffer
1232 *
1233 * Compress and append data to the internal buffer. The data buffer
1234 * will be expanded if needed to store the additional data.
1235 *
1236 * Returns the number of bytes appended to the buffer or -1 on error.
1237 */
1238static int
1239xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) {
1240
1241 int z_err;
1242 size_t min_accept;
1243
1244 if ( ( buff == NULL ) || ( src == NULL ) )
1245 return ( -1 );
1246
1247 buff->zctrl.avail_in = len;
1248 buff->zctrl.next_in = (unsigned char *)src;
1249 while ( buff->zctrl.avail_in > 0 ) {
1250 /*
1251 ** Extend the buffer prior to deflate call if a reasonable amount
1252 ** of output buffer space is not available.
1253 */
1254 min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO;
1255 if ( buff->zctrl.avail_out <= min_accept ) {
1256 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1257 return ( -1 );
1258 }
1259
1260 z_err = deflate( &buff->zctrl, Z_NO_FLUSH );
1261 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001262 xmlChar msg[500];
1263 xmlStrPrintf(msg, 500,
1264 (const xmlChar *) "xmlZMemBuffAppend: %s %d %s - %d",
Daniel Veillardf012a642001-07-23 19:10:52 +00001265 "Compression error while appending",
1266 len, "bytes to buffer. ZLIB error", z_err );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001267 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001268 return ( -1 );
1269 }
1270 }
1271
1272 buff->crc = crc32( buff->crc, (unsigned char *)src, len );
1273
1274 return ( len );
1275}
1276
1277/**
1278 * xmlZMemBuffGetContent
1279 * @buff: Compressed memory content buffer
1280 * @data_ref: Pointer reference to point to compressed content
1281 *
1282 * Flushes the compression buffers, appends gzip file trailers and
1283 * returns the compressed content and length of the compressed data.
1284 * NOTE: The gzip trailer code here is plagiarized from zlib source.
1285 *
1286 * Returns the length of the compressed data or -1 on error.
1287 */
1288static int
1289xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) {
1290
1291 int zlgth = -1;
1292 int z_err;
1293
1294 if ( ( buff == NULL ) || ( data_ref == NULL ) )
1295 return ( -1 );
1296
1297 /* Need to loop until compression output buffers are flushed */
1298
1299 do
1300 {
1301 z_err = deflate( &buff->zctrl, Z_FINISH );
1302 if ( z_err == Z_OK ) {
1303 /* In this case Z_OK means more buffer space needed */
1304
1305 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1306 return ( -1 );
1307 }
1308 }
1309 while ( z_err == Z_OK );
1310
1311 /* If the compression state is not Z_STREAM_END, some error occurred */
1312
1313 if ( z_err == Z_STREAM_END ) {
1314
1315 /* Need to append the gzip data trailer */
1316
1317 if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) {
1318 if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 )
1319 return ( -1 );
1320 }
1321
1322 /*
1323 ** For whatever reason, the CRC and length data are pushed out
1324 ** in reverse byte order. So a memcpy can't be used here.
1325 */
1326
1327 append_reverse_ulong( buff, buff->crc );
1328 append_reverse_ulong( buff, buff->zctrl.total_in );
1329
1330 zlgth = buff->zctrl.next_out - buff->zbuff;
1331 *data_ref = (char *)buff->zbuff;
1332 }
1333
Daniel Veillard05d987b2003-10-08 11:54:57 +00001334 else {
1335 xmlChar msg[500];
1336 xmlStrPrintf(msg, 500,
1337 (const xmlChar *) "xmlZMemBuffGetContent: %s - %d\n",
1338 "Error flushing zlib buffers. Error code", z_err );
1339 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1340 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001341
1342 return ( zlgth );
1343}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001344#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001345#endif /* HAVE_ZLIB_H */
1346
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001347#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001348/**
1349 * xmlFreeHTTPWriteCtxt
1350 * @ctxt: Context to cleanup
1351 *
1352 * Free allocated memory and reclaim system resources.
1353 *
1354 * No return value.
1355 */
1356static void
1357xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt )
1358{
1359 if ( ctxt->uri != NULL )
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001360 xmlFree( ctxt->uri );
Daniel Veillardf012a642001-07-23 19:10:52 +00001361
1362 if ( ctxt->doc_buff != NULL ) {
1363
1364#ifdef HAVE_ZLIB_H
1365 if ( ctxt->compression > 0 ) {
1366 xmlFreeZMemBuff( ctxt->doc_buff );
1367 }
1368 else
1369#endif
1370 {
1371 xmlOutputBufferClose( ctxt->doc_buff );
1372 }
1373 }
1374
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001375 xmlFree( ctxt );
Daniel Veillardf012a642001-07-23 19:10:52 +00001376 return;
1377}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001378#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001379
1380
Owen Taylor3473f882001-02-23 17:55:21 +00001381/**
1382 * xmlIOHTTPMatch:
1383 * @filename: the URI for matching
1384 *
1385 * check if the URI matches an HTTP one
1386 *
1387 * Returns 1 if matches, 0 otherwise
1388 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001389int
Owen Taylor3473f882001-02-23 17:55:21 +00001390xmlIOHTTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001391 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "http://", 7))
Owen Taylor3473f882001-02-23 17:55:21 +00001392 return(1);
1393 return(0);
1394}
1395
1396/**
1397 * xmlIOHTTPOpen:
1398 * @filename: the URI for matching
1399 *
1400 * open an HTTP I/O channel
1401 *
1402 * Returns an I/O context or NULL in case of error
1403 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001404void *
Owen Taylor3473f882001-02-23 17:55:21 +00001405xmlIOHTTPOpen (const char *filename) {
1406 return(xmlNanoHTTPOpen(filename, NULL));
1407}
1408
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001409#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001410/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001411 * xmlIOHTTPOpenW:
Daniel Veillardf012a642001-07-23 19:10:52 +00001412 * @post_uri: The destination URI for the document
1413 * @compression: The compression desired for the document.
1414 *
1415 * Open a temporary buffer to collect the document for a subsequent HTTP POST
1416 * request. Non-static as is called from the output buffer creation routine.
1417 *
1418 * Returns an I/O context or NULL in case of error.
1419 */
1420
1421void *
Daniel Veillard572577e2002-01-18 16:23:55 +00001422xmlIOHTTPOpenW(const char *post_uri, int compression)
1423{
Daniel Veillardf012a642001-07-23 19:10:52 +00001424
Daniel Veillard572577e2002-01-18 16:23:55 +00001425 xmlIOHTTPWriteCtxtPtr ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001426
Daniel Veillard572577e2002-01-18 16:23:55 +00001427 if (post_uri == NULL)
1428 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001429
Daniel Veillard572577e2002-01-18 16:23:55 +00001430 ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt));
1431 if (ctxt == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001432 xmlIOErrMemory("creating HTTP output context");
Daniel Veillard572577e2002-01-18 16:23:55 +00001433 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001434 }
1435
Daniel Veillard572577e2002-01-18 16:23:55 +00001436 (void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt));
Daniel Veillardf012a642001-07-23 19:10:52 +00001437
Daniel Veillard572577e2002-01-18 16:23:55 +00001438 ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri);
1439 if (ctxt->uri == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001440 xmlIOErrMemory("copying URI");
Daniel Veillard572577e2002-01-18 16:23:55 +00001441 xmlFreeHTTPWriteCtxt(ctxt);
1442 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001443 }
1444
1445 /*
Daniel Veillard572577e2002-01-18 16:23:55 +00001446 * ** Since the document length is required for an HTTP post,
1447 * ** need to put the document into a buffer. A memory buffer
1448 * ** is being used to avoid pushing the data to disk and back.
1449 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001450
1451#ifdef HAVE_ZLIB_H
Daniel Veillard572577e2002-01-18 16:23:55 +00001452 if ((compression > 0) && (compression <= 9)) {
1453
1454 ctxt->compression = compression;
1455 ctxt->doc_buff = xmlCreateZMemBuff(compression);
1456 } else
Daniel Veillardf012a642001-07-23 19:10:52 +00001457#endif
1458 {
Daniel Veillard572577e2002-01-18 16:23:55 +00001459 /* Any character conversions should have been done before this */
Daniel Veillardf012a642001-07-23 19:10:52 +00001460
Daniel Veillard572577e2002-01-18 16:23:55 +00001461 ctxt->doc_buff = xmlAllocOutputBuffer(NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001462 }
1463
Daniel Veillard572577e2002-01-18 16:23:55 +00001464 if (ctxt->doc_buff == NULL) {
1465 xmlFreeHTTPWriteCtxt(ctxt);
1466 ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001467 }
1468
Daniel Veillard572577e2002-01-18 16:23:55 +00001469 return (ctxt);
Daniel Veillardf012a642001-07-23 19:10:52 +00001470}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001471#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001472
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001473#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001474/**
1475 * xmlIOHTTPDfltOpenW
1476 * @post_uri: The destination URI for this document.
1477 *
1478 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
1479 * HTTP post command. This function should generally not be used as
1480 * the open callback is short circuited in xmlOutputBufferCreateFile.
1481 *
1482 * Returns a pointer to the new IO context.
1483 */
1484static void *
1485xmlIOHTTPDfltOpenW( const char * post_uri ) {
1486 return ( xmlIOHTTPOpenW( post_uri, 0 ) );
1487}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001488#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001489
1490/**
Owen Taylor3473f882001-02-23 17:55:21 +00001491 * xmlIOHTTPRead:
1492 * @context: the I/O context
1493 * @buffer: where to drop data
1494 * @len: number of bytes to write
1495 *
1496 * Read @len bytes to @buffer from the I/O channel.
1497 *
1498 * Returns the number of bytes written
1499 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001500int
Owen Taylor3473f882001-02-23 17:55:21 +00001501xmlIOHTTPRead(void * context, char * buffer, int len) {
1502 return(xmlNanoHTTPRead(context, &buffer[0], len));
1503}
1504
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001505#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001506/**
Daniel Veillardf012a642001-07-23 19:10:52 +00001507 * xmlIOHTTPWrite
1508 * @context: previously opened writing context
1509 * @buffer: data to output to temporary buffer
1510 * @len: bytes to output
1511 *
1512 * Collect data from memory buffer into a temporary file for later
1513 * processing.
1514 *
1515 * Returns number of bytes written.
1516 */
1517
1518static int
1519xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
1520
1521 xmlIOHTTPWriteCtxtPtr ctxt = context;
1522
1523 if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
1524 return ( -1 );
1525
1526 if ( len > 0 ) {
1527
1528 /* Use gzwrite or fwrite as previously setup in the open call */
1529
1530#ifdef HAVE_ZLIB_H
1531 if ( ctxt->compression > 0 )
1532 len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len );
1533
1534 else
1535#endif
1536 len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
1537
1538 if ( len < 0 ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001539 xmlChar msg[500];
1540 xmlStrPrintf(msg, 500,
1541 (const xmlChar *) "xmlIOHTTPWrite: %s\n%s '%s'.\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001542 "Error appending to internal buffer.",
1543 "Error sending document to URI",
1544 ctxt->uri );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001545 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001546 }
1547 }
1548
1549 return ( len );
1550}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001551#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001552
1553
1554/**
Owen Taylor3473f882001-02-23 17:55:21 +00001555 * xmlIOHTTPClose:
1556 * @context: the I/O context
1557 *
1558 * Close an HTTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001559 *
1560 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00001561 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001562int
Owen Taylor3473f882001-02-23 17:55:21 +00001563xmlIOHTTPClose (void * context) {
1564 xmlNanoHTTPClose(context);
Daniel Veillardf012a642001-07-23 19:10:52 +00001565 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001566}
Daniel Veillardf012a642001-07-23 19:10:52 +00001567
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001568#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001569/**
1570 * xmlIOHTTCloseWrite
1571 * @context: The I/O context
1572 * @http_mthd: The HTTP method to be used when sending the data
1573 *
1574 * Close the transmit HTTP I/O channel and actually send the data.
1575 */
1576static int
1577xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
1578
1579 int close_rc = -1;
1580 int http_rtn = 0;
1581 int content_lgth = 0;
1582 xmlIOHTTPWriteCtxtPtr ctxt = context;
1583
1584 char * http_content = NULL;
1585 char * content_encoding = NULL;
1586 char * content_type = (char *) "text/xml";
1587 void * http_ctxt = NULL;
1588
1589 if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
1590 return ( -1 );
1591
1592 /* Retrieve the content from the appropriate buffer */
1593
1594#ifdef HAVE_ZLIB_H
1595
1596 if ( ctxt->compression > 0 ) {
1597 content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
1598 content_encoding = (char *) "Content-Encoding: gzip";
1599 }
1600 else
1601#endif
1602 {
1603 /* Pull the data out of the memory output buffer */
1604
1605 xmlOutputBufferPtr dctxt = ctxt->doc_buff;
1606 http_content = (char *)dctxt->buffer->content;
1607 content_lgth = dctxt->buffer->use;
1608 }
1609
1610 if ( http_content == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001611 xmlChar msg[500];
1612 xmlStrPrintf(msg, 500,
1613 (const xmlChar *) "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
1614 "Error retrieving content.\nUnable to",
1615 http_mthd, "data to URI", ctxt->uri );
1616 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001617 }
1618
1619 else {
1620
1621 http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
1622 &content_type, content_encoding,
1623 content_lgth );
1624
1625 if ( http_ctxt != NULL ) {
1626#ifdef DEBUG_HTTP
1627 /* If testing/debugging - dump reply with request content */
1628
1629 FILE * tst_file = NULL;
1630 char buffer[ 4096 ];
1631 char * dump_name = NULL;
1632 int avail;
1633
1634 xmlGenericError( xmlGenericErrorContext,
1635 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
1636 http_mthd, ctxt->uri,
1637 xmlNanoHTTPReturnCode( http_ctxt ) );
1638
1639 /*
1640 ** Since either content or reply may be gzipped,
1641 ** dump them to separate files instead of the
1642 ** standard error context.
1643 */
1644
1645 dump_name = tempnam( NULL, "lxml" );
1646 if ( dump_name != NULL ) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001647 (void)snprintf( buffer, sizeof(buffer), "%s.content", dump_name );
Daniel Veillardf012a642001-07-23 19:10:52 +00001648
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00001649 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00001650 if ( tst_file != NULL ) {
1651 xmlGenericError( xmlGenericErrorContext,
1652 "Transmitted content saved in file: %s\n", buffer );
1653
1654 fwrite( http_content, sizeof( char ),
1655 content_lgth, tst_file );
1656 fclose( tst_file );
1657 }
1658
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001659 (void)snprintf( buffer, sizeof(buffer), "%s.reply", dump_name );
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00001660 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00001661 if ( tst_file != NULL ) {
1662 xmlGenericError( xmlGenericErrorContext,
1663 "Reply content saved in file: %s\n", buffer );
1664
1665
1666 while ( (avail = xmlNanoHTTPRead( http_ctxt,
1667 buffer, sizeof( buffer ) )) > 0 ) {
1668
1669 fwrite( buffer, sizeof( char ), avail, tst_file );
1670 }
1671
1672 fclose( tst_file );
1673 }
1674
1675 free( dump_name );
1676 }
1677#endif /* DEBUG_HTTP */
1678
1679 http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
1680 if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
1681 close_rc = 0;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001682 else {
1683 xmlChar msg[500];
1684 xmlStrPrintf(msg, 500,
1685 (const xmlChar *) "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001686 http_mthd, content_lgth,
1687 "bytes to URI", ctxt->uri,
1688 "failed. HTTP return code:", http_rtn );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001689 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1690 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001691
1692 xmlNanoHTTPClose( http_ctxt );
1693 xmlFree( content_type );
1694 }
1695 }
1696
1697 /* Final cleanups */
1698
1699 xmlFreeHTTPWriteCtxt( ctxt );
1700
1701 return ( close_rc );
1702}
1703
1704/**
1705 * xmlIOHTTPClosePut
1706 *
1707 * @context: The I/O context
1708 *
1709 * Close the transmit HTTP I/O channel and actually send data using a PUT
1710 * HTTP method.
1711 */
1712static int
1713xmlIOHTTPClosePut( void * ctxt ) {
1714 return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
1715}
1716
1717
1718/**
1719 * xmlIOHTTPClosePost
1720 *
1721 * @context: The I/O context
1722 *
1723 * Close the transmit HTTP I/O channel and actually send data using a POST
1724 * HTTP method.
1725 */
1726static int
1727xmlIOHTTPClosePost( void * ctxt ) {
1728 return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
1729}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001730#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001731
Owen Taylor3473f882001-02-23 17:55:21 +00001732#endif /* LIBXML_HTTP_ENABLED */
1733
1734#ifdef LIBXML_FTP_ENABLED
1735/************************************************************************
1736 * *
1737 * I/O for FTP file accesses *
1738 * *
1739 ************************************************************************/
1740/**
1741 * xmlIOFTPMatch:
1742 * @filename: the URI for matching
1743 *
1744 * check if the URI matches an FTP one
1745 *
1746 * Returns 1 if matches, 0 otherwise
1747 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001748int
Owen Taylor3473f882001-02-23 17:55:21 +00001749xmlIOFTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001750 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "ftp://", 6))
Owen Taylor3473f882001-02-23 17:55:21 +00001751 return(1);
1752 return(0);
1753}
1754
1755/**
1756 * xmlIOFTPOpen:
1757 * @filename: the URI for matching
1758 *
1759 * open an FTP I/O channel
1760 *
1761 * Returns an I/O context or NULL in case of error
1762 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001763void *
Owen Taylor3473f882001-02-23 17:55:21 +00001764xmlIOFTPOpen (const char *filename) {
1765 return(xmlNanoFTPOpen(filename));
1766}
1767
1768/**
1769 * xmlIOFTPRead:
1770 * @context: the I/O context
1771 * @buffer: where to drop data
1772 * @len: number of bytes to write
1773 *
1774 * Read @len bytes to @buffer from the I/O channel.
1775 *
1776 * Returns the number of bytes written
1777 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001778int
Owen Taylor3473f882001-02-23 17:55:21 +00001779xmlIOFTPRead(void * context, char * buffer, int len) {
1780 return(xmlNanoFTPRead(context, &buffer[0], len));
1781}
1782
1783/**
1784 * xmlIOFTPClose:
1785 * @context: the I/O context
1786 *
1787 * Close an FTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001788 *
1789 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00001790 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001791int
Owen Taylor3473f882001-02-23 17:55:21 +00001792xmlIOFTPClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001793 return ( xmlNanoFTPClose(context) );
Owen Taylor3473f882001-02-23 17:55:21 +00001794}
1795#endif /* LIBXML_FTP_ENABLED */
1796
1797
1798/**
1799 * xmlRegisterInputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001800 * @matchFunc: the xmlInputMatchCallback
1801 * @openFunc: the xmlInputOpenCallback
1802 * @readFunc: the xmlInputReadCallback
1803 * @closeFunc: the xmlInputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001804 *
1805 * Register a new set of I/O callback for handling parser input.
1806 *
1807 * Returns the registered handler number or -1 in case of error
1808 */
1809int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001810xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
1811 xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
1812 xmlInputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001813 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
1814 return(-1);
1815 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001816 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
1817 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
1818 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
1819 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00001820 xmlInputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00001821 return(xmlInputCallbackNr++);
1822}
1823
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001824#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001825/**
1826 * xmlRegisterOutputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001827 * @matchFunc: the xmlOutputMatchCallback
1828 * @openFunc: the xmlOutputOpenCallback
1829 * @writeFunc: the xmlOutputWriteCallback
1830 * @closeFunc: the xmlOutputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001831 *
1832 * Register a new set of I/O callback for handling output.
1833 *
1834 * Returns the registered handler number or -1 in case of error
1835 */
1836int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001837xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
1838 xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
1839 xmlOutputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001840 if (xmlOutputCallbackNr >= MAX_INPUT_CALLBACK) {
1841 return(-1);
1842 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001843 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
1844 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
1845 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
1846 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00001847 xmlOutputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00001848 return(xmlOutputCallbackNr++);
1849}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001850#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001851
1852/**
1853 * xmlRegisterDefaultInputCallbacks:
1854 *
1855 * Registers the default compiled-in I/O handlers.
1856 */
1857void
Owen Taylor3473f882001-02-23 17:55:21 +00001858xmlRegisterDefaultInputCallbacks
Owen Taylor3473f882001-02-23 17:55:21 +00001859(void) {
1860 if (xmlInputCallbackInitialized)
1861 return;
1862
1863 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
1864 xmlFileRead, xmlFileClose);
1865#ifdef HAVE_ZLIB_H
1866 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1867 xmlGzfileRead, xmlGzfileClose);
1868#endif /* HAVE_ZLIB_H */
1869
1870#ifdef LIBXML_HTTP_ENABLED
1871 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
1872 xmlIOHTTPRead, xmlIOHTTPClose);
1873#endif /* LIBXML_HTTP_ENABLED */
1874
1875#ifdef LIBXML_FTP_ENABLED
1876 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1877 xmlIOFTPRead, xmlIOFTPClose);
1878#endif /* LIBXML_FTP_ENABLED */
1879 xmlInputCallbackInitialized = 1;
1880}
1881
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001882#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001883/**
1884 * xmlRegisterDefaultOutputCallbacks:
1885 *
1886 * Registers the default compiled-in I/O handlers.
1887 */
1888void
Owen Taylor3473f882001-02-23 17:55:21 +00001889xmlRegisterDefaultOutputCallbacks
Owen Taylor3473f882001-02-23 17:55:21 +00001890(void) {
1891 if (xmlOutputCallbackInitialized)
1892 return;
1893
1894 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
1895 xmlFileWrite, xmlFileClose);
Daniel Veillardf012a642001-07-23 19:10:52 +00001896
1897#ifdef LIBXML_HTTP_ENABLED
1898 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
1899 xmlIOHTTPWrite, xmlIOHTTPClosePut);
1900#endif
1901
Owen Taylor3473f882001-02-23 17:55:21 +00001902/*********************************
1903 No way a-priori to distinguish between gzipped files from
1904 uncompressed ones except opening if existing then closing
1905 and saving with same compression ratio ... a pain.
1906
1907#ifdef HAVE_ZLIB_H
1908 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1909 xmlGzfileWrite, xmlGzfileClose);
1910#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001911
1912 Nor FTP PUT ....
1913#ifdef LIBXML_FTP_ENABLED
1914 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1915 xmlIOFTPWrite, xmlIOFTPClose);
1916#endif
1917 **********************************/
1918 xmlOutputCallbackInitialized = 1;
1919}
1920
Daniel Veillardf012a642001-07-23 19:10:52 +00001921#ifdef LIBXML_HTTP_ENABLED
1922/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001923 * xmlRegisterHTTPPostCallbacks:
Daniel Veillardf012a642001-07-23 19:10:52 +00001924 *
1925 * By default, libxml submits HTTP output requests using the "PUT" method.
1926 * Calling this method changes the HTTP output method to use the "POST"
1927 * method instead.
1928 *
1929 */
1930void
1931xmlRegisterHTTPPostCallbacks( void ) {
1932
1933 /* Register defaults if not done previously */
1934
1935 if ( xmlOutputCallbackInitialized == 0 )
1936 xmlRegisterDefaultOutputCallbacks( );
1937
1938 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
1939 xmlIOHTTPWrite, xmlIOHTTPClosePost);
1940 return;
1941}
1942#endif
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001943#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001944
Owen Taylor3473f882001-02-23 17:55:21 +00001945/**
1946 * xmlAllocParserInputBuffer:
1947 * @enc: the charset encoding if known
1948 *
1949 * Create a buffered parser input for progressive parsing
1950 *
1951 * Returns the new parser input or NULL
1952 */
1953xmlParserInputBufferPtr
1954xmlAllocParserInputBuffer(xmlCharEncoding enc) {
1955 xmlParserInputBufferPtr ret;
1956
1957 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
1958 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001959 xmlIOErrMemory("creating input buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00001960 return(NULL);
1961 }
1962 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00001963 ret->buffer = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00001964 if (ret->buffer == NULL) {
1965 xmlFree(ret);
1966 return(NULL);
1967 }
1968 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
1969 ret->encoder = xmlGetCharEncodingHandler(enc);
1970 if (ret->encoder != NULL)
Daniel Veillard6155d8a2003-08-19 15:01:28 +00001971 ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00001972 else
1973 ret->raw = NULL;
1974 ret->readcallback = NULL;
1975 ret->closecallback = NULL;
1976 ret->context = NULL;
William M. Brackc07329e2003-09-08 01:57:30 +00001977 ret->compressed = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00001978
1979 return(ret);
1980}
1981
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001982#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001983/**
1984 * xmlAllocOutputBuffer:
1985 * @encoder: the encoding converter or NULL
1986 *
1987 * Create a buffered parser output
1988 *
1989 * Returns the new parser output or NULL
1990 */
1991xmlOutputBufferPtr
1992xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
1993 xmlOutputBufferPtr ret;
1994
1995 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
1996 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001997 xmlIOErrMemory("creating output buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00001998 return(NULL);
1999 }
2000 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
2001 ret->buffer = xmlBufferCreate();
2002 if (ret->buffer == NULL) {
2003 xmlFree(ret);
2004 return(NULL);
2005 }
2006 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
2007 ret->encoder = encoder;
2008 if (encoder != NULL) {
2009 ret->conv = xmlBufferCreateSize(4000);
2010 /*
2011 * This call is designed to initiate the encoder state
2012 */
2013 xmlCharEncOutFunc(encoder, ret->conv, NULL);
2014 } else
2015 ret->conv = NULL;
2016 ret->writecallback = NULL;
2017 ret->closecallback = NULL;
2018 ret->context = NULL;
2019 ret->written = 0;
2020
2021 return(ret);
2022}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002023#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002024
2025/**
2026 * xmlFreeParserInputBuffer:
2027 * @in: a buffered parser input
2028 *
2029 * Free up the memory used by a buffered parser input
2030 */
2031void
2032xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
Daniel Veillard8d8bf2c2003-09-17 19:36:25 +00002033 if (in == NULL) return;
2034
Owen Taylor3473f882001-02-23 17:55:21 +00002035 if (in->raw) {
2036 xmlBufferFree(in->raw);
2037 in->raw = NULL;
2038 }
2039 if (in->encoder != NULL) {
2040 xmlCharEncCloseFunc(in->encoder);
2041 }
2042 if (in->closecallback != NULL) {
2043 in->closecallback(in->context);
2044 }
2045 if (in->buffer != NULL) {
2046 xmlBufferFree(in->buffer);
2047 in->buffer = NULL;
2048 }
2049
Owen Taylor3473f882001-02-23 17:55:21 +00002050 xmlFree(in);
2051}
2052
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002053#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002054/**
2055 * xmlOutputBufferClose:
2056 * @out: a buffered output
2057 *
2058 * flushes and close the output I/O channel
2059 * and free up all the associated resources
2060 *
2061 * Returns the number of byte written or -1 in case of error.
2062 */
2063int
Daniel Veillard828ce832003-10-08 19:19:10 +00002064xmlOutputBufferClose(xmlOutputBufferPtr out)
2065{
Owen Taylor3473f882001-02-23 17:55:21 +00002066 int written;
Daniel Veillardf012a642001-07-23 19:10:52 +00002067 int err_rc = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002068
2069 if (out == NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002070 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002071 if (out->writecallback != NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002072 xmlOutputBufferFlush(out);
Owen Taylor3473f882001-02-23 17:55:21 +00002073 if (out->closecallback != NULL) {
Daniel Veillard828ce832003-10-08 19:19:10 +00002074 err_rc = out->closecallback(out->context);
Owen Taylor3473f882001-02-23 17:55:21 +00002075 }
2076 written = out->written;
2077 if (out->conv) {
2078 xmlBufferFree(out->conv);
Daniel Veillard828ce832003-10-08 19:19:10 +00002079 out->conv = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002080 }
2081 if (out->encoder != NULL) {
2082 xmlCharEncCloseFunc(out->encoder);
2083 }
2084 if (out->buffer != NULL) {
2085 xmlBufferFree(out->buffer);
Daniel Veillard828ce832003-10-08 19:19:10 +00002086 out->buffer = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002087 }
2088
Daniel Veillard828ce832003-10-08 19:19:10 +00002089 if (out->error)
2090 err_rc = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00002091 xmlFree(out);
Daniel Veillard828ce832003-10-08 19:19:10 +00002092 return ((err_rc == 0) ? written : err_rc);
Owen Taylor3473f882001-02-23 17:55:21 +00002093}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002094#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002095
2096/**
2097 * xmlParserInputBufferCreateFilename:
2098 * @URI: a C string containing the URI or filename
2099 * @enc: the charset encoding if known
2100 *
2101 * Create a buffered parser input for the progressive parsing of a file
2102 * If filename is "-' then we use stdin as the input.
2103 * Automatic support for ZLIB/Compress compressed document is provided
2104 * by default if found at compile-time.
2105 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
2106 *
2107 * Returns the new parser input or NULL
2108 */
2109xmlParserInputBufferPtr
Daniel Veillard3e59fc52003-04-18 12:34:58 +00002110xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002111 xmlParserInputBufferPtr ret;
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) {
Daniel Veillard388236f2001-07-08 18:35:48 +00002130 break;
Daniel Veillard847332a2003-10-18 11:29:40 +00002131 }
Daniel Veillard388236f2001-07-08 18:35:48 +00002132 }
Owen Taylor3473f882001-02-23 17:55:21 +00002133 }
2134 }
2135 if (context == NULL) {
2136 return(NULL);
2137 }
2138
2139 /*
2140 * Allocate the Input buffer front-end.
2141 */
2142 ret = xmlAllocParserInputBuffer(enc);
2143 if (ret != NULL) {
2144 ret->context = context;
2145 ret->readcallback = xmlInputCallbackTable[i].readcallback;
2146 ret->closecallback = xmlInputCallbackTable[i].closecallback;
William M. Brackc07329e2003-09-08 01:57:30 +00002147#ifdef HAVE_ZLIB_H
2148 if (xmlInputCallbackTable[i].opencallback == xmlGzfileOpen) {
2149 if (((z_stream *)context)->avail_in > 4) {
2150 char *cptr, buff4[4];
Daniel Veillard07cb8222003-09-10 10:51:05 +00002151 cptr = (char *) ((z_stream *)context)->next_in;
William M. Brackc07329e2003-09-08 01:57:30 +00002152 if (gzread(context, buff4, 4) == 4) {
2153 if (strncmp(buff4, cptr, 4) == 0)
2154 ret->compressed = 0;
2155 else
2156 ret->compressed = 1;
2157 gzrewind(context);
2158 }
2159 }
2160 }
2161#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002162 }
2163 return(ret);
2164}
2165
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002166#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002167/**
2168 * xmlOutputBufferCreateFilename:
2169 * @URI: a C string containing the URI or filename
2170 * @encoder: the encoding converter or NULL
2171 * @compression: the compression ration (0 none, 9 max).
2172 *
2173 * Create a buffered output for the progressive saving of a file
2174 * If filename is "-' then we use stdout as the output.
2175 * Automatic support for ZLIB/Compress compressed document is provided
2176 * by default if found at compile-time.
2177 * TODO: currently if compression is set, the library only support
2178 * writing to a local file.
2179 *
2180 * Returns the new output or NULL
2181 */
2182xmlOutputBufferPtr
2183xmlOutputBufferCreateFilename(const char *URI,
2184 xmlCharEncodingHandlerPtr encoder,
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002185 int compression ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00002186 xmlOutputBufferPtr ret;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002187 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002188 void *context = NULL;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002189 char *unescaped;
Owen Taylor3473f882001-02-23 17:55:21 +00002190
Daniel Veillard4432df22003-09-28 18:58:27 +00002191#ifdef LIBXML_HTTP_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00002192 int is_http_uri = 0; /* Can't change if HTTP disabled */
Daniel Veillard4432df22003-09-28 18:58:27 +00002193#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00002194
Owen Taylor3473f882001-02-23 17:55:21 +00002195 if (xmlOutputCallbackInitialized == 0)
2196 xmlRegisterDefaultOutputCallbacks();
2197
2198 if (URI == NULL) return(NULL);
2199
Daniel Veillardf012a642001-07-23 19:10:52 +00002200#ifdef LIBXML_HTTP_ENABLED
2201 /* Need to prevent HTTP URI's from falling into zlib short circuit */
2202
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002203 is_http_uri = xmlIOHTTPMatch( URI );
Daniel Veillardf012a642001-07-23 19:10:52 +00002204#endif
2205
Owen Taylor3473f882001-02-23 17:55:21 +00002206
2207 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002208 * Try to find one of the output accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002209 * Go in reverse to give precedence to user defined handlers.
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002210 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00002211 */
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002212 unescaped = xmlURIUnescapeString(URI, 0, NULL);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002213 if (unescaped != NULL) {
2214#ifdef HAVE_ZLIB_H
2215 if ((compression > 0) && (compression <= 9) && (is_http_uri == 0)) {
2216 context = xmlGzfileOpenW(unescaped, compression);
2217 if (context != NULL) {
2218 ret = xmlAllocOutputBuffer(encoder);
2219 if (ret != NULL) {
2220 ret->context = context;
2221 ret->writecallback = xmlGzfileWrite;
2222 ret->closecallback = xmlGzfileClose;
2223 }
2224 xmlFree(unescaped);
2225 return(ret);
2226 }
2227 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002228#endif
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002229 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2230 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
2231 (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
2232#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2233 /* Need to pass compression parameter into HTTP open calls */
2234 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2235 context = xmlIOHTTPOpenW(unescaped, compression);
2236 else
2237#endif
2238 context = xmlOutputCallbackTable[i].opencallback(unescaped);
2239 if (context != NULL)
2240 break;
2241 }
2242 }
2243 xmlFree(unescaped);
2244 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002245
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002246 /*
2247 * If this failed try with a non-escaped URI this may be a strange
2248 * filename
2249 */
2250 if (context == NULL) {
2251#ifdef HAVE_ZLIB_H
2252 if ((compression > 0) && (compression <= 9) && (is_http_uri == 0)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002253 context = xmlGzfileOpenW(URI, compression);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002254 if (context != NULL) {
2255 ret = xmlAllocOutputBuffer(encoder);
2256 if (ret != NULL) {
2257 ret->context = context;
2258 ret->writecallback = xmlGzfileWrite;
2259 ret->closecallback = xmlGzfileClose;
2260 }
2261 return(ret);
2262 }
2263 }
2264#endif
2265 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2266 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002267 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002268#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2269 /* Need to pass compression parameter into HTTP open calls */
2270 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2271 context = xmlIOHTTPOpenW(URI, compression);
2272 else
2273#endif
2274 context = xmlOutputCallbackTable[i].opencallback(URI);
2275 if (context != NULL)
2276 break;
2277 }
Owen Taylor3473f882001-02-23 17:55:21 +00002278 }
2279 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002280
Owen Taylor3473f882001-02-23 17:55:21 +00002281 if (context == NULL) {
2282 return(NULL);
2283 }
2284
2285 /*
2286 * Allocate the Output buffer front-end.
2287 */
2288 ret = xmlAllocOutputBuffer(encoder);
2289 if (ret != NULL) {
2290 ret->context = context;
2291 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
2292 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
2293 }
2294 return(ret);
2295}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002296#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002297
2298/**
2299 * xmlParserInputBufferCreateFile:
2300 * @file: a FILE*
2301 * @enc: the charset encoding if known
2302 *
2303 * Create a buffered parser input for the progressive parsing of a FILE *
2304 * buffered C I/O
2305 *
2306 * Returns the new parser input or NULL
2307 */
2308xmlParserInputBufferPtr
2309xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
2310 xmlParserInputBufferPtr ret;
2311
2312 if (xmlInputCallbackInitialized == 0)
2313 xmlRegisterDefaultInputCallbacks();
2314
2315 if (file == NULL) return(NULL);
2316
2317 ret = xmlAllocParserInputBuffer(enc);
2318 if (ret != NULL) {
2319 ret->context = file;
2320 ret->readcallback = xmlFileRead;
2321 ret->closecallback = xmlFileFlush;
2322 }
2323
2324 return(ret);
2325}
2326
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002327#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002328/**
2329 * xmlOutputBufferCreateFile:
2330 * @file: a FILE*
2331 * @encoder: the encoding converter or NULL
2332 *
2333 * Create a buffered output for the progressive saving to a FILE *
2334 * buffered C I/O
2335 *
2336 * Returns the new parser output or NULL
2337 */
2338xmlOutputBufferPtr
2339xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
2340 xmlOutputBufferPtr ret;
2341
2342 if (xmlOutputCallbackInitialized == 0)
2343 xmlRegisterDefaultOutputCallbacks();
2344
2345 if (file == NULL) return(NULL);
2346
2347 ret = xmlAllocOutputBuffer(encoder);
2348 if (ret != NULL) {
2349 ret->context = file;
2350 ret->writecallback = xmlFileWrite;
2351 ret->closecallback = xmlFileFlush;
2352 }
2353
2354 return(ret);
2355}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002356#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002357
2358/**
2359 * xmlParserInputBufferCreateFd:
2360 * @fd: a file descriptor number
2361 * @enc: the charset encoding if known
2362 *
2363 * Create a buffered parser input for the progressive parsing for the input
2364 * from a file descriptor
2365 *
2366 * Returns the new parser input or NULL
2367 */
2368xmlParserInputBufferPtr
2369xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
2370 xmlParserInputBufferPtr ret;
2371
2372 if (fd < 0) return(NULL);
2373
2374 ret = xmlAllocParserInputBuffer(enc);
2375 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002376 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002377 ret->readcallback = xmlFdRead;
2378 ret->closecallback = xmlFdClose;
2379 }
2380
2381 return(ret);
2382}
2383
2384/**
2385 * xmlParserInputBufferCreateMem:
2386 * @mem: the memory input
2387 * @size: the length of the memory block
2388 * @enc: the charset encoding if known
2389 *
2390 * Create a buffered parser input for the progressive parsing for the input
2391 * from a memory area.
2392 *
2393 * Returns the new parser input or NULL
2394 */
2395xmlParserInputBufferPtr
2396xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
2397 xmlParserInputBufferPtr ret;
2398
2399 if (size <= 0) return(NULL);
2400 if (mem == NULL) return(NULL);
2401
2402 ret = xmlAllocParserInputBuffer(enc);
2403 if (ret != NULL) {
2404 ret->context = (void *) mem;
2405 ret->readcallback = (xmlInputReadCallback) xmlNop;
2406 ret->closecallback = NULL;
2407 xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size);
2408 }
2409
2410 return(ret);
2411}
2412
2413/**
Daniel Veillard53350552003-09-18 13:35:51 +00002414 * xmlParserInputBufferCreateStatic:
2415 * @mem: the memory input
2416 * @size: the length of the memory block
2417 * @enc: the charset encoding if known
2418 *
2419 * Create a buffered parser input for the progressive parsing for the input
2420 * from an immutable memory area. This will not copy the memory area to
2421 * the buffer, but the memory is expected to be available until the end of
2422 * the parsing, this is useful for example when using mmap'ed file.
2423 *
2424 * Returns the new parser input or NULL
2425 */
2426xmlParserInputBufferPtr
2427xmlParserInputBufferCreateStatic(const char *mem, int size,
2428 xmlCharEncoding enc) {
2429 xmlParserInputBufferPtr ret;
2430
2431 if (size <= 0) return(NULL);
2432 if (mem == NULL) return(NULL);
2433
2434 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2435 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002436 xmlIOErrMemory("creating input buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00002437 return(NULL);
2438 }
2439 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillarde72c5082003-09-19 12:44:05 +00002440 ret->buffer = xmlBufferCreateStatic((void *)mem, (size_t) size);
Daniel Veillard53350552003-09-18 13:35:51 +00002441 if (ret->buffer == NULL) {
2442 xmlFree(ret);
2443 return(NULL);
2444 }
2445 ret->encoder = xmlGetCharEncodingHandler(enc);
2446 if (ret->encoder != NULL)
2447 ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
2448 else
2449 ret->raw = NULL;
2450 ret->compressed = -1;
2451 ret->context = (void *) mem;
2452 ret->readcallback = NULL;
2453 ret->closecallback = NULL;
2454
2455 return(ret);
2456}
2457
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002458#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard53350552003-09-18 13:35:51 +00002459/**
Owen Taylor3473f882001-02-23 17:55:21 +00002460 * xmlOutputBufferCreateFd:
2461 * @fd: a file descriptor number
2462 * @encoder: the encoding converter or NULL
2463 *
2464 * Create a buffered output for the progressive saving
2465 * to a file descriptor
2466 *
2467 * Returns the new parser output or NULL
2468 */
2469xmlOutputBufferPtr
2470xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
2471 xmlOutputBufferPtr ret;
2472
2473 if (fd < 0) return(NULL);
2474
2475 ret = xmlAllocOutputBuffer(encoder);
2476 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002477 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002478 ret->writecallback = xmlFdWrite;
Daniel Veillard7db38712002-02-07 16:39:11 +00002479 ret->closecallback = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002480 }
2481
2482 return(ret);
2483}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002484#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002485
2486/**
2487 * xmlParserInputBufferCreateIO:
2488 * @ioread: an I/O read function
2489 * @ioclose: an I/O close function
2490 * @ioctx: an I/O handler
2491 * @enc: the charset encoding if known
2492 *
2493 * Create a buffered parser input for the progressive parsing for the input
2494 * from an I/O handler
2495 *
2496 * Returns the new parser input or NULL
2497 */
2498xmlParserInputBufferPtr
2499xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
2500 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
2501 xmlParserInputBufferPtr ret;
2502
2503 if (ioread == NULL) return(NULL);
2504
2505 ret = xmlAllocParserInputBuffer(enc);
2506 if (ret != NULL) {
2507 ret->context = (void *) ioctx;
2508 ret->readcallback = ioread;
2509 ret->closecallback = ioclose;
2510 }
2511
2512 return(ret);
2513}
2514
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002515#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002516/**
2517 * xmlOutputBufferCreateIO:
2518 * @iowrite: an I/O write function
2519 * @ioclose: an I/O close function
2520 * @ioctx: an I/O handler
Daniel Veillard9d06d302002-01-22 18:15:52 +00002521 * @encoder: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002522 *
2523 * Create a buffered output for the progressive saving
2524 * to an I/O handler
2525 *
2526 * Returns the new parser output or NULL
2527 */
2528xmlOutputBufferPtr
2529xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
2530 xmlOutputCloseCallback ioclose, void *ioctx,
2531 xmlCharEncodingHandlerPtr encoder) {
2532 xmlOutputBufferPtr ret;
2533
2534 if (iowrite == NULL) return(NULL);
2535
2536 ret = xmlAllocOutputBuffer(encoder);
2537 if (ret != NULL) {
2538 ret->context = (void *) ioctx;
2539 ret->writecallback = iowrite;
2540 ret->closecallback = ioclose;
2541 }
2542
2543 return(ret);
2544}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002545#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002546
2547/**
2548 * xmlParserInputBufferPush:
2549 * @in: a buffered parser input
2550 * @len: the size in bytes of the array.
2551 * @buf: an char array
2552 *
2553 * Push the content of the arry in the input buffer
2554 * This routine handle the I18N transcoding to internal UTF-8
2555 * This is used when operating the parser in progressive (push) mode.
2556 *
2557 * Returns the number of chars read and stored in the buffer, or -1
2558 * in case of error.
2559 */
2560int
2561xmlParserInputBufferPush(xmlParserInputBufferPtr in,
2562 int len, const char *buf) {
2563 int nbchars = 0;
2564
2565 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002566 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002567 if (in->encoder != NULL) {
2568 /*
2569 * Store the data in the incoming raw buffer
2570 */
2571 if (in->raw == NULL) {
2572 in->raw = xmlBufferCreate();
2573 }
2574 xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
2575
2576 /*
2577 * convert as much as possible to the parser reading buffer.
2578 */
2579 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2580 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002581 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002582 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002583 return(-1);
2584 }
2585 } else {
2586 nbchars = len;
2587 xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
2588 }
2589#ifdef DEBUG_INPUT
2590 xmlGenericError(xmlGenericErrorContext,
2591 "I/O: pushed %d chars, buffer %d/%d\n",
2592 nbchars, in->buffer->use, in->buffer->size);
2593#endif
2594 return(nbchars);
2595}
2596
2597/**
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002598 * endOfInput:
2599 *
2600 * When reading from an Input channel indicated end of file or error
2601 * don't reread from it again.
2602 */
2603static int
2604endOfInput (void * context ATTRIBUTE_UNUSED,
2605 char * buffer ATTRIBUTE_UNUSED,
2606 int len ATTRIBUTE_UNUSED) {
2607 return(0);
2608}
2609
2610/**
Owen Taylor3473f882001-02-23 17:55:21 +00002611 * xmlParserInputBufferGrow:
2612 * @in: a buffered parser input
2613 * @len: indicative value of the amount of chars to read
2614 *
2615 * Grow up the content of the input buffer, the old data are preserved
2616 * This routine handle the I18N transcoding to internal UTF-8
2617 * This routine is used when operating the parser in normal (pull) mode
2618 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002619 * TODO: one should be able to remove one extra copy by copying directly
Owen Taylor3473f882001-02-23 17:55:21 +00002620 * onto in->buffer or in->raw
2621 *
2622 * Returns the number of chars read and stored in the buffer, or -1
2623 * in case of error.
2624 */
2625int
2626xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
2627 char *buffer = NULL;
2628 int res = 0;
2629 int nbchars = 0;
2630 int buffree;
Daniel Veillard9e412302002-06-10 15:59:44 +00002631 unsigned int needSize;
Owen Taylor3473f882001-02-23 17:55:21 +00002632
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002633 if ((in == NULL) || (in->error)) return(-1);
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002634 if ((len <= MINLEN) && (len != 4))
Owen Taylor3473f882001-02-23 17:55:21 +00002635 len = MINLEN;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002636
Owen Taylor3473f882001-02-23 17:55:21 +00002637 buffree = in->buffer->size - in->buffer->use;
2638 if (buffree <= 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002639 xmlIOErr(XML_IO_BUFFER_FULL, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002640 in->error = XML_IO_BUFFER_FULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002641 return(0);
2642 }
Owen Taylor3473f882001-02-23 17:55:21 +00002643
Daniel Veillarde5354492002-05-16 08:43:22 +00002644 needSize = in->buffer->use + len + 1;
2645 if (needSize > in->buffer->size){
2646 if (!xmlBufferResize(in->buffer, needSize)){
Daniel Veillard05d987b2003-10-08 11:54:57 +00002647 xmlIOErrMemory("growing input buffer");
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002648 in->error = XML_ERR_NO_MEMORY;
Daniel Veillarde5354492002-05-16 08:43:22 +00002649 return(0);
2650 }
Owen Taylor3473f882001-02-23 17:55:21 +00002651 }
Daniel Veillarde5354492002-05-16 08:43:22 +00002652 buffer = (char *)&in->buffer->content[in->buffer->use];
Owen Taylor3473f882001-02-23 17:55:21 +00002653
2654 /*
2655 * Call the read method for this I/O type.
2656 */
2657 if (in->readcallback != NULL) {
2658 res = in->readcallback(in->context, &buffer[0], len);
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002659 if (res <= 0)
2660 in->readcallback = endOfInput;
Owen Taylor3473f882001-02-23 17:55:21 +00002661 } else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002662 xmlIOErr(XML_IO_NO_INPUT, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002663 in->error = XML_IO_NO_INPUT;
Owen Taylor3473f882001-02-23 17:55:21 +00002664 return(-1);
2665 }
2666 if (res < 0) {
Owen Taylor3473f882001-02-23 17:55:21 +00002667 return(-1);
2668 }
2669 len = res;
2670 if (in->encoder != NULL) {
2671 /*
2672 * Store the data in the incoming raw buffer
2673 */
2674 if (in->raw == NULL) {
2675 in->raw = xmlBufferCreate();
2676 }
2677 xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
2678
2679 /*
2680 * convert as much as possible to the parser reading buffer.
2681 */
2682 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2683 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002684 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002685 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002686 return(-1);
2687 }
2688 } else {
2689 nbchars = len;
Daniel Veillarde5354492002-05-16 08:43:22 +00002690 in->buffer->use += nbchars;
2691 buffer[nbchars] = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002692 }
2693#ifdef DEBUG_INPUT
2694 xmlGenericError(xmlGenericErrorContext,
2695 "I/O: read %d chars, buffer %d/%d\n",
2696 nbchars, in->buffer->use, in->buffer->size);
2697#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002698 return(nbchars);
2699}
2700
2701/**
2702 * xmlParserInputBufferRead:
2703 * @in: a buffered parser input
2704 * @len: indicative value of the amount of chars to read
2705 *
2706 * Refresh the content of the input buffer, the old data are considered
2707 * consumed
2708 * This routine handle the I18N transcoding to internal UTF-8
2709 *
2710 * Returns the number of chars read and stored in the buffer, or -1
2711 * in case of error.
2712 */
2713int
2714xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002715 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002716 if (in->readcallback != NULL)
2717 return(xmlParserInputBufferGrow(in, len));
Daniel Veillard53350552003-09-18 13:35:51 +00002718 else if ((in->buffer != NULL) &&
2719 (in->buffer->alloc == XML_BUFFER_ALLOC_IMMUTABLE))
2720 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002721 else
2722 return(-1);
2723}
2724
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002725#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002726/**
2727 * xmlOutputBufferWrite:
2728 * @out: a buffered parser output
2729 * @len: the size in bytes of the array.
2730 * @buf: an char array
2731 *
2732 * Write the content of the array in the output I/O buffer
2733 * This routine handle the I18N transcoding from internal UTF-8
2734 * The buffer is lossless, i.e. will store in case of partial
2735 * or delayed writes.
2736 *
2737 * Returns the number of chars immediately written, or -1
2738 * in case of error.
2739 */
2740int
2741xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
2742 int nbchars = 0; /* number of chars to output to I/O */
2743 int ret; /* return from function call */
2744 int written = 0; /* number of char written to I/O so far */
2745 int chunk; /* number of byte curreent processed from buf */
2746
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002747 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002748 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002749 if (out->error) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002750
2751 do {
2752 chunk = len;
2753 if (chunk > 4 * MINLEN)
2754 chunk = 4 * MINLEN;
2755
2756 /*
2757 * first handle encoding stuff.
2758 */
2759 if (out->encoder != NULL) {
2760 /*
2761 * Store the data in the incoming raw buffer
2762 */
2763 if (out->conv == NULL) {
2764 out->conv = xmlBufferCreate();
2765 }
2766 xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2767
2768 if ((out->buffer->use < MINLEN) && (chunk == len))
2769 goto done;
2770
2771 /*
2772 * convert as much as possible to the parser reading buffer.
2773 */
2774 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
Daniel Veillard809faa52003-02-10 15:43:53 +00002775 if ((ret < 0) && (ret != -3)) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002776 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002777 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002778 return(-1);
2779 }
2780 nbchars = out->conv->use;
2781 } else {
2782 xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2783 nbchars = out->buffer->use;
2784 }
2785 buf += chunk;
2786 len -= chunk;
2787
2788 if ((nbchars < MINLEN) && (len <= 0))
2789 goto done;
2790
2791 if (out->writecallback) {
2792 /*
2793 * second write the stuff to the I/O channel
2794 */
2795 if (out->encoder != NULL) {
2796 ret = out->writecallback(out->context,
2797 (const char *)out->conv->content, nbchars);
2798 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002799 xmlBufferShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002800 } else {
2801 ret = out->writecallback(out->context,
2802 (const char *)out->buffer->content, nbchars);
2803 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002804 xmlBufferShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002805 }
2806 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002807 xmlIOErr(XML_IO_WRITE, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002808 out->error = XML_IO_WRITE;
Owen Taylor3473f882001-02-23 17:55:21 +00002809 return(ret);
2810 }
2811 out->written += ret;
2812 }
2813 written += nbchars;
2814 } while (len > 0);
2815
2816done:
2817#ifdef DEBUG_INPUT
2818 xmlGenericError(xmlGenericErrorContext,
2819 "I/O: wrote %d chars\n", written);
2820#endif
2821 return(written);
2822}
2823
2824/**
2825 * xmlOutputBufferWriteString:
2826 * @out: a buffered parser output
2827 * @str: a zero terminated C string
2828 *
2829 * Write the content of the string in the output I/O buffer
2830 * This routine handle the I18N transcoding from internal UTF-8
2831 * The buffer is lossless, i.e. will store in case of partial
2832 * or delayed writes.
2833 *
2834 * Returns the number of chars immediately written, or -1
2835 * in case of error.
2836 */
2837int
2838xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
2839 int len;
2840
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002841 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002842 if (str == NULL)
2843 return(-1);
2844 len = strlen(str);
2845
2846 if (len > 0)
2847 return(xmlOutputBufferWrite(out, len, str));
2848 return(len);
2849}
2850
2851/**
2852 * xmlOutputBufferFlush:
2853 * @out: a buffered output
2854 *
2855 * flushes the output I/O channel
2856 *
2857 * Returns the number of byte written or -1 in case of error.
2858 */
2859int
2860xmlOutputBufferFlush(xmlOutputBufferPtr out) {
2861 int nbchars = 0, ret = 0;
2862
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002863 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002864 /*
2865 * first handle encoding stuff.
2866 */
2867 if ((out->conv != NULL) && (out->encoder != NULL)) {
2868 /*
2869 * convert as much as possible to the parser reading buffer.
2870 */
2871 nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
2872 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002873 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002874 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002875 return(-1);
2876 }
2877 }
2878
2879 /*
2880 * second flush the stuff to the I/O channel
2881 */
2882 if ((out->conv != NULL) && (out->encoder != NULL) &&
2883 (out->writecallback != NULL)) {
2884 ret = out->writecallback(out->context,
2885 (const char *)out->conv->content, out->conv->use);
2886 if (ret >= 0)
2887 xmlBufferShrink(out->conv, ret);
2888 } else if (out->writecallback != NULL) {
2889 ret = out->writecallback(out->context,
2890 (const char *)out->buffer->content, out->buffer->use);
2891 if (ret >= 0)
2892 xmlBufferShrink(out->buffer, ret);
2893 }
2894 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002895 xmlIOErr(XML_IO_FLUSH, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002896 out->error = XML_IO_FLUSH;
Owen Taylor3473f882001-02-23 17:55:21 +00002897 return(ret);
2898 }
2899 out->written += ret;
2900
2901#ifdef DEBUG_INPUT
2902 xmlGenericError(xmlGenericErrorContext,
2903 "I/O: flushed %d chars\n", ret);
2904#endif
2905 return(ret);
2906}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002907#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002908
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002909/**
Owen Taylor3473f882001-02-23 17:55:21 +00002910 * xmlParserGetDirectory:
2911 * @filename: the path to a file
2912 *
2913 * lookup the directory for that file
2914 *
2915 * Returns a new allocated string containing the directory, or NULL.
2916 */
2917char *
2918xmlParserGetDirectory(const char *filename) {
2919 char *ret = NULL;
2920 char dir[1024];
2921 char *cur;
2922 char sep = '/';
2923
Igor Zlatkovic9181cc02002-09-29 17:51:06 +00002924#ifdef _WIN32_WCE /* easy way by now ... wince does not have dirs! */
2925 return NULL;
2926#endif
2927
Owen Taylor3473f882001-02-23 17:55:21 +00002928 if (xmlInputCallbackInitialized == 0)
2929 xmlRegisterDefaultInputCallbacks();
2930
2931 if (filename == NULL) return(NULL);
Daniel Veillard3c5ed912002-01-08 10:36:16 +00002932#if defined(WIN32) && !defined(__CYGWIN__)
Owen Taylor3473f882001-02-23 17:55:21 +00002933 sep = '\\';
2934#endif
2935
2936 strncpy(dir, filename, 1023);
2937 dir[1023] = 0;
2938 cur = &dir[strlen(dir)];
2939 while (cur > dir) {
2940 if (*cur == sep) break;
2941 cur --;
2942 }
2943 if (*cur == sep) {
2944 if (cur == dir) dir[1] = 0;
2945 else *cur = 0;
2946 ret = xmlMemStrdup(dir);
2947 } else {
2948 if (getcwd(dir, 1024) != NULL) {
2949 dir[1023] = 0;
2950 ret = xmlMemStrdup(dir);
2951 }
2952 }
2953 return(ret);
2954}
2955
2956/****************************************************************
2957 * *
2958 * External entities loading *
2959 * *
2960 ****************************************************************/
2961
Daniel Veillarda840b692003-10-19 13:35:37 +00002962/**
2963 * xmlCheckHTTPInput:
2964 * @ctxt: an XML parser context
2965 * @ret: an XML parser input
2966 *
2967 * Check an input in case it was created from an HTTP stream, in that
2968 * case it will handle encoding and update of the base URL in case of
2969 * redirection. It also checks for HTTP errors in which case the input
2970 * is cleanly freed up and an appropriate error is raised in context
2971 *
2972 * Returns the input or NULL in case of HTTP error.
2973 */
2974xmlParserInputPtr
2975xmlCheckHTTPInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr ret) {
2976#ifdef LIBXML_HTTP_ENABLED
2977 if ((ret != NULL) && (ret->buf != NULL) &&
2978 (ret->buf->readcallback == xmlIOHTTPRead) &&
2979 (ret->buf->context != NULL)) {
2980 const char *encoding;
2981 const char *redir;
2982 const char *mime;
2983 int code;
2984
2985 code = xmlNanoHTTPReturnCode(ret->buf->context);
2986 if (code >= 400) {
2987 /* fatal error */
2988 if (ret->filename != NULL)
Daniel Veillarde8039df2003-10-27 11:25:13 +00002989 __xmlLoaderErr(ctxt, "failed to load HTTP resource \"%s\"\n",
Daniel Veillarda840b692003-10-19 13:35:37 +00002990 (const char *) ret->filename);
2991 else
Daniel Veillarde8039df2003-10-27 11:25:13 +00002992 __xmlLoaderErr(ctxt, "failed to load HTTP resource\n", NULL);
Daniel Veillarda840b692003-10-19 13:35:37 +00002993 xmlFreeInputStream(ret);
2994 ret = NULL;
2995 } else {
2996
2997 mime = xmlNanoHTTPMimeType(ret->buf->context);
2998 if ((xmlStrstr(BAD_CAST mime, BAD_CAST "/xml")) ||
2999 (xmlStrstr(BAD_CAST mime, BAD_CAST "+xml"))) {
3000 encoding = xmlNanoHTTPEncoding(ret->buf->context);
3001 if (encoding != NULL) {
3002 xmlCharEncodingHandlerPtr handler;
3003
3004 handler = xmlFindCharEncodingHandler(encoding);
3005 if (handler != NULL) {
3006 xmlSwitchInputEncoding(ctxt, ret, handler);
3007 } else {
3008 __xmlErrEncoding(ctxt, XML_ERR_UNKNOWN_ENCODING,
3009 "Unknown encoding %s",
3010 BAD_CAST encoding, NULL);
3011 }
3012 if (ret->encoding == NULL)
3013 ret->encoding = xmlStrdup(BAD_CAST encoding);
3014 }
3015#if 0
3016 } else if (xmlStrstr(BAD_CAST mime, BAD_CAST "html")) {
3017#endif
3018 }
3019 redir = xmlNanoHTTPRedir(ret->buf->context);
3020 if (redir != NULL) {
3021 if (ret->filename != NULL)
3022 xmlFree((xmlChar *) ret->filename);
3023 if (ret->directory != NULL) {
3024 xmlFree((xmlChar *) ret->directory);
3025 ret->directory = NULL;
3026 }
3027 ret->filename =
3028 (char *) xmlStrdup((const xmlChar *) redir);
3029 }
3030 }
3031 }
3032#endif
3033 return(ret);
3034}
3035
Daniel Veillard561b7f82002-03-20 21:55:57 +00003036static int xmlSysIDExists(const char *URL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003037#ifdef HAVE_STAT
3038 int ret;
3039 struct stat info;
3040 const char *path;
3041
3042 if (URL == NULL)
3043 return(0);
3044
Daniel Veillardf4862f02002-09-10 11:13:43 +00003045 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003046#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00003047 path = &URL[17];
3048#else
Daniel Veillard6990bf32001-08-23 21:17:48 +00003049 path = &URL[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00003050#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003051 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003052#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard6990bf32001-08-23 21:17:48 +00003053 path = &URL[8];
3054#else
3055 path = &URL[7];
3056#endif
3057 } else
3058 path = URL;
3059 ret = stat(path, &info);
Daniel Veillard561b7f82002-03-20 21:55:57 +00003060 if (ret == 0)
3061 return(1);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003062#endif
Daniel Veillard561b7f82002-03-20 21:55:57 +00003063 return(0);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003064}
Daniel Veillard6990bf32001-08-23 21:17:48 +00003065
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003066/**
Owen Taylor3473f882001-02-23 17:55:21 +00003067 * xmlDefaultExternalEntityLoader:
3068 * @URL: the URL for the entity to load
3069 * @ID: the System ID for the entity to load
3070 * @ctxt: the context in which the entity is called or NULL
3071 *
3072 * By default we don't load external entitites, yet.
3073 *
3074 * Returns a new allocated xmlParserInputPtr, or NULL.
3075 */
Daniel Veillarda840b692003-10-19 13:35:37 +00003076static xmlParserInputPtr
Owen Taylor3473f882001-02-23 17:55:21 +00003077xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
Daniel Veillarda840b692003-10-19 13:35:37 +00003078 xmlParserCtxtPtr ctxt)
3079{
Owen Taylor3473f882001-02-23 17:55:21 +00003080 xmlParserInputPtr ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003081 xmlChar *resource = NULL;
Daniel Veillarda840b692003-10-19 13:35:37 +00003082
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003083#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003084 xmlCatalogAllow pref;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003085#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003086
3087#ifdef DEBUG_EXTERNAL_ENTITIES
3088 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda840b692003-10-19 13:35:37 +00003089 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00003090#endif
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003091#ifdef LIBXML_CATALOG_ENABLED
3092 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003093 * If the resource doesn't exists as a file,
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003094 * try to load it from the resource pointed in the catalogs
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003095 */
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003096 pref = xmlCatalogGetDefaults();
3097
Daniel Veillard561b7f82002-03-20 21:55:57 +00003098 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlSysIDExists(URL))) {
Daniel Veillarda840b692003-10-19 13:35:37 +00003099 /*
3100 * Do a local lookup
3101 */
3102 if ((ctxt->catalogs != NULL) &&
3103 ((pref == XML_CATA_ALLOW_ALL) ||
3104 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3105 resource = xmlCatalogLocalResolve(ctxt->catalogs,
3106 (const xmlChar *) ID,
3107 (const xmlChar *) URL);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003108 }
Daniel Veillarda840b692003-10-19 13:35:37 +00003109 /*
3110 * Try a global lookup
3111 */
3112 if ((resource == NULL) &&
3113 ((pref == XML_CATA_ALLOW_ALL) ||
3114 (pref == XML_CATA_ALLOW_GLOBAL))) {
3115 resource = xmlCatalogResolve((const xmlChar *) ID,
3116 (const xmlChar *) URL);
3117 }
3118 if ((resource == NULL) && (URL != NULL))
3119 resource = xmlStrdup((const xmlChar *) URL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003120
Daniel Veillarda840b692003-10-19 13:35:37 +00003121 /*
3122 * TODO: do an URI lookup on the reference
3123 */
3124 if ((resource != NULL)
3125 && (!xmlSysIDExists((const char *) resource))) {
3126 xmlChar *tmp = NULL;
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003127
Daniel Veillarda840b692003-10-19 13:35:37 +00003128 if ((ctxt->catalogs != NULL) &&
3129 ((pref == XML_CATA_ALLOW_ALL) ||
3130 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3131 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
3132 }
3133 if ((tmp == NULL) &&
3134 ((pref == XML_CATA_ALLOW_ALL) ||
3135 (pref == XML_CATA_ALLOW_GLOBAL))) {
3136 tmp = xmlCatalogResolveURI(resource);
3137 }
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003138
Daniel Veillarda840b692003-10-19 13:35:37 +00003139 if (tmp != NULL) {
3140 xmlFree(resource);
3141 resource = tmp;
3142 }
3143 }
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003144 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003145#endif
3146
3147 if (resource == NULL)
Daniel Veillarda840b692003-10-19 13:35:37 +00003148 resource = (xmlChar *) URL;
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003149
3150 if (resource == NULL) {
Daniel Veillarda840b692003-10-19 13:35:37 +00003151 if (ID == NULL)
3152 ID = "NULL";
Daniel Veillarde8039df2003-10-27 11:25:13 +00003153 __xmlLoaderErr(ctxt, "failed to load external entity \"%s\"\n", ID);
Daniel Veillarda840b692003-10-19 13:35:37 +00003154 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003155 }
Daniel Veillarda840b692003-10-19 13:35:37 +00003156 ret = xmlNewInputFromFile(ctxt, (const char *) resource);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003157 if ((resource != NULL) && (resource != (xmlChar *) URL))
Daniel Veillarda840b692003-10-19 13:35:37 +00003158 xmlFree(resource);
3159 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003160}
3161
3162static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
3163 xmlDefaultExternalEntityLoader;
3164
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003165/**
Owen Taylor3473f882001-02-23 17:55:21 +00003166 * xmlSetExternalEntityLoader:
3167 * @f: the new entity resolver function
3168 *
3169 * Changes the defaultexternal entity resolver function for the application
3170 */
3171void
3172xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
3173 xmlCurrentExternalEntityLoader = f;
3174}
3175
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003176/**
Owen Taylor3473f882001-02-23 17:55:21 +00003177 * xmlGetExternalEntityLoader:
3178 *
3179 * Get the default external entity resolver function for the application
3180 *
3181 * Returns the xmlExternalEntityLoader function pointer
3182 */
3183xmlExternalEntityLoader
3184xmlGetExternalEntityLoader(void) {
3185 return(xmlCurrentExternalEntityLoader);
3186}
3187
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003188/**
Owen Taylor3473f882001-02-23 17:55:21 +00003189 * xmlLoadExternalEntity:
3190 * @URL: the URL for the entity to load
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00003191 * @ID: the Public ID for the entity to load
Owen Taylor3473f882001-02-23 17:55:21 +00003192 * @ctxt: the context in which the entity is called or NULL
3193 *
3194 * Load an external entity, note that the use of this function for
3195 * unparsed entities may generate problems
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003196 * TODO: a more generic External entity API must be designed
Owen Taylor3473f882001-02-23 17:55:21 +00003197 *
3198 * Returns the xmlParserInputPtr or NULL
3199 */
3200xmlParserInputPtr
3201xmlLoadExternalEntity(const char *URL, const char *ID,
3202 xmlParserCtxtPtr ctxt) {
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00003203 if ((URL != NULL) && (xmlSysIDExists(URL) == 0)) {
3204 char *canonicFilename;
3205 xmlParserInputPtr ret;
3206
3207 canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL);
3208 if (canonicFilename == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003209 xmlIOErrMemory("building canonical path\n");
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00003210 return(NULL);
3211 }
3212
3213 ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt);
3214 xmlFree(canonicFilename);
3215 return(ret);
3216 }
Owen Taylor3473f882001-02-23 17:55:21 +00003217 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
3218}
3219
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003220/************************************************************************
3221 * *
3222 * Disabling Network access *
3223 * *
3224 ************************************************************************/
3225
3226#ifdef LIBXML_CATALOG_ENABLED
3227static int
3228xmlNoNetExists(const char *URL)
3229{
3230#ifdef HAVE_STAT
3231 int ret;
3232 struct stat info;
3233 const char *path;
3234
3235 if (URL == NULL)
3236 return (0);
3237
Daniel Veillardf4862f02002-09-10 11:13:43 +00003238 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003239#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00003240 path = &URL[17];
3241#else
3242 path = &URL[16];
3243#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003244 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003245#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003246 path = &URL[8];
3247#else
3248 path = &URL[7];
3249#endif
3250 } else
3251 path = URL;
3252 ret = stat(path, &info);
3253 if (ret == 0)
3254 return (1);
3255#endif
3256 return (0);
3257}
3258#endif
3259
3260/**
3261 * xmlNoNetExternalEntityLoader:
3262 * @URL: the URL for the entity to load
3263 * @ID: the System ID for the entity to load
3264 * @ctxt: the context in which the entity is called or NULL
3265 *
3266 * A specific entity loader disabling network accesses, though still
3267 * allowing local catalog accesses for resolution.
3268 *
3269 * Returns a new allocated xmlParserInputPtr, or NULL.
3270 */
3271xmlParserInputPtr
3272xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
3273 xmlParserCtxtPtr ctxt) {
3274 xmlParserInputPtr input = NULL;
3275 xmlChar *resource = NULL;
3276
3277#ifdef LIBXML_CATALOG_ENABLED
3278 xmlCatalogAllow pref;
3279
3280 /*
3281 * If the resource doesn't exists as a file,
3282 * try to load it from the resource pointed in the catalogs
3283 */
3284 pref = xmlCatalogGetDefaults();
3285
3286 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
3287 /*
3288 * Do a local lookup
3289 */
3290 if ((ctxt->catalogs != NULL) &&
3291 ((pref == XML_CATA_ALLOW_ALL) ||
3292 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3293 resource = xmlCatalogLocalResolve(ctxt->catalogs,
3294 (const xmlChar *)ID,
3295 (const xmlChar *)URL);
3296 }
3297 /*
3298 * Try a global lookup
3299 */
3300 if ((resource == NULL) &&
3301 ((pref == XML_CATA_ALLOW_ALL) ||
3302 (pref == XML_CATA_ALLOW_GLOBAL))) {
3303 resource = xmlCatalogResolve((const xmlChar *)ID,
3304 (const xmlChar *)URL);
3305 }
3306 if ((resource == NULL) && (URL != NULL))
3307 resource = xmlStrdup((const xmlChar *) URL);
3308
3309 /*
3310 * TODO: do an URI lookup on the reference
3311 */
3312 if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
3313 xmlChar *tmp = NULL;
3314
3315 if ((ctxt->catalogs != NULL) &&
3316 ((pref == XML_CATA_ALLOW_ALL) ||
3317 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3318 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
3319 }
3320 if ((tmp == NULL) &&
3321 ((pref == XML_CATA_ALLOW_ALL) ||
3322 (pref == XML_CATA_ALLOW_GLOBAL))) {
3323 tmp = xmlCatalogResolveURI(resource);
3324 }
3325
3326 if (tmp != NULL) {
3327 xmlFree(resource);
3328 resource = tmp;
3329 }
3330 }
3331 }
3332#endif
3333 if (resource == NULL)
3334 resource = (xmlChar *) URL;
3335
3336 if (resource != NULL) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003337 if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
3338 (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003339 xmlIOErr(XML_IO_NETWORK_ATTEMPT, (const char *) resource);
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003340 if (resource != (xmlChar *) URL)
3341 xmlFree(resource);
3342 return(NULL);
3343 }
3344 }
3345 input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
3346 if (resource != (xmlChar *) URL)
3347 xmlFree(resource);
3348 return(input);
3349}
3350