blob: 0225aa05bb3f092c0aa6c11ab84ea2ac9b1c7071 [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
Daniel Veillard157fee02003-10-31 10:36:03 +0000412 if ((ctxt != NULL) && (ctxt->disableSAX != 0) &&
413 (ctxt->instate == XML_PARSER_EOF))
414 return;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000415 if ((ctxt != NULL) && (ctxt->sax != NULL)) {
416 if (ctxt->validate) {
417 channel = ctxt->sax->error;
418 level = XML_ERR_ERROR;
419 } else {
420 channel = ctxt->sax->warning;
421 level = XML_ERR_WARNING;
422 }
Daniel Veillard659e71e2003-10-10 14:10:40 +0000423 schannel = ctxt->sax->serror;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000424 data = ctxt->userData;
425 }
Daniel Veillard659e71e2003-10-10 14:10:40 +0000426 __xmlRaiseError(schannel, channel, data, ctxt, NULL, XML_FROM_IO,
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000427 XML_IO_LOAD_ERROR, level, NULL, 0,
428 filename, NULL, NULL, 0, 0,
429 msg, filename);
430
431}
432
Daniel Veillard05d987b2003-10-08 11:54:57 +0000433/************************************************************************
434 * *
435 * Tree memory error handler *
436 * *
437 ************************************************************************/
Daniel Veillardf4862f02002-09-10 11:13:43 +0000438/**
Daniel Veillard01c13b52002-12-10 15:19:08 +0000439 * xmlNormalizeWindowsPath:
Daniel Veillard33300b42003-04-17 09:09:19 +0000440 * @path: the input file path
Daniel Veillardf4862f02002-09-10 11:13:43 +0000441 *
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +0000442 * This function is obsolete. Please see xmlURIFromPath in uri.c for
443 * a better solution.
Daniel Veillard33300b42003-04-17 09:09:19 +0000444 *
445 * Returns a canonicalized version of the path
Daniel Veillardf4862f02002-09-10 11:13:43 +0000446 */
447xmlChar *
448xmlNormalizeWindowsPath(const xmlChar *path)
449{
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +0000450 return xmlCanonicPath(path);
Daniel Veillardf4862f02002-09-10 11:13:43 +0000451}
452
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000453/**
454 * xmlCleanupInputCallbacks:
455 *
456 * clears the entire input callback table. this includes the
457 * compiled-in I/O.
458 */
459void
460xmlCleanupInputCallbacks(void)
461{
462 int i;
463
464 if (!xmlInputCallbackInitialized)
465 return;
466
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000467 for (i = xmlInputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000468 xmlInputCallbackTable[i].matchcallback = NULL;
469 xmlInputCallbackTable[i].opencallback = NULL;
470 xmlInputCallbackTable[i].readcallback = NULL;
471 xmlInputCallbackTable[i].closecallback = NULL;
472 }
473
474 xmlInputCallbackNr = 0;
Aleksey Sanin9c45ba82002-06-06 21:46:13 +0000475 xmlInputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000476}
477
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000478#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000479/**
480 * xmlCleanupOutputCallbacks:
481 *
482 * clears the entire output callback table. this includes the
483 * compiled-in I/O callbacks.
484 */
485void
486xmlCleanupOutputCallbacks(void)
487{
488 int i;
489
490 if (!xmlOutputCallbackInitialized)
491 return;
492
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000493 for (i = xmlOutputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000494 xmlOutputCallbackTable[i].matchcallback = NULL;
495 xmlOutputCallbackTable[i].opencallback = NULL;
496 xmlOutputCallbackTable[i].writecallback = NULL;
497 xmlOutputCallbackTable[i].closecallback = NULL;
498 }
499
500 xmlOutputCallbackNr = 0;
Aleksey Sanin9c45ba82002-06-06 21:46:13 +0000501 xmlOutputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000502}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000503#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000504
Owen Taylor3473f882001-02-23 17:55:21 +0000505/************************************************************************
506 * *
507 * Standard I/O for file accesses *
508 * *
509 ************************************************************************/
510
511/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000512 * xmlCheckFilename:
Owen Taylor3473f882001-02-23 17:55:21 +0000513 * @path: the path to check
514 *
515 * function checks to see if @path is a valid source
516 * (file, socket...) for XML.
517 *
518 * if stat is not available on the target machine,
519 * returns 1. if stat fails, returns 0 (if calling
520 * stat on the filename fails, it can't be right).
521 * if stat succeeds and the file is a directory,
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000522 * returns 2. otherwise returns 1.
Owen Taylor3473f882001-02-23 17:55:21 +0000523 */
524
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000525int
Owen Taylor3473f882001-02-23 17:55:21 +0000526xmlCheckFilename (const char *path)
527{
528#ifdef HAVE_STAT
Owen Taylor3473f882001-02-23 17:55:21 +0000529 struct stat stat_buffer;
530
531 if (stat(path, &stat_buffer) == -1)
532 return 0;
533
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000534#ifdef S_ISDIR
Owen Taylor3473f882001-02-23 17:55:21 +0000535 if (S_ISDIR(stat_buffer.st_mode)) {
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000536 return 2;
Owen Taylor3473f882001-02-23 17:55:21 +0000537 }
Owen Taylor3473f882001-02-23 17:55:21 +0000538#endif
539#endif
540 return 1;
541}
542
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000543static int
Owen Taylor3473f882001-02-23 17:55:21 +0000544xmlNop(void) {
545 return(0);
546}
547
548/**
Owen Taylor3473f882001-02-23 17:55:21 +0000549 * xmlFdRead:
550 * @context: the I/O context
551 * @buffer: where to drop data
552 * @len: number of bytes to read
553 *
554 * Read @len bytes to @buffer from the I/O channel.
555 *
556 * Returns the number of bytes written
557 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000558static int
Owen Taylor3473f882001-02-23 17:55:21 +0000559xmlFdRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000560 int ret;
561
562 ret = read((int) (long) context, &buffer[0], len);
563 if (ret < 0) xmlIOErr(0, "read()");
564 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000565}
566
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000567#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000568/**
569 * xmlFdWrite:
570 * @context: the I/O context
571 * @buffer: where to get data
572 * @len: number of bytes to write
573 *
574 * Write @len bytes from @buffer to the I/O channel.
575 *
576 * Returns the number of bytes written
577 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000578static int
Owen Taylor3473f882001-02-23 17:55:21 +0000579xmlFdWrite (void * context, const char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000580 int ret;
581
582 ret = write((int) (long) context, &buffer[0], len);
583 if (ret < 0) xmlIOErr(0, "write()");
584 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000585}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000586#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000587
588/**
589 * xmlFdClose:
590 * @context: the I/O context
591 *
592 * Close an I/O channel
Daniel Veillardf012a642001-07-23 19:10:52 +0000593 *
594 * Returns 0 in case of success and error code otherwise
Owen Taylor3473f882001-02-23 17:55:21 +0000595 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000596static int
Owen Taylor3473f882001-02-23 17:55:21 +0000597xmlFdClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000598 int ret;
599 ret = close((int) (long) context);
600 if (ret < 0) xmlIOErr(0, "close()");
601 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000602}
603
604/**
605 * xmlFileMatch:
606 * @filename: the URI for matching
607 *
608 * input from FILE *
609 *
610 * Returns 1 if matches, 0 otherwise
611 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000612int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000613xmlFileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000614 return(1);
615}
616
617/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000618 * xmlFileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +0000619 * @filename: the URI for matching
620 *
621 * input from FILE *, supports compressed input
622 * if @filename is " " then the standard input is used
623 *
624 * Returns an I/O context or NULL in case of error
625 */
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000626static void *
627xmlFileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +0000628 const char *path = NULL;
629 FILE *fd;
630
631 if (!strcmp(filename, "-")) {
632 fd = stdin;
633 return((void *) fd);
634 }
635
Daniel Veillardf4862f02002-09-10 11:13:43 +0000636 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000637#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000638 path = &filename[17];
639#else
Owen Taylor3473f882001-02-23 17:55:21 +0000640 path = &filename[16];
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000641#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000642 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000643#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000644 path = &filename[8];
645#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000646 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000647#endif
648 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000649 path = filename;
650
651 if (path == NULL)
652 return(NULL);
653 if (!xmlCheckFilename(path))
654 return(NULL);
655
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000656#if defined(WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
Owen Taylor3473f882001-02-23 17:55:21 +0000657 fd = fopen(path, "rb");
658#else
659 fd = fopen(path, "r");
660#endif /* WIN32 */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000661 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +0000662 return((void *) fd);
663}
664
665/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000666 * xmlFileOpen:
667 * @filename: the URI for matching
668 *
669 * Wrapper around xmlFileOpen_real that try it with an unescaped
670 * version of @filename, if this fails fallback to @filename
Daniel Veillard71531f32003-02-05 13:19:53 +0000671 *
672 * Returns a handler or NULL in case or failure
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000673 */
674void *
675xmlFileOpen (const char *filename) {
676 char *unescaped;
677 void *retval;
678 unescaped = xmlURIUnescapeString(filename, 0, NULL);
679 if (unescaped != NULL) {
680 retval = xmlFileOpen_real(unescaped);
681 } else {
682 retval = xmlFileOpen_real(filename);
683 }
684 xmlFree(unescaped);
685 return retval;
686}
687
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000688#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000689/**
Owen Taylor3473f882001-02-23 17:55:21 +0000690 * xmlFileOpenW:
691 * @filename: the URI for matching
692 *
693 * output to from FILE *,
694 * if @filename is "-" then the standard output is used
695 *
696 * Returns an I/O context or NULL in case of error
697 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000698static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000699xmlFileOpenW (const char *filename) {
700 const char *path = NULL;
701 FILE *fd;
702
703 if (!strcmp(filename, "-")) {
704 fd = stdout;
705 return((void *) fd);
706 }
707
Daniel Veillardf4862f02002-09-10 11:13:43 +0000708 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000709#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000710 path = &filename[17];
711#else
Owen Taylor3473f882001-02-23 17:55:21 +0000712 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000713#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000714 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000715#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000716 path = &filename[8];
717#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000718 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000719#endif
720 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000721 path = filename;
722
723 if (path == NULL)
724 return(NULL);
725
Daniel Veillardcbbd78d2003-07-20 15:21:30 +0000726 fd = fopen(path, "wb");
Daniel Veillard05d987b2003-10-08 11:54:57 +0000727 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +0000728 return((void *) fd);
729}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000730#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000731
732/**
733 * xmlFileRead:
734 * @context: the I/O context
735 * @buffer: where to drop data
736 * @len: number of bytes to write
737 *
738 * Read @len bytes to @buffer from the I/O channel.
739 *
740 * Returns the number of bytes written
741 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000742int
Owen Taylor3473f882001-02-23 17:55:21 +0000743xmlFileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000744 int ret;
745 ret = fread(&buffer[0], 1, len, (FILE *) context);
746 if (ret < 0) xmlIOErr(0, "fread()");
747 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000748}
749
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000750#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000751/**
752 * xmlFileWrite:
753 * @context: the I/O context
754 * @buffer: where to drop data
755 * @len: number of bytes to write
756 *
757 * Write @len bytes from @buffer to the I/O channel.
758 *
759 * Returns the number of bytes written
760 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000761static int
Owen Taylor3473f882001-02-23 17:55:21 +0000762xmlFileWrite (void * context, const char * buffer, int len) {
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000763 int items;
764
765 items = fwrite(&buffer[0], len, 1, (FILE *) context);
Daniel Veillard97bf4d02003-10-08 18:58:28 +0000766 if ((items == 0) && (ferror((FILE *) context))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000767 xmlIOErr(0, "fwrite()");
Daniel Veillard97bf4d02003-10-08 18:58:28 +0000768 return(-1);
769 }
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000770 return(items * len);
Owen Taylor3473f882001-02-23 17:55:21 +0000771}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000772#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000773
774/**
775 * xmlFileClose:
776 * @context: the I/O context
777 *
778 * Close an I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000779 *
780 * Returns 0 or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +0000781 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000782int
Owen Taylor3473f882001-02-23 17:55:21 +0000783xmlFileClose (void * context) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000784 FILE *fil;
Daniel Veillard05d987b2003-10-08 11:54:57 +0000785 int ret;
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000786
787 fil = (FILE *) context;
788 if (fil == stdin)
789 return(0);
790 if (fil == stdout)
791 return(0);
Daniel Veillardcd337f02001-11-22 18:20:37 +0000792 if (fil == stderr)
793 return(0);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000794 ret = ( fclose((FILE *) context) == EOF ) ? -1 : 0;
795 if (ret < 0)
796 xmlIOErr(0, "fclose()");
797 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000798}
799
800/**
801 * xmlFileFlush:
802 * @context: the I/O context
803 *
804 * Flush an I/O channel
805 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000806static int
Owen Taylor3473f882001-02-23 17:55:21 +0000807xmlFileFlush (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000808 int ret;
809 ret = ( fflush((FILE *) context) == EOF ) ? -1 : 0;
810 if (ret < 0)
811 xmlIOErr(0, "fflush()");
812 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000813}
814
815#ifdef HAVE_ZLIB_H
816/************************************************************************
817 * *
818 * I/O for compressed file accesses *
819 * *
820 ************************************************************************/
821/**
822 * xmlGzfileMatch:
823 * @filename: the URI for matching
824 *
825 * input from compressed file test
826 *
827 * Returns 1 if matches, 0 otherwise
828 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000829static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000830xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000831 return(1);
832}
833
834/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000835 * xmlGzfileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +0000836 * @filename: the URI for matching
837 *
838 * input from compressed file open
839 * if @filename is " " then the standard input is used
840 *
841 * Returns an I/O context or NULL in case of error
842 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000843static void *
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000844xmlGzfileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +0000845 const char *path = NULL;
846 gzFile fd;
847
848 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000849 fd = gzdopen(dup(0), "rb");
Owen Taylor3473f882001-02-23 17:55:21 +0000850 return((void *) fd);
851 }
852
Daniel Veillardf4862f02002-09-10 11:13:43 +0000853 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000854#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000855 path = &filename[17];
856#else
Owen Taylor3473f882001-02-23 17:55:21 +0000857 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000858#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000859 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000860#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000861 path = &filename[8];
862#else
Owen Taylor3473f882001-02-23 17:55:21 +0000863 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000864#endif
865 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000866 path = filename;
867
868 if (path == NULL)
869 return(NULL);
870 if (!xmlCheckFilename(path))
871 return(NULL);
872
873 fd = gzopen(path, "rb");
874 return((void *) fd);
875}
876
877/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000878 * xmlGzfileOpen:
879 * @filename: the URI for matching
880 *
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +0000881 * Wrapper around xmlGzfileOpen if the open fais, it will
882 * try to unescape @filename
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000883 */
884static void *
885xmlGzfileOpen (const char *filename) {
886 char *unescaped;
887 void *retval;
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +0000888
889 retval = xmlGzfileOpen_real(filename);
890 if (retval == NULL) {
891 unescaped = xmlURIUnescapeString(filename, 0, NULL);
892 if (unescaped != NULL) {
893 retval = xmlGzfileOpen_real(unescaped);
894 }
895 xmlFree(unescaped);
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000896 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000897 return retval;
898}
899
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000900#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000901/**
Owen Taylor3473f882001-02-23 17:55:21 +0000902 * xmlGzfileOpenW:
903 * @filename: the URI for matching
904 * @compression: the compression factor (0 - 9 included)
905 *
906 * input from compressed file open
907 * if @filename is " " then the standard input is used
908 *
909 * Returns an I/O context or NULL in case of error
910 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000911static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000912xmlGzfileOpenW (const char *filename, int compression) {
913 const char *path = NULL;
914 char mode[15];
915 gzFile fd;
916
Aleksey Sanin49cc9752002-06-14 17:07:10 +0000917 snprintf(mode, sizeof(mode), "wb%d", compression);
Owen Taylor3473f882001-02-23 17:55:21 +0000918 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000919 fd = gzdopen(dup(1), mode);
Owen Taylor3473f882001-02-23 17:55:21 +0000920 return((void *) fd);
921 }
922
Daniel Veillardf4862f02002-09-10 11:13:43 +0000923 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000924#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000925 path = &filename[17];
926#else
Owen Taylor3473f882001-02-23 17:55:21 +0000927 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000928#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000929 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000930#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000931 path = &filename[8];
932#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000933 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000934#endif
935 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000936 path = filename;
937
938 if (path == NULL)
939 return(NULL);
940
941 fd = gzopen(path, mode);
942 return((void *) fd);
943}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000944#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000945
946/**
947 * xmlGzfileRead:
948 * @context: the I/O context
949 * @buffer: where to drop data
950 * @len: number of bytes to write
951 *
952 * Read @len bytes to @buffer from the compressed I/O channel.
953 *
954 * Returns the number of bytes written
955 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000956static int
Owen Taylor3473f882001-02-23 17:55:21 +0000957xmlGzfileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000958 int ret;
959
960 ret = gzread((gzFile) context, &buffer[0], len);
961 if (ret < 0) xmlIOErr(0, "gzread()");
962 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000963}
964
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000965#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000966/**
967 * xmlGzfileWrite:
968 * @context: the I/O context
969 * @buffer: where to drop data
970 * @len: number of bytes to write
971 *
972 * Write @len bytes from @buffer to the compressed I/O channel.
973 *
974 * Returns the number of bytes written
975 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000976static int
Owen Taylor3473f882001-02-23 17:55:21 +0000977xmlGzfileWrite (void * context, const char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000978 int ret;
979
980 ret = gzwrite((gzFile) context, (char *) &buffer[0], len);
981 if (ret < 0) xmlIOErr(0, "gzwrite()");
982 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000983}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000984#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000985
986/**
987 * xmlGzfileClose:
988 * @context: the I/O context
989 *
990 * Close a compressed I/O channel
991 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000992static int
Owen Taylor3473f882001-02-23 17:55:21 +0000993xmlGzfileClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000994 int ret;
995
996 ret = (gzclose((gzFile) context) == Z_OK ) ? 0 : -1;
997 if (ret < 0) xmlIOErr(0, "gzclose()");
998 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000999}
1000#endif /* HAVE_ZLIB_H */
1001
1002#ifdef LIBXML_HTTP_ENABLED
1003/************************************************************************
1004 * *
1005 * I/O for HTTP file accesses *
1006 * *
1007 ************************************************************************/
Daniel Veillardf012a642001-07-23 19:10:52 +00001008
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001009#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001010typedef struct xmlIOHTTPWriteCtxt_
1011{
1012 int compression;
1013
1014 char * uri;
1015
1016 void * doc_buff;
1017
1018} xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr;
1019
1020#ifdef HAVE_ZLIB_H
1021
1022#define DFLT_WBITS ( -15 )
1023#define DFLT_MEM_LVL ( 8 )
1024#define GZ_MAGIC1 ( 0x1f )
1025#define GZ_MAGIC2 ( 0x8b )
1026#define LXML_ZLIB_OS_CODE ( 0x03 )
1027#define INIT_HTTP_BUFF_SIZE ( 32768 )
1028#define DFLT_ZLIB_RATIO ( 5 )
1029
1030/*
1031** Data structure and functions to work with sending compressed data
1032** via HTTP.
1033*/
1034
1035typedef struct xmlZMemBuff_
1036{
1037 unsigned long size;
1038 unsigned long crc;
1039
1040 unsigned char * zbuff;
1041 z_stream zctrl;
1042
1043} xmlZMemBuff, *xmlZMemBuffPtr;
1044
1045/**
1046 * append_reverse_ulong
1047 * @buff: Compressed memory buffer
1048 * @data: Unsigned long to append
1049 *
1050 * Append a unsigned long in reverse byte order to the end of the
1051 * memory buffer.
1052 */
1053static void
1054append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) {
1055
1056 int idx;
1057
1058 if ( buff == NULL )
1059 return;
1060
1061 /*
1062 ** This is plagiarized from putLong in gzio.c (zlib source) where
1063 ** the number "4" is hardcoded. If zlib is ever patched to
1064 ** support 64 bit file sizes, this code would need to be patched
1065 ** as well.
1066 */
1067
1068 for ( idx = 0; idx < 4; idx++ ) {
1069 *buff->zctrl.next_out = ( data & 0xff );
1070 data >>= 8;
1071 buff->zctrl.next_out++;
1072 }
1073
1074 return;
1075}
1076
1077/**
1078 *
1079 * xmlFreeZMemBuff
1080 * @buff: The memory buffer context to clear
1081 *
1082 * Release all the resources associated with the compressed memory buffer.
1083 */
1084static void
1085xmlFreeZMemBuff( xmlZMemBuffPtr buff ) {
William M. Brack78637da2003-07-31 14:47:38 +00001086
1087#ifdef DEBUG_HTTP
Daniel Veillardf012a642001-07-23 19:10:52 +00001088 int z_err;
William M. Brack78637da2003-07-31 14:47:38 +00001089#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001090
1091 if ( buff == NULL )
1092 return;
1093
1094 xmlFree( buff->zbuff );
Daniel Veillardf012a642001-07-23 19:10:52 +00001095#ifdef DEBUG_HTTP
William M. Brack78637da2003-07-31 14:47:38 +00001096 z_err = deflateEnd( &buff->zctrl );
Daniel Veillardf012a642001-07-23 19:10:52 +00001097 if ( z_err != Z_OK )
1098 xmlGenericError( xmlGenericErrorContext,
1099 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
1100 z_err );
William M. Brack78637da2003-07-31 14:47:38 +00001101#else
1102 deflateEnd( &buff->zctrl );
William M. Brack779af002003-08-01 15:55:39 +00001103#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001104
1105 xmlFree( buff );
1106 return;
1107}
1108
1109/**
1110 * xmlCreateZMemBuff
1111 *@compression: Compression value to use
1112 *
1113 * Create a memory buffer to hold the compressed XML document. The
1114 * compressed document in memory will end up being identical to what
1115 * would be created if gzopen/gzwrite/gzclose were being used to
1116 * write the document to disk. The code for the header/trailer data to
1117 * the compression is plagiarized from the zlib source files.
1118 */
1119static void *
1120xmlCreateZMemBuff( int compression ) {
1121
1122 int z_err;
1123 int hdr_lgth;
1124 xmlZMemBuffPtr buff = NULL;
1125
1126 if ( ( compression < 1 ) || ( compression > 9 ) )
1127 return ( NULL );
1128
1129 /* Create the control and data areas */
1130
1131 buff = xmlMalloc( sizeof( xmlZMemBuff ) );
1132 if ( buff == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001133 xmlIOErrMemory("creating buffer context");
Daniel Veillardf012a642001-07-23 19:10:52 +00001134 return ( NULL );
1135 }
1136
1137 (void)memset( buff, 0, sizeof( xmlZMemBuff ) );
1138 buff->size = INIT_HTTP_BUFF_SIZE;
1139 buff->zbuff = xmlMalloc( buff->size );
1140 if ( buff->zbuff == NULL ) {
1141 xmlFreeZMemBuff( buff );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001142 xmlIOErrMemory("creating buffer");
Daniel Veillardf012a642001-07-23 19:10:52 +00001143 return ( NULL );
1144 }
1145
1146 z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
1147 DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
1148 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001149 xmlChar msg[500];
Daniel Veillardf012a642001-07-23 19:10:52 +00001150 xmlFreeZMemBuff( buff );
1151 buff = NULL;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001152 xmlStrPrintf(msg, 500,
1153 (const xmlChar *) "xmlCreateZMemBuff: %s %d\n",
1154 "Error initializing compression context. ZLIB error:",
1155 z_err );
1156 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001157 return ( NULL );
1158 }
1159
1160 /* Set the header data. The CRC will be needed for the trailer */
Daniel Veillardf012a642001-07-23 19:10:52 +00001161 buff->crc = crc32( 0L, Z_NULL, 0 );
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001162 hdr_lgth = snprintf( (char *)buff->zbuff, buff->size,
1163 "%c%c%c%c%c%c%c%c%c%c",
Daniel Veillardf012a642001-07-23 19:10:52 +00001164 GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED,
1165 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE );
1166 buff->zctrl.next_out = buff->zbuff + hdr_lgth;
1167 buff->zctrl.avail_out = buff->size - hdr_lgth;
1168
1169 return ( buff );
1170}
1171
1172/**
1173 * xmlZMemBuffExtend
1174 * @buff: Buffer used to compress and consolidate data.
1175 * @ext_amt: Number of bytes to extend the buffer.
1176 *
1177 * Extend the internal buffer used to store the compressed data by the
1178 * specified amount.
1179 *
1180 * Returns 0 on success or -1 on failure to extend the buffer. On failure
1181 * the original buffer still exists at the original size.
1182 */
1183static int
1184xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) {
1185
1186 int rc = -1;
1187 size_t new_size;
1188 size_t cur_used;
1189
1190 unsigned char * tmp_ptr = NULL;
1191
1192 if ( buff == NULL )
1193 return ( -1 );
1194
1195 else if ( ext_amt == 0 )
1196 return ( 0 );
1197
1198 cur_used = buff->zctrl.next_out - buff->zbuff;
1199 new_size = buff->size + ext_amt;
1200
1201#ifdef DEBUG_HTTP
1202 if ( cur_used > new_size )
1203 xmlGenericError( xmlGenericErrorContext,
1204 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
1205 "Buffer overwrite detected during compressed memory",
1206 "buffer extension. Overflowed by",
1207 (cur_used - new_size ) );
1208#endif
1209
1210 tmp_ptr = xmlRealloc( buff->zbuff, new_size );
1211 if ( tmp_ptr != NULL ) {
1212 rc = 0;
1213 buff->size = new_size;
1214 buff->zbuff = tmp_ptr;
1215 buff->zctrl.next_out = tmp_ptr + cur_used;
1216 buff->zctrl.avail_out = new_size - cur_used;
1217 }
1218 else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001219 xmlChar msg[500];
1220 xmlStrPrintf(msg, 500,
1221 (const xmlChar *) "xmlZMemBuffExtend: %s %lu bytes.\n",
1222 "Allocation failure extending output buffer to",
1223 new_size );
1224 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001225 }
1226
1227 return ( rc );
1228}
1229
1230/**
1231 * xmlZMemBuffAppend
1232 * @buff: Buffer used to compress and consolidate data
1233 * @src: Uncompressed source content to append to buffer
1234 * @len: Length of source data to append to buffer
1235 *
1236 * Compress and append data to the internal buffer. The data buffer
1237 * will be expanded if needed to store the additional data.
1238 *
1239 * Returns the number of bytes appended to the buffer or -1 on error.
1240 */
1241static int
1242xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) {
1243
1244 int z_err;
1245 size_t min_accept;
1246
1247 if ( ( buff == NULL ) || ( src == NULL ) )
1248 return ( -1 );
1249
1250 buff->zctrl.avail_in = len;
1251 buff->zctrl.next_in = (unsigned char *)src;
1252 while ( buff->zctrl.avail_in > 0 ) {
1253 /*
1254 ** Extend the buffer prior to deflate call if a reasonable amount
1255 ** of output buffer space is not available.
1256 */
1257 min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO;
1258 if ( buff->zctrl.avail_out <= min_accept ) {
1259 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1260 return ( -1 );
1261 }
1262
1263 z_err = deflate( &buff->zctrl, Z_NO_FLUSH );
1264 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001265 xmlChar msg[500];
1266 xmlStrPrintf(msg, 500,
1267 (const xmlChar *) "xmlZMemBuffAppend: %s %d %s - %d",
Daniel Veillardf012a642001-07-23 19:10:52 +00001268 "Compression error while appending",
1269 len, "bytes to buffer. ZLIB error", z_err );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001270 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001271 return ( -1 );
1272 }
1273 }
1274
1275 buff->crc = crc32( buff->crc, (unsigned char *)src, len );
1276
1277 return ( len );
1278}
1279
1280/**
1281 * xmlZMemBuffGetContent
1282 * @buff: Compressed memory content buffer
1283 * @data_ref: Pointer reference to point to compressed content
1284 *
1285 * Flushes the compression buffers, appends gzip file trailers and
1286 * returns the compressed content and length of the compressed data.
1287 * NOTE: The gzip trailer code here is plagiarized from zlib source.
1288 *
1289 * Returns the length of the compressed data or -1 on error.
1290 */
1291static int
1292xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) {
1293
1294 int zlgth = -1;
1295 int z_err;
1296
1297 if ( ( buff == NULL ) || ( data_ref == NULL ) )
1298 return ( -1 );
1299
1300 /* Need to loop until compression output buffers are flushed */
1301
1302 do
1303 {
1304 z_err = deflate( &buff->zctrl, Z_FINISH );
1305 if ( z_err == Z_OK ) {
1306 /* In this case Z_OK means more buffer space needed */
1307
1308 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1309 return ( -1 );
1310 }
1311 }
1312 while ( z_err == Z_OK );
1313
1314 /* If the compression state is not Z_STREAM_END, some error occurred */
1315
1316 if ( z_err == Z_STREAM_END ) {
1317
1318 /* Need to append the gzip data trailer */
1319
1320 if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) {
1321 if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 )
1322 return ( -1 );
1323 }
1324
1325 /*
1326 ** For whatever reason, the CRC and length data are pushed out
1327 ** in reverse byte order. So a memcpy can't be used here.
1328 */
1329
1330 append_reverse_ulong( buff, buff->crc );
1331 append_reverse_ulong( buff, buff->zctrl.total_in );
1332
1333 zlgth = buff->zctrl.next_out - buff->zbuff;
1334 *data_ref = (char *)buff->zbuff;
1335 }
1336
Daniel Veillard05d987b2003-10-08 11:54:57 +00001337 else {
1338 xmlChar msg[500];
1339 xmlStrPrintf(msg, 500,
1340 (const xmlChar *) "xmlZMemBuffGetContent: %s - %d\n",
1341 "Error flushing zlib buffers. Error code", z_err );
1342 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1343 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001344
1345 return ( zlgth );
1346}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001347#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001348#endif /* HAVE_ZLIB_H */
1349
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001350#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001351/**
1352 * xmlFreeHTTPWriteCtxt
1353 * @ctxt: Context to cleanup
1354 *
1355 * Free allocated memory and reclaim system resources.
1356 *
1357 * No return value.
1358 */
1359static void
1360xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt )
1361{
1362 if ( ctxt->uri != NULL )
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001363 xmlFree( ctxt->uri );
Daniel Veillardf012a642001-07-23 19:10:52 +00001364
1365 if ( ctxt->doc_buff != NULL ) {
1366
1367#ifdef HAVE_ZLIB_H
1368 if ( ctxt->compression > 0 ) {
1369 xmlFreeZMemBuff( ctxt->doc_buff );
1370 }
1371 else
1372#endif
1373 {
1374 xmlOutputBufferClose( ctxt->doc_buff );
1375 }
1376 }
1377
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001378 xmlFree( ctxt );
Daniel Veillardf012a642001-07-23 19:10:52 +00001379 return;
1380}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001381#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001382
1383
Owen Taylor3473f882001-02-23 17:55:21 +00001384/**
1385 * xmlIOHTTPMatch:
1386 * @filename: the URI for matching
1387 *
1388 * check if the URI matches an HTTP one
1389 *
1390 * Returns 1 if matches, 0 otherwise
1391 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001392int
Owen Taylor3473f882001-02-23 17:55:21 +00001393xmlIOHTTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001394 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "http://", 7))
Owen Taylor3473f882001-02-23 17:55:21 +00001395 return(1);
1396 return(0);
1397}
1398
1399/**
1400 * xmlIOHTTPOpen:
1401 * @filename: the URI for matching
1402 *
1403 * open an HTTP I/O channel
1404 *
1405 * Returns an I/O context or NULL in case of error
1406 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001407void *
Owen Taylor3473f882001-02-23 17:55:21 +00001408xmlIOHTTPOpen (const char *filename) {
1409 return(xmlNanoHTTPOpen(filename, NULL));
1410}
1411
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001412#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001413/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001414 * xmlIOHTTPOpenW:
Daniel Veillardf012a642001-07-23 19:10:52 +00001415 * @post_uri: The destination URI for the document
1416 * @compression: The compression desired for the document.
1417 *
1418 * Open a temporary buffer to collect the document for a subsequent HTTP POST
1419 * request. Non-static as is called from the output buffer creation routine.
1420 *
1421 * Returns an I/O context or NULL in case of error.
1422 */
1423
1424void *
Daniel Veillard572577e2002-01-18 16:23:55 +00001425xmlIOHTTPOpenW(const char *post_uri, int compression)
1426{
Daniel Veillardf012a642001-07-23 19:10:52 +00001427
Daniel Veillard572577e2002-01-18 16:23:55 +00001428 xmlIOHTTPWriteCtxtPtr ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001429
Daniel Veillard572577e2002-01-18 16:23:55 +00001430 if (post_uri == NULL)
1431 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001432
Daniel Veillard572577e2002-01-18 16:23:55 +00001433 ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt));
1434 if (ctxt == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001435 xmlIOErrMemory("creating HTTP output context");
Daniel Veillard572577e2002-01-18 16:23:55 +00001436 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001437 }
1438
Daniel Veillard572577e2002-01-18 16:23:55 +00001439 (void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt));
Daniel Veillardf012a642001-07-23 19:10:52 +00001440
Daniel Veillard572577e2002-01-18 16:23:55 +00001441 ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri);
1442 if (ctxt->uri == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001443 xmlIOErrMemory("copying URI");
Daniel Veillard572577e2002-01-18 16:23:55 +00001444 xmlFreeHTTPWriteCtxt(ctxt);
1445 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001446 }
1447
1448 /*
Daniel Veillard572577e2002-01-18 16:23:55 +00001449 * ** Since the document length is required for an HTTP post,
1450 * ** need to put the document into a buffer. A memory buffer
1451 * ** is being used to avoid pushing the data to disk and back.
1452 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001453
1454#ifdef HAVE_ZLIB_H
Daniel Veillard572577e2002-01-18 16:23:55 +00001455 if ((compression > 0) && (compression <= 9)) {
1456
1457 ctxt->compression = compression;
1458 ctxt->doc_buff = xmlCreateZMemBuff(compression);
1459 } else
Daniel Veillardf012a642001-07-23 19:10:52 +00001460#endif
1461 {
Daniel Veillard572577e2002-01-18 16:23:55 +00001462 /* Any character conversions should have been done before this */
Daniel Veillardf012a642001-07-23 19:10:52 +00001463
Daniel Veillard572577e2002-01-18 16:23:55 +00001464 ctxt->doc_buff = xmlAllocOutputBuffer(NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001465 }
1466
Daniel Veillard572577e2002-01-18 16:23:55 +00001467 if (ctxt->doc_buff == NULL) {
1468 xmlFreeHTTPWriteCtxt(ctxt);
1469 ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001470 }
1471
Daniel Veillard572577e2002-01-18 16:23:55 +00001472 return (ctxt);
Daniel Veillardf012a642001-07-23 19:10:52 +00001473}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001474#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001475
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001476#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001477/**
1478 * xmlIOHTTPDfltOpenW
1479 * @post_uri: The destination URI for this document.
1480 *
1481 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
1482 * HTTP post command. This function should generally not be used as
1483 * the open callback is short circuited in xmlOutputBufferCreateFile.
1484 *
1485 * Returns a pointer to the new IO context.
1486 */
1487static void *
1488xmlIOHTTPDfltOpenW( const char * post_uri ) {
1489 return ( xmlIOHTTPOpenW( post_uri, 0 ) );
1490}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001491#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001492
1493/**
Owen Taylor3473f882001-02-23 17:55:21 +00001494 * xmlIOHTTPRead:
1495 * @context: the I/O context
1496 * @buffer: where to drop data
1497 * @len: number of bytes to write
1498 *
1499 * Read @len bytes to @buffer from the I/O channel.
1500 *
1501 * Returns the number of bytes written
1502 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001503int
Owen Taylor3473f882001-02-23 17:55:21 +00001504xmlIOHTTPRead(void * context, char * buffer, int len) {
1505 return(xmlNanoHTTPRead(context, &buffer[0], len));
1506}
1507
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001508#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001509/**
Daniel Veillardf012a642001-07-23 19:10:52 +00001510 * xmlIOHTTPWrite
1511 * @context: previously opened writing context
1512 * @buffer: data to output to temporary buffer
1513 * @len: bytes to output
1514 *
1515 * Collect data from memory buffer into a temporary file for later
1516 * processing.
1517 *
1518 * Returns number of bytes written.
1519 */
1520
1521static int
1522xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
1523
1524 xmlIOHTTPWriteCtxtPtr ctxt = context;
1525
1526 if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
1527 return ( -1 );
1528
1529 if ( len > 0 ) {
1530
1531 /* Use gzwrite or fwrite as previously setup in the open call */
1532
1533#ifdef HAVE_ZLIB_H
1534 if ( ctxt->compression > 0 )
1535 len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len );
1536
1537 else
1538#endif
1539 len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
1540
1541 if ( len < 0 ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001542 xmlChar msg[500];
1543 xmlStrPrintf(msg, 500,
1544 (const xmlChar *) "xmlIOHTTPWrite: %s\n%s '%s'.\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001545 "Error appending to internal buffer.",
1546 "Error sending document to URI",
1547 ctxt->uri );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001548 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001549 }
1550 }
1551
1552 return ( len );
1553}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001554#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001555
1556
1557/**
Owen Taylor3473f882001-02-23 17:55:21 +00001558 * xmlIOHTTPClose:
1559 * @context: the I/O context
1560 *
1561 * Close an HTTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001562 *
1563 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00001564 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001565int
Owen Taylor3473f882001-02-23 17:55:21 +00001566xmlIOHTTPClose (void * context) {
1567 xmlNanoHTTPClose(context);
Daniel Veillardf012a642001-07-23 19:10:52 +00001568 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001569}
Daniel Veillardf012a642001-07-23 19:10:52 +00001570
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001571#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001572/**
1573 * xmlIOHTTCloseWrite
1574 * @context: The I/O context
1575 * @http_mthd: The HTTP method to be used when sending the data
1576 *
1577 * Close the transmit HTTP I/O channel and actually send the data.
1578 */
1579static int
1580xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
1581
1582 int close_rc = -1;
1583 int http_rtn = 0;
1584 int content_lgth = 0;
1585 xmlIOHTTPWriteCtxtPtr ctxt = context;
1586
1587 char * http_content = NULL;
1588 char * content_encoding = NULL;
1589 char * content_type = (char *) "text/xml";
1590 void * http_ctxt = NULL;
1591
1592 if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
1593 return ( -1 );
1594
1595 /* Retrieve the content from the appropriate buffer */
1596
1597#ifdef HAVE_ZLIB_H
1598
1599 if ( ctxt->compression > 0 ) {
1600 content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
1601 content_encoding = (char *) "Content-Encoding: gzip";
1602 }
1603 else
1604#endif
1605 {
1606 /* Pull the data out of the memory output buffer */
1607
1608 xmlOutputBufferPtr dctxt = ctxt->doc_buff;
1609 http_content = (char *)dctxt->buffer->content;
1610 content_lgth = dctxt->buffer->use;
1611 }
1612
1613 if ( http_content == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001614 xmlChar msg[500];
1615 xmlStrPrintf(msg, 500,
1616 (const xmlChar *) "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
1617 "Error retrieving content.\nUnable to",
1618 http_mthd, "data to URI", ctxt->uri );
1619 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001620 }
1621
1622 else {
1623
1624 http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
1625 &content_type, content_encoding,
1626 content_lgth );
1627
1628 if ( http_ctxt != NULL ) {
1629#ifdef DEBUG_HTTP
1630 /* If testing/debugging - dump reply with request content */
1631
1632 FILE * tst_file = NULL;
1633 char buffer[ 4096 ];
1634 char * dump_name = NULL;
1635 int avail;
1636
1637 xmlGenericError( xmlGenericErrorContext,
1638 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
1639 http_mthd, ctxt->uri,
1640 xmlNanoHTTPReturnCode( http_ctxt ) );
1641
1642 /*
1643 ** Since either content or reply may be gzipped,
1644 ** dump them to separate files instead of the
1645 ** standard error context.
1646 */
1647
1648 dump_name = tempnam( NULL, "lxml" );
1649 if ( dump_name != NULL ) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001650 (void)snprintf( buffer, sizeof(buffer), "%s.content", dump_name );
Daniel Veillardf012a642001-07-23 19:10:52 +00001651
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00001652 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00001653 if ( tst_file != NULL ) {
1654 xmlGenericError( xmlGenericErrorContext,
1655 "Transmitted content saved in file: %s\n", buffer );
1656
1657 fwrite( http_content, sizeof( char ),
1658 content_lgth, tst_file );
1659 fclose( tst_file );
1660 }
1661
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001662 (void)snprintf( buffer, sizeof(buffer), "%s.reply", dump_name );
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00001663 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00001664 if ( tst_file != NULL ) {
1665 xmlGenericError( xmlGenericErrorContext,
1666 "Reply content saved in file: %s\n", buffer );
1667
1668
1669 while ( (avail = xmlNanoHTTPRead( http_ctxt,
1670 buffer, sizeof( buffer ) )) > 0 ) {
1671
1672 fwrite( buffer, sizeof( char ), avail, tst_file );
1673 }
1674
1675 fclose( tst_file );
1676 }
1677
1678 free( dump_name );
1679 }
1680#endif /* DEBUG_HTTP */
1681
1682 http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
1683 if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
1684 close_rc = 0;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001685 else {
1686 xmlChar msg[500];
1687 xmlStrPrintf(msg, 500,
1688 (const xmlChar *) "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001689 http_mthd, content_lgth,
1690 "bytes to URI", ctxt->uri,
1691 "failed. HTTP return code:", http_rtn );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001692 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1693 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001694
1695 xmlNanoHTTPClose( http_ctxt );
1696 xmlFree( content_type );
1697 }
1698 }
1699
1700 /* Final cleanups */
1701
1702 xmlFreeHTTPWriteCtxt( ctxt );
1703
1704 return ( close_rc );
1705}
1706
1707/**
1708 * xmlIOHTTPClosePut
1709 *
1710 * @context: The I/O context
1711 *
1712 * Close the transmit HTTP I/O channel and actually send data using a PUT
1713 * HTTP method.
1714 */
1715static int
1716xmlIOHTTPClosePut( void * ctxt ) {
1717 return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
1718}
1719
1720
1721/**
1722 * xmlIOHTTPClosePost
1723 *
1724 * @context: The I/O context
1725 *
1726 * Close the transmit HTTP I/O channel and actually send data using a POST
1727 * HTTP method.
1728 */
1729static int
1730xmlIOHTTPClosePost( void * ctxt ) {
1731 return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
1732}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001733#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001734
Owen Taylor3473f882001-02-23 17:55:21 +00001735#endif /* LIBXML_HTTP_ENABLED */
1736
1737#ifdef LIBXML_FTP_ENABLED
1738/************************************************************************
1739 * *
1740 * I/O for FTP file accesses *
1741 * *
1742 ************************************************************************/
1743/**
1744 * xmlIOFTPMatch:
1745 * @filename: the URI for matching
1746 *
1747 * check if the URI matches an FTP one
1748 *
1749 * Returns 1 if matches, 0 otherwise
1750 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001751int
Owen Taylor3473f882001-02-23 17:55:21 +00001752xmlIOFTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001753 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "ftp://", 6))
Owen Taylor3473f882001-02-23 17:55:21 +00001754 return(1);
1755 return(0);
1756}
1757
1758/**
1759 * xmlIOFTPOpen:
1760 * @filename: the URI for matching
1761 *
1762 * open an FTP I/O channel
1763 *
1764 * Returns an I/O context or NULL in case of error
1765 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001766void *
Owen Taylor3473f882001-02-23 17:55:21 +00001767xmlIOFTPOpen (const char *filename) {
1768 return(xmlNanoFTPOpen(filename));
1769}
1770
1771/**
1772 * xmlIOFTPRead:
1773 * @context: the I/O context
1774 * @buffer: where to drop data
1775 * @len: number of bytes to write
1776 *
1777 * Read @len bytes to @buffer from the I/O channel.
1778 *
1779 * Returns the number of bytes written
1780 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001781int
Owen Taylor3473f882001-02-23 17:55:21 +00001782xmlIOFTPRead(void * context, char * buffer, int len) {
1783 return(xmlNanoFTPRead(context, &buffer[0], len));
1784}
1785
1786/**
1787 * xmlIOFTPClose:
1788 * @context: the I/O context
1789 *
1790 * Close an FTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001791 *
1792 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00001793 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001794int
Owen Taylor3473f882001-02-23 17:55:21 +00001795xmlIOFTPClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001796 return ( xmlNanoFTPClose(context) );
Owen Taylor3473f882001-02-23 17:55:21 +00001797}
1798#endif /* LIBXML_FTP_ENABLED */
1799
1800
1801/**
1802 * xmlRegisterInputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001803 * @matchFunc: the xmlInputMatchCallback
1804 * @openFunc: the xmlInputOpenCallback
1805 * @readFunc: the xmlInputReadCallback
1806 * @closeFunc: the xmlInputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001807 *
1808 * Register a new set of I/O callback for handling parser input.
1809 *
1810 * Returns the registered handler number or -1 in case of error
1811 */
1812int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001813xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
1814 xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
1815 xmlInputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001816 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
1817 return(-1);
1818 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001819 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
1820 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
1821 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
1822 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00001823 xmlInputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00001824 return(xmlInputCallbackNr++);
1825}
1826
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001827#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001828/**
1829 * xmlRegisterOutputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001830 * @matchFunc: the xmlOutputMatchCallback
1831 * @openFunc: the xmlOutputOpenCallback
1832 * @writeFunc: the xmlOutputWriteCallback
1833 * @closeFunc: the xmlOutputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001834 *
1835 * Register a new set of I/O callback for handling output.
1836 *
1837 * Returns the registered handler number or -1 in case of error
1838 */
1839int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001840xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
1841 xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
1842 xmlOutputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001843 if (xmlOutputCallbackNr >= MAX_INPUT_CALLBACK) {
1844 return(-1);
1845 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001846 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
1847 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
1848 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
1849 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00001850 xmlOutputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00001851 return(xmlOutputCallbackNr++);
1852}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001853#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001854
1855/**
1856 * xmlRegisterDefaultInputCallbacks:
1857 *
1858 * Registers the default compiled-in I/O handlers.
1859 */
1860void
Owen Taylor3473f882001-02-23 17:55:21 +00001861xmlRegisterDefaultInputCallbacks
Owen Taylor3473f882001-02-23 17:55:21 +00001862(void) {
1863 if (xmlInputCallbackInitialized)
1864 return;
1865
1866 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
1867 xmlFileRead, xmlFileClose);
1868#ifdef HAVE_ZLIB_H
1869 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1870 xmlGzfileRead, xmlGzfileClose);
1871#endif /* HAVE_ZLIB_H */
1872
1873#ifdef LIBXML_HTTP_ENABLED
1874 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
1875 xmlIOHTTPRead, xmlIOHTTPClose);
1876#endif /* LIBXML_HTTP_ENABLED */
1877
1878#ifdef LIBXML_FTP_ENABLED
1879 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1880 xmlIOFTPRead, xmlIOFTPClose);
1881#endif /* LIBXML_FTP_ENABLED */
1882 xmlInputCallbackInitialized = 1;
1883}
1884
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001885#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001886/**
1887 * xmlRegisterDefaultOutputCallbacks:
1888 *
1889 * Registers the default compiled-in I/O handlers.
1890 */
1891void
Owen Taylor3473f882001-02-23 17:55:21 +00001892xmlRegisterDefaultOutputCallbacks
Owen Taylor3473f882001-02-23 17:55:21 +00001893(void) {
1894 if (xmlOutputCallbackInitialized)
1895 return;
1896
1897 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
1898 xmlFileWrite, xmlFileClose);
Daniel Veillardf012a642001-07-23 19:10:52 +00001899
1900#ifdef LIBXML_HTTP_ENABLED
1901 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
1902 xmlIOHTTPWrite, xmlIOHTTPClosePut);
1903#endif
1904
Owen Taylor3473f882001-02-23 17:55:21 +00001905/*********************************
1906 No way a-priori to distinguish between gzipped files from
1907 uncompressed ones except opening if existing then closing
1908 and saving with same compression ratio ... a pain.
1909
1910#ifdef HAVE_ZLIB_H
1911 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1912 xmlGzfileWrite, xmlGzfileClose);
1913#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001914
1915 Nor FTP PUT ....
1916#ifdef LIBXML_FTP_ENABLED
1917 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1918 xmlIOFTPWrite, xmlIOFTPClose);
1919#endif
1920 **********************************/
1921 xmlOutputCallbackInitialized = 1;
1922}
1923
Daniel Veillardf012a642001-07-23 19:10:52 +00001924#ifdef LIBXML_HTTP_ENABLED
1925/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001926 * xmlRegisterHTTPPostCallbacks:
Daniel Veillardf012a642001-07-23 19:10:52 +00001927 *
1928 * By default, libxml submits HTTP output requests using the "PUT" method.
1929 * Calling this method changes the HTTP output method to use the "POST"
1930 * method instead.
1931 *
1932 */
1933void
1934xmlRegisterHTTPPostCallbacks( void ) {
1935
1936 /* Register defaults if not done previously */
1937
1938 if ( xmlOutputCallbackInitialized == 0 )
1939 xmlRegisterDefaultOutputCallbacks( );
1940
1941 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
1942 xmlIOHTTPWrite, xmlIOHTTPClosePost);
1943 return;
1944}
1945#endif
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001946#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001947
Owen Taylor3473f882001-02-23 17:55:21 +00001948/**
1949 * xmlAllocParserInputBuffer:
1950 * @enc: the charset encoding if known
1951 *
1952 * Create a buffered parser input for progressive parsing
1953 *
1954 * Returns the new parser input or NULL
1955 */
1956xmlParserInputBufferPtr
1957xmlAllocParserInputBuffer(xmlCharEncoding enc) {
1958 xmlParserInputBufferPtr ret;
1959
1960 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
1961 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001962 xmlIOErrMemory("creating input buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00001963 return(NULL);
1964 }
1965 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00001966 ret->buffer = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00001967 if (ret->buffer == NULL) {
1968 xmlFree(ret);
1969 return(NULL);
1970 }
1971 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
1972 ret->encoder = xmlGetCharEncodingHandler(enc);
1973 if (ret->encoder != NULL)
Daniel Veillard6155d8a2003-08-19 15:01:28 +00001974 ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00001975 else
1976 ret->raw = NULL;
1977 ret->readcallback = NULL;
1978 ret->closecallback = NULL;
1979 ret->context = NULL;
William M. Brackc07329e2003-09-08 01:57:30 +00001980 ret->compressed = -1;
Daniel Veillard36711902004-02-11 13:25:26 +00001981 ret->rawconsumed = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001982
1983 return(ret);
1984}
1985
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001986#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001987/**
1988 * xmlAllocOutputBuffer:
1989 * @encoder: the encoding converter or NULL
1990 *
1991 * Create a buffered parser output
1992 *
1993 * Returns the new parser output or NULL
1994 */
1995xmlOutputBufferPtr
1996xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
1997 xmlOutputBufferPtr ret;
1998
1999 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
2000 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002001 xmlIOErrMemory("creating output buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00002002 return(NULL);
2003 }
2004 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
2005 ret->buffer = xmlBufferCreate();
2006 if (ret->buffer == NULL) {
2007 xmlFree(ret);
2008 return(NULL);
2009 }
2010 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
2011 ret->encoder = encoder;
2012 if (encoder != NULL) {
2013 ret->conv = xmlBufferCreateSize(4000);
2014 /*
2015 * This call is designed to initiate the encoder state
2016 */
2017 xmlCharEncOutFunc(encoder, ret->conv, NULL);
2018 } else
2019 ret->conv = NULL;
2020 ret->writecallback = NULL;
2021 ret->closecallback = NULL;
2022 ret->context = NULL;
2023 ret->written = 0;
2024
2025 return(ret);
2026}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002027#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002028
2029/**
2030 * xmlFreeParserInputBuffer:
2031 * @in: a buffered parser input
2032 *
2033 * Free up the memory used by a buffered parser input
2034 */
2035void
2036xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
Daniel Veillard8d8bf2c2003-09-17 19:36:25 +00002037 if (in == NULL) return;
2038
Owen Taylor3473f882001-02-23 17:55:21 +00002039 if (in->raw) {
2040 xmlBufferFree(in->raw);
2041 in->raw = NULL;
2042 }
2043 if (in->encoder != NULL) {
2044 xmlCharEncCloseFunc(in->encoder);
2045 }
2046 if (in->closecallback != NULL) {
2047 in->closecallback(in->context);
2048 }
2049 if (in->buffer != NULL) {
2050 xmlBufferFree(in->buffer);
2051 in->buffer = NULL;
2052 }
2053
Owen Taylor3473f882001-02-23 17:55:21 +00002054 xmlFree(in);
2055}
2056
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002057#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002058/**
2059 * xmlOutputBufferClose:
2060 * @out: a buffered output
2061 *
2062 * flushes and close the output I/O channel
2063 * and free up all the associated resources
2064 *
2065 * Returns the number of byte written or -1 in case of error.
2066 */
2067int
Daniel Veillard828ce832003-10-08 19:19:10 +00002068xmlOutputBufferClose(xmlOutputBufferPtr out)
2069{
Owen Taylor3473f882001-02-23 17:55:21 +00002070 int written;
Daniel Veillardf012a642001-07-23 19:10:52 +00002071 int err_rc = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002072
2073 if (out == NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002074 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002075 if (out->writecallback != NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002076 xmlOutputBufferFlush(out);
Owen Taylor3473f882001-02-23 17:55:21 +00002077 if (out->closecallback != NULL) {
Daniel Veillard828ce832003-10-08 19:19:10 +00002078 err_rc = out->closecallback(out->context);
Owen Taylor3473f882001-02-23 17:55:21 +00002079 }
2080 written = out->written;
2081 if (out->conv) {
2082 xmlBufferFree(out->conv);
Daniel Veillard828ce832003-10-08 19:19:10 +00002083 out->conv = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002084 }
2085 if (out->encoder != NULL) {
2086 xmlCharEncCloseFunc(out->encoder);
2087 }
2088 if (out->buffer != NULL) {
2089 xmlBufferFree(out->buffer);
Daniel Veillard828ce832003-10-08 19:19:10 +00002090 out->buffer = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002091 }
2092
Daniel Veillard828ce832003-10-08 19:19:10 +00002093 if (out->error)
2094 err_rc = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00002095 xmlFree(out);
Daniel Veillard828ce832003-10-08 19:19:10 +00002096 return ((err_rc == 0) ? written : err_rc);
Owen Taylor3473f882001-02-23 17:55:21 +00002097}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002098#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002099
2100/**
2101 * xmlParserInputBufferCreateFilename:
2102 * @URI: a C string containing the URI or filename
2103 * @enc: the charset encoding if known
2104 *
2105 * Create a buffered parser input for the progressive parsing of a file
2106 * If filename is "-' then we use stdin as the input.
2107 * Automatic support for ZLIB/Compress compressed document is provided
2108 * by default if found at compile-time.
2109 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
2110 *
2111 * Returns the new parser input or NULL
2112 */
2113xmlParserInputBufferPtr
Daniel Veillard3e59fc52003-04-18 12:34:58 +00002114xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002115 xmlParserInputBufferPtr ret;
Daniel Veillard388236f2001-07-08 18:35:48 +00002116 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002117 void *context = NULL;
2118
2119 if (xmlInputCallbackInitialized == 0)
2120 xmlRegisterDefaultInputCallbacks();
2121
2122 if (URI == NULL) return(NULL);
2123
2124 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002125 * Try to find one of the input accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002126 * Go in reverse to give precedence to user defined handlers.
Daniel Veillard388236f2001-07-08 18:35:48 +00002127 */
2128 if (context == NULL) {
2129 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
2130 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
2131 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002132 context = xmlInputCallbackTable[i].opencallback(URI);
Daniel Veillard847332a2003-10-18 11:29:40 +00002133 if (context != NULL) {
Daniel Veillard388236f2001-07-08 18:35:48 +00002134 break;
Daniel Veillard847332a2003-10-18 11:29:40 +00002135 }
Daniel Veillard388236f2001-07-08 18:35:48 +00002136 }
Owen Taylor3473f882001-02-23 17:55:21 +00002137 }
2138 }
2139 if (context == NULL) {
2140 return(NULL);
2141 }
2142
2143 /*
2144 * Allocate the Input buffer front-end.
2145 */
2146 ret = xmlAllocParserInputBuffer(enc);
2147 if (ret != NULL) {
2148 ret->context = context;
2149 ret->readcallback = xmlInputCallbackTable[i].readcallback;
2150 ret->closecallback = xmlInputCallbackTable[i].closecallback;
William M. Brackc07329e2003-09-08 01:57:30 +00002151#ifdef HAVE_ZLIB_H
William M. Brackc5cbf992003-10-29 22:15:13 +00002152 if ((xmlInputCallbackTable[i].opencallback == xmlGzfileOpen) &&
2153 (strcmp(URI, "-") != 0)) {
William M. Brackc07329e2003-09-08 01:57:30 +00002154 if (((z_stream *)context)->avail_in > 4) {
2155 char *cptr, buff4[4];
Daniel Veillard07cb8222003-09-10 10:51:05 +00002156 cptr = (char *) ((z_stream *)context)->next_in;
William M. Brackc07329e2003-09-08 01:57:30 +00002157 if (gzread(context, buff4, 4) == 4) {
2158 if (strncmp(buff4, cptr, 4) == 0)
2159 ret->compressed = 0;
2160 else
2161 ret->compressed = 1;
2162 gzrewind(context);
2163 }
2164 }
2165 }
2166#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002167 }
2168 return(ret);
2169}
2170
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002171#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002172/**
2173 * xmlOutputBufferCreateFilename:
2174 * @URI: a C string containing the URI or filename
2175 * @encoder: the encoding converter or NULL
2176 * @compression: the compression ration (0 none, 9 max).
2177 *
2178 * Create a buffered output for the progressive saving of a file
2179 * If filename is "-' then we use stdout as the output.
2180 * Automatic support for ZLIB/Compress compressed document is provided
2181 * by default if found at compile-time.
2182 * TODO: currently if compression is set, the library only support
2183 * writing to a local file.
2184 *
2185 * Returns the new output or NULL
2186 */
2187xmlOutputBufferPtr
2188xmlOutputBufferCreateFilename(const char *URI,
2189 xmlCharEncodingHandlerPtr encoder,
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002190 int compression ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00002191 xmlOutputBufferPtr ret;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002192 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002193 void *context = NULL;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002194 char *unescaped;
Owen Taylor3473f882001-02-23 17:55:21 +00002195
Daniel Veillardf012a642001-07-23 19:10:52 +00002196 int is_http_uri = 0; /* Can't change if HTTP disabled */
2197
Owen Taylor3473f882001-02-23 17:55:21 +00002198 if (xmlOutputCallbackInitialized == 0)
2199 xmlRegisterDefaultOutputCallbacks();
2200
2201 if (URI == NULL) return(NULL);
2202
Daniel Veillardf012a642001-07-23 19:10:52 +00002203#ifdef LIBXML_HTTP_ENABLED
2204 /* Need to prevent HTTP URI's from falling into zlib short circuit */
2205
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002206 is_http_uri = xmlIOHTTPMatch( URI );
Daniel Veillardf012a642001-07-23 19:10:52 +00002207#endif
2208
Owen Taylor3473f882001-02-23 17:55:21 +00002209
2210 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002211 * Try to find one of the output accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002212 * Go in reverse to give precedence to user defined handlers.
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002213 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00002214 */
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002215 unescaped = xmlURIUnescapeString(URI, 0, NULL);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002216 if (unescaped != NULL) {
2217#ifdef HAVE_ZLIB_H
2218 if ((compression > 0) && (compression <= 9) && (is_http_uri == 0)) {
2219 context = xmlGzfileOpenW(unescaped, compression);
2220 if (context != NULL) {
2221 ret = xmlAllocOutputBuffer(encoder);
2222 if (ret != NULL) {
2223 ret->context = context;
2224 ret->writecallback = xmlGzfileWrite;
2225 ret->closecallback = xmlGzfileClose;
2226 }
2227 xmlFree(unescaped);
2228 return(ret);
2229 }
2230 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002231#endif
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002232 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2233 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
2234 (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
2235#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2236 /* Need to pass compression parameter into HTTP open calls */
2237 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2238 context = xmlIOHTTPOpenW(unescaped, compression);
2239 else
2240#endif
2241 context = xmlOutputCallbackTable[i].opencallback(unescaped);
2242 if (context != NULL)
2243 break;
2244 }
2245 }
2246 xmlFree(unescaped);
2247 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002248
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002249 /*
2250 * If this failed try with a non-escaped URI this may be a strange
2251 * filename
2252 */
2253 if (context == NULL) {
2254#ifdef HAVE_ZLIB_H
2255 if ((compression > 0) && (compression <= 9) && (is_http_uri == 0)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002256 context = xmlGzfileOpenW(URI, compression);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002257 if (context != NULL) {
2258 ret = xmlAllocOutputBuffer(encoder);
2259 if (ret != NULL) {
2260 ret->context = context;
2261 ret->writecallback = xmlGzfileWrite;
2262 ret->closecallback = xmlGzfileClose;
2263 }
2264 return(ret);
2265 }
2266 }
2267#endif
2268 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2269 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002270 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002271#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2272 /* Need to pass compression parameter into HTTP open calls */
2273 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2274 context = xmlIOHTTPOpenW(URI, compression);
2275 else
2276#endif
2277 context = xmlOutputCallbackTable[i].opencallback(URI);
2278 if (context != NULL)
2279 break;
2280 }
Owen Taylor3473f882001-02-23 17:55:21 +00002281 }
2282 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002283
Owen Taylor3473f882001-02-23 17:55:21 +00002284 if (context == NULL) {
2285 return(NULL);
2286 }
2287
2288 /*
2289 * Allocate the Output buffer front-end.
2290 */
2291 ret = xmlAllocOutputBuffer(encoder);
2292 if (ret != NULL) {
2293 ret->context = context;
2294 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
2295 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
2296 }
2297 return(ret);
2298}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002299#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002300
2301/**
2302 * xmlParserInputBufferCreateFile:
2303 * @file: a FILE*
2304 * @enc: the charset encoding if known
2305 *
2306 * Create a buffered parser input for the progressive parsing of a FILE *
2307 * buffered C I/O
2308 *
2309 * Returns the new parser input or NULL
2310 */
2311xmlParserInputBufferPtr
2312xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
2313 xmlParserInputBufferPtr ret;
2314
2315 if (xmlInputCallbackInitialized == 0)
2316 xmlRegisterDefaultInputCallbacks();
2317
2318 if (file == NULL) return(NULL);
2319
2320 ret = xmlAllocParserInputBuffer(enc);
2321 if (ret != NULL) {
2322 ret->context = file;
2323 ret->readcallback = xmlFileRead;
2324 ret->closecallback = xmlFileFlush;
2325 }
2326
2327 return(ret);
2328}
2329
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002330#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002331/**
2332 * xmlOutputBufferCreateFile:
2333 * @file: a FILE*
2334 * @encoder: the encoding converter or NULL
2335 *
2336 * Create a buffered output for the progressive saving to a FILE *
2337 * buffered C I/O
2338 *
2339 * Returns the new parser output or NULL
2340 */
2341xmlOutputBufferPtr
2342xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
2343 xmlOutputBufferPtr ret;
2344
2345 if (xmlOutputCallbackInitialized == 0)
2346 xmlRegisterDefaultOutputCallbacks();
2347
2348 if (file == NULL) return(NULL);
2349
2350 ret = xmlAllocOutputBuffer(encoder);
2351 if (ret != NULL) {
2352 ret->context = file;
2353 ret->writecallback = xmlFileWrite;
2354 ret->closecallback = xmlFileFlush;
2355 }
2356
2357 return(ret);
2358}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002359#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002360
2361/**
2362 * xmlParserInputBufferCreateFd:
2363 * @fd: a file descriptor number
2364 * @enc: the charset encoding if known
2365 *
2366 * Create a buffered parser input for the progressive parsing for the input
2367 * from a file descriptor
2368 *
2369 * Returns the new parser input or NULL
2370 */
2371xmlParserInputBufferPtr
2372xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
2373 xmlParserInputBufferPtr ret;
2374
2375 if (fd < 0) return(NULL);
2376
2377 ret = xmlAllocParserInputBuffer(enc);
2378 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002379 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002380 ret->readcallback = xmlFdRead;
2381 ret->closecallback = xmlFdClose;
2382 }
2383
2384 return(ret);
2385}
2386
2387/**
2388 * xmlParserInputBufferCreateMem:
2389 * @mem: the memory input
2390 * @size: the length of the memory block
2391 * @enc: the charset encoding if known
2392 *
2393 * Create a buffered parser input for the progressive parsing for the input
2394 * from a memory area.
2395 *
2396 * Returns the new parser input or NULL
2397 */
2398xmlParserInputBufferPtr
2399xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
2400 xmlParserInputBufferPtr ret;
2401
2402 if (size <= 0) return(NULL);
2403 if (mem == NULL) return(NULL);
2404
2405 ret = xmlAllocParserInputBuffer(enc);
2406 if (ret != NULL) {
2407 ret->context = (void *) mem;
2408 ret->readcallback = (xmlInputReadCallback) xmlNop;
2409 ret->closecallback = NULL;
2410 xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size);
2411 }
2412
2413 return(ret);
2414}
2415
2416/**
Daniel Veillard53350552003-09-18 13:35:51 +00002417 * xmlParserInputBufferCreateStatic:
2418 * @mem: the memory input
2419 * @size: the length of the memory block
2420 * @enc: the charset encoding if known
2421 *
2422 * Create a buffered parser input for the progressive parsing for the input
2423 * from an immutable memory area. This will not copy the memory area to
2424 * the buffer, but the memory is expected to be available until the end of
2425 * the parsing, this is useful for example when using mmap'ed file.
2426 *
2427 * Returns the new parser input or NULL
2428 */
2429xmlParserInputBufferPtr
2430xmlParserInputBufferCreateStatic(const char *mem, int size,
2431 xmlCharEncoding enc) {
2432 xmlParserInputBufferPtr ret;
2433
2434 if (size <= 0) return(NULL);
2435 if (mem == NULL) return(NULL);
2436
2437 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2438 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002439 xmlIOErrMemory("creating input buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00002440 return(NULL);
2441 }
2442 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillarde72c5082003-09-19 12:44:05 +00002443 ret->buffer = xmlBufferCreateStatic((void *)mem, (size_t) size);
Daniel Veillard53350552003-09-18 13:35:51 +00002444 if (ret->buffer == NULL) {
2445 xmlFree(ret);
2446 return(NULL);
2447 }
2448 ret->encoder = xmlGetCharEncodingHandler(enc);
2449 if (ret->encoder != NULL)
2450 ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
2451 else
2452 ret->raw = NULL;
2453 ret->compressed = -1;
2454 ret->context = (void *) mem;
2455 ret->readcallback = NULL;
2456 ret->closecallback = NULL;
2457
2458 return(ret);
2459}
2460
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002461#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard53350552003-09-18 13:35:51 +00002462/**
Owen Taylor3473f882001-02-23 17:55:21 +00002463 * xmlOutputBufferCreateFd:
2464 * @fd: a file descriptor number
2465 * @encoder: the encoding converter or NULL
2466 *
2467 * Create a buffered output for the progressive saving
2468 * to a file descriptor
2469 *
2470 * Returns the new parser output or NULL
2471 */
2472xmlOutputBufferPtr
2473xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
2474 xmlOutputBufferPtr ret;
2475
2476 if (fd < 0) return(NULL);
2477
2478 ret = xmlAllocOutputBuffer(encoder);
2479 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002480 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002481 ret->writecallback = xmlFdWrite;
Daniel Veillard7db38712002-02-07 16:39:11 +00002482 ret->closecallback = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002483 }
2484
2485 return(ret);
2486}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002487#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002488
2489/**
2490 * xmlParserInputBufferCreateIO:
2491 * @ioread: an I/O read function
2492 * @ioclose: an I/O close function
2493 * @ioctx: an I/O handler
2494 * @enc: the charset encoding if known
2495 *
2496 * Create a buffered parser input for the progressive parsing for the input
2497 * from an I/O handler
2498 *
2499 * Returns the new parser input or NULL
2500 */
2501xmlParserInputBufferPtr
2502xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
2503 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
2504 xmlParserInputBufferPtr ret;
2505
2506 if (ioread == NULL) return(NULL);
2507
2508 ret = xmlAllocParserInputBuffer(enc);
2509 if (ret != NULL) {
2510 ret->context = (void *) ioctx;
2511 ret->readcallback = ioread;
2512 ret->closecallback = ioclose;
2513 }
2514
2515 return(ret);
2516}
2517
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002518#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002519/**
2520 * xmlOutputBufferCreateIO:
2521 * @iowrite: an I/O write function
2522 * @ioclose: an I/O close function
2523 * @ioctx: an I/O handler
Daniel Veillard9d06d302002-01-22 18:15:52 +00002524 * @encoder: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002525 *
2526 * Create a buffered output for the progressive saving
2527 * to an I/O handler
2528 *
2529 * Returns the new parser output or NULL
2530 */
2531xmlOutputBufferPtr
2532xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
2533 xmlOutputCloseCallback ioclose, void *ioctx,
2534 xmlCharEncodingHandlerPtr encoder) {
2535 xmlOutputBufferPtr ret;
2536
2537 if (iowrite == NULL) return(NULL);
2538
2539 ret = xmlAllocOutputBuffer(encoder);
2540 if (ret != NULL) {
2541 ret->context = (void *) ioctx;
2542 ret->writecallback = iowrite;
2543 ret->closecallback = ioclose;
2544 }
2545
2546 return(ret);
2547}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002548#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002549
2550/**
2551 * xmlParserInputBufferPush:
2552 * @in: a buffered parser input
2553 * @len: the size in bytes of the array.
2554 * @buf: an char array
2555 *
2556 * Push the content of the arry in the input buffer
2557 * This routine handle the I18N transcoding to internal UTF-8
2558 * This is used when operating the parser in progressive (push) mode.
2559 *
2560 * Returns the number of chars read and stored in the buffer, or -1
2561 * in case of error.
2562 */
2563int
2564xmlParserInputBufferPush(xmlParserInputBufferPtr in,
2565 int len, const char *buf) {
2566 int nbchars = 0;
2567
2568 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002569 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002570 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00002571 unsigned int use;
2572
Owen Taylor3473f882001-02-23 17:55:21 +00002573 /*
2574 * Store the data in the incoming raw buffer
2575 */
2576 if (in->raw == NULL) {
2577 in->raw = xmlBufferCreate();
2578 }
2579 xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
2580
2581 /*
2582 * convert as much as possible to the parser reading buffer.
2583 */
Daniel Veillard36711902004-02-11 13:25:26 +00002584 use = in->raw->use;
Owen Taylor3473f882001-02-23 17:55:21 +00002585 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2586 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002587 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002588 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002589 return(-1);
2590 }
Daniel Veillard36711902004-02-11 13:25:26 +00002591 in->rawconsumed += (use - in->raw->use);
Owen Taylor3473f882001-02-23 17:55:21 +00002592 } else {
2593 nbchars = len;
2594 xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
2595 }
2596#ifdef DEBUG_INPUT
2597 xmlGenericError(xmlGenericErrorContext,
2598 "I/O: pushed %d chars, buffer %d/%d\n",
2599 nbchars, in->buffer->use, in->buffer->size);
2600#endif
2601 return(nbchars);
2602}
2603
2604/**
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002605 * endOfInput:
2606 *
2607 * When reading from an Input channel indicated end of file or error
2608 * don't reread from it again.
2609 */
2610static int
2611endOfInput (void * context ATTRIBUTE_UNUSED,
2612 char * buffer ATTRIBUTE_UNUSED,
2613 int len ATTRIBUTE_UNUSED) {
2614 return(0);
2615}
2616
2617/**
Owen Taylor3473f882001-02-23 17:55:21 +00002618 * xmlParserInputBufferGrow:
2619 * @in: a buffered parser input
2620 * @len: indicative value of the amount of chars to read
2621 *
2622 * Grow up the content of the input buffer, the old data are preserved
2623 * This routine handle the I18N transcoding to internal UTF-8
2624 * This routine is used when operating the parser in normal (pull) mode
2625 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002626 * TODO: one should be able to remove one extra copy by copying directly
Owen Taylor3473f882001-02-23 17:55:21 +00002627 * onto in->buffer or in->raw
2628 *
2629 * Returns the number of chars read and stored in the buffer, or -1
2630 * in case of error.
2631 */
2632int
2633xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
2634 char *buffer = NULL;
2635 int res = 0;
2636 int nbchars = 0;
2637 int buffree;
Daniel Veillard9e412302002-06-10 15:59:44 +00002638 unsigned int needSize;
Owen Taylor3473f882001-02-23 17:55:21 +00002639
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002640 if ((in == NULL) || (in->error)) return(-1);
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002641 if ((len <= MINLEN) && (len != 4))
Owen Taylor3473f882001-02-23 17:55:21 +00002642 len = MINLEN;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002643
Owen Taylor3473f882001-02-23 17:55:21 +00002644 buffree = in->buffer->size - in->buffer->use;
2645 if (buffree <= 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002646 xmlIOErr(XML_IO_BUFFER_FULL, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002647 in->error = XML_IO_BUFFER_FULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002648 return(0);
2649 }
Owen Taylor3473f882001-02-23 17:55:21 +00002650
Daniel Veillarde5354492002-05-16 08:43:22 +00002651 needSize = in->buffer->use + len + 1;
2652 if (needSize > in->buffer->size){
2653 if (!xmlBufferResize(in->buffer, needSize)){
Daniel Veillard05d987b2003-10-08 11:54:57 +00002654 xmlIOErrMemory("growing input buffer");
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002655 in->error = XML_ERR_NO_MEMORY;
Daniel Veillarde5354492002-05-16 08:43:22 +00002656 return(0);
2657 }
Owen Taylor3473f882001-02-23 17:55:21 +00002658 }
Daniel Veillarde5354492002-05-16 08:43:22 +00002659 buffer = (char *)&in->buffer->content[in->buffer->use];
Owen Taylor3473f882001-02-23 17:55:21 +00002660
2661 /*
2662 * Call the read method for this I/O type.
2663 */
2664 if (in->readcallback != NULL) {
2665 res = in->readcallback(in->context, &buffer[0], len);
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002666 if (res <= 0)
2667 in->readcallback = endOfInput;
Owen Taylor3473f882001-02-23 17:55:21 +00002668 } else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002669 xmlIOErr(XML_IO_NO_INPUT, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002670 in->error = XML_IO_NO_INPUT;
Owen Taylor3473f882001-02-23 17:55:21 +00002671 return(-1);
2672 }
2673 if (res < 0) {
Owen Taylor3473f882001-02-23 17:55:21 +00002674 return(-1);
2675 }
2676 len = res;
2677 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00002678 unsigned int use;
2679
Owen Taylor3473f882001-02-23 17:55:21 +00002680 /*
2681 * Store the data in the incoming raw buffer
2682 */
2683 if (in->raw == NULL) {
2684 in->raw = xmlBufferCreate();
2685 }
2686 xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
2687
2688 /*
2689 * convert as much as possible to the parser reading buffer.
2690 */
Daniel Veillard36711902004-02-11 13:25:26 +00002691 use = in->raw->use;
Owen Taylor3473f882001-02-23 17:55:21 +00002692 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2693 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002694 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002695 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002696 return(-1);
2697 }
Daniel Veillard36711902004-02-11 13:25:26 +00002698 in->rawconsumed += (use - in->raw->use);
Owen Taylor3473f882001-02-23 17:55:21 +00002699 } else {
2700 nbchars = len;
Daniel Veillarde5354492002-05-16 08:43:22 +00002701 in->buffer->use += nbchars;
2702 buffer[nbchars] = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002703 }
2704#ifdef DEBUG_INPUT
2705 xmlGenericError(xmlGenericErrorContext,
2706 "I/O: read %d chars, buffer %d/%d\n",
2707 nbchars, in->buffer->use, in->buffer->size);
2708#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002709 return(nbchars);
2710}
2711
2712/**
2713 * xmlParserInputBufferRead:
2714 * @in: a buffered parser input
2715 * @len: indicative value of the amount of chars to read
2716 *
2717 * Refresh the content of the input buffer, the old data are considered
2718 * consumed
2719 * This routine handle the I18N transcoding to internal UTF-8
2720 *
2721 * Returns the number of chars read and stored in the buffer, or -1
2722 * in case of error.
2723 */
2724int
2725xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002726 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002727 if (in->readcallback != NULL)
2728 return(xmlParserInputBufferGrow(in, len));
Daniel Veillard53350552003-09-18 13:35:51 +00002729 else if ((in->buffer != NULL) &&
2730 (in->buffer->alloc == XML_BUFFER_ALLOC_IMMUTABLE))
2731 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002732 else
2733 return(-1);
2734}
2735
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002736#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002737/**
2738 * xmlOutputBufferWrite:
2739 * @out: a buffered parser output
2740 * @len: the size in bytes of the array.
2741 * @buf: an char array
2742 *
2743 * Write the content of the array in the output I/O buffer
2744 * This routine handle the I18N transcoding from internal UTF-8
2745 * The buffer is lossless, i.e. will store in case of partial
2746 * or delayed writes.
2747 *
2748 * Returns the number of chars immediately written, or -1
2749 * in case of error.
2750 */
2751int
2752xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
2753 int nbchars = 0; /* number of chars to output to I/O */
2754 int ret; /* return from function call */
2755 int written = 0; /* number of char written to I/O so far */
2756 int chunk; /* number of byte curreent processed from buf */
2757
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002758 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002759 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002760 if (out->error) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002761
2762 do {
2763 chunk = len;
2764 if (chunk > 4 * MINLEN)
2765 chunk = 4 * MINLEN;
2766
2767 /*
2768 * first handle encoding stuff.
2769 */
2770 if (out->encoder != NULL) {
2771 /*
2772 * Store the data in the incoming raw buffer
2773 */
2774 if (out->conv == NULL) {
2775 out->conv = xmlBufferCreate();
2776 }
2777 xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2778
2779 if ((out->buffer->use < MINLEN) && (chunk == len))
2780 goto done;
2781
2782 /*
2783 * convert as much as possible to the parser reading buffer.
2784 */
2785 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
Daniel Veillard809faa52003-02-10 15:43:53 +00002786 if ((ret < 0) && (ret != -3)) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002787 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002788 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002789 return(-1);
2790 }
2791 nbchars = out->conv->use;
2792 } else {
2793 xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2794 nbchars = out->buffer->use;
2795 }
2796 buf += chunk;
2797 len -= chunk;
2798
2799 if ((nbchars < MINLEN) && (len <= 0))
2800 goto done;
2801
2802 if (out->writecallback) {
2803 /*
2804 * second write the stuff to the I/O channel
2805 */
2806 if (out->encoder != NULL) {
2807 ret = out->writecallback(out->context,
2808 (const char *)out->conv->content, nbchars);
2809 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002810 xmlBufferShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002811 } else {
2812 ret = out->writecallback(out->context,
2813 (const char *)out->buffer->content, nbchars);
2814 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002815 xmlBufferShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002816 }
2817 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002818 xmlIOErr(XML_IO_WRITE, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002819 out->error = XML_IO_WRITE;
Owen Taylor3473f882001-02-23 17:55:21 +00002820 return(ret);
2821 }
2822 out->written += ret;
2823 }
2824 written += nbchars;
2825 } while (len > 0);
2826
2827done:
2828#ifdef DEBUG_INPUT
2829 xmlGenericError(xmlGenericErrorContext,
2830 "I/O: wrote %d chars\n", written);
2831#endif
2832 return(written);
2833}
2834
2835/**
2836 * xmlOutputBufferWriteString:
2837 * @out: a buffered parser output
2838 * @str: a zero terminated C string
2839 *
2840 * Write the content of the string in the output I/O buffer
2841 * This routine handle the I18N transcoding from internal UTF-8
2842 * The buffer is lossless, i.e. will store in case of partial
2843 * or delayed writes.
2844 *
2845 * Returns the number of chars immediately written, or -1
2846 * in case of error.
2847 */
2848int
2849xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
2850 int len;
2851
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002852 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002853 if (str == NULL)
2854 return(-1);
2855 len = strlen(str);
2856
2857 if (len > 0)
2858 return(xmlOutputBufferWrite(out, len, str));
2859 return(len);
2860}
2861
2862/**
2863 * xmlOutputBufferFlush:
2864 * @out: a buffered output
2865 *
2866 * flushes the output I/O channel
2867 *
2868 * Returns the number of byte written or -1 in case of error.
2869 */
2870int
2871xmlOutputBufferFlush(xmlOutputBufferPtr out) {
2872 int nbchars = 0, ret = 0;
2873
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002874 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002875 /*
2876 * first handle encoding stuff.
2877 */
2878 if ((out->conv != NULL) && (out->encoder != NULL)) {
2879 /*
2880 * convert as much as possible to the parser reading buffer.
2881 */
2882 nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
2883 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002884 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002885 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002886 return(-1);
2887 }
2888 }
2889
2890 /*
2891 * second flush the stuff to the I/O channel
2892 */
2893 if ((out->conv != NULL) && (out->encoder != NULL) &&
2894 (out->writecallback != NULL)) {
2895 ret = out->writecallback(out->context,
2896 (const char *)out->conv->content, out->conv->use);
2897 if (ret >= 0)
2898 xmlBufferShrink(out->conv, ret);
2899 } else if (out->writecallback != NULL) {
2900 ret = out->writecallback(out->context,
2901 (const char *)out->buffer->content, out->buffer->use);
2902 if (ret >= 0)
2903 xmlBufferShrink(out->buffer, ret);
2904 }
2905 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002906 xmlIOErr(XML_IO_FLUSH, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002907 out->error = XML_IO_FLUSH;
Owen Taylor3473f882001-02-23 17:55:21 +00002908 return(ret);
2909 }
2910 out->written += ret;
2911
2912#ifdef DEBUG_INPUT
2913 xmlGenericError(xmlGenericErrorContext,
2914 "I/O: flushed %d chars\n", ret);
2915#endif
2916 return(ret);
2917}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002918#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002919
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002920/**
Owen Taylor3473f882001-02-23 17:55:21 +00002921 * xmlParserGetDirectory:
2922 * @filename: the path to a file
2923 *
2924 * lookup the directory for that file
2925 *
2926 * Returns a new allocated string containing the directory, or NULL.
2927 */
2928char *
2929xmlParserGetDirectory(const char *filename) {
2930 char *ret = NULL;
2931 char dir[1024];
2932 char *cur;
2933 char sep = '/';
2934
Igor Zlatkovic9181cc02002-09-29 17:51:06 +00002935#ifdef _WIN32_WCE /* easy way by now ... wince does not have dirs! */
2936 return NULL;
2937#endif
2938
Owen Taylor3473f882001-02-23 17:55:21 +00002939 if (xmlInputCallbackInitialized == 0)
2940 xmlRegisterDefaultInputCallbacks();
2941
2942 if (filename == NULL) return(NULL);
Daniel Veillard3c5ed912002-01-08 10:36:16 +00002943#if defined(WIN32) && !defined(__CYGWIN__)
Owen Taylor3473f882001-02-23 17:55:21 +00002944 sep = '\\';
2945#endif
2946
2947 strncpy(dir, filename, 1023);
2948 dir[1023] = 0;
2949 cur = &dir[strlen(dir)];
2950 while (cur > dir) {
2951 if (*cur == sep) break;
2952 cur --;
2953 }
2954 if (*cur == sep) {
2955 if (cur == dir) dir[1] = 0;
2956 else *cur = 0;
2957 ret = xmlMemStrdup(dir);
2958 } else {
2959 if (getcwd(dir, 1024) != NULL) {
2960 dir[1023] = 0;
2961 ret = xmlMemStrdup(dir);
2962 }
2963 }
2964 return(ret);
2965}
2966
2967/****************************************************************
2968 * *
2969 * External entities loading *
2970 * *
2971 ****************************************************************/
2972
Daniel Veillarda840b692003-10-19 13:35:37 +00002973/**
2974 * xmlCheckHTTPInput:
2975 * @ctxt: an XML parser context
2976 * @ret: an XML parser input
2977 *
2978 * Check an input in case it was created from an HTTP stream, in that
2979 * case it will handle encoding and update of the base URL in case of
2980 * redirection. It also checks for HTTP errors in which case the input
2981 * is cleanly freed up and an appropriate error is raised in context
2982 *
2983 * Returns the input or NULL in case of HTTP error.
2984 */
2985xmlParserInputPtr
2986xmlCheckHTTPInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr ret) {
2987#ifdef LIBXML_HTTP_ENABLED
2988 if ((ret != NULL) && (ret->buf != NULL) &&
2989 (ret->buf->readcallback == xmlIOHTTPRead) &&
2990 (ret->buf->context != NULL)) {
2991 const char *encoding;
2992 const char *redir;
2993 const char *mime;
2994 int code;
2995
2996 code = xmlNanoHTTPReturnCode(ret->buf->context);
2997 if (code >= 400) {
2998 /* fatal error */
2999 if (ret->filename != NULL)
Daniel Veillarde8039df2003-10-27 11:25:13 +00003000 __xmlLoaderErr(ctxt, "failed to load HTTP resource \"%s\"\n",
Daniel Veillarda840b692003-10-19 13:35:37 +00003001 (const char *) ret->filename);
3002 else
Daniel Veillarde8039df2003-10-27 11:25:13 +00003003 __xmlLoaderErr(ctxt, "failed to load HTTP resource\n", NULL);
Daniel Veillarda840b692003-10-19 13:35:37 +00003004 xmlFreeInputStream(ret);
3005 ret = NULL;
3006 } else {
3007
3008 mime = xmlNanoHTTPMimeType(ret->buf->context);
3009 if ((xmlStrstr(BAD_CAST mime, BAD_CAST "/xml")) ||
3010 (xmlStrstr(BAD_CAST mime, BAD_CAST "+xml"))) {
3011 encoding = xmlNanoHTTPEncoding(ret->buf->context);
3012 if (encoding != NULL) {
3013 xmlCharEncodingHandlerPtr handler;
3014
3015 handler = xmlFindCharEncodingHandler(encoding);
3016 if (handler != NULL) {
3017 xmlSwitchInputEncoding(ctxt, ret, handler);
3018 } else {
3019 __xmlErrEncoding(ctxt, XML_ERR_UNKNOWN_ENCODING,
3020 "Unknown encoding %s",
3021 BAD_CAST encoding, NULL);
3022 }
3023 if (ret->encoding == NULL)
3024 ret->encoding = xmlStrdup(BAD_CAST encoding);
3025 }
3026#if 0
3027 } else if (xmlStrstr(BAD_CAST mime, BAD_CAST "html")) {
3028#endif
3029 }
3030 redir = xmlNanoHTTPRedir(ret->buf->context);
3031 if (redir != NULL) {
3032 if (ret->filename != NULL)
3033 xmlFree((xmlChar *) ret->filename);
3034 if (ret->directory != NULL) {
3035 xmlFree((xmlChar *) ret->directory);
3036 ret->directory = NULL;
3037 }
3038 ret->filename =
3039 (char *) xmlStrdup((const xmlChar *) redir);
3040 }
3041 }
3042 }
3043#endif
3044 return(ret);
3045}
3046
Daniel Veillard561b7f82002-03-20 21:55:57 +00003047static int xmlSysIDExists(const char *URL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003048#ifdef HAVE_STAT
3049 int ret;
3050 struct stat info;
3051 const char *path;
3052
3053 if (URL == NULL)
3054 return(0);
3055
Daniel Veillardf4862f02002-09-10 11:13:43 +00003056 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003057#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00003058 path = &URL[17];
3059#else
Daniel Veillard6990bf32001-08-23 21:17:48 +00003060 path = &URL[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00003061#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003062 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003063#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard6990bf32001-08-23 21:17:48 +00003064 path = &URL[8];
3065#else
3066 path = &URL[7];
3067#endif
3068 } else
3069 path = URL;
3070 ret = stat(path, &info);
Daniel Veillard561b7f82002-03-20 21:55:57 +00003071 if (ret == 0)
3072 return(1);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003073#endif
Daniel Veillard561b7f82002-03-20 21:55:57 +00003074 return(0);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003075}
Daniel Veillard6990bf32001-08-23 21:17:48 +00003076
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003077/**
Owen Taylor3473f882001-02-23 17:55:21 +00003078 * xmlDefaultExternalEntityLoader:
3079 * @URL: the URL for the entity to load
3080 * @ID: the System ID for the entity to load
3081 * @ctxt: the context in which the entity is called or NULL
3082 *
3083 * By default we don't load external entitites, yet.
3084 *
3085 * Returns a new allocated xmlParserInputPtr, or NULL.
3086 */
Daniel Veillarda840b692003-10-19 13:35:37 +00003087static xmlParserInputPtr
Owen Taylor3473f882001-02-23 17:55:21 +00003088xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
Daniel Veillarda840b692003-10-19 13:35:37 +00003089 xmlParserCtxtPtr ctxt)
3090{
Owen Taylor3473f882001-02-23 17:55:21 +00003091 xmlParserInputPtr ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003092 xmlChar *resource = NULL;
Daniel Veillarda840b692003-10-19 13:35:37 +00003093
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003094#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003095 xmlCatalogAllow pref;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003096#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003097
3098#ifdef DEBUG_EXTERNAL_ENTITIES
3099 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda840b692003-10-19 13:35:37 +00003100 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00003101#endif
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003102#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillard61b93382003-11-03 14:28:31 +00003103 if ((ctxt != NULL) && (ctxt->options & XML_PARSE_NONET)) {
3104 int options = ctxt->options;
3105
3106 ctxt->options -= XML_PARSE_NONET;
3107 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
3108 ctxt->options = options;
3109 return(ret);
3110 }
3111
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003112 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003113 * If the resource doesn't exists as a file,
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003114 * try to load it from the resource pointed in the catalogs
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003115 */
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003116 pref = xmlCatalogGetDefaults();
3117
Daniel Veillard561b7f82002-03-20 21:55:57 +00003118 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlSysIDExists(URL))) {
Daniel Veillarda840b692003-10-19 13:35:37 +00003119 /*
3120 * Do a local lookup
3121 */
3122 if ((ctxt->catalogs != NULL) &&
3123 ((pref == XML_CATA_ALLOW_ALL) ||
3124 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3125 resource = xmlCatalogLocalResolve(ctxt->catalogs,
3126 (const xmlChar *) ID,
3127 (const xmlChar *) URL);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003128 }
Daniel Veillarda840b692003-10-19 13:35:37 +00003129 /*
3130 * Try a global lookup
3131 */
3132 if ((resource == NULL) &&
3133 ((pref == XML_CATA_ALLOW_ALL) ||
3134 (pref == XML_CATA_ALLOW_GLOBAL))) {
3135 resource = xmlCatalogResolve((const xmlChar *) ID,
3136 (const xmlChar *) URL);
3137 }
3138 if ((resource == NULL) && (URL != NULL))
3139 resource = xmlStrdup((const xmlChar *) URL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003140
Daniel Veillarda840b692003-10-19 13:35:37 +00003141 /*
3142 * TODO: do an URI lookup on the reference
3143 */
3144 if ((resource != NULL)
3145 && (!xmlSysIDExists((const char *) resource))) {
3146 xmlChar *tmp = NULL;
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003147
Daniel Veillarda840b692003-10-19 13:35:37 +00003148 if ((ctxt->catalogs != NULL) &&
3149 ((pref == XML_CATA_ALLOW_ALL) ||
3150 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3151 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
3152 }
3153 if ((tmp == NULL) &&
3154 ((pref == XML_CATA_ALLOW_ALL) ||
3155 (pref == XML_CATA_ALLOW_GLOBAL))) {
3156 tmp = xmlCatalogResolveURI(resource);
3157 }
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003158
Daniel Veillarda840b692003-10-19 13:35:37 +00003159 if (tmp != NULL) {
3160 xmlFree(resource);
3161 resource = tmp;
3162 }
3163 }
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003164 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003165#endif
3166
3167 if (resource == NULL)
Daniel Veillarda840b692003-10-19 13:35:37 +00003168 resource = (xmlChar *) URL;
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003169
3170 if (resource == NULL) {
Daniel Veillarda840b692003-10-19 13:35:37 +00003171 if (ID == NULL)
3172 ID = "NULL";
Daniel Veillarde8039df2003-10-27 11:25:13 +00003173 __xmlLoaderErr(ctxt, "failed to load external entity \"%s\"\n", ID);
Daniel Veillarda840b692003-10-19 13:35:37 +00003174 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003175 }
Daniel Veillarda840b692003-10-19 13:35:37 +00003176 ret = xmlNewInputFromFile(ctxt, (const char *) resource);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003177 if ((resource != NULL) && (resource != (xmlChar *) URL))
Daniel Veillarda840b692003-10-19 13:35:37 +00003178 xmlFree(resource);
3179 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003180}
3181
3182static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
3183 xmlDefaultExternalEntityLoader;
3184
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003185/**
Owen Taylor3473f882001-02-23 17:55:21 +00003186 * xmlSetExternalEntityLoader:
3187 * @f: the new entity resolver function
3188 *
3189 * Changes the defaultexternal entity resolver function for the application
3190 */
3191void
3192xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
3193 xmlCurrentExternalEntityLoader = f;
3194}
3195
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003196/**
Owen Taylor3473f882001-02-23 17:55:21 +00003197 * xmlGetExternalEntityLoader:
3198 *
3199 * Get the default external entity resolver function for the application
3200 *
3201 * Returns the xmlExternalEntityLoader function pointer
3202 */
3203xmlExternalEntityLoader
3204xmlGetExternalEntityLoader(void) {
3205 return(xmlCurrentExternalEntityLoader);
3206}
3207
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003208/**
Owen Taylor3473f882001-02-23 17:55:21 +00003209 * xmlLoadExternalEntity:
3210 * @URL: the URL for the entity to load
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00003211 * @ID: the Public ID for the entity to load
Owen Taylor3473f882001-02-23 17:55:21 +00003212 * @ctxt: the context in which the entity is called or NULL
3213 *
3214 * Load an external entity, note that the use of this function for
3215 * unparsed entities may generate problems
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003216 * TODO: a more generic External entity API must be designed
Owen Taylor3473f882001-02-23 17:55:21 +00003217 *
3218 * Returns the xmlParserInputPtr or NULL
3219 */
3220xmlParserInputPtr
3221xmlLoadExternalEntity(const char *URL, const char *ID,
3222 xmlParserCtxtPtr ctxt) {
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00003223 if ((URL != NULL) && (xmlSysIDExists(URL) == 0)) {
3224 char *canonicFilename;
3225 xmlParserInputPtr ret;
3226
3227 canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL);
3228 if (canonicFilename == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003229 xmlIOErrMemory("building canonical path\n");
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00003230 return(NULL);
3231 }
3232
3233 ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt);
3234 xmlFree(canonicFilename);
3235 return(ret);
3236 }
Owen Taylor3473f882001-02-23 17:55:21 +00003237 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
3238}
3239
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003240/************************************************************************
3241 * *
3242 * Disabling Network access *
3243 * *
3244 ************************************************************************/
3245
3246#ifdef LIBXML_CATALOG_ENABLED
3247static int
3248xmlNoNetExists(const char *URL)
3249{
3250#ifdef HAVE_STAT
3251 int ret;
3252 struct stat info;
3253 const char *path;
3254
3255 if (URL == NULL)
3256 return (0);
3257
Daniel Veillardf4862f02002-09-10 11:13:43 +00003258 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003259#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00003260 path = &URL[17];
3261#else
3262 path = &URL[16];
3263#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003264 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003265#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003266 path = &URL[8];
3267#else
3268 path = &URL[7];
3269#endif
3270 } else
3271 path = URL;
3272 ret = stat(path, &info);
3273 if (ret == 0)
3274 return (1);
3275#endif
3276 return (0);
3277}
3278#endif
3279
3280/**
3281 * xmlNoNetExternalEntityLoader:
3282 * @URL: the URL for the entity to load
3283 * @ID: the System ID for the entity to load
3284 * @ctxt: the context in which the entity is called or NULL
3285 *
3286 * A specific entity loader disabling network accesses, though still
3287 * allowing local catalog accesses for resolution.
3288 *
3289 * Returns a new allocated xmlParserInputPtr, or NULL.
3290 */
3291xmlParserInputPtr
3292xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
3293 xmlParserCtxtPtr ctxt) {
3294 xmlParserInputPtr input = NULL;
3295 xmlChar *resource = NULL;
3296
3297#ifdef LIBXML_CATALOG_ENABLED
3298 xmlCatalogAllow pref;
3299
3300 /*
3301 * If the resource doesn't exists as a file,
3302 * try to load it from the resource pointed in the catalogs
3303 */
3304 pref = xmlCatalogGetDefaults();
3305
3306 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
3307 /*
3308 * Do a local lookup
3309 */
3310 if ((ctxt->catalogs != NULL) &&
3311 ((pref == XML_CATA_ALLOW_ALL) ||
3312 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3313 resource = xmlCatalogLocalResolve(ctxt->catalogs,
3314 (const xmlChar *)ID,
3315 (const xmlChar *)URL);
3316 }
3317 /*
3318 * Try a global lookup
3319 */
3320 if ((resource == NULL) &&
3321 ((pref == XML_CATA_ALLOW_ALL) ||
3322 (pref == XML_CATA_ALLOW_GLOBAL))) {
3323 resource = xmlCatalogResolve((const xmlChar *)ID,
3324 (const xmlChar *)URL);
3325 }
3326 if ((resource == NULL) && (URL != NULL))
3327 resource = xmlStrdup((const xmlChar *) URL);
3328
3329 /*
3330 * TODO: do an URI lookup on the reference
3331 */
3332 if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
3333 xmlChar *tmp = NULL;
3334
3335 if ((ctxt->catalogs != NULL) &&
3336 ((pref == XML_CATA_ALLOW_ALL) ||
3337 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3338 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
3339 }
3340 if ((tmp == NULL) &&
3341 ((pref == XML_CATA_ALLOW_ALL) ||
3342 (pref == XML_CATA_ALLOW_GLOBAL))) {
3343 tmp = xmlCatalogResolveURI(resource);
3344 }
3345
3346 if (tmp != NULL) {
3347 xmlFree(resource);
3348 resource = tmp;
3349 }
3350 }
3351 }
3352#endif
3353 if (resource == NULL)
3354 resource = (xmlChar *) URL;
3355
3356 if (resource != NULL) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003357 if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
3358 (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003359 xmlIOErr(XML_IO_NETWORK_ATTEMPT, (const char *) resource);
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003360 if (resource != (xmlChar *) URL)
3361 xmlFree(resource);
3362 return(NULL);
3363 }
3364 }
3365 input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
3366 if (resource != (xmlChar *) URL)
3367 xmlFree(resource);
3368 return(input);
3369}
3370