blob: 8c4b68fd6dd0dd49cace15e5143e7b0a0e2717f4 [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;
Daniel Veillard500a1de2004-03-22 15:22:58 +0000788 if ((fil == stdout) || (fil == stderr)) {
789 ret = fflush(fil);
790 if (ret < 0)
791 xmlIOErr(0, "fflush()");
792 return(0);
793 }
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000794 if (fil == stdin)
795 return(0);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000796 ret = ( fclose((FILE *) context) == EOF ) ? -1 : 0;
797 if (ret < 0)
798 xmlIOErr(0, "fclose()");
799 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000800}
801
802/**
803 * xmlFileFlush:
804 * @context: the I/O context
805 *
806 * Flush an I/O channel
807 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000808static int
Owen Taylor3473f882001-02-23 17:55:21 +0000809xmlFileFlush (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000810 int ret;
811 ret = ( fflush((FILE *) context) == EOF ) ? -1 : 0;
812 if (ret < 0)
813 xmlIOErr(0, "fflush()");
814 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000815}
816
817#ifdef HAVE_ZLIB_H
818/************************************************************************
819 * *
820 * I/O for compressed file accesses *
821 * *
822 ************************************************************************/
823/**
824 * xmlGzfileMatch:
825 * @filename: the URI for matching
826 *
827 * input from compressed file test
828 *
829 * Returns 1 if matches, 0 otherwise
830 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000831static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000832xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000833 return(1);
834}
835
836/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000837 * xmlGzfileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +0000838 * @filename: the URI for matching
839 *
840 * input from compressed file open
841 * if @filename is " " then the standard input is used
842 *
843 * Returns an I/O context or NULL in case of error
844 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000845static void *
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000846xmlGzfileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +0000847 const char *path = NULL;
848 gzFile fd;
849
850 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000851 fd = gzdopen(dup(0), "rb");
Owen Taylor3473f882001-02-23 17:55:21 +0000852 return((void *) fd);
853 }
854
Daniel Veillardf4862f02002-09-10 11:13:43 +0000855 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000856#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000857 path = &filename[17];
858#else
Owen Taylor3473f882001-02-23 17:55:21 +0000859 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000860#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000861 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000862#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000863 path = &filename[8];
864#else
Owen Taylor3473f882001-02-23 17:55:21 +0000865 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000866#endif
867 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000868 path = filename;
869
870 if (path == NULL)
871 return(NULL);
872 if (!xmlCheckFilename(path))
873 return(NULL);
874
875 fd = gzopen(path, "rb");
876 return((void *) fd);
877}
878
879/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000880 * xmlGzfileOpen:
881 * @filename: the URI for matching
882 *
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +0000883 * Wrapper around xmlGzfileOpen if the open fais, it will
884 * try to unescape @filename
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000885 */
886static void *
887xmlGzfileOpen (const char *filename) {
888 char *unescaped;
889 void *retval;
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +0000890
891 retval = xmlGzfileOpen_real(filename);
892 if (retval == NULL) {
893 unescaped = xmlURIUnescapeString(filename, 0, NULL);
894 if (unescaped != NULL) {
895 retval = xmlGzfileOpen_real(unescaped);
896 }
897 xmlFree(unescaped);
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000898 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000899 return retval;
900}
901
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000902#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000903/**
Owen Taylor3473f882001-02-23 17:55:21 +0000904 * xmlGzfileOpenW:
905 * @filename: the URI for matching
906 * @compression: the compression factor (0 - 9 included)
907 *
908 * input from compressed file open
909 * if @filename is " " then the standard input is used
910 *
911 * Returns an I/O context or NULL in case of error
912 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000913static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000914xmlGzfileOpenW (const char *filename, int compression) {
915 const char *path = NULL;
916 char mode[15];
917 gzFile fd;
918
Aleksey Sanin49cc9752002-06-14 17:07:10 +0000919 snprintf(mode, sizeof(mode), "wb%d", compression);
Owen Taylor3473f882001-02-23 17:55:21 +0000920 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000921 fd = gzdopen(dup(1), mode);
Owen Taylor3473f882001-02-23 17:55:21 +0000922 return((void *) fd);
923 }
924
Daniel Veillardf4862f02002-09-10 11:13:43 +0000925 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000926#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000927 path = &filename[17];
928#else
Owen Taylor3473f882001-02-23 17:55:21 +0000929 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000930#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000931 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000932#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000933 path = &filename[8];
934#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000935 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000936#endif
937 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000938 path = filename;
939
940 if (path == NULL)
941 return(NULL);
942
943 fd = gzopen(path, mode);
944 return((void *) fd);
945}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000946#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000947
948/**
949 * xmlGzfileRead:
950 * @context: the I/O context
951 * @buffer: where to drop data
952 * @len: number of bytes to write
953 *
954 * Read @len bytes to @buffer from the compressed I/O channel.
955 *
956 * Returns the number of bytes written
957 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000958static int
Owen Taylor3473f882001-02-23 17:55:21 +0000959xmlGzfileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000960 int ret;
961
962 ret = gzread((gzFile) context, &buffer[0], len);
963 if (ret < 0) xmlIOErr(0, "gzread()");
964 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000965}
966
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000967#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000968/**
969 * xmlGzfileWrite:
970 * @context: the I/O context
971 * @buffer: where to drop data
972 * @len: number of bytes to write
973 *
974 * Write @len bytes from @buffer to the compressed I/O channel.
975 *
976 * Returns the number of bytes written
977 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000978static int
Owen Taylor3473f882001-02-23 17:55:21 +0000979xmlGzfileWrite (void * context, const char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000980 int ret;
981
982 ret = gzwrite((gzFile) context, (char *) &buffer[0], len);
983 if (ret < 0) xmlIOErr(0, "gzwrite()");
984 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000985}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000986#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000987
988/**
989 * xmlGzfileClose:
990 * @context: the I/O context
991 *
992 * Close a compressed I/O channel
993 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000994static int
Owen Taylor3473f882001-02-23 17:55:21 +0000995xmlGzfileClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000996 int ret;
997
998 ret = (gzclose((gzFile) context) == Z_OK ) ? 0 : -1;
999 if (ret < 0) xmlIOErr(0, "gzclose()");
1000 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001001}
1002#endif /* HAVE_ZLIB_H */
1003
1004#ifdef LIBXML_HTTP_ENABLED
1005/************************************************************************
1006 * *
1007 * I/O for HTTP file accesses *
1008 * *
1009 ************************************************************************/
Daniel Veillardf012a642001-07-23 19:10:52 +00001010
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001011#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001012typedef struct xmlIOHTTPWriteCtxt_
1013{
1014 int compression;
1015
1016 char * uri;
1017
1018 void * doc_buff;
1019
1020} xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr;
1021
1022#ifdef HAVE_ZLIB_H
1023
1024#define DFLT_WBITS ( -15 )
1025#define DFLT_MEM_LVL ( 8 )
1026#define GZ_MAGIC1 ( 0x1f )
1027#define GZ_MAGIC2 ( 0x8b )
1028#define LXML_ZLIB_OS_CODE ( 0x03 )
1029#define INIT_HTTP_BUFF_SIZE ( 32768 )
1030#define DFLT_ZLIB_RATIO ( 5 )
1031
1032/*
1033** Data structure and functions to work with sending compressed data
1034** via HTTP.
1035*/
1036
1037typedef struct xmlZMemBuff_
1038{
1039 unsigned long size;
1040 unsigned long crc;
1041
1042 unsigned char * zbuff;
1043 z_stream zctrl;
1044
1045} xmlZMemBuff, *xmlZMemBuffPtr;
1046
1047/**
1048 * append_reverse_ulong
1049 * @buff: Compressed memory buffer
1050 * @data: Unsigned long to append
1051 *
1052 * Append a unsigned long in reverse byte order to the end of the
1053 * memory buffer.
1054 */
1055static void
1056append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) {
1057
1058 int idx;
1059
1060 if ( buff == NULL )
1061 return;
1062
1063 /*
1064 ** This is plagiarized from putLong in gzio.c (zlib source) where
1065 ** the number "4" is hardcoded. If zlib is ever patched to
1066 ** support 64 bit file sizes, this code would need to be patched
1067 ** as well.
1068 */
1069
1070 for ( idx = 0; idx < 4; idx++ ) {
1071 *buff->zctrl.next_out = ( data & 0xff );
1072 data >>= 8;
1073 buff->zctrl.next_out++;
1074 }
1075
1076 return;
1077}
1078
1079/**
1080 *
1081 * xmlFreeZMemBuff
1082 * @buff: The memory buffer context to clear
1083 *
1084 * Release all the resources associated with the compressed memory buffer.
1085 */
1086static void
1087xmlFreeZMemBuff( xmlZMemBuffPtr buff ) {
William M. Brack78637da2003-07-31 14:47:38 +00001088
1089#ifdef DEBUG_HTTP
Daniel Veillardf012a642001-07-23 19:10:52 +00001090 int z_err;
William M. Brack78637da2003-07-31 14:47:38 +00001091#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001092
1093 if ( buff == NULL )
1094 return;
1095
1096 xmlFree( buff->zbuff );
Daniel Veillardf012a642001-07-23 19:10:52 +00001097#ifdef DEBUG_HTTP
William M. Brack78637da2003-07-31 14:47:38 +00001098 z_err = deflateEnd( &buff->zctrl );
Daniel Veillardf012a642001-07-23 19:10:52 +00001099 if ( z_err != Z_OK )
1100 xmlGenericError( xmlGenericErrorContext,
1101 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
1102 z_err );
William M. Brack78637da2003-07-31 14:47:38 +00001103#else
1104 deflateEnd( &buff->zctrl );
William M. Brack779af002003-08-01 15:55:39 +00001105#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001106
1107 xmlFree( buff );
1108 return;
1109}
1110
1111/**
1112 * xmlCreateZMemBuff
1113 *@compression: Compression value to use
1114 *
1115 * Create a memory buffer to hold the compressed XML document. The
1116 * compressed document in memory will end up being identical to what
1117 * would be created if gzopen/gzwrite/gzclose were being used to
1118 * write the document to disk. The code for the header/trailer data to
1119 * the compression is plagiarized from the zlib source files.
1120 */
1121static void *
1122xmlCreateZMemBuff( int compression ) {
1123
1124 int z_err;
1125 int hdr_lgth;
1126 xmlZMemBuffPtr buff = NULL;
1127
1128 if ( ( compression < 1 ) || ( compression > 9 ) )
1129 return ( NULL );
1130
1131 /* Create the control and data areas */
1132
1133 buff = xmlMalloc( sizeof( xmlZMemBuff ) );
1134 if ( buff == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001135 xmlIOErrMemory("creating buffer context");
Daniel Veillardf012a642001-07-23 19:10:52 +00001136 return ( NULL );
1137 }
1138
1139 (void)memset( buff, 0, sizeof( xmlZMemBuff ) );
1140 buff->size = INIT_HTTP_BUFF_SIZE;
1141 buff->zbuff = xmlMalloc( buff->size );
1142 if ( buff->zbuff == NULL ) {
1143 xmlFreeZMemBuff( buff );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001144 xmlIOErrMemory("creating buffer");
Daniel Veillardf012a642001-07-23 19:10:52 +00001145 return ( NULL );
1146 }
1147
1148 z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
1149 DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
1150 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001151 xmlChar msg[500];
Daniel Veillardf012a642001-07-23 19:10:52 +00001152 xmlFreeZMemBuff( buff );
1153 buff = NULL;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001154 xmlStrPrintf(msg, 500,
1155 (const xmlChar *) "xmlCreateZMemBuff: %s %d\n",
1156 "Error initializing compression context. ZLIB error:",
1157 z_err );
1158 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001159 return ( NULL );
1160 }
1161
1162 /* Set the header data. The CRC will be needed for the trailer */
Daniel Veillardf012a642001-07-23 19:10:52 +00001163 buff->crc = crc32( 0L, Z_NULL, 0 );
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001164 hdr_lgth = snprintf( (char *)buff->zbuff, buff->size,
1165 "%c%c%c%c%c%c%c%c%c%c",
Daniel Veillardf012a642001-07-23 19:10:52 +00001166 GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED,
1167 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE );
1168 buff->zctrl.next_out = buff->zbuff + hdr_lgth;
1169 buff->zctrl.avail_out = buff->size - hdr_lgth;
1170
1171 return ( buff );
1172}
1173
1174/**
1175 * xmlZMemBuffExtend
1176 * @buff: Buffer used to compress and consolidate data.
1177 * @ext_amt: Number of bytes to extend the buffer.
1178 *
1179 * Extend the internal buffer used to store the compressed data by the
1180 * specified amount.
1181 *
1182 * Returns 0 on success or -1 on failure to extend the buffer. On failure
1183 * the original buffer still exists at the original size.
1184 */
1185static int
1186xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) {
1187
1188 int rc = -1;
1189 size_t new_size;
1190 size_t cur_used;
1191
1192 unsigned char * tmp_ptr = NULL;
1193
1194 if ( buff == NULL )
1195 return ( -1 );
1196
1197 else if ( ext_amt == 0 )
1198 return ( 0 );
1199
1200 cur_used = buff->zctrl.next_out - buff->zbuff;
1201 new_size = buff->size + ext_amt;
1202
1203#ifdef DEBUG_HTTP
1204 if ( cur_used > new_size )
1205 xmlGenericError( xmlGenericErrorContext,
1206 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
1207 "Buffer overwrite detected during compressed memory",
1208 "buffer extension. Overflowed by",
1209 (cur_used - new_size ) );
1210#endif
1211
1212 tmp_ptr = xmlRealloc( buff->zbuff, new_size );
1213 if ( tmp_ptr != NULL ) {
1214 rc = 0;
1215 buff->size = new_size;
1216 buff->zbuff = tmp_ptr;
1217 buff->zctrl.next_out = tmp_ptr + cur_used;
1218 buff->zctrl.avail_out = new_size - cur_used;
1219 }
1220 else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001221 xmlChar msg[500];
1222 xmlStrPrintf(msg, 500,
1223 (const xmlChar *) "xmlZMemBuffExtend: %s %lu bytes.\n",
1224 "Allocation failure extending output buffer to",
1225 new_size );
1226 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001227 }
1228
1229 return ( rc );
1230}
1231
1232/**
1233 * xmlZMemBuffAppend
1234 * @buff: Buffer used to compress and consolidate data
1235 * @src: Uncompressed source content to append to buffer
1236 * @len: Length of source data to append to buffer
1237 *
1238 * Compress and append data to the internal buffer. The data buffer
1239 * will be expanded if needed to store the additional data.
1240 *
1241 * Returns the number of bytes appended to the buffer or -1 on error.
1242 */
1243static int
1244xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) {
1245
1246 int z_err;
1247 size_t min_accept;
1248
1249 if ( ( buff == NULL ) || ( src == NULL ) )
1250 return ( -1 );
1251
1252 buff->zctrl.avail_in = len;
1253 buff->zctrl.next_in = (unsigned char *)src;
1254 while ( buff->zctrl.avail_in > 0 ) {
1255 /*
1256 ** Extend the buffer prior to deflate call if a reasonable amount
1257 ** of output buffer space is not available.
1258 */
1259 min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO;
1260 if ( buff->zctrl.avail_out <= min_accept ) {
1261 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1262 return ( -1 );
1263 }
1264
1265 z_err = deflate( &buff->zctrl, Z_NO_FLUSH );
1266 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001267 xmlChar msg[500];
1268 xmlStrPrintf(msg, 500,
1269 (const xmlChar *) "xmlZMemBuffAppend: %s %d %s - %d",
Daniel Veillardf012a642001-07-23 19:10:52 +00001270 "Compression error while appending",
1271 len, "bytes to buffer. ZLIB error", z_err );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001272 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001273 return ( -1 );
1274 }
1275 }
1276
1277 buff->crc = crc32( buff->crc, (unsigned char *)src, len );
1278
1279 return ( len );
1280}
1281
1282/**
1283 * xmlZMemBuffGetContent
1284 * @buff: Compressed memory content buffer
1285 * @data_ref: Pointer reference to point to compressed content
1286 *
1287 * Flushes the compression buffers, appends gzip file trailers and
1288 * returns the compressed content and length of the compressed data.
1289 * NOTE: The gzip trailer code here is plagiarized from zlib source.
1290 *
1291 * Returns the length of the compressed data or -1 on error.
1292 */
1293static int
1294xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) {
1295
1296 int zlgth = -1;
1297 int z_err;
1298
1299 if ( ( buff == NULL ) || ( data_ref == NULL ) )
1300 return ( -1 );
1301
1302 /* Need to loop until compression output buffers are flushed */
1303
1304 do
1305 {
1306 z_err = deflate( &buff->zctrl, Z_FINISH );
1307 if ( z_err == Z_OK ) {
1308 /* In this case Z_OK means more buffer space needed */
1309
1310 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1311 return ( -1 );
1312 }
1313 }
1314 while ( z_err == Z_OK );
1315
1316 /* If the compression state is not Z_STREAM_END, some error occurred */
1317
1318 if ( z_err == Z_STREAM_END ) {
1319
1320 /* Need to append the gzip data trailer */
1321
1322 if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) {
1323 if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 )
1324 return ( -1 );
1325 }
1326
1327 /*
1328 ** For whatever reason, the CRC and length data are pushed out
1329 ** in reverse byte order. So a memcpy can't be used here.
1330 */
1331
1332 append_reverse_ulong( buff, buff->crc );
1333 append_reverse_ulong( buff, buff->zctrl.total_in );
1334
1335 zlgth = buff->zctrl.next_out - buff->zbuff;
1336 *data_ref = (char *)buff->zbuff;
1337 }
1338
Daniel Veillard05d987b2003-10-08 11:54:57 +00001339 else {
1340 xmlChar msg[500];
1341 xmlStrPrintf(msg, 500,
1342 (const xmlChar *) "xmlZMemBuffGetContent: %s - %d\n",
1343 "Error flushing zlib buffers. Error code", z_err );
1344 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1345 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001346
1347 return ( zlgth );
1348}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001349#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001350#endif /* HAVE_ZLIB_H */
1351
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001352#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001353/**
1354 * xmlFreeHTTPWriteCtxt
1355 * @ctxt: Context to cleanup
1356 *
1357 * Free allocated memory and reclaim system resources.
1358 *
1359 * No return value.
1360 */
1361static void
1362xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt )
1363{
1364 if ( ctxt->uri != NULL )
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001365 xmlFree( ctxt->uri );
Daniel Veillardf012a642001-07-23 19:10:52 +00001366
1367 if ( ctxt->doc_buff != NULL ) {
1368
1369#ifdef HAVE_ZLIB_H
1370 if ( ctxt->compression > 0 ) {
1371 xmlFreeZMemBuff( ctxt->doc_buff );
1372 }
1373 else
1374#endif
1375 {
1376 xmlOutputBufferClose( ctxt->doc_buff );
1377 }
1378 }
1379
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001380 xmlFree( ctxt );
Daniel Veillardf012a642001-07-23 19:10:52 +00001381 return;
1382}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001383#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001384
1385
Owen Taylor3473f882001-02-23 17:55:21 +00001386/**
1387 * xmlIOHTTPMatch:
1388 * @filename: the URI for matching
1389 *
1390 * check if the URI matches an HTTP one
1391 *
1392 * Returns 1 if matches, 0 otherwise
1393 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001394int
Owen Taylor3473f882001-02-23 17:55:21 +00001395xmlIOHTTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001396 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "http://", 7))
Owen Taylor3473f882001-02-23 17:55:21 +00001397 return(1);
1398 return(0);
1399}
1400
1401/**
1402 * xmlIOHTTPOpen:
1403 * @filename: the URI for matching
1404 *
1405 * open an HTTP I/O channel
1406 *
1407 * Returns an I/O context or NULL in case of error
1408 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001409void *
Owen Taylor3473f882001-02-23 17:55:21 +00001410xmlIOHTTPOpen (const char *filename) {
1411 return(xmlNanoHTTPOpen(filename, NULL));
1412}
1413
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001414#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001415/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001416 * xmlIOHTTPOpenW:
Daniel Veillardf012a642001-07-23 19:10:52 +00001417 * @post_uri: The destination URI for the document
1418 * @compression: The compression desired for the document.
1419 *
1420 * Open a temporary buffer to collect the document for a subsequent HTTP POST
1421 * request. Non-static as is called from the output buffer creation routine.
1422 *
1423 * Returns an I/O context or NULL in case of error.
1424 */
1425
1426void *
Daniel Veillard572577e2002-01-18 16:23:55 +00001427xmlIOHTTPOpenW(const char *post_uri, int compression)
1428{
Daniel Veillardf012a642001-07-23 19:10:52 +00001429
Daniel Veillard572577e2002-01-18 16:23:55 +00001430 xmlIOHTTPWriteCtxtPtr ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001431
Daniel Veillard572577e2002-01-18 16:23:55 +00001432 if (post_uri == NULL)
1433 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001434
Daniel Veillard572577e2002-01-18 16:23:55 +00001435 ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt));
1436 if (ctxt == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001437 xmlIOErrMemory("creating HTTP output context");
Daniel Veillard572577e2002-01-18 16:23:55 +00001438 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001439 }
1440
Daniel Veillard572577e2002-01-18 16:23:55 +00001441 (void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt));
Daniel Veillardf012a642001-07-23 19:10:52 +00001442
Daniel Veillard572577e2002-01-18 16:23:55 +00001443 ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri);
1444 if (ctxt->uri == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001445 xmlIOErrMemory("copying URI");
Daniel Veillard572577e2002-01-18 16:23:55 +00001446 xmlFreeHTTPWriteCtxt(ctxt);
1447 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001448 }
1449
1450 /*
Daniel Veillard572577e2002-01-18 16:23:55 +00001451 * ** Since the document length is required for an HTTP post,
1452 * ** need to put the document into a buffer. A memory buffer
1453 * ** is being used to avoid pushing the data to disk and back.
1454 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001455
1456#ifdef HAVE_ZLIB_H
Daniel Veillard572577e2002-01-18 16:23:55 +00001457 if ((compression > 0) && (compression <= 9)) {
1458
1459 ctxt->compression = compression;
1460 ctxt->doc_buff = xmlCreateZMemBuff(compression);
1461 } else
Daniel Veillardf012a642001-07-23 19:10:52 +00001462#endif
1463 {
Daniel Veillard572577e2002-01-18 16:23:55 +00001464 /* Any character conversions should have been done before this */
Daniel Veillardf012a642001-07-23 19:10:52 +00001465
Daniel Veillard572577e2002-01-18 16:23:55 +00001466 ctxt->doc_buff = xmlAllocOutputBuffer(NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001467 }
1468
Daniel Veillard572577e2002-01-18 16:23:55 +00001469 if (ctxt->doc_buff == NULL) {
1470 xmlFreeHTTPWriteCtxt(ctxt);
1471 ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001472 }
1473
Daniel Veillard572577e2002-01-18 16:23:55 +00001474 return (ctxt);
Daniel Veillardf012a642001-07-23 19:10:52 +00001475}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001476#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001477
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001478#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001479/**
1480 * xmlIOHTTPDfltOpenW
1481 * @post_uri: The destination URI for this document.
1482 *
1483 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
1484 * HTTP post command. This function should generally not be used as
1485 * the open callback is short circuited in xmlOutputBufferCreateFile.
1486 *
1487 * Returns a pointer to the new IO context.
1488 */
1489static void *
1490xmlIOHTTPDfltOpenW( const char * post_uri ) {
1491 return ( xmlIOHTTPOpenW( post_uri, 0 ) );
1492}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001493#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001494
1495/**
Owen Taylor3473f882001-02-23 17:55:21 +00001496 * xmlIOHTTPRead:
1497 * @context: the I/O context
1498 * @buffer: where to drop data
1499 * @len: number of bytes to write
1500 *
1501 * Read @len bytes to @buffer from the I/O channel.
1502 *
1503 * Returns the number of bytes written
1504 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001505int
Owen Taylor3473f882001-02-23 17:55:21 +00001506xmlIOHTTPRead(void * context, char * buffer, int len) {
1507 return(xmlNanoHTTPRead(context, &buffer[0], len));
1508}
1509
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001510#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001511/**
Daniel Veillardf012a642001-07-23 19:10:52 +00001512 * xmlIOHTTPWrite
1513 * @context: previously opened writing context
1514 * @buffer: data to output to temporary buffer
1515 * @len: bytes to output
1516 *
1517 * Collect data from memory buffer into a temporary file for later
1518 * processing.
1519 *
1520 * Returns number of bytes written.
1521 */
1522
1523static int
1524xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
1525
1526 xmlIOHTTPWriteCtxtPtr ctxt = context;
1527
1528 if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
1529 return ( -1 );
1530
1531 if ( len > 0 ) {
1532
1533 /* Use gzwrite or fwrite as previously setup in the open call */
1534
1535#ifdef HAVE_ZLIB_H
1536 if ( ctxt->compression > 0 )
1537 len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len );
1538
1539 else
1540#endif
1541 len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
1542
1543 if ( len < 0 ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001544 xmlChar msg[500];
1545 xmlStrPrintf(msg, 500,
1546 (const xmlChar *) "xmlIOHTTPWrite: %s\n%s '%s'.\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001547 "Error appending to internal buffer.",
1548 "Error sending document to URI",
1549 ctxt->uri );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001550 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001551 }
1552 }
1553
1554 return ( len );
1555}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001556#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001557
1558
1559/**
Owen Taylor3473f882001-02-23 17:55:21 +00001560 * xmlIOHTTPClose:
1561 * @context: the I/O context
1562 *
1563 * Close an HTTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001564 *
1565 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00001566 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001567int
Owen Taylor3473f882001-02-23 17:55:21 +00001568xmlIOHTTPClose (void * context) {
1569 xmlNanoHTTPClose(context);
Daniel Veillardf012a642001-07-23 19:10:52 +00001570 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001571}
Daniel Veillardf012a642001-07-23 19:10:52 +00001572
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001573#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001574/**
1575 * xmlIOHTTCloseWrite
1576 * @context: The I/O context
1577 * @http_mthd: The HTTP method to be used when sending the data
1578 *
1579 * Close the transmit HTTP I/O channel and actually send the data.
1580 */
1581static int
1582xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
1583
1584 int close_rc = -1;
1585 int http_rtn = 0;
1586 int content_lgth = 0;
1587 xmlIOHTTPWriteCtxtPtr ctxt = context;
1588
1589 char * http_content = NULL;
1590 char * content_encoding = NULL;
1591 char * content_type = (char *) "text/xml";
1592 void * http_ctxt = NULL;
1593
1594 if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
1595 return ( -1 );
1596
1597 /* Retrieve the content from the appropriate buffer */
1598
1599#ifdef HAVE_ZLIB_H
1600
1601 if ( ctxt->compression > 0 ) {
1602 content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
1603 content_encoding = (char *) "Content-Encoding: gzip";
1604 }
1605 else
1606#endif
1607 {
1608 /* Pull the data out of the memory output buffer */
1609
1610 xmlOutputBufferPtr dctxt = ctxt->doc_buff;
1611 http_content = (char *)dctxt->buffer->content;
1612 content_lgth = dctxt->buffer->use;
1613 }
1614
1615 if ( http_content == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001616 xmlChar msg[500];
1617 xmlStrPrintf(msg, 500,
1618 (const xmlChar *) "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
1619 "Error retrieving content.\nUnable to",
1620 http_mthd, "data to URI", ctxt->uri );
1621 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001622 }
1623
1624 else {
1625
1626 http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
1627 &content_type, content_encoding,
1628 content_lgth );
1629
1630 if ( http_ctxt != NULL ) {
1631#ifdef DEBUG_HTTP
1632 /* If testing/debugging - dump reply with request content */
1633
1634 FILE * tst_file = NULL;
1635 char buffer[ 4096 ];
1636 char * dump_name = NULL;
1637 int avail;
1638
1639 xmlGenericError( xmlGenericErrorContext,
1640 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
1641 http_mthd, ctxt->uri,
1642 xmlNanoHTTPReturnCode( http_ctxt ) );
1643
1644 /*
1645 ** Since either content or reply may be gzipped,
1646 ** dump them to separate files instead of the
1647 ** standard error context.
1648 */
1649
1650 dump_name = tempnam( NULL, "lxml" );
1651 if ( dump_name != NULL ) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001652 (void)snprintf( buffer, sizeof(buffer), "%s.content", dump_name );
Daniel Veillardf012a642001-07-23 19:10:52 +00001653
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00001654 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00001655 if ( tst_file != NULL ) {
1656 xmlGenericError( xmlGenericErrorContext,
1657 "Transmitted content saved in file: %s\n", buffer );
1658
1659 fwrite( http_content, sizeof( char ),
1660 content_lgth, tst_file );
1661 fclose( tst_file );
1662 }
1663
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001664 (void)snprintf( buffer, sizeof(buffer), "%s.reply", dump_name );
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00001665 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00001666 if ( tst_file != NULL ) {
1667 xmlGenericError( xmlGenericErrorContext,
1668 "Reply content saved in file: %s\n", buffer );
1669
1670
1671 while ( (avail = xmlNanoHTTPRead( http_ctxt,
1672 buffer, sizeof( buffer ) )) > 0 ) {
1673
1674 fwrite( buffer, sizeof( char ), avail, tst_file );
1675 }
1676
1677 fclose( tst_file );
1678 }
1679
1680 free( dump_name );
1681 }
1682#endif /* DEBUG_HTTP */
1683
1684 http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
1685 if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
1686 close_rc = 0;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001687 else {
1688 xmlChar msg[500];
1689 xmlStrPrintf(msg, 500,
1690 (const xmlChar *) "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001691 http_mthd, content_lgth,
1692 "bytes to URI", ctxt->uri,
1693 "failed. HTTP return code:", http_rtn );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001694 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1695 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001696
1697 xmlNanoHTTPClose( http_ctxt );
1698 xmlFree( content_type );
1699 }
1700 }
1701
1702 /* Final cleanups */
1703
1704 xmlFreeHTTPWriteCtxt( ctxt );
1705
1706 return ( close_rc );
1707}
1708
1709/**
1710 * xmlIOHTTPClosePut
1711 *
1712 * @context: The I/O context
1713 *
1714 * Close the transmit HTTP I/O channel and actually send data using a PUT
1715 * HTTP method.
1716 */
1717static int
1718xmlIOHTTPClosePut( void * ctxt ) {
1719 return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
1720}
1721
1722
1723/**
1724 * xmlIOHTTPClosePost
1725 *
1726 * @context: The I/O context
1727 *
1728 * Close the transmit HTTP I/O channel and actually send data using a POST
1729 * HTTP method.
1730 */
1731static int
1732xmlIOHTTPClosePost( void * ctxt ) {
1733 return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
1734}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001735#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001736
Owen Taylor3473f882001-02-23 17:55:21 +00001737#endif /* LIBXML_HTTP_ENABLED */
1738
1739#ifdef LIBXML_FTP_ENABLED
1740/************************************************************************
1741 * *
1742 * I/O for FTP file accesses *
1743 * *
1744 ************************************************************************/
1745/**
1746 * xmlIOFTPMatch:
1747 * @filename: the URI for matching
1748 *
1749 * check if the URI matches an FTP one
1750 *
1751 * Returns 1 if matches, 0 otherwise
1752 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001753int
Owen Taylor3473f882001-02-23 17:55:21 +00001754xmlIOFTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001755 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "ftp://", 6))
Owen Taylor3473f882001-02-23 17:55:21 +00001756 return(1);
1757 return(0);
1758}
1759
1760/**
1761 * xmlIOFTPOpen:
1762 * @filename: the URI for matching
1763 *
1764 * open an FTP I/O channel
1765 *
1766 * Returns an I/O context or NULL in case of error
1767 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001768void *
Owen Taylor3473f882001-02-23 17:55:21 +00001769xmlIOFTPOpen (const char *filename) {
1770 return(xmlNanoFTPOpen(filename));
1771}
1772
1773/**
1774 * xmlIOFTPRead:
1775 * @context: the I/O context
1776 * @buffer: where to drop data
1777 * @len: number of bytes to write
1778 *
1779 * Read @len bytes to @buffer from the I/O channel.
1780 *
1781 * Returns the number of bytes written
1782 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001783int
Owen Taylor3473f882001-02-23 17:55:21 +00001784xmlIOFTPRead(void * context, char * buffer, int len) {
1785 return(xmlNanoFTPRead(context, &buffer[0], len));
1786}
1787
1788/**
1789 * xmlIOFTPClose:
1790 * @context: the I/O context
1791 *
1792 * Close an FTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001793 *
1794 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00001795 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001796int
Owen Taylor3473f882001-02-23 17:55:21 +00001797xmlIOFTPClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001798 return ( xmlNanoFTPClose(context) );
Owen Taylor3473f882001-02-23 17:55:21 +00001799}
1800#endif /* LIBXML_FTP_ENABLED */
1801
1802
1803/**
1804 * xmlRegisterInputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001805 * @matchFunc: the xmlInputMatchCallback
1806 * @openFunc: the xmlInputOpenCallback
1807 * @readFunc: the xmlInputReadCallback
1808 * @closeFunc: the xmlInputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001809 *
1810 * Register a new set of I/O callback for handling parser input.
1811 *
1812 * Returns the registered handler number or -1 in case of error
1813 */
1814int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001815xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
1816 xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
1817 xmlInputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001818 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
1819 return(-1);
1820 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001821 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
1822 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
1823 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
1824 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00001825 xmlInputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00001826 return(xmlInputCallbackNr++);
1827}
1828
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001829#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001830/**
1831 * xmlRegisterOutputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001832 * @matchFunc: the xmlOutputMatchCallback
1833 * @openFunc: the xmlOutputOpenCallback
1834 * @writeFunc: the xmlOutputWriteCallback
1835 * @closeFunc: the xmlOutputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001836 *
1837 * Register a new set of I/O callback for handling output.
1838 *
1839 * Returns the registered handler number or -1 in case of error
1840 */
1841int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001842xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
1843 xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
1844 xmlOutputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001845 if (xmlOutputCallbackNr >= MAX_INPUT_CALLBACK) {
1846 return(-1);
1847 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001848 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
1849 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
1850 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
1851 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00001852 xmlOutputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00001853 return(xmlOutputCallbackNr++);
1854}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001855#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001856
1857/**
1858 * xmlRegisterDefaultInputCallbacks:
1859 *
1860 * Registers the default compiled-in I/O handlers.
1861 */
1862void
Owen Taylor3473f882001-02-23 17:55:21 +00001863xmlRegisterDefaultInputCallbacks
Owen Taylor3473f882001-02-23 17:55:21 +00001864(void) {
1865 if (xmlInputCallbackInitialized)
1866 return;
1867
1868 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
1869 xmlFileRead, xmlFileClose);
1870#ifdef HAVE_ZLIB_H
1871 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1872 xmlGzfileRead, xmlGzfileClose);
1873#endif /* HAVE_ZLIB_H */
1874
1875#ifdef LIBXML_HTTP_ENABLED
1876 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
1877 xmlIOHTTPRead, xmlIOHTTPClose);
1878#endif /* LIBXML_HTTP_ENABLED */
1879
1880#ifdef LIBXML_FTP_ENABLED
1881 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1882 xmlIOFTPRead, xmlIOFTPClose);
1883#endif /* LIBXML_FTP_ENABLED */
1884 xmlInputCallbackInitialized = 1;
1885}
1886
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001887#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001888/**
1889 * xmlRegisterDefaultOutputCallbacks:
1890 *
1891 * Registers the default compiled-in I/O handlers.
1892 */
1893void
Owen Taylor3473f882001-02-23 17:55:21 +00001894xmlRegisterDefaultOutputCallbacks
Owen Taylor3473f882001-02-23 17:55:21 +00001895(void) {
1896 if (xmlOutputCallbackInitialized)
1897 return;
1898
1899 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
1900 xmlFileWrite, xmlFileClose);
Daniel Veillardf012a642001-07-23 19:10:52 +00001901
1902#ifdef LIBXML_HTTP_ENABLED
1903 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
1904 xmlIOHTTPWrite, xmlIOHTTPClosePut);
1905#endif
1906
Owen Taylor3473f882001-02-23 17:55:21 +00001907/*********************************
1908 No way a-priori to distinguish between gzipped files from
1909 uncompressed ones except opening if existing then closing
1910 and saving with same compression ratio ... a pain.
1911
1912#ifdef HAVE_ZLIB_H
1913 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1914 xmlGzfileWrite, xmlGzfileClose);
1915#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001916
1917 Nor FTP PUT ....
1918#ifdef LIBXML_FTP_ENABLED
1919 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1920 xmlIOFTPWrite, xmlIOFTPClose);
1921#endif
1922 **********************************/
1923 xmlOutputCallbackInitialized = 1;
1924}
1925
Daniel Veillardf012a642001-07-23 19:10:52 +00001926#ifdef LIBXML_HTTP_ENABLED
1927/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001928 * xmlRegisterHTTPPostCallbacks:
Daniel Veillardf012a642001-07-23 19:10:52 +00001929 *
1930 * By default, libxml submits HTTP output requests using the "PUT" method.
1931 * Calling this method changes the HTTP output method to use the "POST"
1932 * method instead.
1933 *
1934 */
1935void
1936xmlRegisterHTTPPostCallbacks( void ) {
1937
1938 /* Register defaults if not done previously */
1939
1940 if ( xmlOutputCallbackInitialized == 0 )
1941 xmlRegisterDefaultOutputCallbacks( );
1942
1943 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
1944 xmlIOHTTPWrite, xmlIOHTTPClosePost);
1945 return;
1946}
1947#endif
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001948#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001949
Owen Taylor3473f882001-02-23 17:55:21 +00001950/**
1951 * xmlAllocParserInputBuffer:
1952 * @enc: the charset encoding if known
1953 *
1954 * Create a buffered parser input for progressive parsing
1955 *
1956 * Returns the new parser input or NULL
1957 */
1958xmlParserInputBufferPtr
1959xmlAllocParserInputBuffer(xmlCharEncoding enc) {
1960 xmlParserInputBufferPtr ret;
1961
1962 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
1963 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001964 xmlIOErrMemory("creating input buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00001965 return(NULL);
1966 }
1967 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00001968 ret->buffer = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00001969 if (ret->buffer == NULL) {
1970 xmlFree(ret);
1971 return(NULL);
1972 }
1973 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
1974 ret->encoder = xmlGetCharEncodingHandler(enc);
1975 if (ret->encoder != NULL)
Daniel Veillard6155d8a2003-08-19 15:01:28 +00001976 ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00001977 else
1978 ret->raw = NULL;
1979 ret->readcallback = NULL;
1980 ret->closecallback = NULL;
1981 ret->context = NULL;
William M. Brackc07329e2003-09-08 01:57:30 +00001982 ret->compressed = -1;
Daniel Veillard36711902004-02-11 13:25:26 +00001983 ret->rawconsumed = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001984
1985 return(ret);
1986}
1987
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001988#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001989/**
1990 * xmlAllocOutputBuffer:
1991 * @encoder: the encoding converter or NULL
1992 *
1993 * Create a buffered parser output
1994 *
1995 * Returns the new parser output or NULL
1996 */
1997xmlOutputBufferPtr
1998xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
1999 xmlOutputBufferPtr ret;
2000
2001 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
2002 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002003 xmlIOErrMemory("creating output buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00002004 return(NULL);
2005 }
2006 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
2007 ret->buffer = xmlBufferCreate();
2008 if (ret->buffer == NULL) {
2009 xmlFree(ret);
2010 return(NULL);
2011 }
2012 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
2013 ret->encoder = encoder;
2014 if (encoder != NULL) {
2015 ret->conv = xmlBufferCreateSize(4000);
2016 /*
2017 * This call is designed to initiate the encoder state
2018 */
2019 xmlCharEncOutFunc(encoder, ret->conv, NULL);
2020 } else
2021 ret->conv = NULL;
2022 ret->writecallback = NULL;
2023 ret->closecallback = NULL;
2024 ret->context = NULL;
2025 ret->written = 0;
2026
2027 return(ret);
2028}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002029#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002030
2031/**
2032 * xmlFreeParserInputBuffer:
2033 * @in: a buffered parser input
2034 *
2035 * Free up the memory used by a buffered parser input
2036 */
2037void
2038xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
Daniel Veillard8d8bf2c2003-09-17 19:36:25 +00002039 if (in == NULL) return;
2040
Owen Taylor3473f882001-02-23 17:55:21 +00002041 if (in->raw) {
2042 xmlBufferFree(in->raw);
2043 in->raw = NULL;
2044 }
2045 if (in->encoder != NULL) {
2046 xmlCharEncCloseFunc(in->encoder);
2047 }
2048 if (in->closecallback != NULL) {
2049 in->closecallback(in->context);
2050 }
2051 if (in->buffer != NULL) {
2052 xmlBufferFree(in->buffer);
2053 in->buffer = NULL;
2054 }
2055
Owen Taylor3473f882001-02-23 17:55:21 +00002056 xmlFree(in);
2057}
2058
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002059#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002060/**
2061 * xmlOutputBufferClose:
2062 * @out: a buffered output
2063 *
2064 * flushes and close the output I/O channel
2065 * and free up all the associated resources
2066 *
2067 * Returns the number of byte written or -1 in case of error.
2068 */
2069int
Daniel Veillard828ce832003-10-08 19:19:10 +00002070xmlOutputBufferClose(xmlOutputBufferPtr out)
2071{
Owen Taylor3473f882001-02-23 17:55:21 +00002072 int written;
Daniel Veillardf012a642001-07-23 19:10:52 +00002073 int err_rc = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002074
2075 if (out == NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002076 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002077 if (out->writecallback != NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002078 xmlOutputBufferFlush(out);
Owen Taylor3473f882001-02-23 17:55:21 +00002079 if (out->closecallback != NULL) {
Daniel Veillard828ce832003-10-08 19:19:10 +00002080 err_rc = out->closecallback(out->context);
Owen Taylor3473f882001-02-23 17:55:21 +00002081 }
2082 written = out->written;
2083 if (out->conv) {
2084 xmlBufferFree(out->conv);
Daniel Veillard828ce832003-10-08 19:19:10 +00002085 out->conv = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002086 }
2087 if (out->encoder != NULL) {
2088 xmlCharEncCloseFunc(out->encoder);
2089 }
2090 if (out->buffer != NULL) {
2091 xmlBufferFree(out->buffer);
Daniel Veillard828ce832003-10-08 19:19:10 +00002092 out->buffer = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002093 }
2094
Daniel Veillard828ce832003-10-08 19:19:10 +00002095 if (out->error)
2096 err_rc = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00002097 xmlFree(out);
Daniel Veillard828ce832003-10-08 19:19:10 +00002098 return ((err_rc == 0) ? written : err_rc);
Owen Taylor3473f882001-02-23 17:55:21 +00002099}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002100#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002101
2102/**
2103 * xmlParserInputBufferCreateFilename:
2104 * @URI: a C string containing the URI or filename
2105 * @enc: the charset encoding if known
2106 *
2107 * Create a buffered parser input for the progressive parsing of a file
2108 * If filename is "-' then we use stdin as the input.
2109 * Automatic support for ZLIB/Compress compressed document is provided
2110 * by default if found at compile-time.
2111 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
2112 *
2113 * Returns the new parser input or NULL
2114 */
2115xmlParserInputBufferPtr
Daniel Veillard3e59fc52003-04-18 12:34:58 +00002116xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002117 xmlParserInputBufferPtr ret;
Daniel Veillard388236f2001-07-08 18:35:48 +00002118 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002119 void *context = NULL;
2120
2121 if (xmlInputCallbackInitialized == 0)
2122 xmlRegisterDefaultInputCallbacks();
2123
2124 if (URI == NULL) return(NULL);
2125
2126 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002127 * Try to find one of the input accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002128 * Go in reverse to give precedence to user defined handlers.
Daniel Veillard388236f2001-07-08 18:35:48 +00002129 */
2130 if (context == NULL) {
2131 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
2132 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
2133 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002134 context = xmlInputCallbackTable[i].opencallback(URI);
Daniel Veillard847332a2003-10-18 11:29:40 +00002135 if (context != NULL) {
Daniel Veillard388236f2001-07-08 18:35:48 +00002136 break;
Daniel Veillard847332a2003-10-18 11:29:40 +00002137 }
Daniel Veillard388236f2001-07-08 18:35:48 +00002138 }
Owen Taylor3473f882001-02-23 17:55:21 +00002139 }
2140 }
2141 if (context == NULL) {
2142 return(NULL);
2143 }
2144
2145 /*
2146 * Allocate the Input buffer front-end.
2147 */
2148 ret = xmlAllocParserInputBuffer(enc);
2149 if (ret != NULL) {
2150 ret->context = context;
2151 ret->readcallback = xmlInputCallbackTable[i].readcallback;
2152 ret->closecallback = xmlInputCallbackTable[i].closecallback;
William M. Brackc07329e2003-09-08 01:57:30 +00002153#ifdef HAVE_ZLIB_H
William M. Brackc5cbf992003-10-29 22:15:13 +00002154 if ((xmlInputCallbackTable[i].opencallback == xmlGzfileOpen) &&
2155 (strcmp(URI, "-") != 0)) {
William M. Brackc07329e2003-09-08 01:57:30 +00002156 if (((z_stream *)context)->avail_in > 4) {
2157 char *cptr, buff4[4];
Daniel Veillard07cb8222003-09-10 10:51:05 +00002158 cptr = (char *) ((z_stream *)context)->next_in;
William M. Brackc07329e2003-09-08 01:57:30 +00002159 if (gzread(context, buff4, 4) == 4) {
2160 if (strncmp(buff4, cptr, 4) == 0)
2161 ret->compressed = 0;
2162 else
2163 ret->compressed = 1;
2164 gzrewind(context);
2165 }
2166 }
2167 }
2168#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002169 }
2170 return(ret);
2171}
2172
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002173#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002174/**
2175 * xmlOutputBufferCreateFilename:
2176 * @URI: a C string containing the URI or filename
2177 * @encoder: the encoding converter or NULL
2178 * @compression: the compression ration (0 none, 9 max).
2179 *
2180 * Create a buffered output for the progressive saving of a file
2181 * If filename is "-' then we use stdout as the output.
2182 * Automatic support for ZLIB/Compress compressed document is provided
2183 * by default if found at compile-time.
2184 * TODO: currently if compression is set, the library only support
2185 * writing to a local file.
2186 *
2187 * Returns the new output or NULL
2188 */
2189xmlOutputBufferPtr
2190xmlOutputBufferCreateFilename(const char *URI,
2191 xmlCharEncodingHandlerPtr encoder,
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002192 int compression ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00002193 xmlOutputBufferPtr ret;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002194 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002195 void *context = NULL;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002196 char *unescaped;
Owen Taylor3473f882001-02-23 17:55:21 +00002197
Daniel Veillardf012a642001-07-23 19:10:52 +00002198 int is_http_uri = 0; /* Can't change if HTTP disabled */
2199
Owen Taylor3473f882001-02-23 17:55:21 +00002200 if (xmlOutputCallbackInitialized == 0)
2201 xmlRegisterDefaultOutputCallbacks();
2202
2203 if (URI == NULL) return(NULL);
2204
Daniel Veillardf012a642001-07-23 19:10:52 +00002205#ifdef LIBXML_HTTP_ENABLED
2206 /* Need to prevent HTTP URI's from falling into zlib short circuit */
2207
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002208 is_http_uri = xmlIOHTTPMatch( URI );
Daniel Veillardf012a642001-07-23 19:10:52 +00002209#endif
2210
Owen Taylor3473f882001-02-23 17:55:21 +00002211
2212 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002213 * Try to find one of the output accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002214 * Go in reverse to give precedence to user defined handlers.
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002215 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00002216 */
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002217 unescaped = xmlURIUnescapeString(URI, 0, NULL);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002218 if (unescaped != NULL) {
2219#ifdef HAVE_ZLIB_H
2220 if ((compression > 0) && (compression <= 9) && (is_http_uri == 0)) {
2221 context = xmlGzfileOpenW(unescaped, compression);
2222 if (context != NULL) {
2223 ret = xmlAllocOutputBuffer(encoder);
2224 if (ret != NULL) {
2225 ret->context = context;
2226 ret->writecallback = xmlGzfileWrite;
2227 ret->closecallback = xmlGzfileClose;
2228 }
2229 xmlFree(unescaped);
2230 return(ret);
2231 }
2232 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002233#endif
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002234 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2235 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
2236 (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
2237#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2238 /* Need to pass compression parameter into HTTP open calls */
2239 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2240 context = xmlIOHTTPOpenW(unescaped, compression);
2241 else
2242#endif
2243 context = xmlOutputCallbackTable[i].opencallback(unescaped);
2244 if (context != NULL)
2245 break;
2246 }
2247 }
2248 xmlFree(unescaped);
2249 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002250
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002251 /*
2252 * If this failed try with a non-escaped URI this may be a strange
2253 * filename
2254 */
2255 if (context == NULL) {
2256#ifdef HAVE_ZLIB_H
2257 if ((compression > 0) && (compression <= 9) && (is_http_uri == 0)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002258 context = xmlGzfileOpenW(URI, compression);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002259 if (context != NULL) {
2260 ret = xmlAllocOutputBuffer(encoder);
2261 if (ret != NULL) {
2262 ret->context = context;
2263 ret->writecallback = xmlGzfileWrite;
2264 ret->closecallback = xmlGzfileClose;
2265 }
2266 return(ret);
2267 }
2268 }
2269#endif
2270 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2271 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002272 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002273#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2274 /* Need to pass compression parameter into HTTP open calls */
2275 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2276 context = xmlIOHTTPOpenW(URI, compression);
2277 else
2278#endif
2279 context = xmlOutputCallbackTable[i].opencallback(URI);
2280 if (context != NULL)
2281 break;
2282 }
Owen Taylor3473f882001-02-23 17:55:21 +00002283 }
2284 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002285
Owen Taylor3473f882001-02-23 17:55:21 +00002286 if (context == NULL) {
2287 return(NULL);
2288 }
2289
2290 /*
2291 * Allocate the Output buffer front-end.
2292 */
2293 ret = xmlAllocOutputBuffer(encoder);
2294 if (ret != NULL) {
2295 ret->context = context;
2296 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
2297 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
2298 }
2299 return(ret);
2300}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002301#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002302
2303/**
2304 * xmlParserInputBufferCreateFile:
2305 * @file: a FILE*
2306 * @enc: the charset encoding if known
2307 *
2308 * Create a buffered parser input for the progressive parsing of a FILE *
2309 * buffered C I/O
2310 *
2311 * Returns the new parser input or NULL
2312 */
2313xmlParserInputBufferPtr
2314xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
2315 xmlParserInputBufferPtr ret;
2316
2317 if (xmlInputCallbackInitialized == 0)
2318 xmlRegisterDefaultInputCallbacks();
2319
2320 if (file == NULL) return(NULL);
2321
2322 ret = xmlAllocParserInputBuffer(enc);
2323 if (ret != NULL) {
2324 ret->context = file;
2325 ret->readcallback = xmlFileRead;
2326 ret->closecallback = xmlFileFlush;
2327 }
2328
2329 return(ret);
2330}
2331
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002332#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002333/**
2334 * xmlOutputBufferCreateFile:
2335 * @file: a FILE*
2336 * @encoder: the encoding converter or NULL
2337 *
2338 * Create a buffered output for the progressive saving to a FILE *
2339 * buffered C I/O
2340 *
2341 * Returns the new parser output or NULL
2342 */
2343xmlOutputBufferPtr
2344xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
2345 xmlOutputBufferPtr ret;
2346
2347 if (xmlOutputCallbackInitialized == 0)
2348 xmlRegisterDefaultOutputCallbacks();
2349
2350 if (file == NULL) return(NULL);
2351
2352 ret = xmlAllocOutputBuffer(encoder);
2353 if (ret != NULL) {
2354 ret->context = file;
2355 ret->writecallback = xmlFileWrite;
2356 ret->closecallback = xmlFileFlush;
2357 }
2358
2359 return(ret);
2360}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002361#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002362
2363/**
2364 * xmlParserInputBufferCreateFd:
2365 * @fd: a file descriptor number
2366 * @enc: the charset encoding if known
2367 *
2368 * Create a buffered parser input for the progressive parsing for the input
2369 * from a file descriptor
2370 *
2371 * Returns the new parser input or NULL
2372 */
2373xmlParserInputBufferPtr
2374xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
2375 xmlParserInputBufferPtr ret;
2376
2377 if (fd < 0) return(NULL);
2378
2379 ret = xmlAllocParserInputBuffer(enc);
2380 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002381 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002382 ret->readcallback = xmlFdRead;
2383 ret->closecallback = xmlFdClose;
2384 }
2385
2386 return(ret);
2387}
2388
2389/**
2390 * xmlParserInputBufferCreateMem:
2391 * @mem: the memory input
2392 * @size: the length of the memory block
2393 * @enc: the charset encoding if known
2394 *
2395 * Create a buffered parser input for the progressive parsing for the input
2396 * from a memory area.
2397 *
2398 * Returns the new parser input or NULL
2399 */
2400xmlParserInputBufferPtr
2401xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
2402 xmlParserInputBufferPtr ret;
2403
2404 if (size <= 0) return(NULL);
2405 if (mem == NULL) return(NULL);
2406
2407 ret = xmlAllocParserInputBuffer(enc);
2408 if (ret != NULL) {
2409 ret->context = (void *) mem;
2410 ret->readcallback = (xmlInputReadCallback) xmlNop;
2411 ret->closecallback = NULL;
2412 xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size);
2413 }
2414
2415 return(ret);
2416}
2417
2418/**
Daniel Veillard53350552003-09-18 13:35:51 +00002419 * xmlParserInputBufferCreateStatic:
2420 * @mem: the memory input
2421 * @size: the length of the memory block
2422 * @enc: the charset encoding if known
2423 *
2424 * Create a buffered parser input for the progressive parsing for the input
2425 * from an immutable memory area. This will not copy the memory area to
2426 * the buffer, but the memory is expected to be available until the end of
2427 * the parsing, this is useful for example when using mmap'ed file.
2428 *
2429 * Returns the new parser input or NULL
2430 */
2431xmlParserInputBufferPtr
2432xmlParserInputBufferCreateStatic(const char *mem, int size,
2433 xmlCharEncoding enc) {
2434 xmlParserInputBufferPtr ret;
2435
2436 if (size <= 0) return(NULL);
2437 if (mem == NULL) return(NULL);
2438
2439 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2440 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002441 xmlIOErrMemory("creating input buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00002442 return(NULL);
2443 }
2444 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillarde72c5082003-09-19 12:44:05 +00002445 ret->buffer = xmlBufferCreateStatic((void *)mem, (size_t) size);
Daniel Veillard53350552003-09-18 13:35:51 +00002446 if (ret->buffer == NULL) {
2447 xmlFree(ret);
2448 return(NULL);
2449 }
2450 ret->encoder = xmlGetCharEncodingHandler(enc);
2451 if (ret->encoder != NULL)
2452 ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
2453 else
2454 ret->raw = NULL;
2455 ret->compressed = -1;
2456 ret->context = (void *) mem;
2457 ret->readcallback = NULL;
2458 ret->closecallback = NULL;
2459
2460 return(ret);
2461}
2462
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002463#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard53350552003-09-18 13:35:51 +00002464/**
Owen Taylor3473f882001-02-23 17:55:21 +00002465 * xmlOutputBufferCreateFd:
2466 * @fd: a file descriptor number
2467 * @encoder: the encoding converter or NULL
2468 *
2469 * Create a buffered output for the progressive saving
2470 * to a file descriptor
2471 *
2472 * Returns the new parser output or NULL
2473 */
2474xmlOutputBufferPtr
2475xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
2476 xmlOutputBufferPtr ret;
2477
2478 if (fd < 0) return(NULL);
2479
2480 ret = xmlAllocOutputBuffer(encoder);
2481 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002482 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002483 ret->writecallback = xmlFdWrite;
Daniel Veillard7db38712002-02-07 16:39:11 +00002484 ret->closecallback = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002485 }
2486
2487 return(ret);
2488}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002489#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002490
2491/**
2492 * xmlParserInputBufferCreateIO:
2493 * @ioread: an I/O read function
2494 * @ioclose: an I/O close function
2495 * @ioctx: an I/O handler
2496 * @enc: the charset encoding if known
2497 *
2498 * Create a buffered parser input for the progressive parsing for the input
2499 * from an I/O handler
2500 *
2501 * Returns the new parser input or NULL
2502 */
2503xmlParserInputBufferPtr
2504xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
2505 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
2506 xmlParserInputBufferPtr ret;
2507
2508 if (ioread == NULL) return(NULL);
2509
2510 ret = xmlAllocParserInputBuffer(enc);
2511 if (ret != NULL) {
2512 ret->context = (void *) ioctx;
2513 ret->readcallback = ioread;
2514 ret->closecallback = ioclose;
2515 }
2516
2517 return(ret);
2518}
2519
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002520#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002521/**
2522 * xmlOutputBufferCreateIO:
2523 * @iowrite: an I/O write function
2524 * @ioclose: an I/O close function
2525 * @ioctx: an I/O handler
Daniel Veillard9d06d302002-01-22 18:15:52 +00002526 * @encoder: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002527 *
2528 * Create a buffered output for the progressive saving
2529 * to an I/O handler
2530 *
2531 * Returns the new parser output or NULL
2532 */
2533xmlOutputBufferPtr
2534xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
2535 xmlOutputCloseCallback ioclose, void *ioctx,
2536 xmlCharEncodingHandlerPtr encoder) {
2537 xmlOutputBufferPtr ret;
2538
2539 if (iowrite == NULL) return(NULL);
2540
2541 ret = xmlAllocOutputBuffer(encoder);
2542 if (ret != NULL) {
2543 ret->context = (void *) ioctx;
2544 ret->writecallback = iowrite;
2545 ret->closecallback = ioclose;
2546 }
2547
2548 return(ret);
2549}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002550#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002551
2552/**
2553 * xmlParserInputBufferPush:
2554 * @in: a buffered parser input
2555 * @len: the size in bytes of the array.
2556 * @buf: an char array
2557 *
2558 * Push the content of the arry in the input buffer
2559 * This routine handle the I18N transcoding to internal UTF-8
2560 * This is used when operating the parser in progressive (push) mode.
2561 *
2562 * Returns the number of chars read and stored in the buffer, or -1
2563 * in case of error.
2564 */
2565int
2566xmlParserInputBufferPush(xmlParserInputBufferPtr in,
2567 int len, const char *buf) {
2568 int nbchars = 0;
2569
2570 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002571 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002572 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00002573 unsigned int use;
2574
Owen Taylor3473f882001-02-23 17:55:21 +00002575 /*
2576 * Store the data in the incoming raw buffer
2577 */
2578 if (in->raw == NULL) {
2579 in->raw = xmlBufferCreate();
2580 }
2581 xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
2582
2583 /*
2584 * convert as much as possible to the parser reading buffer.
2585 */
Daniel Veillard36711902004-02-11 13:25:26 +00002586 use = in->raw->use;
Owen Taylor3473f882001-02-23 17:55:21 +00002587 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2588 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002589 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002590 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002591 return(-1);
2592 }
Daniel Veillard36711902004-02-11 13:25:26 +00002593 in->rawconsumed += (use - in->raw->use);
Owen Taylor3473f882001-02-23 17:55:21 +00002594 } else {
2595 nbchars = len;
2596 xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
2597 }
2598#ifdef DEBUG_INPUT
2599 xmlGenericError(xmlGenericErrorContext,
2600 "I/O: pushed %d chars, buffer %d/%d\n",
2601 nbchars, in->buffer->use, in->buffer->size);
2602#endif
2603 return(nbchars);
2604}
2605
2606/**
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002607 * endOfInput:
2608 *
2609 * When reading from an Input channel indicated end of file or error
2610 * don't reread from it again.
2611 */
2612static int
2613endOfInput (void * context ATTRIBUTE_UNUSED,
2614 char * buffer ATTRIBUTE_UNUSED,
2615 int len ATTRIBUTE_UNUSED) {
2616 return(0);
2617}
2618
2619/**
Owen Taylor3473f882001-02-23 17:55:21 +00002620 * xmlParserInputBufferGrow:
2621 * @in: a buffered parser input
2622 * @len: indicative value of the amount of chars to read
2623 *
2624 * Grow up the content of the input buffer, the old data are preserved
2625 * This routine handle the I18N transcoding to internal UTF-8
2626 * This routine is used when operating the parser in normal (pull) mode
2627 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002628 * TODO: one should be able to remove one extra copy by copying directly
Owen Taylor3473f882001-02-23 17:55:21 +00002629 * onto in->buffer or in->raw
2630 *
2631 * Returns the number of chars read and stored in the buffer, or -1
2632 * in case of error.
2633 */
2634int
2635xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
2636 char *buffer = NULL;
2637 int res = 0;
2638 int nbchars = 0;
2639 int buffree;
Daniel Veillard9e412302002-06-10 15:59:44 +00002640 unsigned int needSize;
Owen Taylor3473f882001-02-23 17:55:21 +00002641
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002642 if ((in == NULL) || (in->error)) return(-1);
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002643 if ((len <= MINLEN) && (len != 4))
Owen Taylor3473f882001-02-23 17:55:21 +00002644 len = MINLEN;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002645
Owen Taylor3473f882001-02-23 17:55:21 +00002646 buffree = in->buffer->size - in->buffer->use;
2647 if (buffree <= 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002648 xmlIOErr(XML_IO_BUFFER_FULL, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002649 in->error = XML_IO_BUFFER_FULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002650 return(0);
2651 }
Owen Taylor3473f882001-02-23 17:55:21 +00002652
Daniel Veillarde5354492002-05-16 08:43:22 +00002653 needSize = in->buffer->use + len + 1;
2654 if (needSize > in->buffer->size){
2655 if (!xmlBufferResize(in->buffer, needSize)){
Daniel Veillard05d987b2003-10-08 11:54:57 +00002656 xmlIOErrMemory("growing input buffer");
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002657 in->error = XML_ERR_NO_MEMORY;
Daniel Veillarde5354492002-05-16 08:43:22 +00002658 return(0);
2659 }
Owen Taylor3473f882001-02-23 17:55:21 +00002660 }
Daniel Veillarde5354492002-05-16 08:43:22 +00002661 buffer = (char *)&in->buffer->content[in->buffer->use];
Owen Taylor3473f882001-02-23 17:55:21 +00002662
2663 /*
2664 * Call the read method for this I/O type.
2665 */
2666 if (in->readcallback != NULL) {
2667 res = in->readcallback(in->context, &buffer[0], len);
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002668 if (res <= 0)
2669 in->readcallback = endOfInput;
Owen Taylor3473f882001-02-23 17:55:21 +00002670 } else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002671 xmlIOErr(XML_IO_NO_INPUT, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002672 in->error = XML_IO_NO_INPUT;
Owen Taylor3473f882001-02-23 17:55:21 +00002673 return(-1);
2674 }
2675 if (res < 0) {
Owen Taylor3473f882001-02-23 17:55:21 +00002676 return(-1);
2677 }
2678 len = res;
2679 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00002680 unsigned int use;
2681
Owen Taylor3473f882001-02-23 17:55:21 +00002682 /*
2683 * Store the data in the incoming raw buffer
2684 */
2685 if (in->raw == NULL) {
2686 in->raw = xmlBufferCreate();
2687 }
2688 xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
2689
2690 /*
2691 * convert as much as possible to the parser reading buffer.
2692 */
Daniel Veillard36711902004-02-11 13:25:26 +00002693 use = in->raw->use;
Owen Taylor3473f882001-02-23 17:55:21 +00002694 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2695 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002696 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002697 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002698 return(-1);
2699 }
Daniel Veillard36711902004-02-11 13:25:26 +00002700 in->rawconsumed += (use - in->raw->use);
Owen Taylor3473f882001-02-23 17:55:21 +00002701 } else {
2702 nbchars = len;
Daniel Veillarde5354492002-05-16 08:43:22 +00002703 in->buffer->use += nbchars;
2704 buffer[nbchars] = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002705 }
2706#ifdef DEBUG_INPUT
2707 xmlGenericError(xmlGenericErrorContext,
2708 "I/O: read %d chars, buffer %d/%d\n",
2709 nbchars, in->buffer->use, in->buffer->size);
2710#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002711 return(nbchars);
2712}
2713
2714/**
2715 * xmlParserInputBufferRead:
2716 * @in: a buffered parser input
2717 * @len: indicative value of the amount of chars to read
2718 *
2719 * Refresh the content of the input buffer, the old data are considered
2720 * consumed
2721 * This routine handle the I18N transcoding to internal UTF-8
2722 *
2723 * Returns the number of chars read and stored in the buffer, or -1
2724 * in case of error.
2725 */
2726int
2727xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002728 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002729 if (in->readcallback != NULL)
2730 return(xmlParserInputBufferGrow(in, len));
Daniel Veillard53350552003-09-18 13:35:51 +00002731 else if ((in->buffer != NULL) &&
2732 (in->buffer->alloc == XML_BUFFER_ALLOC_IMMUTABLE))
2733 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002734 else
2735 return(-1);
2736}
2737
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002738#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002739/**
2740 * xmlOutputBufferWrite:
2741 * @out: a buffered parser output
2742 * @len: the size in bytes of the array.
2743 * @buf: an char array
2744 *
2745 * Write the content of the array in the output I/O buffer
2746 * This routine handle the I18N transcoding from internal UTF-8
2747 * The buffer is lossless, i.e. will store in case of partial
2748 * or delayed writes.
2749 *
2750 * Returns the number of chars immediately written, or -1
2751 * in case of error.
2752 */
2753int
2754xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
2755 int nbchars = 0; /* number of chars to output to I/O */
2756 int ret; /* return from function call */
2757 int written = 0; /* number of char written to I/O so far */
2758 int chunk; /* number of byte curreent processed from buf */
2759
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002760 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002761 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002762 if (out->error) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002763
2764 do {
2765 chunk = len;
2766 if (chunk > 4 * MINLEN)
2767 chunk = 4 * MINLEN;
2768
2769 /*
2770 * first handle encoding stuff.
2771 */
2772 if (out->encoder != NULL) {
2773 /*
2774 * Store the data in the incoming raw buffer
2775 */
2776 if (out->conv == NULL) {
2777 out->conv = xmlBufferCreate();
2778 }
2779 xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2780
2781 if ((out->buffer->use < MINLEN) && (chunk == len))
2782 goto done;
2783
2784 /*
2785 * convert as much as possible to the parser reading buffer.
2786 */
2787 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
Daniel Veillard809faa52003-02-10 15:43:53 +00002788 if ((ret < 0) && (ret != -3)) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002789 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002790 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002791 return(-1);
2792 }
2793 nbchars = out->conv->use;
2794 } else {
2795 xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2796 nbchars = out->buffer->use;
2797 }
2798 buf += chunk;
2799 len -= chunk;
2800
2801 if ((nbchars < MINLEN) && (len <= 0))
2802 goto done;
2803
2804 if (out->writecallback) {
2805 /*
2806 * second write the stuff to the I/O channel
2807 */
2808 if (out->encoder != NULL) {
2809 ret = out->writecallback(out->context,
2810 (const char *)out->conv->content, nbchars);
2811 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002812 xmlBufferShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002813 } else {
2814 ret = out->writecallback(out->context,
2815 (const char *)out->buffer->content, nbchars);
2816 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002817 xmlBufferShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002818 }
2819 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002820 xmlIOErr(XML_IO_WRITE, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002821 out->error = XML_IO_WRITE;
Owen Taylor3473f882001-02-23 17:55:21 +00002822 return(ret);
2823 }
2824 out->written += ret;
2825 }
2826 written += nbchars;
2827 } while (len > 0);
2828
2829done:
2830#ifdef DEBUG_INPUT
2831 xmlGenericError(xmlGenericErrorContext,
2832 "I/O: wrote %d chars\n", written);
2833#endif
2834 return(written);
2835}
2836
2837/**
2838 * xmlOutputBufferWriteString:
2839 * @out: a buffered parser output
2840 * @str: a zero terminated C string
2841 *
2842 * Write the content of the string in the output I/O buffer
2843 * This routine handle the I18N transcoding from internal UTF-8
2844 * The buffer is lossless, i.e. will store in case of partial
2845 * or delayed writes.
2846 *
2847 * Returns the number of chars immediately written, or -1
2848 * in case of error.
2849 */
2850int
2851xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
2852 int len;
2853
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002854 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002855 if (str == NULL)
2856 return(-1);
2857 len = strlen(str);
2858
2859 if (len > 0)
2860 return(xmlOutputBufferWrite(out, len, str));
2861 return(len);
2862}
2863
2864/**
2865 * xmlOutputBufferFlush:
2866 * @out: a buffered output
2867 *
2868 * flushes the output I/O channel
2869 *
2870 * Returns the number of byte written or -1 in case of error.
2871 */
2872int
2873xmlOutputBufferFlush(xmlOutputBufferPtr out) {
2874 int nbchars = 0, ret = 0;
2875
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002876 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002877 /*
2878 * first handle encoding stuff.
2879 */
2880 if ((out->conv != NULL) && (out->encoder != NULL)) {
2881 /*
2882 * convert as much as possible to the parser reading buffer.
2883 */
2884 nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
2885 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002886 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002887 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002888 return(-1);
2889 }
2890 }
2891
2892 /*
2893 * second flush the stuff to the I/O channel
2894 */
2895 if ((out->conv != NULL) && (out->encoder != NULL) &&
2896 (out->writecallback != NULL)) {
2897 ret = out->writecallback(out->context,
2898 (const char *)out->conv->content, out->conv->use);
2899 if (ret >= 0)
2900 xmlBufferShrink(out->conv, ret);
2901 } else if (out->writecallback != NULL) {
2902 ret = out->writecallback(out->context,
2903 (const char *)out->buffer->content, out->buffer->use);
2904 if (ret >= 0)
2905 xmlBufferShrink(out->buffer, ret);
2906 }
2907 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002908 xmlIOErr(XML_IO_FLUSH, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002909 out->error = XML_IO_FLUSH;
Owen Taylor3473f882001-02-23 17:55:21 +00002910 return(ret);
2911 }
2912 out->written += ret;
2913
2914#ifdef DEBUG_INPUT
2915 xmlGenericError(xmlGenericErrorContext,
2916 "I/O: flushed %d chars\n", ret);
2917#endif
2918 return(ret);
2919}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002920#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002921
Daniel Veillard5e2dace2001-07-18 19:30:27 +00002922/**
Owen Taylor3473f882001-02-23 17:55:21 +00002923 * xmlParserGetDirectory:
2924 * @filename: the path to a file
2925 *
2926 * lookup the directory for that file
2927 *
2928 * Returns a new allocated string containing the directory, or NULL.
2929 */
2930char *
2931xmlParserGetDirectory(const char *filename) {
2932 char *ret = NULL;
2933 char dir[1024];
2934 char *cur;
2935 char sep = '/';
2936
Igor Zlatkovic9181cc02002-09-29 17:51:06 +00002937#ifdef _WIN32_WCE /* easy way by now ... wince does not have dirs! */
2938 return NULL;
2939#endif
2940
Owen Taylor3473f882001-02-23 17:55:21 +00002941 if (xmlInputCallbackInitialized == 0)
2942 xmlRegisterDefaultInputCallbacks();
2943
2944 if (filename == NULL) return(NULL);
Daniel Veillard3c5ed912002-01-08 10:36:16 +00002945#if defined(WIN32) && !defined(__CYGWIN__)
Owen Taylor3473f882001-02-23 17:55:21 +00002946 sep = '\\';
2947#endif
2948
2949 strncpy(dir, filename, 1023);
2950 dir[1023] = 0;
2951 cur = &dir[strlen(dir)];
2952 while (cur > dir) {
2953 if (*cur == sep) break;
2954 cur --;
2955 }
2956 if (*cur == sep) {
2957 if (cur == dir) dir[1] = 0;
2958 else *cur = 0;
2959 ret = xmlMemStrdup(dir);
2960 } else {
2961 if (getcwd(dir, 1024) != NULL) {
2962 dir[1023] = 0;
2963 ret = xmlMemStrdup(dir);
2964 }
2965 }
2966 return(ret);
2967}
2968
2969/****************************************************************
2970 * *
2971 * External entities loading *
2972 * *
2973 ****************************************************************/
2974
Daniel Veillarda840b692003-10-19 13:35:37 +00002975/**
2976 * xmlCheckHTTPInput:
2977 * @ctxt: an XML parser context
2978 * @ret: an XML parser input
2979 *
2980 * Check an input in case it was created from an HTTP stream, in that
2981 * case it will handle encoding and update of the base URL in case of
2982 * redirection. It also checks for HTTP errors in which case the input
2983 * is cleanly freed up and an appropriate error is raised in context
2984 *
2985 * Returns the input or NULL in case of HTTP error.
2986 */
2987xmlParserInputPtr
2988xmlCheckHTTPInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr ret) {
2989#ifdef LIBXML_HTTP_ENABLED
2990 if ((ret != NULL) && (ret->buf != NULL) &&
2991 (ret->buf->readcallback == xmlIOHTTPRead) &&
2992 (ret->buf->context != NULL)) {
2993 const char *encoding;
2994 const char *redir;
2995 const char *mime;
2996 int code;
2997
2998 code = xmlNanoHTTPReturnCode(ret->buf->context);
2999 if (code >= 400) {
3000 /* fatal error */
3001 if (ret->filename != NULL)
Daniel Veillarde8039df2003-10-27 11:25:13 +00003002 __xmlLoaderErr(ctxt, "failed to load HTTP resource \"%s\"\n",
Daniel Veillarda840b692003-10-19 13:35:37 +00003003 (const char *) ret->filename);
3004 else
Daniel Veillarde8039df2003-10-27 11:25:13 +00003005 __xmlLoaderErr(ctxt, "failed to load HTTP resource\n", NULL);
Daniel Veillarda840b692003-10-19 13:35:37 +00003006 xmlFreeInputStream(ret);
3007 ret = NULL;
3008 } else {
3009
3010 mime = xmlNanoHTTPMimeType(ret->buf->context);
3011 if ((xmlStrstr(BAD_CAST mime, BAD_CAST "/xml")) ||
3012 (xmlStrstr(BAD_CAST mime, BAD_CAST "+xml"))) {
3013 encoding = xmlNanoHTTPEncoding(ret->buf->context);
3014 if (encoding != NULL) {
3015 xmlCharEncodingHandlerPtr handler;
3016
3017 handler = xmlFindCharEncodingHandler(encoding);
3018 if (handler != NULL) {
3019 xmlSwitchInputEncoding(ctxt, ret, handler);
3020 } else {
3021 __xmlErrEncoding(ctxt, XML_ERR_UNKNOWN_ENCODING,
3022 "Unknown encoding %s",
3023 BAD_CAST encoding, NULL);
3024 }
3025 if (ret->encoding == NULL)
3026 ret->encoding = xmlStrdup(BAD_CAST encoding);
3027 }
3028#if 0
3029 } else if (xmlStrstr(BAD_CAST mime, BAD_CAST "html")) {
3030#endif
3031 }
3032 redir = xmlNanoHTTPRedir(ret->buf->context);
3033 if (redir != NULL) {
3034 if (ret->filename != NULL)
3035 xmlFree((xmlChar *) ret->filename);
3036 if (ret->directory != NULL) {
3037 xmlFree((xmlChar *) ret->directory);
3038 ret->directory = NULL;
3039 }
3040 ret->filename =
3041 (char *) xmlStrdup((const xmlChar *) redir);
3042 }
3043 }
3044 }
3045#endif
3046 return(ret);
3047}
3048
Daniel Veillard561b7f82002-03-20 21:55:57 +00003049static int xmlSysIDExists(const char *URL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003050#ifdef HAVE_STAT
3051 int ret;
3052 struct stat info;
3053 const char *path;
3054
3055 if (URL == NULL)
3056 return(0);
3057
Daniel Veillardf4862f02002-09-10 11:13:43 +00003058 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003059#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00003060 path = &URL[17];
3061#else
Daniel Veillard6990bf32001-08-23 21:17:48 +00003062 path = &URL[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00003063#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003064 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003065#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard6990bf32001-08-23 21:17:48 +00003066 path = &URL[8];
3067#else
3068 path = &URL[7];
3069#endif
3070 } else
3071 path = URL;
3072 ret = stat(path, &info);
Daniel Veillard561b7f82002-03-20 21:55:57 +00003073 if (ret == 0)
3074 return(1);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003075#endif
Daniel Veillard561b7f82002-03-20 21:55:57 +00003076 return(0);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003077}
Daniel Veillard6990bf32001-08-23 21:17:48 +00003078
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003079/**
Owen Taylor3473f882001-02-23 17:55:21 +00003080 * xmlDefaultExternalEntityLoader:
3081 * @URL: the URL for the entity to load
3082 * @ID: the System ID for the entity to load
3083 * @ctxt: the context in which the entity is called or NULL
3084 *
3085 * By default we don't load external entitites, yet.
3086 *
3087 * Returns a new allocated xmlParserInputPtr, or NULL.
3088 */
Daniel Veillarda840b692003-10-19 13:35:37 +00003089static xmlParserInputPtr
Owen Taylor3473f882001-02-23 17:55:21 +00003090xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
Daniel Veillarda840b692003-10-19 13:35:37 +00003091 xmlParserCtxtPtr ctxt)
3092{
Owen Taylor3473f882001-02-23 17:55:21 +00003093 xmlParserInputPtr ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003094 xmlChar *resource = NULL;
Daniel Veillarda840b692003-10-19 13:35:37 +00003095
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003096#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003097 xmlCatalogAllow pref;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003098#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003099
3100#ifdef DEBUG_EXTERNAL_ENTITIES
3101 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda840b692003-10-19 13:35:37 +00003102 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00003103#endif
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003104#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillard61b93382003-11-03 14:28:31 +00003105 if ((ctxt != NULL) && (ctxt->options & XML_PARSE_NONET)) {
3106 int options = ctxt->options;
3107
3108 ctxt->options -= XML_PARSE_NONET;
3109 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
3110 ctxt->options = options;
3111 return(ret);
3112 }
3113
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003114 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003115 * If the resource doesn't exists as a file,
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003116 * try to load it from the resource pointed in the catalogs
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003117 */
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003118 pref = xmlCatalogGetDefaults();
3119
Daniel Veillard561b7f82002-03-20 21:55:57 +00003120 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlSysIDExists(URL))) {
Daniel Veillarda840b692003-10-19 13:35:37 +00003121 /*
3122 * Do a local lookup
3123 */
3124 if ((ctxt->catalogs != NULL) &&
3125 ((pref == XML_CATA_ALLOW_ALL) ||
3126 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3127 resource = xmlCatalogLocalResolve(ctxt->catalogs,
3128 (const xmlChar *) ID,
3129 (const xmlChar *) URL);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003130 }
Daniel Veillarda840b692003-10-19 13:35:37 +00003131 /*
3132 * Try a global lookup
3133 */
3134 if ((resource == NULL) &&
3135 ((pref == XML_CATA_ALLOW_ALL) ||
3136 (pref == XML_CATA_ALLOW_GLOBAL))) {
3137 resource = xmlCatalogResolve((const xmlChar *) ID,
3138 (const xmlChar *) URL);
3139 }
3140 if ((resource == NULL) && (URL != NULL))
3141 resource = xmlStrdup((const xmlChar *) URL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003142
Daniel Veillarda840b692003-10-19 13:35:37 +00003143 /*
3144 * TODO: do an URI lookup on the reference
3145 */
3146 if ((resource != NULL)
3147 && (!xmlSysIDExists((const char *) resource))) {
3148 xmlChar *tmp = NULL;
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003149
Daniel Veillarda840b692003-10-19 13:35:37 +00003150 if ((ctxt->catalogs != NULL) &&
3151 ((pref == XML_CATA_ALLOW_ALL) ||
3152 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3153 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
3154 }
3155 if ((tmp == NULL) &&
3156 ((pref == XML_CATA_ALLOW_ALL) ||
3157 (pref == XML_CATA_ALLOW_GLOBAL))) {
3158 tmp = xmlCatalogResolveURI(resource);
3159 }
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003160
Daniel Veillarda840b692003-10-19 13:35:37 +00003161 if (tmp != NULL) {
3162 xmlFree(resource);
3163 resource = tmp;
3164 }
3165 }
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003166 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003167#endif
3168
3169 if (resource == NULL)
Daniel Veillarda840b692003-10-19 13:35:37 +00003170 resource = (xmlChar *) URL;
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003171
3172 if (resource == NULL) {
Daniel Veillarda840b692003-10-19 13:35:37 +00003173 if (ID == NULL)
3174 ID = "NULL";
Daniel Veillarde8039df2003-10-27 11:25:13 +00003175 __xmlLoaderErr(ctxt, "failed to load external entity \"%s\"\n", ID);
Daniel Veillarda840b692003-10-19 13:35:37 +00003176 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003177 }
Daniel Veillarda840b692003-10-19 13:35:37 +00003178 ret = xmlNewInputFromFile(ctxt, (const char *) resource);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003179 if ((resource != NULL) && (resource != (xmlChar *) URL))
Daniel Veillarda840b692003-10-19 13:35:37 +00003180 xmlFree(resource);
3181 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003182}
3183
3184static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
3185 xmlDefaultExternalEntityLoader;
3186
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003187/**
Owen Taylor3473f882001-02-23 17:55:21 +00003188 * xmlSetExternalEntityLoader:
3189 * @f: the new entity resolver function
3190 *
3191 * Changes the defaultexternal entity resolver function for the application
3192 */
3193void
3194xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
3195 xmlCurrentExternalEntityLoader = f;
3196}
3197
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003198/**
Owen Taylor3473f882001-02-23 17:55:21 +00003199 * xmlGetExternalEntityLoader:
3200 *
3201 * Get the default external entity resolver function for the application
3202 *
3203 * Returns the xmlExternalEntityLoader function pointer
3204 */
3205xmlExternalEntityLoader
3206xmlGetExternalEntityLoader(void) {
3207 return(xmlCurrentExternalEntityLoader);
3208}
3209
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003210/**
Owen Taylor3473f882001-02-23 17:55:21 +00003211 * xmlLoadExternalEntity:
3212 * @URL: the URL for the entity to load
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00003213 * @ID: the Public ID for the entity to load
Owen Taylor3473f882001-02-23 17:55:21 +00003214 * @ctxt: the context in which the entity is called or NULL
3215 *
3216 * Load an external entity, note that the use of this function for
3217 * unparsed entities may generate problems
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003218 * TODO: a more generic External entity API must be designed
Owen Taylor3473f882001-02-23 17:55:21 +00003219 *
3220 * Returns the xmlParserInputPtr or NULL
3221 */
3222xmlParserInputPtr
3223xmlLoadExternalEntity(const char *URL, const char *ID,
3224 xmlParserCtxtPtr ctxt) {
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00003225 if ((URL != NULL) && (xmlSysIDExists(URL) == 0)) {
3226 char *canonicFilename;
3227 xmlParserInputPtr ret;
3228
3229 canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL);
3230 if (canonicFilename == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003231 xmlIOErrMemory("building canonical path\n");
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00003232 return(NULL);
3233 }
3234
3235 ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt);
3236 xmlFree(canonicFilename);
3237 return(ret);
3238 }
Owen Taylor3473f882001-02-23 17:55:21 +00003239 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
3240}
3241
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003242/************************************************************************
3243 * *
3244 * Disabling Network access *
3245 * *
3246 ************************************************************************/
3247
3248#ifdef LIBXML_CATALOG_ENABLED
3249static int
3250xmlNoNetExists(const char *URL)
3251{
3252#ifdef HAVE_STAT
3253 int ret;
3254 struct stat info;
3255 const char *path;
3256
3257 if (URL == NULL)
3258 return (0);
3259
Daniel Veillardf4862f02002-09-10 11:13:43 +00003260 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003261#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00003262 path = &URL[17];
3263#else
3264 path = &URL[16];
3265#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003266 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003267#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003268 path = &URL[8];
3269#else
3270 path = &URL[7];
3271#endif
3272 } else
3273 path = URL;
3274 ret = stat(path, &info);
3275 if (ret == 0)
3276 return (1);
3277#endif
3278 return (0);
3279}
3280#endif
3281
3282/**
3283 * xmlNoNetExternalEntityLoader:
3284 * @URL: the URL for the entity to load
3285 * @ID: the System ID for the entity to load
3286 * @ctxt: the context in which the entity is called or NULL
3287 *
3288 * A specific entity loader disabling network accesses, though still
3289 * allowing local catalog accesses for resolution.
3290 *
3291 * Returns a new allocated xmlParserInputPtr, or NULL.
3292 */
3293xmlParserInputPtr
3294xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
3295 xmlParserCtxtPtr ctxt) {
3296 xmlParserInputPtr input = NULL;
3297 xmlChar *resource = NULL;
3298
3299#ifdef LIBXML_CATALOG_ENABLED
3300 xmlCatalogAllow pref;
3301
3302 /*
3303 * If the resource doesn't exists as a file,
3304 * try to load it from the resource pointed in the catalogs
3305 */
3306 pref = xmlCatalogGetDefaults();
3307
3308 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
3309 /*
3310 * Do a local lookup
3311 */
3312 if ((ctxt->catalogs != NULL) &&
3313 ((pref == XML_CATA_ALLOW_ALL) ||
3314 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3315 resource = xmlCatalogLocalResolve(ctxt->catalogs,
3316 (const xmlChar *)ID,
3317 (const xmlChar *)URL);
3318 }
3319 /*
3320 * Try a global lookup
3321 */
3322 if ((resource == NULL) &&
3323 ((pref == XML_CATA_ALLOW_ALL) ||
3324 (pref == XML_CATA_ALLOW_GLOBAL))) {
3325 resource = xmlCatalogResolve((const xmlChar *)ID,
3326 (const xmlChar *)URL);
3327 }
3328 if ((resource == NULL) && (URL != NULL))
3329 resource = xmlStrdup((const xmlChar *) URL);
3330
3331 /*
3332 * TODO: do an URI lookup on the reference
3333 */
3334 if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
3335 xmlChar *tmp = NULL;
3336
3337 if ((ctxt->catalogs != NULL) &&
3338 ((pref == XML_CATA_ALLOW_ALL) ||
3339 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3340 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
3341 }
3342 if ((tmp == NULL) &&
3343 ((pref == XML_CATA_ALLOW_ALL) ||
3344 (pref == XML_CATA_ALLOW_GLOBAL))) {
3345 tmp = xmlCatalogResolveURI(resource);
3346 }
3347
3348 if (tmp != NULL) {
3349 xmlFree(resource);
3350 resource = tmp;
3351 }
3352 }
3353 }
3354#endif
3355 if (resource == NULL)
3356 resource = (xmlChar *) URL;
3357
3358 if (resource != NULL) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003359 if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
3360 (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003361 xmlIOErr(XML_IO_NETWORK_ATTEMPT, (const char *) resource);
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003362 if (resource != (xmlChar *) URL)
3363 xmlFree(resource);
3364 return(NULL);
3365 }
3366 }
3367 input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
3368 if (resource != (xmlChar *) URL)
3369 xmlFree(resource);
3370 return(input);
3371}
3372