blob: f30f775bce867a2847000add95919e19caec6ef2 [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 */
Daniel Veillard29b17482004-08-16 00:39:03 +0000185 "connection refused", /* ECONNREFUSED */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000186 "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 Veillard5ea30d72004-11-08 11:54:28 +0000423 if (ctxt->sax->initialized == XML_SAX2_MAGIC)
424 schannel = ctxt->sax->serror;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000425 data = ctxt->userData;
426 }
Daniel Veillard659e71e2003-10-10 14:10:40 +0000427 __xmlRaiseError(schannel, channel, data, ctxt, NULL, XML_FROM_IO,
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000428 XML_IO_LOAD_ERROR, level, NULL, 0,
429 filename, NULL, NULL, 0, 0,
430 msg, filename);
431
432}
433
Daniel Veillard05d987b2003-10-08 11:54:57 +0000434/************************************************************************
435 * *
436 * Tree memory error handler *
437 * *
438 ************************************************************************/
Daniel Veillardf4862f02002-09-10 11:13:43 +0000439/**
Daniel Veillard01c13b52002-12-10 15:19:08 +0000440 * xmlNormalizeWindowsPath:
Daniel Veillard33300b42003-04-17 09:09:19 +0000441 * @path: the input file path
Daniel Veillardf4862f02002-09-10 11:13:43 +0000442 *
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +0000443 * This function is obsolete. Please see xmlURIFromPath in uri.c for
444 * a better solution.
Daniel Veillard33300b42003-04-17 09:09:19 +0000445 *
446 * Returns a canonicalized version of the path
Daniel Veillardf4862f02002-09-10 11:13:43 +0000447 */
448xmlChar *
449xmlNormalizeWindowsPath(const xmlChar *path)
450{
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +0000451 return xmlCanonicPath(path);
Daniel Veillardf4862f02002-09-10 11:13:43 +0000452}
453
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000454/**
455 * xmlCleanupInputCallbacks:
456 *
457 * clears the entire input callback table. this includes the
458 * compiled-in I/O.
459 */
460void
461xmlCleanupInputCallbacks(void)
462{
463 int i;
464
465 if (!xmlInputCallbackInitialized)
466 return;
467
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000468 for (i = xmlInputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000469 xmlInputCallbackTable[i].matchcallback = NULL;
470 xmlInputCallbackTable[i].opencallback = NULL;
471 xmlInputCallbackTable[i].readcallback = NULL;
472 xmlInputCallbackTable[i].closecallback = NULL;
473 }
474
475 xmlInputCallbackNr = 0;
Aleksey Sanin9c45ba82002-06-06 21:46:13 +0000476 xmlInputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000477}
478
Daniel Veillardaecc0dc2004-05-08 02:32:07 +0000479/**
William M. Brack4e3a9fa2004-08-03 22:41:11 +0000480 * xmlPopInputCallbacks:
Daniel Veillardaecc0dc2004-05-08 02:32:07 +0000481 *
482 * Clear the top input callback from the input stack. this includes the
483 * compiled-in I/O.
484 *
485 * Returns the number of input callback registered or -1 in case of error.
486 */
487int
488xmlPopInputCallbacks(void)
489{
490 if (!xmlInputCallbackInitialized)
491 return(-1);
492
493 if (xmlInputCallbackNr <= 0)
494 return(-1);
495
496 xmlInputCallbackNr--;
497 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = NULL;
498 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = NULL;
499 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = NULL;
500 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = NULL;
501
502 return(xmlInputCallbackNr);
503}
504
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000505#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000506/**
507 * xmlCleanupOutputCallbacks:
508 *
509 * clears the entire output callback table. this includes the
510 * compiled-in I/O callbacks.
511 */
512void
513xmlCleanupOutputCallbacks(void)
514{
515 int i;
516
517 if (!xmlOutputCallbackInitialized)
518 return;
519
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000520 for (i = xmlOutputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000521 xmlOutputCallbackTable[i].matchcallback = NULL;
522 xmlOutputCallbackTable[i].opencallback = NULL;
523 xmlOutputCallbackTable[i].writecallback = NULL;
524 xmlOutputCallbackTable[i].closecallback = NULL;
525 }
526
527 xmlOutputCallbackNr = 0;
Aleksey Sanin9c45ba82002-06-06 21:46:13 +0000528 xmlOutputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000529}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000530#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000531
Owen Taylor3473f882001-02-23 17:55:21 +0000532/************************************************************************
533 * *
534 * Standard I/O for file accesses *
535 * *
536 ************************************************************************/
537
538/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000539 * xmlCheckFilename:
Owen Taylor3473f882001-02-23 17:55:21 +0000540 * @path: the path to check
541 *
542 * function checks to see if @path is a valid source
543 * (file, socket...) for XML.
544 *
545 * if stat is not available on the target machine,
546 * returns 1. if stat fails, returns 0 (if calling
547 * stat on the filename fails, it can't be right).
548 * if stat succeeds and the file is a directory,
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000549 * returns 2. otherwise returns 1.
Owen Taylor3473f882001-02-23 17:55:21 +0000550 */
551
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000552int
Owen Taylor3473f882001-02-23 17:55:21 +0000553xmlCheckFilename (const char *path)
554{
555#ifdef HAVE_STAT
Owen Taylor3473f882001-02-23 17:55:21 +0000556 struct stat stat_buffer;
557
Daniel Veillard34099b42004-11-04 17:34:35 +0000558 if (path == NULL)
559 return(0);
560
Owen Taylor3473f882001-02-23 17:55:21 +0000561 if (stat(path, &stat_buffer) == -1)
562 return 0;
563
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000564#ifdef S_ISDIR
Owen Taylor3473f882001-02-23 17:55:21 +0000565 if (S_ISDIR(stat_buffer.st_mode)) {
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000566 return 2;
Owen Taylor3473f882001-02-23 17:55:21 +0000567 }
Owen Taylor3473f882001-02-23 17:55:21 +0000568#endif
569#endif
Daniel Veillard34099b42004-11-04 17:34:35 +0000570 if (path == NULL)
571 return(0);
572
Owen Taylor3473f882001-02-23 17:55:21 +0000573 return 1;
574}
575
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000576static int
Owen Taylor3473f882001-02-23 17:55:21 +0000577xmlNop(void) {
578 return(0);
579}
580
581/**
Owen Taylor3473f882001-02-23 17:55:21 +0000582 * xmlFdRead:
583 * @context: the I/O context
584 * @buffer: where to drop data
585 * @len: number of bytes to read
586 *
587 * Read @len bytes to @buffer from the I/O channel.
588 *
589 * Returns the number of bytes written
590 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000591static int
Owen Taylor3473f882001-02-23 17:55:21 +0000592xmlFdRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000593 int ret;
594
595 ret = read((int) (long) context, &buffer[0], len);
596 if (ret < 0) xmlIOErr(0, "read()");
597 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000598}
599
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000600#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000601/**
602 * xmlFdWrite:
603 * @context: the I/O context
604 * @buffer: where to get data
605 * @len: number of bytes to write
606 *
607 * Write @len bytes from @buffer to the I/O channel.
608 *
609 * Returns the number of bytes written
610 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000611static int
Owen Taylor3473f882001-02-23 17:55:21 +0000612xmlFdWrite (void * context, const char * buffer, int len) {
Daniel Veillard9b693b42005-10-28 14:54:17 +0000613 int ret = 0;
Daniel Veillard05d987b2003-10-08 11:54:57 +0000614
Daniel Veillard9b693b42005-10-28 14:54:17 +0000615 if (len > 0) {
616 ret = write((int) (long) context, &buffer[0], len);
617 if (ret < 0) xmlIOErr(0, "write()");
618 }
Daniel Veillard05d987b2003-10-08 11:54:57 +0000619 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000620}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000621#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000622
623/**
624 * xmlFdClose:
625 * @context: the I/O context
626 *
627 * Close an I/O channel
Daniel Veillardf012a642001-07-23 19:10:52 +0000628 *
629 * Returns 0 in case of success and error code otherwise
Owen Taylor3473f882001-02-23 17:55:21 +0000630 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000631static int
Owen Taylor3473f882001-02-23 17:55:21 +0000632xmlFdClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000633 int ret;
634 ret = close((int) (long) context);
635 if (ret < 0) xmlIOErr(0, "close()");
636 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000637}
638
639/**
640 * xmlFileMatch:
641 * @filename: the URI for matching
642 *
643 * input from FILE *
644 *
645 * Returns 1 if matches, 0 otherwise
646 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000647int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000648xmlFileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000649 return(1);
650}
651
652/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000653 * xmlFileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +0000654 * @filename: the URI for matching
655 *
656 * input from FILE *, supports compressed input
657 * if @filename is " " then the standard input is used
658 *
659 * Returns an I/O context or NULL in case of error
660 */
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000661static void *
662xmlFileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +0000663 const char *path = NULL;
664 FILE *fd;
665
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000666 if (filename == NULL)
667 return(NULL);
668
Owen Taylor3473f882001-02-23 17:55:21 +0000669 if (!strcmp(filename, "-")) {
670 fd = stdin;
671 return((void *) fd);
672 }
673
Daniel Veillardf4862f02002-09-10 11:13:43 +0000674 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000675#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000676 path = &filename[17];
677#else
Owen Taylor3473f882001-02-23 17:55:21 +0000678 path = &filename[16];
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000679#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000680 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000681#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000682 path = &filename[8];
683#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000684 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000685#endif
686 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000687 path = filename;
688
689 if (path == NULL)
690 return(NULL);
691 if (!xmlCheckFilename(path))
692 return(NULL);
693
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000694#if defined(WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
Owen Taylor3473f882001-02-23 17:55:21 +0000695 fd = fopen(path, "rb");
696#else
697 fd = fopen(path, "r");
698#endif /* WIN32 */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000699 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +0000700 return((void *) fd);
701}
702
703/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000704 * xmlFileOpen:
705 * @filename: the URI for matching
706 *
707 * Wrapper around xmlFileOpen_real that try it with an unescaped
708 * version of @filename, if this fails fallback to @filename
Daniel Veillard71531f32003-02-05 13:19:53 +0000709 *
710 * Returns a handler or NULL in case or failure
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000711 */
712void *
713xmlFileOpen (const char *filename) {
714 char *unescaped;
715 void *retval;
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000716
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000717 unescaped = xmlURIUnescapeString(filename, 0, NULL);
718 if (unescaped != NULL) {
719 retval = xmlFileOpen_real(unescaped);
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000720 xmlFree(unescaped);
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000721 } else {
722 retval = xmlFileOpen_real(filename);
723 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000724 return retval;
725}
726
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000727#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000728/**
Owen Taylor3473f882001-02-23 17:55:21 +0000729 * xmlFileOpenW:
730 * @filename: the URI for matching
731 *
732 * output to from FILE *,
733 * if @filename is "-" then the standard output is used
734 *
735 * Returns an I/O context or NULL in case of error
736 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000737static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000738xmlFileOpenW (const char *filename) {
739 const char *path = NULL;
740 FILE *fd;
741
742 if (!strcmp(filename, "-")) {
743 fd = stdout;
744 return((void *) fd);
745 }
746
Daniel Veillardf4862f02002-09-10 11:13:43 +0000747 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000748#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000749 path = &filename[17];
750#else
Owen Taylor3473f882001-02-23 17:55:21 +0000751 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000752#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000753 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000754#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000755 path = &filename[8];
756#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000757 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000758#endif
759 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000760 path = filename;
761
762 if (path == NULL)
763 return(NULL);
764
Daniel Veillardcbbd78d2003-07-20 15:21:30 +0000765 fd = fopen(path, "wb");
Daniel Veillard05d987b2003-10-08 11:54:57 +0000766 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +0000767 return((void *) fd);
768}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000769#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000770
771/**
772 * xmlFileRead:
773 * @context: the I/O context
774 * @buffer: where to drop data
775 * @len: number of bytes to write
776 *
777 * Read @len bytes to @buffer from the I/O channel.
778 *
Daniel Veillardce682bc2004-11-05 17:22:25 +0000779 * Returns the number of bytes written or < 0 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +0000780 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000781int
Owen Taylor3473f882001-02-23 17:55:21 +0000782xmlFileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000783 int ret;
Daniel Veillardce682bc2004-11-05 17:22:25 +0000784 if ((context == NULL) || (buffer == NULL))
785 return(-1);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000786 ret = fread(&buffer[0], 1, len, (FILE *) context);
787 if (ret < 0) xmlIOErr(0, "fread()");
788 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000789}
790
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000791#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000792/**
793 * xmlFileWrite:
794 * @context: the I/O context
795 * @buffer: where to drop data
796 * @len: number of bytes to write
797 *
798 * Write @len bytes from @buffer to the I/O channel.
799 *
800 * Returns the number of bytes written
801 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000802static int
Owen Taylor3473f882001-02-23 17:55:21 +0000803xmlFileWrite (void * context, const char * buffer, int len) {
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000804 int items;
805
Daniel Veillardce682bc2004-11-05 17:22:25 +0000806 if ((context == NULL) || (buffer == NULL))
807 return(-1);
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000808 items = fwrite(&buffer[0], len, 1, (FILE *) context);
Daniel Veillard97bf4d02003-10-08 18:58:28 +0000809 if ((items == 0) && (ferror((FILE *) context))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000810 xmlIOErr(0, "fwrite()");
Daniel Veillard97bf4d02003-10-08 18:58:28 +0000811 return(-1);
812 }
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000813 return(items * len);
Owen Taylor3473f882001-02-23 17:55:21 +0000814}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000815#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000816
817/**
818 * xmlFileClose:
819 * @context: the I/O context
820 *
821 * Close an I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000822 *
823 * Returns 0 or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +0000824 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000825int
Owen Taylor3473f882001-02-23 17:55:21 +0000826xmlFileClose (void * context) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000827 FILE *fil;
Daniel Veillard05d987b2003-10-08 11:54:57 +0000828 int ret;
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000829
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000830 if (context == NULL)
831 return(-1);
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000832 fil = (FILE *) context;
Daniel Veillard500a1de2004-03-22 15:22:58 +0000833 if ((fil == stdout) || (fil == stderr)) {
834 ret = fflush(fil);
835 if (ret < 0)
836 xmlIOErr(0, "fflush()");
837 return(0);
838 }
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000839 if (fil == stdin)
840 return(0);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000841 ret = ( fclose((FILE *) context) == EOF ) ? -1 : 0;
842 if (ret < 0)
843 xmlIOErr(0, "fclose()");
844 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000845}
846
847/**
848 * xmlFileFlush:
849 * @context: the I/O context
850 *
851 * Flush an I/O channel
852 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000853static int
Owen Taylor3473f882001-02-23 17:55:21 +0000854xmlFileFlush (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000855 int ret;
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000856
857 if (context == NULL)
858 return(-1);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000859 ret = ( fflush((FILE *) context) == EOF ) ? -1 : 0;
860 if (ret < 0)
861 xmlIOErr(0, "fflush()");
862 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000863}
864
Daniel Veillard9a00fd22005-11-09 08:56:26 +0000865#ifdef LIBXML_OUTPUT_ENABLED
866/**
867 * xmlBufferWrite:
868 * @context: the xmlBuffer
869 * @buffer: the data to write
870 * @len: number of bytes to write
871 *
872 * Write @len bytes from @buffer to the xml buffer
873 *
874 * Returns the number of bytes written
875 */
876static int
877xmlBufferWrite (void * context, const char * buffer, int len) {
878 int ret;
879
880 ret = xmlBufferAdd((xmlBufferPtr) context, (const xmlChar *) buffer, len);
881 if (ret != 0)
882 return(-1);
883 return(len);
884}
885
886/**
887 * xmlBufferClose:
888 * @context: the xmlBuffer
889 *
890 * Close a buffer
891 *
892 * Returns 0 or -1 in case of error
893 */
894static int
895xmlBufferClose (void * context) {
896 return(0);
897}
898#endif
899
Owen Taylor3473f882001-02-23 17:55:21 +0000900#ifdef HAVE_ZLIB_H
901/************************************************************************
902 * *
903 * I/O for compressed file accesses *
904 * *
905 ************************************************************************/
906/**
907 * xmlGzfileMatch:
908 * @filename: the URI for matching
909 *
910 * input from compressed file test
911 *
912 * Returns 1 if matches, 0 otherwise
913 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000914static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000915xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000916 return(1);
917}
918
919/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000920 * xmlGzfileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +0000921 * @filename: the URI for matching
922 *
923 * input from compressed file open
924 * if @filename is " " then the standard input is used
925 *
926 * Returns an I/O context or NULL in case of error
927 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000928static void *
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000929xmlGzfileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +0000930 const char *path = NULL;
931 gzFile fd;
932
933 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000934 fd = gzdopen(dup(0), "rb");
Owen Taylor3473f882001-02-23 17:55:21 +0000935 return((void *) fd);
936 }
937
Daniel Veillardf4862f02002-09-10 11:13:43 +0000938 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000939#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000940 path = &filename[17];
941#else
Owen Taylor3473f882001-02-23 17:55:21 +0000942 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000943#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000944 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000945#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000946 path = &filename[8];
947#else
Owen Taylor3473f882001-02-23 17:55:21 +0000948 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000949#endif
950 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000951 path = filename;
952
953 if (path == NULL)
954 return(NULL);
955 if (!xmlCheckFilename(path))
956 return(NULL);
957
958 fd = gzopen(path, "rb");
959 return((void *) fd);
960}
961
962/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000963 * xmlGzfileOpen:
964 * @filename: the URI for matching
965 *
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +0000966 * Wrapper around xmlGzfileOpen if the open fais, it will
967 * try to unescape @filename
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000968 */
969static void *
970xmlGzfileOpen (const char *filename) {
971 char *unescaped;
972 void *retval;
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +0000973
974 retval = xmlGzfileOpen_real(filename);
975 if (retval == NULL) {
976 unescaped = xmlURIUnescapeString(filename, 0, NULL);
977 if (unescaped != NULL) {
978 retval = xmlGzfileOpen_real(unescaped);
979 }
980 xmlFree(unescaped);
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000981 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000982 return retval;
983}
984
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000985#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000986/**
Owen Taylor3473f882001-02-23 17:55:21 +0000987 * xmlGzfileOpenW:
988 * @filename: the URI for matching
989 * @compression: the compression factor (0 - 9 included)
990 *
991 * input from compressed file open
992 * if @filename is " " then the standard input is used
993 *
994 * Returns an I/O context or NULL in case of error
995 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000996static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000997xmlGzfileOpenW (const char *filename, int compression) {
998 const char *path = NULL;
999 char mode[15];
1000 gzFile fd;
1001
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001002 snprintf(mode, sizeof(mode), "wb%d", compression);
Owen Taylor3473f882001-02-23 17:55:21 +00001003 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001004 fd = gzdopen(dup(1), mode);
Owen Taylor3473f882001-02-23 17:55:21 +00001005 return((void *) fd);
1006 }
1007
Daniel Veillardf4862f02002-09-10 11:13:43 +00001008 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001009#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00001010 path = &filename[17];
1011#else
Owen Taylor3473f882001-02-23 17:55:21 +00001012 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00001013#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001014 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001015#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +00001016 path = &filename[8];
1017#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +00001018 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +00001019#endif
1020 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001021 path = filename;
1022
1023 if (path == NULL)
1024 return(NULL);
1025
1026 fd = gzopen(path, mode);
1027 return((void *) fd);
1028}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001029#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001030
1031/**
1032 * xmlGzfileRead:
1033 * @context: the I/O context
1034 * @buffer: where to drop data
1035 * @len: number of bytes to write
1036 *
1037 * Read @len bytes to @buffer from the compressed I/O channel.
1038 *
1039 * Returns the number of bytes written
1040 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001041static int
Owen Taylor3473f882001-02-23 17:55:21 +00001042xmlGzfileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001043 int ret;
1044
1045 ret = gzread((gzFile) context, &buffer[0], len);
1046 if (ret < 0) xmlIOErr(0, "gzread()");
1047 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001048}
1049
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001050#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001051/**
1052 * xmlGzfileWrite:
1053 * @context: the I/O context
1054 * @buffer: where to drop data
1055 * @len: number of bytes to write
1056 *
1057 * Write @len bytes from @buffer to the compressed I/O channel.
1058 *
1059 * Returns the number of bytes written
1060 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001061static int
Owen Taylor3473f882001-02-23 17:55:21 +00001062xmlGzfileWrite (void * context, const char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001063 int ret;
1064
1065 ret = gzwrite((gzFile) context, (char *) &buffer[0], len);
1066 if (ret < 0) xmlIOErr(0, "gzwrite()");
1067 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001068}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001069#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001070
1071/**
1072 * xmlGzfileClose:
1073 * @context: the I/O context
1074 *
1075 * Close a compressed I/O channel
1076 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001077static int
Owen Taylor3473f882001-02-23 17:55:21 +00001078xmlGzfileClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001079 int ret;
1080
1081 ret = (gzclose((gzFile) context) == Z_OK ) ? 0 : -1;
1082 if (ret < 0) xmlIOErr(0, "gzclose()");
1083 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001084}
1085#endif /* HAVE_ZLIB_H */
1086
1087#ifdef LIBXML_HTTP_ENABLED
1088/************************************************************************
1089 * *
1090 * I/O for HTTP file accesses *
1091 * *
1092 ************************************************************************/
Daniel Veillardf012a642001-07-23 19:10:52 +00001093
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001094#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001095typedef struct xmlIOHTTPWriteCtxt_
1096{
1097 int compression;
1098
1099 char * uri;
1100
1101 void * doc_buff;
1102
1103} xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr;
1104
1105#ifdef HAVE_ZLIB_H
1106
1107#define DFLT_WBITS ( -15 )
1108#define DFLT_MEM_LVL ( 8 )
1109#define GZ_MAGIC1 ( 0x1f )
1110#define GZ_MAGIC2 ( 0x8b )
1111#define LXML_ZLIB_OS_CODE ( 0x03 )
1112#define INIT_HTTP_BUFF_SIZE ( 32768 )
1113#define DFLT_ZLIB_RATIO ( 5 )
1114
1115/*
1116** Data structure and functions to work with sending compressed data
1117** via HTTP.
1118*/
1119
1120typedef struct xmlZMemBuff_
1121{
1122 unsigned long size;
1123 unsigned long crc;
1124
1125 unsigned char * zbuff;
1126 z_stream zctrl;
1127
1128} xmlZMemBuff, *xmlZMemBuffPtr;
1129
1130/**
1131 * append_reverse_ulong
1132 * @buff: Compressed memory buffer
1133 * @data: Unsigned long to append
1134 *
1135 * Append a unsigned long in reverse byte order to the end of the
1136 * memory buffer.
1137 */
1138static void
1139append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) {
1140
1141 int idx;
1142
1143 if ( buff == NULL )
1144 return;
1145
1146 /*
1147 ** This is plagiarized from putLong in gzio.c (zlib source) where
1148 ** the number "4" is hardcoded. If zlib is ever patched to
1149 ** support 64 bit file sizes, this code would need to be patched
1150 ** as well.
1151 */
1152
1153 for ( idx = 0; idx < 4; idx++ ) {
1154 *buff->zctrl.next_out = ( data & 0xff );
1155 data >>= 8;
1156 buff->zctrl.next_out++;
1157 }
1158
1159 return;
1160}
1161
1162/**
1163 *
1164 * xmlFreeZMemBuff
1165 * @buff: The memory buffer context to clear
1166 *
1167 * Release all the resources associated with the compressed memory buffer.
1168 */
1169static void
1170xmlFreeZMemBuff( xmlZMemBuffPtr buff ) {
William M. Brack78637da2003-07-31 14:47:38 +00001171
1172#ifdef DEBUG_HTTP
Daniel Veillardf012a642001-07-23 19:10:52 +00001173 int z_err;
William M. Brack78637da2003-07-31 14:47:38 +00001174#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001175
1176 if ( buff == NULL )
1177 return;
1178
1179 xmlFree( buff->zbuff );
Daniel Veillardf012a642001-07-23 19:10:52 +00001180#ifdef DEBUG_HTTP
William M. Brack78637da2003-07-31 14:47:38 +00001181 z_err = deflateEnd( &buff->zctrl );
Daniel Veillardf012a642001-07-23 19:10:52 +00001182 if ( z_err != Z_OK )
1183 xmlGenericError( xmlGenericErrorContext,
1184 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
1185 z_err );
William M. Brack78637da2003-07-31 14:47:38 +00001186#else
1187 deflateEnd( &buff->zctrl );
William M. Brack779af002003-08-01 15:55:39 +00001188#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001189
1190 xmlFree( buff );
1191 return;
1192}
1193
1194/**
1195 * xmlCreateZMemBuff
1196 *@compression: Compression value to use
1197 *
1198 * Create a memory buffer to hold the compressed XML document. The
1199 * compressed document in memory will end up being identical to what
1200 * would be created if gzopen/gzwrite/gzclose were being used to
1201 * write the document to disk. The code for the header/trailer data to
1202 * the compression is plagiarized from the zlib source files.
1203 */
1204static void *
1205xmlCreateZMemBuff( int compression ) {
1206
1207 int z_err;
1208 int hdr_lgth;
1209 xmlZMemBuffPtr buff = NULL;
1210
1211 if ( ( compression < 1 ) || ( compression > 9 ) )
1212 return ( NULL );
1213
1214 /* Create the control and data areas */
1215
1216 buff = xmlMalloc( sizeof( xmlZMemBuff ) );
1217 if ( buff == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001218 xmlIOErrMemory("creating buffer context");
Daniel Veillardf012a642001-07-23 19:10:52 +00001219 return ( NULL );
1220 }
1221
1222 (void)memset( buff, 0, sizeof( xmlZMemBuff ) );
1223 buff->size = INIT_HTTP_BUFF_SIZE;
1224 buff->zbuff = xmlMalloc( buff->size );
1225 if ( buff->zbuff == NULL ) {
1226 xmlFreeZMemBuff( buff );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001227 xmlIOErrMemory("creating buffer");
Daniel Veillardf012a642001-07-23 19:10:52 +00001228 return ( NULL );
1229 }
1230
1231 z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
1232 DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
1233 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001234 xmlChar msg[500];
Daniel Veillardf012a642001-07-23 19:10:52 +00001235 xmlFreeZMemBuff( buff );
1236 buff = NULL;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001237 xmlStrPrintf(msg, 500,
1238 (const xmlChar *) "xmlCreateZMemBuff: %s %d\n",
1239 "Error initializing compression context. ZLIB error:",
1240 z_err );
1241 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001242 return ( NULL );
1243 }
1244
1245 /* Set the header data. The CRC will be needed for the trailer */
Daniel Veillard24505b02005-07-28 23:49:35 +00001246 buff->crc = crc32( 0L, NULL, 0 );
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001247 hdr_lgth = snprintf( (char *)buff->zbuff, buff->size,
1248 "%c%c%c%c%c%c%c%c%c%c",
Daniel Veillardf012a642001-07-23 19:10:52 +00001249 GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED,
1250 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE );
1251 buff->zctrl.next_out = buff->zbuff + hdr_lgth;
1252 buff->zctrl.avail_out = buff->size - hdr_lgth;
1253
1254 return ( buff );
1255}
1256
1257/**
1258 * xmlZMemBuffExtend
1259 * @buff: Buffer used to compress and consolidate data.
1260 * @ext_amt: Number of bytes to extend the buffer.
1261 *
1262 * Extend the internal buffer used to store the compressed data by the
1263 * specified amount.
1264 *
1265 * Returns 0 on success or -1 on failure to extend the buffer. On failure
1266 * the original buffer still exists at the original size.
1267 */
1268static int
1269xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) {
1270
1271 int rc = -1;
1272 size_t new_size;
1273 size_t cur_used;
1274
1275 unsigned char * tmp_ptr = NULL;
1276
1277 if ( buff == NULL )
1278 return ( -1 );
1279
1280 else if ( ext_amt == 0 )
1281 return ( 0 );
1282
1283 cur_used = buff->zctrl.next_out - buff->zbuff;
1284 new_size = buff->size + ext_amt;
1285
1286#ifdef DEBUG_HTTP
1287 if ( cur_used > new_size )
1288 xmlGenericError( xmlGenericErrorContext,
1289 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
1290 "Buffer overwrite detected during compressed memory",
1291 "buffer extension. Overflowed by",
1292 (cur_used - new_size ) );
1293#endif
1294
1295 tmp_ptr = xmlRealloc( buff->zbuff, new_size );
1296 if ( tmp_ptr != NULL ) {
1297 rc = 0;
1298 buff->size = new_size;
1299 buff->zbuff = tmp_ptr;
1300 buff->zctrl.next_out = tmp_ptr + cur_used;
1301 buff->zctrl.avail_out = new_size - cur_used;
1302 }
1303 else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001304 xmlChar msg[500];
1305 xmlStrPrintf(msg, 500,
1306 (const xmlChar *) "xmlZMemBuffExtend: %s %lu bytes.\n",
1307 "Allocation failure extending output buffer to",
1308 new_size );
1309 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001310 }
1311
1312 return ( rc );
1313}
1314
1315/**
1316 * xmlZMemBuffAppend
1317 * @buff: Buffer used to compress and consolidate data
1318 * @src: Uncompressed source content to append to buffer
1319 * @len: Length of source data to append to buffer
1320 *
1321 * Compress and append data to the internal buffer. The data buffer
1322 * will be expanded if needed to store the additional data.
1323 *
1324 * Returns the number of bytes appended to the buffer or -1 on error.
1325 */
1326static int
1327xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) {
1328
1329 int z_err;
1330 size_t min_accept;
1331
1332 if ( ( buff == NULL ) || ( src == NULL ) )
1333 return ( -1 );
1334
1335 buff->zctrl.avail_in = len;
1336 buff->zctrl.next_in = (unsigned char *)src;
1337 while ( buff->zctrl.avail_in > 0 ) {
1338 /*
1339 ** Extend the buffer prior to deflate call if a reasonable amount
1340 ** of output buffer space is not available.
1341 */
1342 min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO;
1343 if ( buff->zctrl.avail_out <= min_accept ) {
1344 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1345 return ( -1 );
1346 }
1347
1348 z_err = deflate( &buff->zctrl, Z_NO_FLUSH );
1349 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001350 xmlChar msg[500];
1351 xmlStrPrintf(msg, 500,
1352 (const xmlChar *) "xmlZMemBuffAppend: %s %d %s - %d",
Daniel Veillardf012a642001-07-23 19:10:52 +00001353 "Compression error while appending",
1354 len, "bytes to buffer. ZLIB error", z_err );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001355 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001356 return ( -1 );
1357 }
1358 }
1359
1360 buff->crc = crc32( buff->crc, (unsigned char *)src, len );
1361
1362 return ( len );
1363}
1364
1365/**
1366 * xmlZMemBuffGetContent
1367 * @buff: Compressed memory content buffer
1368 * @data_ref: Pointer reference to point to compressed content
1369 *
1370 * Flushes the compression buffers, appends gzip file trailers and
1371 * returns the compressed content and length of the compressed data.
1372 * NOTE: The gzip trailer code here is plagiarized from zlib source.
1373 *
1374 * Returns the length of the compressed data or -1 on error.
1375 */
1376static int
1377xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) {
1378
1379 int zlgth = -1;
1380 int z_err;
1381
1382 if ( ( buff == NULL ) || ( data_ref == NULL ) )
1383 return ( -1 );
1384
1385 /* Need to loop until compression output buffers are flushed */
1386
1387 do
1388 {
1389 z_err = deflate( &buff->zctrl, Z_FINISH );
1390 if ( z_err == Z_OK ) {
1391 /* In this case Z_OK means more buffer space needed */
1392
1393 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1394 return ( -1 );
1395 }
1396 }
1397 while ( z_err == Z_OK );
1398
1399 /* If the compression state is not Z_STREAM_END, some error occurred */
1400
1401 if ( z_err == Z_STREAM_END ) {
1402
1403 /* Need to append the gzip data trailer */
1404
1405 if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) {
1406 if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 )
1407 return ( -1 );
1408 }
1409
1410 /*
1411 ** For whatever reason, the CRC and length data are pushed out
1412 ** in reverse byte order. So a memcpy can't be used here.
1413 */
1414
1415 append_reverse_ulong( buff, buff->crc );
1416 append_reverse_ulong( buff, buff->zctrl.total_in );
1417
1418 zlgth = buff->zctrl.next_out - buff->zbuff;
1419 *data_ref = (char *)buff->zbuff;
1420 }
1421
Daniel Veillard05d987b2003-10-08 11:54:57 +00001422 else {
1423 xmlChar msg[500];
1424 xmlStrPrintf(msg, 500,
1425 (const xmlChar *) "xmlZMemBuffGetContent: %s - %d\n",
1426 "Error flushing zlib buffers. Error code", z_err );
1427 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1428 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001429
1430 return ( zlgth );
1431}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001432#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001433#endif /* HAVE_ZLIB_H */
1434
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001435#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001436/**
1437 * xmlFreeHTTPWriteCtxt
1438 * @ctxt: Context to cleanup
1439 *
1440 * Free allocated memory and reclaim system resources.
1441 *
1442 * No return value.
1443 */
1444static void
1445xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt )
1446{
1447 if ( ctxt->uri != NULL )
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001448 xmlFree( ctxt->uri );
Daniel Veillardf012a642001-07-23 19:10:52 +00001449
1450 if ( ctxt->doc_buff != NULL ) {
1451
1452#ifdef HAVE_ZLIB_H
1453 if ( ctxt->compression > 0 ) {
1454 xmlFreeZMemBuff( ctxt->doc_buff );
1455 }
1456 else
1457#endif
1458 {
1459 xmlOutputBufferClose( ctxt->doc_buff );
1460 }
1461 }
1462
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001463 xmlFree( ctxt );
Daniel Veillardf012a642001-07-23 19:10:52 +00001464 return;
1465}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001466#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001467
1468
Owen Taylor3473f882001-02-23 17:55:21 +00001469/**
1470 * xmlIOHTTPMatch:
1471 * @filename: the URI for matching
1472 *
1473 * check if the URI matches an HTTP one
1474 *
1475 * Returns 1 if matches, 0 otherwise
1476 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001477int
Owen Taylor3473f882001-02-23 17:55:21 +00001478xmlIOHTTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001479 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "http://", 7))
Owen Taylor3473f882001-02-23 17:55:21 +00001480 return(1);
1481 return(0);
1482}
1483
1484/**
1485 * xmlIOHTTPOpen:
1486 * @filename: the URI for matching
1487 *
1488 * open an HTTP I/O channel
1489 *
1490 * Returns an I/O context or NULL in case of error
1491 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001492void *
Owen Taylor3473f882001-02-23 17:55:21 +00001493xmlIOHTTPOpen (const char *filename) {
1494 return(xmlNanoHTTPOpen(filename, NULL));
1495}
1496
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001497#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001498/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001499 * xmlIOHTTPOpenW:
Daniel Veillardf012a642001-07-23 19:10:52 +00001500 * @post_uri: The destination URI for the document
1501 * @compression: The compression desired for the document.
1502 *
1503 * Open a temporary buffer to collect the document for a subsequent HTTP POST
1504 * request. Non-static as is called from the output buffer creation routine.
1505 *
1506 * Returns an I/O context or NULL in case of error.
1507 */
1508
1509void *
Daniel Veillard572577e2002-01-18 16:23:55 +00001510xmlIOHTTPOpenW(const char *post_uri, int compression)
1511{
Daniel Veillardf012a642001-07-23 19:10:52 +00001512
Daniel Veillard572577e2002-01-18 16:23:55 +00001513 xmlIOHTTPWriteCtxtPtr ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001514
Daniel Veillard572577e2002-01-18 16:23:55 +00001515 if (post_uri == NULL)
1516 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001517
Daniel Veillard572577e2002-01-18 16:23:55 +00001518 ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt));
1519 if (ctxt == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001520 xmlIOErrMemory("creating HTTP output context");
Daniel Veillard572577e2002-01-18 16:23:55 +00001521 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001522 }
1523
Daniel Veillard572577e2002-01-18 16:23:55 +00001524 (void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt));
Daniel Veillardf012a642001-07-23 19:10:52 +00001525
Daniel Veillard572577e2002-01-18 16:23:55 +00001526 ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri);
1527 if (ctxt->uri == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001528 xmlIOErrMemory("copying URI");
Daniel Veillard572577e2002-01-18 16:23:55 +00001529 xmlFreeHTTPWriteCtxt(ctxt);
1530 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001531 }
1532
1533 /*
Daniel Veillard572577e2002-01-18 16:23:55 +00001534 * ** Since the document length is required for an HTTP post,
1535 * ** need to put the document into a buffer. A memory buffer
1536 * ** is being used to avoid pushing the data to disk and back.
1537 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001538
1539#ifdef HAVE_ZLIB_H
Daniel Veillard572577e2002-01-18 16:23:55 +00001540 if ((compression > 0) && (compression <= 9)) {
1541
1542 ctxt->compression = compression;
1543 ctxt->doc_buff = xmlCreateZMemBuff(compression);
1544 } else
Daniel Veillardf012a642001-07-23 19:10:52 +00001545#endif
1546 {
Daniel Veillard572577e2002-01-18 16:23:55 +00001547 /* Any character conversions should have been done before this */
Daniel Veillardf012a642001-07-23 19:10:52 +00001548
Daniel Veillard572577e2002-01-18 16:23:55 +00001549 ctxt->doc_buff = xmlAllocOutputBuffer(NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001550 }
1551
Daniel Veillard572577e2002-01-18 16:23:55 +00001552 if (ctxt->doc_buff == NULL) {
1553 xmlFreeHTTPWriteCtxt(ctxt);
1554 ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001555 }
1556
Daniel Veillard572577e2002-01-18 16:23:55 +00001557 return (ctxt);
Daniel Veillardf012a642001-07-23 19:10:52 +00001558}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001559#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001560
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001561#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001562/**
1563 * xmlIOHTTPDfltOpenW
1564 * @post_uri: The destination URI for this document.
1565 *
1566 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
1567 * HTTP post command. This function should generally not be used as
1568 * the open callback is short circuited in xmlOutputBufferCreateFile.
1569 *
1570 * Returns a pointer to the new IO context.
1571 */
1572static void *
1573xmlIOHTTPDfltOpenW( const char * post_uri ) {
1574 return ( xmlIOHTTPOpenW( post_uri, 0 ) );
1575}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001576#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001577
1578/**
Owen Taylor3473f882001-02-23 17:55:21 +00001579 * xmlIOHTTPRead:
1580 * @context: the I/O context
1581 * @buffer: where to drop data
1582 * @len: number of bytes to write
1583 *
1584 * Read @len bytes to @buffer from the I/O channel.
1585 *
1586 * Returns the number of bytes written
1587 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001588int
Owen Taylor3473f882001-02-23 17:55:21 +00001589xmlIOHTTPRead(void * context, char * buffer, int len) {
Daniel Veillard5ea30d72004-11-08 11:54:28 +00001590 if ((buffer == NULL) || (len < 0)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001591 return(xmlNanoHTTPRead(context, &buffer[0], len));
1592}
1593
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001594#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001595/**
Daniel Veillardf012a642001-07-23 19:10:52 +00001596 * xmlIOHTTPWrite
1597 * @context: previously opened writing context
1598 * @buffer: data to output to temporary buffer
1599 * @len: bytes to output
1600 *
1601 * Collect data from memory buffer into a temporary file for later
1602 * processing.
1603 *
1604 * Returns number of bytes written.
1605 */
1606
1607static int
1608xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
1609
1610 xmlIOHTTPWriteCtxtPtr ctxt = context;
1611
1612 if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
1613 return ( -1 );
1614
1615 if ( len > 0 ) {
1616
1617 /* Use gzwrite or fwrite as previously setup in the open call */
1618
1619#ifdef HAVE_ZLIB_H
1620 if ( ctxt->compression > 0 )
1621 len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len );
1622
1623 else
1624#endif
1625 len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
1626
1627 if ( len < 0 ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001628 xmlChar msg[500];
1629 xmlStrPrintf(msg, 500,
1630 (const xmlChar *) "xmlIOHTTPWrite: %s\n%s '%s'.\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001631 "Error appending to internal buffer.",
1632 "Error sending document to URI",
1633 ctxt->uri );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001634 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001635 }
1636 }
1637
1638 return ( len );
1639}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001640#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001641
1642
1643/**
Owen Taylor3473f882001-02-23 17:55:21 +00001644 * xmlIOHTTPClose:
1645 * @context: the I/O context
1646 *
1647 * Close an HTTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001648 *
1649 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00001650 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001651int
Owen Taylor3473f882001-02-23 17:55:21 +00001652xmlIOHTTPClose (void * context) {
1653 xmlNanoHTTPClose(context);
Daniel Veillardf012a642001-07-23 19:10:52 +00001654 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001655}
Daniel Veillardf012a642001-07-23 19:10:52 +00001656
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001657#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001658/**
1659 * xmlIOHTTCloseWrite
1660 * @context: The I/O context
1661 * @http_mthd: The HTTP method to be used when sending the data
1662 *
1663 * Close the transmit HTTP I/O channel and actually send the data.
1664 */
1665static int
1666xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
1667
1668 int close_rc = -1;
1669 int http_rtn = 0;
1670 int content_lgth = 0;
1671 xmlIOHTTPWriteCtxtPtr ctxt = context;
1672
1673 char * http_content = NULL;
1674 char * content_encoding = NULL;
1675 char * content_type = (char *) "text/xml";
1676 void * http_ctxt = NULL;
1677
1678 if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
1679 return ( -1 );
1680
1681 /* Retrieve the content from the appropriate buffer */
1682
1683#ifdef HAVE_ZLIB_H
1684
1685 if ( ctxt->compression > 0 ) {
1686 content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
1687 content_encoding = (char *) "Content-Encoding: gzip";
1688 }
1689 else
1690#endif
1691 {
1692 /* Pull the data out of the memory output buffer */
1693
1694 xmlOutputBufferPtr dctxt = ctxt->doc_buff;
1695 http_content = (char *)dctxt->buffer->content;
1696 content_lgth = dctxt->buffer->use;
1697 }
1698
1699 if ( http_content == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001700 xmlChar msg[500];
1701 xmlStrPrintf(msg, 500,
1702 (const xmlChar *) "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
1703 "Error retrieving content.\nUnable to",
1704 http_mthd, "data to URI", ctxt->uri );
1705 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001706 }
1707
1708 else {
1709
1710 http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
1711 &content_type, content_encoding,
1712 content_lgth );
1713
1714 if ( http_ctxt != NULL ) {
1715#ifdef DEBUG_HTTP
1716 /* If testing/debugging - dump reply with request content */
1717
1718 FILE * tst_file = NULL;
1719 char buffer[ 4096 ];
1720 char * dump_name = NULL;
1721 int avail;
1722
1723 xmlGenericError( xmlGenericErrorContext,
1724 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
1725 http_mthd, ctxt->uri,
1726 xmlNanoHTTPReturnCode( http_ctxt ) );
1727
1728 /*
1729 ** Since either content or reply may be gzipped,
1730 ** dump them to separate files instead of the
1731 ** standard error context.
1732 */
1733
1734 dump_name = tempnam( NULL, "lxml" );
1735 if ( dump_name != NULL ) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001736 (void)snprintf( buffer, sizeof(buffer), "%s.content", dump_name );
Daniel Veillardf012a642001-07-23 19:10:52 +00001737
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00001738 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00001739 if ( tst_file != NULL ) {
1740 xmlGenericError( xmlGenericErrorContext,
1741 "Transmitted content saved in file: %s\n", buffer );
1742
1743 fwrite( http_content, sizeof( char ),
1744 content_lgth, tst_file );
1745 fclose( tst_file );
1746 }
1747
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001748 (void)snprintf( buffer, sizeof(buffer), "%s.reply", dump_name );
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00001749 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00001750 if ( tst_file != NULL ) {
1751 xmlGenericError( xmlGenericErrorContext,
1752 "Reply content saved in file: %s\n", buffer );
1753
1754
1755 while ( (avail = xmlNanoHTTPRead( http_ctxt,
1756 buffer, sizeof( buffer ) )) > 0 ) {
1757
1758 fwrite( buffer, sizeof( char ), avail, tst_file );
1759 }
1760
1761 fclose( tst_file );
1762 }
1763
1764 free( dump_name );
1765 }
1766#endif /* DEBUG_HTTP */
1767
1768 http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
1769 if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
1770 close_rc = 0;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001771 else {
1772 xmlChar msg[500];
1773 xmlStrPrintf(msg, 500,
1774 (const xmlChar *) "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001775 http_mthd, content_lgth,
1776 "bytes to URI", ctxt->uri,
1777 "failed. HTTP return code:", http_rtn );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001778 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1779 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001780
1781 xmlNanoHTTPClose( http_ctxt );
1782 xmlFree( content_type );
1783 }
1784 }
1785
1786 /* Final cleanups */
1787
1788 xmlFreeHTTPWriteCtxt( ctxt );
1789
1790 return ( close_rc );
1791}
1792
1793/**
1794 * xmlIOHTTPClosePut
1795 *
1796 * @context: The I/O context
1797 *
1798 * Close the transmit HTTP I/O channel and actually send data using a PUT
1799 * HTTP method.
1800 */
1801static int
1802xmlIOHTTPClosePut( void * ctxt ) {
1803 return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
1804}
1805
1806
1807/**
1808 * xmlIOHTTPClosePost
1809 *
1810 * @context: The I/O context
1811 *
1812 * Close the transmit HTTP I/O channel and actually send data using a POST
1813 * HTTP method.
1814 */
1815static int
1816xmlIOHTTPClosePost( void * ctxt ) {
1817 return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
1818}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001819#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001820
Owen Taylor3473f882001-02-23 17:55:21 +00001821#endif /* LIBXML_HTTP_ENABLED */
1822
1823#ifdef LIBXML_FTP_ENABLED
1824/************************************************************************
1825 * *
1826 * I/O for FTP file accesses *
1827 * *
1828 ************************************************************************/
1829/**
1830 * xmlIOFTPMatch:
1831 * @filename: the URI for matching
1832 *
1833 * check if the URI matches an FTP one
1834 *
1835 * Returns 1 if matches, 0 otherwise
1836 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001837int
Owen Taylor3473f882001-02-23 17:55:21 +00001838xmlIOFTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001839 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "ftp://", 6))
Owen Taylor3473f882001-02-23 17:55:21 +00001840 return(1);
1841 return(0);
1842}
1843
1844/**
1845 * xmlIOFTPOpen:
1846 * @filename: the URI for matching
1847 *
1848 * open an FTP I/O channel
1849 *
1850 * Returns an I/O context or NULL in case of error
1851 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001852void *
Owen Taylor3473f882001-02-23 17:55:21 +00001853xmlIOFTPOpen (const char *filename) {
1854 return(xmlNanoFTPOpen(filename));
1855}
1856
1857/**
1858 * xmlIOFTPRead:
1859 * @context: the I/O context
1860 * @buffer: where to drop data
1861 * @len: number of bytes to write
1862 *
1863 * Read @len bytes to @buffer from the I/O channel.
1864 *
1865 * Returns the number of bytes written
1866 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001867int
Owen Taylor3473f882001-02-23 17:55:21 +00001868xmlIOFTPRead(void * context, char * buffer, int len) {
Daniel Veillard5ea30d72004-11-08 11:54:28 +00001869 if ((buffer == NULL) || (len < 0)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001870 return(xmlNanoFTPRead(context, &buffer[0], len));
1871}
1872
1873/**
1874 * xmlIOFTPClose:
1875 * @context: the I/O context
1876 *
1877 * Close an FTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001878 *
1879 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00001880 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001881int
Owen Taylor3473f882001-02-23 17:55:21 +00001882xmlIOFTPClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001883 return ( xmlNanoFTPClose(context) );
Owen Taylor3473f882001-02-23 17:55:21 +00001884}
1885#endif /* LIBXML_FTP_ENABLED */
1886
1887
1888/**
1889 * xmlRegisterInputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001890 * @matchFunc: the xmlInputMatchCallback
1891 * @openFunc: the xmlInputOpenCallback
1892 * @readFunc: the xmlInputReadCallback
1893 * @closeFunc: the xmlInputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001894 *
1895 * Register a new set of I/O callback for handling parser input.
1896 *
1897 * Returns the registered handler number or -1 in case of error
1898 */
1899int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001900xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
1901 xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
1902 xmlInputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001903 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
1904 return(-1);
1905 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001906 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
1907 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
1908 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
1909 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00001910 xmlInputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00001911 return(xmlInputCallbackNr++);
1912}
1913
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001914#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001915/**
1916 * xmlRegisterOutputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001917 * @matchFunc: the xmlOutputMatchCallback
1918 * @openFunc: the xmlOutputOpenCallback
1919 * @writeFunc: the xmlOutputWriteCallback
1920 * @closeFunc: the xmlOutputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001921 *
1922 * Register a new set of I/O callback for handling output.
1923 *
1924 * Returns the registered handler number or -1 in case of error
1925 */
1926int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001927xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
1928 xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
1929 xmlOutputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001930 if (xmlOutputCallbackNr >= MAX_INPUT_CALLBACK) {
1931 return(-1);
1932 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001933 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
1934 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
1935 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
1936 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00001937 xmlOutputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00001938 return(xmlOutputCallbackNr++);
1939}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001940#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001941
1942/**
1943 * xmlRegisterDefaultInputCallbacks:
1944 *
1945 * Registers the default compiled-in I/O handlers.
1946 */
1947void
Owen Taylor3473f882001-02-23 17:55:21 +00001948xmlRegisterDefaultInputCallbacks
Owen Taylor3473f882001-02-23 17:55:21 +00001949(void) {
1950 if (xmlInputCallbackInitialized)
1951 return;
1952
1953 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
1954 xmlFileRead, xmlFileClose);
1955#ifdef HAVE_ZLIB_H
1956 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1957 xmlGzfileRead, xmlGzfileClose);
1958#endif /* HAVE_ZLIB_H */
1959
1960#ifdef LIBXML_HTTP_ENABLED
1961 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
1962 xmlIOHTTPRead, xmlIOHTTPClose);
1963#endif /* LIBXML_HTTP_ENABLED */
1964
1965#ifdef LIBXML_FTP_ENABLED
1966 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1967 xmlIOFTPRead, xmlIOFTPClose);
1968#endif /* LIBXML_FTP_ENABLED */
1969 xmlInputCallbackInitialized = 1;
1970}
1971
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001972#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001973/**
1974 * xmlRegisterDefaultOutputCallbacks:
1975 *
1976 * Registers the default compiled-in I/O handlers.
1977 */
1978void
Owen Taylor3473f882001-02-23 17:55:21 +00001979xmlRegisterDefaultOutputCallbacks
Owen Taylor3473f882001-02-23 17:55:21 +00001980(void) {
1981 if (xmlOutputCallbackInitialized)
1982 return;
1983
1984 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
1985 xmlFileWrite, xmlFileClose);
Daniel Veillardf012a642001-07-23 19:10:52 +00001986
1987#ifdef LIBXML_HTTP_ENABLED
1988 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
1989 xmlIOHTTPWrite, xmlIOHTTPClosePut);
1990#endif
1991
Owen Taylor3473f882001-02-23 17:55:21 +00001992/*********************************
1993 No way a-priori to distinguish between gzipped files from
1994 uncompressed ones except opening if existing then closing
1995 and saving with same compression ratio ... a pain.
1996
1997#ifdef HAVE_ZLIB_H
1998 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1999 xmlGzfileWrite, xmlGzfileClose);
2000#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002001
2002 Nor FTP PUT ....
2003#ifdef LIBXML_FTP_ENABLED
2004 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
2005 xmlIOFTPWrite, xmlIOFTPClose);
2006#endif
2007 **********************************/
2008 xmlOutputCallbackInitialized = 1;
2009}
2010
Daniel Veillardf012a642001-07-23 19:10:52 +00002011#ifdef LIBXML_HTTP_ENABLED
2012/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00002013 * xmlRegisterHTTPPostCallbacks:
Daniel Veillardf012a642001-07-23 19:10:52 +00002014 *
2015 * By default, libxml submits HTTP output requests using the "PUT" method.
2016 * Calling this method changes the HTTP output method to use the "POST"
2017 * method instead.
2018 *
2019 */
2020void
2021xmlRegisterHTTPPostCallbacks( void ) {
2022
2023 /* Register defaults if not done previously */
2024
2025 if ( xmlOutputCallbackInitialized == 0 )
2026 xmlRegisterDefaultOutputCallbacks( );
2027
2028 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
2029 xmlIOHTTPWrite, xmlIOHTTPClosePost);
2030 return;
2031}
2032#endif
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002033#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00002034
Owen Taylor3473f882001-02-23 17:55:21 +00002035/**
2036 * xmlAllocParserInputBuffer:
2037 * @enc: the charset encoding if known
2038 *
2039 * Create a buffered parser input for progressive parsing
2040 *
2041 * Returns the new parser input or NULL
2042 */
2043xmlParserInputBufferPtr
2044xmlAllocParserInputBuffer(xmlCharEncoding enc) {
2045 xmlParserInputBufferPtr ret;
2046
2047 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2048 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002049 xmlIOErrMemory("creating input buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00002050 return(NULL);
2051 }
2052 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002053 ret->buffer = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00002054 if (ret->buffer == NULL) {
2055 xmlFree(ret);
2056 return(NULL);
2057 }
2058 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
2059 ret->encoder = xmlGetCharEncodingHandler(enc);
2060 if (ret->encoder != NULL)
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002061 ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00002062 else
2063 ret->raw = NULL;
2064 ret->readcallback = NULL;
2065 ret->closecallback = NULL;
2066 ret->context = NULL;
William M. Brackc07329e2003-09-08 01:57:30 +00002067 ret->compressed = -1;
Daniel Veillard36711902004-02-11 13:25:26 +00002068 ret->rawconsumed = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002069
2070 return(ret);
2071}
2072
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002073#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002074/**
2075 * xmlAllocOutputBuffer:
2076 * @encoder: the encoding converter or NULL
2077 *
2078 * Create a buffered parser output
2079 *
2080 * Returns the new parser output or NULL
2081 */
2082xmlOutputBufferPtr
2083xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
2084 xmlOutputBufferPtr ret;
2085
2086 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
2087 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002088 xmlIOErrMemory("creating output buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00002089 return(NULL);
2090 }
2091 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
2092 ret->buffer = xmlBufferCreate();
2093 if (ret->buffer == NULL) {
2094 xmlFree(ret);
2095 return(NULL);
2096 }
2097 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
2098 ret->encoder = encoder;
2099 if (encoder != NULL) {
2100 ret->conv = xmlBufferCreateSize(4000);
2101 /*
2102 * This call is designed to initiate the encoder state
2103 */
2104 xmlCharEncOutFunc(encoder, ret->conv, NULL);
2105 } else
2106 ret->conv = NULL;
2107 ret->writecallback = NULL;
2108 ret->closecallback = NULL;
2109 ret->context = NULL;
2110 ret->written = 0;
2111
2112 return(ret);
2113}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002114#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002115
2116/**
2117 * xmlFreeParserInputBuffer:
2118 * @in: a buffered parser input
2119 *
2120 * Free up the memory used by a buffered parser input
2121 */
2122void
2123xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
Daniel Veillard8d8bf2c2003-09-17 19:36:25 +00002124 if (in == NULL) return;
2125
Owen Taylor3473f882001-02-23 17:55:21 +00002126 if (in->raw) {
2127 xmlBufferFree(in->raw);
2128 in->raw = NULL;
2129 }
2130 if (in->encoder != NULL) {
2131 xmlCharEncCloseFunc(in->encoder);
2132 }
2133 if (in->closecallback != NULL) {
2134 in->closecallback(in->context);
2135 }
2136 if (in->buffer != NULL) {
2137 xmlBufferFree(in->buffer);
2138 in->buffer = NULL;
2139 }
2140
Owen Taylor3473f882001-02-23 17:55:21 +00002141 xmlFree(in);
2142}
2143
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002144#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002145/**
2146 * xmlOutputBufferClose:
2147 * @out: a buffered output
2148 *
2149 * flushes and close the output I/O channel
2150 * and free up all the associated resources
2151 *
2152 * Returns the number of byte written or -1 in case of error.
2153 */
2154int
Daniel Veillard828ce832003-10-08 19:19:10 +00002155xmlOutputBufferClose(xmlOutputBufferPtr out)
2156{
Owen Taylor3473f882001-02-23 17:55:21 +00002157 int written;
Daniel Veillardf012a642001-07-23 19:10:52 +00002158 int err_rc = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002159
2160 if (out == NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002161 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002162 if (out->writecallback != NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002163 xmlOutputBufferFlush(out);
Owen Taylor3473f882001-02-23 17:55:21 +00002164 if (out->closecallback != NULL) {
Daniel Veillard828ce832003-10-08 19:19:10 +00002165 err_rc = out->closecallback(out->context);
Owen Taylor3473f882001-02-23 17:55:21 +00002166 }
2167 written = out->written;
2168 if (out->conv) {
2169 xmlBufferFree(out->conv);
Daniel Veillard828ce832003-10-08 19:19:10 +00002170 out->conv = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002171 }
2172 if (out->encoder != NULL) {
2173 xmlCharEncCloseFunc(out->encoder);
2174 }
2175 if (out->buffer != NULL) {
2176 xmlBufferFree(out->buffer);
Daniel Veillard828ce832003-10-08 19:19:10 +00002177 out->buffer = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002178 }
2179
Daniel Veillard828ce832003-10-08 19:19:10 +00002180 if (out->error)
2181 err_rc = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00002182 xmlFree(out);
Daniel Veillard828ce832003-10-08 19:19:10 +00002183 return ((err_rc == 0) ? written : err_rc);
Owen Taylor3473f882001-02-23 17:55:21 +00002184}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002185#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002186
Daniel Veillard1b243b42004-06-08 10:16:42 +00002187xmlParserInputBufferPtr
Daniel Veillard0335a842004-06-02 16:18:40 +00002188__xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002189 xmlParserInputBufferPtr ret;
Daniel Veillard388236f2001-07-08 18:35:48 +00002190 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002191 void *context = NULL;
2192
2193 if (xmlInputCallbackInitialized == 0)
2194 xmlRegisterDefaultInputCallbacks();
2195
2196 if (URI == NULL) return(NULL);
2197
2198 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002199 * Try to find one of the input accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002200 * Go in reverse to give precedence to user defined handlers.
Daniel Veillard388236f2001-07-08 18:35:48 +00002201 */
2202 if (context == NULL) {
2203 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
2204 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
2205 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002206 context = xmlInputCallbackTable[i].opencallback(URI);
Daniel Veillard847332a2003-10-18 11:29:40 +00002207 if (context != NULL) {
Daniel Veillard388236f2001-07-08 18:35:48 +00002208 break;
Daniel Veillard847332a2003-10-18 11:29:40 +00002209 }
Daniel Veillard388236f2001-07-08 18:35:48 +00002210 }
Owen Taylor3473f882001-02-23 17:55:21 +00002211 }
2212 }
2213 if (context == NULL) {
2214 return(NULL);
2215 }
2216
2217 /*
2218 * Allocate the Input buffer front-end.
2219 */
2220 ret = xmlAllocParserInputBuffer(enc);
2221 if (ret != NULL) {
2222 ret->context = context;
2223 ret->readcallback = xmlInputCallbackTable[i].readcallback;
2224 ret->closecallback = xmlInputCallbackTable[i].closecallback;
William M. Brackc07329e2003-09-08 01:57:30 +00002225#ifdef HAVE_ZLIB_H
William M. Brackc5cbf992003-10-29 22:15:13 +00002226 if ((xmlInputCallbackTable[i].opencallback == xmlGzfileOpen) &&
2227 (strcmp(URI, "-") != 0)) {
William M. Brackc07329e2003-09-08 01:57:30 +00002228 if (((z_stream *)context)->avail_in > 4) {
2229 char *cptr, buff4[4];
Daniel Veillard07cb8222003-09-10 10:51:05 +00002230 cptr = (char *) ((z_stream *)context)->next_in;
William M. Brackc07329e2003-09-08 01:57:30 +00002231 if (gzread(context, buff4, 4) == 4) {
2232 if (strncmp(buff4, cptr, 4) == 0)
2233 ret->compressed = 0;
2234 else
2235 ret->compressed = 1;
2236 gzrewind(context);
2237 }
2238 }
2239 }
2240#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002241 }
William M. Brack42331a92004-07-29 07:07:16 +00002242 else
2243 xmlInputCallbackTable[i].closecallback (context);
2244
Owen Taylor3473f882001-02-23 17:55:21 +00002245 return(ret);
2246}
2247
2248/**
Daniel Veillard0335a842004-06-02 16:18:40 +00002249 * xmlParserInputBufferCreateFilename:
Owen Taylor3473f882001-02-23 17:55:21 +00002250 * @URI: a C string containing the URI or filename
Daniel Veillard0335a842004-06-02 16:18:40 +00002251 * @enc: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002252 *
Daniel Veillard0335a842004-06-02 16:18:40 +00002253 * Create a buffered parser input for the progressive parsing of a file
2254 * If filename is "-' then we use stdin as the input.
Owen Taylor3473f882001-02-23 17:55:21 +00002255 * Automatic support for ZLIB/Compress compressed document is provided
2256 * by default if found at compile-time.
Daniel Veillard0335a842004-06-02 16:18:40 +00002257 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
Owen Taylor3473f882001-02-23 17:55:21 +00002258 *
Daniel Veillard0335a842004-06-02 16:18:40 +00002259 * Returns the new parser input or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00002260 */
Daniel Veillard0335a842004-06-02 16:18:40 +00002261xmlParserInputBufferPtr
2262xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
2263 if ((xmlParserInputBufferCreateFilenameValue)) {
2264 return xmlParserInputBufferCreateFilenameValue(URI, enc);
2265 }
2266 return __xmlParserInputBufferCreateFilename(URI, enc);
2267}
2268
2269#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard1b243b42004-06-08 10:16:42 +00002270xmlOutputBufferPtr
Daniel Veillard0335a842004-06-02 16:18:40 +00002271__xmlOutputBufferCreateFilename(const char *URI,
Owen Taylor3473f882001-02-23 17:55:21 +00002272 xmlCharEncodingHandlerPtr encoder,
Daniel Veillard0335a842004-06-02 16:18:40 +00002273 int compression ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00002274 xmlOutputBufferPtr ret;
Daniel Veillard966a31e2004-05-09 02:58:44 +00002275 xmlURIPtr puri;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002276 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002277 void *context = NULL;
Daniel Veillard966a31e2004-05-09 02:58:44 +00002278 char *unescaped = NULL;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002279#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002280 int is_file_uri = 1;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002281#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00002282
Owen Taylor3473f882001-02-23 17:55:21 +00002283 if (xmlOutputCallbackInitialized == 0)
2284 xmlRegisterDefaultOutputCallbacks();
2285
2286 if (URI == NULL) return(NULL);
2287
Daniel Veillard966a31e2004-05-09 02:58:44 +00002288 puri = xmlParseURI(URI);
2289 if (puri != NULL) {
Daniel Veillard8fcd2ca2005-07-03 14:42:56 +00002290#ifdef HAVE_ZLIB_H
Daniel Veillard18a65092004-05-11 15:57:42 +00002291 if ((puri->scheme != NULL) &&
2292 (!xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
Daniel Veillard966a31e2004-05-09 02:58:44 +00002293 is_file_uri = 0;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002294#endif
Daniel Veillard966a31e2004-05-09 02:58:44 +00002295 /*
2296 * try to limit the damages of the URI unescaping code.
2297 */
2298 if (puri->scheme != NULL)
2299 unescaped = xmlURIUnescapeString(URI, 0, NULL);
2300 xmlFreeURI(puri);
2301 }
Owen Taylor3473f882001-02-23 17:55:21 +00002302
2303 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002304 * Try to find one of the output accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002305 * Go in reverse to give precedence to user defined handlers.
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002306 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00002307 */
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002308 if (unescaped != NULL) {
2309#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002310 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002311 context = xmlGzfileOpenW(unescaped, compression);
2312 if (context != NULL) {
2313 ret = xmlAllocOutputBuffer(encoder);
2314 if (ret != NULL) {
2315 ret->context = context;
2316 ret->writecallback = xmlGzfileWrite;
2317 ret->closecallback = xmlGzfileClose;
2318 }
2319 xmlFree(unescaped);
2320 return(ret);
2321 }
2322 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002323#endif
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002324 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2325 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
2326 (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
2327#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2328 /* Need to pass compression parameter into HTTP open calls */
2329 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2330 context = xmlIOHTTPOpenW(unescaped, compression);
2331 else
2332#endif
2333 context = xmlOutputCallbackTable[i].opencallback(unescaped);
2334 if (context != NULL)
2335 break;
2336 }
2337 }
2338 xmlFree(unescaped);
2339 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002340
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002341 /*
2342 * If this failed try with a non-escaped URI this may be a strange
2343 * filename
2344 */
2345 if (context == NULL) {
2346#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002347 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002348 context = xmlGzfileOpenW(URI, compression);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002349 if (context != NULL) {
2350 ret = xmlAllocOutputBuffer(encoder);
2351 if (ret != NULL) {
2352 ret->context = context;
2353 ret->writecallback = xmlGzfileWrite;
2354 ret->closecallback = xmlGzfileClose;
2355 }
2356 return(ret);
2357 }
2358 }
2359#endif
2360 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2361 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002362 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002363#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2364 /* Need to pass compression parameter into HTTP open calls */
2365 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2366 context = xmlIOHTTPOpenW(URI, compression);
2367 else
2368#endif
2369 context = xmlOutputCallbackTable[i].opencallback(URI);
2370 if (context != NULL)
2371 break;
2372 }
Owen Taylor3473f882001-02-23 17:55:21 +00002373 }
2374 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002375
Owen Taylor3473f882001-02-23 17:55:21 +00002376 if (context == NULL) {
2377 return(NULL);
2378 }
2379
2380 /*
2381 * Allocate the Output buffer front-end.
2382 */
2383 ret = xmlAllocOutputBuffer(encoder);
2384 if (ret != NULL) {
2385 ret->context = context;
2386 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
2387 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
2388 }
2389 return(ret);
2390}
Daniel Veillard0335a842004-06-02 16:18:40 +00002391
2392/**
2393 * xmlOutputBufferCreateFilename:
2394 * @URI: a C string containing the URI or filename
2395 * @encoder: the encoding converter or NULL
2396 * @compression: the compression ration (0 none, 9 max).
2397 *
2398 * Create a buffered output for the progressive saving of a file
2399 * If filename is "-' then we use stdout as the output.
2400 * Automatic support for ZLIB/Compress compressed document is provided
2401 * by default if found at compile-time.
2402 * TODO: currently if compression is set, the library only support
2403 * writing to a local file.
2404 *
2405 * Returns the new output or NULL
2406 */
2407xmlOutputBufferPtr
2408xmlOutputBufferCreateFilename(const char *URI,
2409 xmlCharEncodingHandlerPtr encoder,
2410 int compression ATTRIBUTE_UNUSED) {
2411 if ((xmlOutputBufferCreateFilenameValue)) {
2412 return xmlOutputBufferCreateFilenameValue(URI, encoder, compression);
2413 }
2414 return __xmlOutputBufferCreateFilename(URI, encoder, compression);
2415}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002416#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002417
2418/**
2419 * xmlParserInputBufferCreateFile:
2420 * @file: a FILE*
2421 * @enc: the charset encoding if known
2422 *
2423 * Create a buffered parser input for the progressive parsing of a FILE *
2424 * buffered C I/O
2425 *
2426 * Returns the new parser input or NULL
2427 */
2428xmlParserInputBufferPtr
2429xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
2430 xmlParserInputBufferPtr ret;
2431
2432 if (xmlInputCallbackInitialized == 0)
2433 xmlRegisterDefaultInputCallbacks();
2434
2435 if (file == NULL) return(NULL);
2436
2437 ret = xmlAllocParserInputBuffer(enc);
2438 if (ret != NULL) {
2439 ret->context = file;
2440 ret->readcallback = xmlFileRead;
2441 ret->closecallback = xmlFileFlush;
2442 }
2443
2444 return(ret);
2445}
2446
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002447#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002448/**
2449 * xmlOutputBufferCreateFile:
2450 * @file: a FILE*
2451 * @encoder: the encoding converter or NULL
2452 *
2453 * Create a buffered output for the progressive saving to a FILE *
2454 * buffered C I/O
2455 *
2456 * Returns the new parser output or NULL
2457 */
2458xmlOutputBufferPtr
2459xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
2460 xmlOutputBufferPtr ret;
2461
2462 if (xmlOutputCallbackInitialized == 0)
2463 xmlRegisterDefaultOutputCallbacks();
2464
2465 if (file == NULL) return(NULL);
2466
2467 ret = xmlAllocOutputBuffer(encoder);
2468 if (ret != NULL) {
2469 ret->context = file;
2470 ret->writecallback = xmlFileWrite;
2471 ret->closecallback = xmlFileFlush;
2472 }
2473
2474 return(ret);
2475}
Daniel Veillard9a00fd22005-11-09 08:56:26 +00002476
2477/**
2478 * xmlOutputBufferCreateBuffer:
2479 * @buffer: a xmlBufferPtr
2480 * @encoder: the encoding converter or NULL
2481 *
2482 * Create a buffered output for the progressive saving to a xmlBuffer
2483 *
2484 * Returns the new parser output or NULL
2485 */
2486xmlOutputBufferPtr
2487xmlOutputBufferCreateBuffer(xmlBufferPtr buffer,
2488 xmlCharEncodingHandlerPtr encoder) {
2489 xmlOutputBufferPtr ret;
2490
2491 if (buffer == NULL) return(NULL);
2492
Rob Richardsa44f2342005-11-09 18:03:45 +00002493 ret = xmlOutputBufferCreateIO((xmlOutputWriteCallback)
2494 xmlBufferWrite,
2495 (xmlOutputCloseCallback)
2496 xmlBufferClose,
2497 (void *) buffer, encoder);
Daniel Veillard9a00fd22005-11-09 08:56:26 +00002498
2499 return(ret);
2500}
2501
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002502#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002503
2504/**
2505 * xmlParserInputBufferCreateFd:
2506 * @fd: a file descriptor number
2507 * @enc: the charset encoding if known
2508 *
2509 * Create a buffered parser input for the progressive parsing for the input
2510 * from a file descriptor
2511 *
2512 * Returns the new parser input or NULL
2513 */
2514xmlParserInputBufferPtr
2515xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
2516 xmlParserInputBufferPtr ret;
2517
2518 if (fd < 0) return(NULL);
2519
2520 ret = xmlAllocParserInputBuffer(enc);
2521 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002522 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002523 ret->readcallback = xmlFdRead;
2524 ret->closecallback = xmlFdClose;
2525 }
2526
2527 return(ret);
2528}
2529
2530/**
2531 * xmlParserInputBufferCreateMem:
2532 * @mem: the memory input
2533 * @size: the length of the memory block
2534 * @enc: the charset encoding if known
2535 *
2536 * Create a buffered parser input for the progressive parsing for the input
2537 * from a memory area.
2538 *
2539 * Returns the new parser input or NULL
2540 */
2541xmlParserInputBufferPtr
2542xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
2543 xmlParserInputBufferPtr ret;
William M. Bracka3215c72004-07-31 16:24:01 +00002544 int errcode;
Owen Taylor3473f882001-02-23 17:55:21 +00002545
2546 if (size <= 0) return(NULL);
2547 if (mem == NULL) return(NULL);
2548
2549 ret = xmlAllocParserInputBuffer(enc);
2550 if (ret != NULL) {
2551 ret->context = (void *) mem;
2552 ret->readcallback = (xmlInputReadCallback) xmlNop;
2553 ret->closecallback = NULL;
William M. Bracka3215c72004-07-31 16:24:01 +00002554 errcode = xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size);
2555 if (errcode != 0) {
2556 xmlFree(ret);
2557 return(NULL);
2558 }
Owen Taylor3473f882001-02-23 17:55:21 +00002559 }
2560
2561 return(ret);
2562}
2563
2564/**
Daniel Veillard53350552003-09-18 13:35:51 +00002565 * xmlParserInputBufferCreateStatic:
2566 * @mem: the memory input
2567 * @size: the length of the memory block
2568 * @enc: the charset encoding if known
2569 *
2570 * Create a buffered parser input for the progressive parsing for the input
2571 * from an immutable memory area. This will not copy the memory area to
2572 * the buffer, but the memory is expected to be available until the end of
2573 * the parsing, this is useful for example when using mmap'ed file.
2574 *
2575 * Returns the new parser input or NULL
2576 */
2577xmlParserInputBufferPtr
2578xmlParserInputBufferCreateStatic(const char *mem, int size,
2579 xmlCharEncoding enc) {
2580 xmlParserInputBufferPtr ret;
2581
2582 if (size <= 0) return(NULL);
2583 if (mem == NULL) return(NULL);
2584
2585 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2586 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002587 xmlIOErrMemory("creating input buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00002588 return(NULL);
2589 }
2590 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillarde72c5082003-09-19 12:44:05 +00002591 ret->buffer = xmlBufferCreateStatic((void *)mem, (size_t) size);
Daniel Veillard53350552003-09-18 13:35:51 +00002592 if (ret->buffer == NULL) {
2593 xmlFree(ret);
2594 return(NULL);
2595 }
2596 ret->encoder = xmlGetCharEncodingHandler(enc);
2597 if (ret->encoder != NULL)
2598 ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
2599 else
2600 ret->raw = NULL;
2601 ret->compressed = -1;
2602 ret->context = (void *) mem;
2603 ret->readcallback = NULL;
2604 ret->closecallback = NULL;
2605
2606 return(ret);
2607}
2608
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002609#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard53350552003-09-18 13:35:51 +00002610/**
Owen Taylor3473f882001-02-23 17:55:21 +00002611 * xmlOutputBufferCreateFd:
2612 * @fd: a file descriptor number
2613 * @encoder: the encoding converter or NULL
2614 *
2615 * Create a buffered output for the progressive saving
2616 * to a file descriptor
2617 *
2618 * Returns the new parser output or NULL
2619 */
2620xmlOutputBufferPtr
2621xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
2622 xmlOutputBufferPtr ret;
2623
2624 if (fd < 0) return(NULL);
2625
2626 ret = xmlAllocOutputBuffer(encoder);
2627 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002628 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002629 ret->writecallback = xmlFdWrite;
Daniel Veillard7db38712002-02-07 16:39:11 +00002630 ret->closecallback = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002631 }
2632
2633 return(ret);
2634}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002635#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002636
2637/**
2638 * xmlParserInputBufferCreateIO:
2639 * @ioread: an I/O read function
2640 * @ioclose: an I/O close function
2641 * @ioctx: an I/O handler
2642 * @enc: the charset encoding if known
2643 *
2644 * Create a buffered parser input for the progressive parsing for the input
2645 * from an I/O handler
2646 *
2647 * Returns the new parser input or NULL
2648 */
2649xmlParserInputBufferPtr
2650xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
2651 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
2652 xmlParserInputBufferPtr ret;
2653
2654 if (ioread == NULL) return(NULL);
2655
2656 ret = xmlAllocParserInputBuffer(enc);
2657 if (ret != NULL) {
2658 ret->context = (void *) ioctx;
2659 ret->readcallback = ioread;
2660 ret->closecallback = ioclose;
2661 }
2662
2663 return(ret);
2664}
2665
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002666#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002667/**
2668 * xmlOutputBufferCreateIO:
2669 * @iowrite: an I/O write function
2670 * @ioclose: an I/O close function
2671 * @ioctx: an I/O handler
Daniel Veillard9d06d302002-01-22 18:15:52 +00002672 * @encoder: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002673 *
2674 * Create a buffered output for the progressive saving
2675 * to an I/O handler
2676 *
2677 * Returns the new parser output or NULL
2678 */
2679xmlOutputBufferPtr
2680xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
2681 xmlOutputCloseCallback ioclose, void *ioctx,
2682 xmlCharEncodingHandlerPtr encoder) {
2683 xmlOutputBufferPtr ret;
2684
2685 if (iowrite == NULL) return(NULL);
2686
2687 ret = xmlAllocOutputBuffer(encoder);
2688 if (ret != NULL) {
2689 ret->context = (void *) ioctx;
2690 ret->writecallback = iowrite;
2691 ret->closecallback = ioclose;
2692 }
2693
2694 return(ret);
2695}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002696#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002697
2698/**
Daniel Veillard1b243b42004-06-08 10:16:42 +00002699 * xmlParserInputBufferCreateFilenameDefault:
2700 * @func: function pointer to the new ParserInputBufferCreateFilenameFunc
2701 *
2702 * Registers a callback for URI input file handling
2703 *
2704 * Returns the old value of the registration function
2705 */
2706xmlParserInputBufferCreateFilenameFunc
2707xmlParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func)
2708{
2709 xmlParserInputBufferCreateFilenameFunc old = xmlParserInputBufferCreateFilenameValue;
2710 if (old == NULL) {
2711 old = __xmlParserInputBufferCreateFilename;
2712 }
2713
2714 xmlParserInputBufferCreateFilenameValue = func;
2715 return(old);
2716}
2717
2718/**
2719 * xmlOutputBufferCreateFilenameDefault:
2720 * @func: function pointer to the new OutputBufferCreateFilenameFunc
2721 *
2722 * Registers a callback for URI output file handling
2723 *
2724 * Returns the old value of the registration function
2725 */
2726xmlOutputBufferCreateFilenameFunc
2727xmlOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func)
2728{
2729 xmlOutputBufferCreateFilenameFunc old = xmlOutputBufferCreateFilenameValue;
2730#ifdef LIBXML_OUTPUT_ENABLED
2731 if (old == NULL) {
2732 old = __xmlOutputBufferCreateFilename;
2733 }
2734#endif
2735 xmlOutputBufferCreateFilenameValue = func;
2736 return(old);
2737}
2738
2739/**
Owen Taylor3473f882001-02-23 17:55:21 +00002740 * xmlParserInputBufferPush:
2741 * @in: a buffered parser input
2742 * @len: the size in bytes of the array.
2743 * @buf: an char array
2744 *
2745 * Push the content of the arry in the input buffer
2746 * This routine handle the I18N transcoding to internal UTF-8
2747 * This is used when operating the parser in progressive (push) mode.
2748 *
2749 * Returns the number of chars read and stored in the buffer, or -1
2750 * in case of error.
2751 */
2752int
2753xmlParserInputBufferPush(xmlParserInputBufferPtr in,
2754 int len, const char *buf) {
2755 int nbchars = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00002756 int ret;
Owen Taylor3473f882001-02-23 17:55:21 +00002757
2758 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002759 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002760 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00002761 unsigned int use;
2762
Owen Taylor3473f882001-02-23 17:55:21 +00002763 /*
2764 * Store the data in the incoming raw buffer
2765 */
2766 if (in->raw == NULL) {
2767 in->raw = xmlBufferCreate();
2768 }
William M. Bracka3215c72004-07-31 16:24:01 +00002769 ret = xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
2770 if (ret != 0)
2771 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002772
2773 /*
2774 * convert as much as possible to the parser reading buffer.
2775 */
Daniel Veillard36711902004-02-11 13:25:26 +00002776 use = in->raw->use;
Owen Taylor3473f882001-02-23 17:55:21 +00002777 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2778 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002779 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002780 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002781 return(-1);
2782 }
Daniel Veillard36711902004-02-11 13:25:26 +00002783 in->rawconsumed += (use - in->raw->use);
Owen Taylor3473f882001-02-23 17:55:21 +00002784 } else {
2785 nbchars = len;
William M. Bracka3215c72004-07-31 16:24:01 +00002786 ret = xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
2787 if (ret != 0)
2788 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002789 }
2790#ifdef DEBUG_INPUT
2791 xmlGenericError(xmlGenericErrorContext,
2792 "I/O: pushed %d chars, buffer %d/%d\n",
2793 nbchars, in->buffer->use, in->buffer->size);
2794#endif
2795 return(nbchars);
2796}
2797
2798/**
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002799 * endOfInput:
2800 *
2801 * When reading from an Input channel indicated end of file or error
2802 * don't reread from it again.
2803 */
2804static int
2805endOfInput (void * context ATTRIBUTE_UNUSED,
2806 char * buffer ATTRIBUTE_UNUSED,
2807 int len ATTRIBUTE_UNUSED) {
2808 return(0);
2809}
2810
2811/**
Owen Taylor3473f882001-02-23 17:55:21 +00002812 * xmlParserInputBufferGrow:
2813 * @in: a buffered parser input
2814 * @len: indicative value of the amount of chars to read
2815 *
2816 * Grow up the content of the input buffer, the old data are preserved
2817 * This routine handle the I18N transcoding to internal UTF-8
2818 * This routine is used when operating the parser in normal (pull) mode
2819 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002820 * TODO: one should be able to remove one extra copy by copying directly
Owen Taylor3473f882001-02-23 17:55:21 +00002821 * onto in->buffer or in->raw
2822 *
2823 * Returns the number of chars read and stored in the buffer, or -1
2824 * in case of error.
2825 */
2826int
2827xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
2828 char *buffer = NULL;
2829 int res = 0;
2830 int nbchars = 0;
2831 int buffree;
Daniel Veillard9e412302002-06-10 15:59:44 +00002832 unsigned int needSize;
Owen Taylor3473f882001-02-23 17:55:21 +00002833
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002834 if ((in == NULL) || (in->error)) return(-1);
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002835 if ((len <= MINLEN) && (len != 4))
Owen Taylor3473f882001-02-23 17:55:21 +00002836 len = MINLEN;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002837
Owen Taylor3473f882001-02-23 17:55:21 +00002838 buffree = in->buffer->size - in->buffer->use;
2839 if (buffree <= 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002840 xmlIOErr(XML_IO_BUFFER_FULL, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002841 in->error = XML_IO_BUFFER_FULL;
William M. Bracka3215c72004-07-31 16:24:01 +00002842 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002843 }
Owen Taylor3473f882001-02-23 17:55:21 +00002844
Daniel Veillarde5354492002-05-16 08:43:22 +00002845 needSize = in->buffer->use + len + 1;
2846 if (needSize > in->buffer->size){
2847 if (!xmlBufferResize(in->buffer, needSize)){
Daniel Veillard05d987b2003-10-08 11:54:57 +00002848 xmlIOErrMemory("growing input buffer");
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002849 in->error = XML_ERR_NO_MEMORY;
William M. Bracka3215c72004-07-31 16:24:01 +00002850 return(-1);
Daniel Veillarde5354492002-05-16 08:43:22 +00002851 }
Owen Taylor3473f882001-02-23 17:55:21 +00002852 }
Daniel Veillarde5354492002-05-16 08:43:22 +00002853 buffer = (char *)&in->buffer->content[in->buffer->use];
Owen Taylor3473f882001-02-23 17:55:21 +00002854
2855 /*
2856 * Call the read method for this I/O type.
2857 */
2858 if (in->readcallback != NULL) {
2859 res = in->readcallback(in->context, &buffer[0], len);
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002860 if (res <= 0)
2861 in->readcallback = endOfInput;
Owen Taylor3473f882001-02-23 17:55:21 +00002862 } else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002863 xmlIOErr(XML_IO_NO_INPUT, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002864 in->error = XML_IO_NO_INPUT;
Owen Taylor3473f882001-02-23 17:55:21 +00002865 return(-1);
2866 }
2867 if (res < 0) {
Owen Taylor3473f882001-02-23 17:55:21 +00002868 return(-1);
2869 }
2870 len = res;
2871 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00002872 unsigned int use;
2873
Owen Taylor3473f882001-02-23 17:55:21 +00002874 /*
2875 * Store the data in the incoming raw buffer
2876 */
2877 if (in->raw == NULL) {
2878 in->raw = xmlBufferCreate();
2879 }
William M. Bracka3215c72004-07-31 16:24:01 +00002880 res = xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
2881 if (res != 0)
2882 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002883
2884 /*
2885 * convert as much as possible to the parser reading buffer.
2886 */
Daniel Veillard36711902004-02-11 13:25:26 +00002887 use = in->raw->use;
Owen Taylor3473f882001-02-23 17:55:21 +00002888 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2889 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002890 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002891 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002892 return(-1);
2893 }
Daniel Veillard36711902004-02-11 13:25:26 +00002894 in->rawconsumed += (use - in->raw->use);
Owen Taylor3473f882001-02-23 17:55:21 +00002895 } else {
2896 nbchars = len;
Daniel Veillarde5354492002-05-16 08:43:22 +00002897 in->buffer->use += nbchars;
2898 buffer[nbchars] = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002899 }
2900#ifdef DEBUG_INPUT
2901 xmlGenericError(xmlGenericErrorContext,
2902 "I/O: read %d chars, buffer %d/%d\n",
2903 nbchars, in->buffer->use, in->buffer->size);
2904#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002905 return(nbchars);
2906}
2907
2908/**
2909 * xmlParserInputBufferRead:
2910 * @in: a buffered parser input
2911 * @len: indicative value of the amount of chars to read
2912 *
2913 * Refresh the content of the input buffer, the old data are considered
2914 * consumed
2915 * This routine handle the I18N transcoding to internal UTF-8
2916 *
2917 * Returns the number of chars read and stored in the buffer, or -1
2918 * in case of error.
2919 */
2920int
2921xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002922 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002923 if (in->readcallback != NULL)
2924 return(xmlParserInputBufferGrow(in, len));
Daniel Veillard53350552003-09-18 13:35:51 +00002925 else if ((in->buffer != NULL) &&
2926 (in->buffer->alloc == XML_BUFFER_ALLOC_IMMUTABLE))
2927 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002928 else
2929 return(-1);
2930}
2931
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002932#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002933/**
2934 * xmlOutputBufferWrite:
2935 * @out: a buffered parser output
2936 * @len: the size in bytes of the array.
2937 * @buf: an char array
2938 *
2939 * Write the content of the array in the output I/O buffer
2940 * This routine handle the I18N transcoding from internal UTF-8
2941 * The buffer is lossless, i.e. will store in case of partial
2942 * or delayed writes.
2943 *
2944 * Returns the number of chars immediately written, or -1
2945 * in case of error.
2946 */
2947int
2948xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
2949 int nbchars = 0; /* number of chars to output to I/O */
2950 int ret; /* return from function call */
2951 int written = 0; /* number of char written to I/O so far */
2952 int chunk; /* number of byte curreent processed from buf */
2953
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002954 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002955 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002956 if (out->error) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002957
2958 do {
2959 chunk = len;
2960 if (chunk > 4 * MINLEN)
2961 chunk = 4 * MINLEN;
2962
2963 /*
2964 * first handle encoding stuff.
2965 */
2966 if (out->encoder != NULL) {
2967 /*
2968 * Store the data in the incoming raw buffer
2969 */
2970 if (out->conv == NULL) {
2971 out->conv = xmlBufferCreate();
2972 }
William M. Bracka3215c72004-07-31 16:24:01 +00002973 ret = xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2974 if (ret != 0)
2975 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002976
2977 if ((out->buffer->use < MINLEN) && (chunk == len))
2978 goto done;
2979
2980 /*
2981 * convert as much as possible to the parser reading buffer.
2982 */
2983 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
Daniel Veillard809faa52003-02-10 15:43:53 +00002984 if ((ret < 0) && (ret != -3)) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002985 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002986 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002987 return(-1);
2988 }
2989 nbchars = out->conv->use;
2990 } else {
William M. Bracka3215c72004-07-31 16:24:01 +00002991 ret = xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2992 if (ret != 0)
2993 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002994 nbchars = out->buffer->use;
2995 }
2996 buf += chunk;
2997 len -= chunk;
2998
2999 if ((nbchars < MINLEN) && (len <= 0))
3000 goto done;
3001
3002 if (out->writecallback) {
3003 /*
3004 * second write the stuff to the I/O channel
3005 */
3006 if (out->encoder != NULL) {
3007 ret = out->writecallback(out->context,
3008 (const char *)out->conv->content, nbchars);
3009 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00003010 xmlBufferShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003011 } else {
3012 ret = out->writecallback(out->context,
3013 (const char *)out->buffer->content, nbchars);
3014 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00003015 xmlBufferShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003016 }
3017 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003018 xmlIOErr(XML_IO_WRITE, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003019 out->error = XML_IO_WRITE;
Owen Taylor3473f882001-02-23 17:55:21 +00003020 return(ret);
3021 }
3022 out->written += ret;
3023 }
3024 written += nbchars;
3025 } while (len > 0);
3026
3027done:
3028#ifdef DEBUG_INPUT
3029 xmlGenericError(xmlGenericErrorContext,
3030 "I/O: wrote %d chars\n", written);
3031#endif
3032 return(written);
3033}
3034
3035/**
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003036 * xmlEscapeContent:
3037 * @out: a pointer to an array of bytes to store the result
3038 * @outlen: the length of @out
3039 * @in: a pointer to an array of unescaped UTF-8 bytes
3040 * @inlen: the length of @in
3041 *
3042 * Take a block of UTF-8 chars in and escape them.
3043 * Returns 0 if success, or -1 otherwise
3044 * The value of @inlen after return is the number of octets consumed
3045 * if the return value is positive, else unpredictable.
3046 * The value of @outlen after return is the number of octets consumed.
3047 */
3048static int
3049xmlEscapeContent(unsigned char* out, int *outlen,
3050 const xmlChar* in, int *inlen) {
3051 unsigned char* outstart = out;
3052 const unsigned char* base = in;
3053 unsigned char* outend = out + *outlen;
3054 const unsigned char* inend;
3055
3056 inend = in + (*inlen);
3057
3058 while ((in < inend) && (out < outend)) {
3059 if (*in == '<') {
3060 if (outend - out < 4) break;
3061 *out++ = '&';
3062 *out++ = 'l';
3063 *out++ = 't';
3064 *out++ = ';';
3065 } else if (*in == '>') {
3066 if (outend - out < 4) break;
3067 *out++ = '&';
3068 *out++ = 'g';
3069 *out++ = 't';
3070 *out++ = ';';
3071 } else if (*in == '&') {
3072 if (outend - out < 5) break;
3073 *out++ = '&';
3074 *out++ = 'a';
3075 *out++ = 'm';
3076 *out++ = 'p';
3077 *out++ = ';';
3078 } else if (*in == '\r') {
3079 if (outend - out < 5) break;
3080 *out++ = '&';
3081 *out++ = '#';
3082 *out++ = '1';
3083 *out++ = '3';
3084 *out++ = ';';
3085 } else {
3086 *out++ = (unsigned char) *in;
3087 }
3088 ++in;
3089 }
3090 *outlen = out - outstart;
3091 *inlen = in - base;
3092 return(0);
3093}
3094
3095/**
3096 * xmlOutputBufferWriteEscape:
3097 * @out: a buffered parser output
3098 * @str: a zero terminated UTF-8 string
Daniel Veillardee8960b2004-05-14 03:25:14 +00003099 * @escaping: an optional escaping function (or NULL)
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003100 *
3101 * Write the content of the string in the output I/O buffer
3102 * This routine escapes the caracters and then handle the I18N
3103 * transcoding from internal UTF-8
3104 * The buffer is lossless, i.e. will store in case of partial
3105 * or delayed writes.
3106 *
3107 * Returns the number of chars immediately written, or -1
3108 * in case of error.
3109 */
3110int
Daniel Veillardee8960b2004-05-14 03:25:14 +00003111xmlOutputBufferWriteEscape(xmlOutputBufferPtr out, const xmlChar *str,
3112 xmlCharEncodingOutputFunc escaping) {
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003113 int nbchars = 0; /* number of chars to output to I/O */
3114 int ret; /* return from function call */
3115 int written = 0; /* number of char written to I/O so far */
Daniel Veillard71b95632004-08-31 12:15:36 +00003116 int oldwritten=0;/* loop guard */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003117 int chunk; /* number of byte currently processed from str */
3118 int len; /* number of bytes in str */
3119 int cons; /* byte from str consumed */
3120
Daniel Veillardce244ad2004-11-05 10:03:46 +00003121 if ((out == NULL) || (out->error) || (str == NULL) ||
3122 (out->buffer == NULL) ||
3123 (out->buffer->alloc == XML_BUFFER_ALLOC_IMMUTABLE)) return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003124 len = strlen((const char *)str);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003125 if (len < 0) return(0);
3126 if (out->error) return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003127 if (escaping == NULL) escaping = xmlEscapeContent;
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003128
3129 do {
Daniel Veillard71b95632004-08-31 12:15:36 +00003130 oldwritten = written;
3131
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003132 /*
3133 * how many bytes to consume and how many bytes to store.
3134 */
3135 cons = len;
3136 chunk = (out->buffer->size - out->buffer->use) - 1;
3137
3138 /*
3139 * first handle encoding stuff.
3140 */
3141 if (out->encoder != NULL) {
3142 /*
3143 * Store the data in the incoming raw buffer
3144 */
3145 if (out->conv == NULL) {
3146 out->conv = xmlBufferCreate();
3147 }
Daniel Veillardee8960b2004-05-14 03:25:14 +00003148 ret = escaping(out->buffer->content + out->buffer->use ,
3149 &chunk, str, &cons);
William M. Brack66e40b12004-11-26 15:45:19 +00003150 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003151 return(-1);
3152 out->buffer->use += chunk;
3153 out->buffer->content[out->buffer->use] = 0;
3154
3155 if ((out->buffer->use < MINLEN) && (cons == len))
3156 goto done;
3157
3158 /*
3159 * convert as much as possible to the output buffer.
3160 */
3161 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
3162 if ((ret < 0) && (ret != -3)) {
3163 xmlIOErr(XML_IO_ENCODER, NULL);
3164 out->error = XML_IO_ENCODER;
3165 return(-1);
3166 }
3167 nbchars = out->conv->use;
3168 } else {
Daniel Veillardee8960b2004-05-14 03:25:14 +00003169 ret = escaping(out->buffer->content + out->buffer->use ,
3170 &chunk, str, &cons);
William M. Brack66e40b12004-11-26 15:45:19 +00003171 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003172 return(-1);
3173 out->buffer->use += chunk;
3174 out->buffer->content[out->buffer->use] = 0;
3175 nbchars = out->buffer->use;
3176 }
3177 str += cons;
3178 len -= cons;
3179
3180 if ((nbchars < MINLEN) && (len <= 0))
3181 goto done;
3182
3183 if (out->writecallback) {
3184 /*
3185 * second write the stuff to the I/O channel
3186 */
3187 if (out->encoder != NULL) {
3188 ret = out->writecallback(out->context,
3189 (const char *)out->conv->content, nbchars);
3190 if (ret >= 0)
3191 xmlBufferShrink(out->conv, ret);
3192 } else {
3193 ret = out->writecallback(out->context,
3194 (const char *)out->buffer->content, nbchars);
3195 if (ret >= 0)
3196 xmlBufferShrink(out->buffer, ret);
3197 }
3198 if (ret < 0) {
3199 xmlIOErr(XML_IO_WRITE, NULL);
3200 out->error = XML_IO_WRITE;
3201 return(ret);
3202 }
3203 out->written += ret;
Daniel Veillard83a75e02004-05-14 21:50:42 +00003204 } else if (out->buffer->size - out->buffer->use < MINLEN) {
3205 xmlBufferResize(out->buffer, out->buffer->size + MINLEN);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003206 }
3207 written += nbchars;
Daniel Veillard71b95632004-08-31 12:15:36 +00003208 } while ((len > 0) && (oldwritten != written));
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003209
3210done:
3211#ifdef DEBUG_INPUT
3212 xmlGenericError(xmlGenericErrorContext,
3213 "I/O: wrote %d chars\n", written);
3214#endif
3215 return(written);
3216}
3217
3218/**
Owen Taylor3473f882001-02-23 17:55:21 +00003219 * xmlOutputBufferWriteString:
3220 * @out: a buffered parser output
3221 * @str: a zero terminated C string
3222 *
3223 * Write the content of the string in the output I/O buffer
3224 * This routine handle the I18N transcoding from internal UTF-8
3225 * The buffer is lossless, i.e. will store in case of partial
3226 * or delayed writes.
3227 *
3228 * Returns the number of chars immediately written, or -1
3229 * in case of error.
3230 */
3231int
3232xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
3233 int len;
3234
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003235 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003236 if (str == NULL)
3237 return(-1);
3238 len = strlen(str);
3239
3240 if (len > 0)
3241 return(xmlOutputBufferWrite(out, len, str));
3242 return(len);
3243}
3244
3245/**
3246 * xmlOutputBufferFlush:
3247 * @out: a buffered output
3248 *
3249 * flushes the output I/O channel
3250 *
3251 * Returns the number of byte written or -1 in case of error.
3252 */
3253int
3254xmlOutputBufferFlush(xmlOutputBufferPtr out) {
3255 int nbchars = 0, ret = 0;
3256
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003257 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003258 /*
3259 * first handle encoding stuff.
3260 */
3261 if ((out->conv != NULL) && (out->encoder != NULL)) {
3262 /*
3263 * convert as much as possible to the parser reading buffer.
3264 */
3265 nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
3266 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003267 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003268 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003269 return(-1);
3270 }
3271 }
3272
3273 /*
3274 * second flush the stuff to the I/O channel
3275 */
3276 if ((out->conv != NULL) && (out->encoder != NULL) &&
3277 (out->writecallback != NULL)) {
3278 ret = out->writecallback(out->context,
3279 (const char *)out->conv->content, out->conv->use);
3280 if (ret >= 0)
3281 xmlBufferShrink(out->conv, ret);
3282 } else if (out->writecallback != NULL) {
3283 ret = out->writecallback(out->context,
3284 (const char *)out->buffer->content, out->buffer->use);
3285 if (ret >= 0)
3286 xmlBufferShrink(out->buffer, ret);
3287 }
3288 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003289 xmlIOErr(XML_IO_FLUSH, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003290 out->error = XML_IO_FLUSH;
Owen Taylor3473f882001-02-23 17:55:21 +00003291 return(ret);
3292 }
3293 out->written += ret;
3294
3295#ifdef DEBUG_INPUT
3296 xmlGenericError(xmlGenericErrorContext,
3297 "I/O: flushed %d chars\n", ret);
3298#endif
3299 return(ret);
3300}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003301#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003302
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003303/**
Owen Taylor3473f882001-02-23 17:55:21 +00003304 * xmlParserGetDirectory:
3305 * @filename: the path to a file
3306 *
3307 * lookup the directory for that file
3308 *
3309 * Returns a new allocated string containing the directory, or NULL.
3310 */
3311char *
3312xmlParserGetDirectory(const char *filename) {
3313 char *ret = NULL;
3314 char dir[1024];
3315 char *cur;
3316 char sep = '/';
3317
Igor Zlatkovic9181cc02002-09-29 17:51:06 +00003318#ifdef _WIN32_WCE /* easy way by now ... wince does not have dirs! */
3319 return NULL;
3320#endif
3321
Owen Taylor3473f882001-02-23 17:55:21 +00003322 if (xmlInputCallbackInitialized == 0)
3323 xmlRegisterDefaultInputCallbacks();
3324
3325 if (filename == NULL) return(NULL);
Daniel Veillard3c5ed912002-01-08 10:36:16 +00003326#if defined(WIN32) && !defined(__CYGWIN__)
Owen Taylor3473f882001-02-23 17:55:21 +00003327 sep = '\\';
3328#endif
3329
3330 strncpy(dir, filename, 1023);
3331 dir[1023] = 0;
3332 cur = &dir[strlen(dir)];
3333 while (cur > dir) {
3334 if (*cur == sep) break;
3335 cur --;
3336 }
3337 if (*cur == sep) {
3338 if (cur == dir) dir[1] = 0;
3339 else *cur = 0;
3340 ret = xmlMemStrdup(dir);
3341 } else {
3342 if (getcwd(dir, 1024) != NULL) {
3343 dir[1023] = 0;
3344 ret = xmlMemStrdup(dir);
3345 }
3346 }
3347 return(ret);
3348}
3349
3350/****************************************************************
3351 * *
3352 * External entities loading *
3353 * *
3354 ****************************************************************/
3355
Daniel Veillarda840b692003-10-19 13:35:37 +00003356/**
3357 * xmlCheckHTTPInput:
3358 * @ctxt: an XML parser context
3359 * @ret: an XML parser input
3360 *
3361 * Check an input in case it was created from an HTTP stream, in that
3362 * case it will handle encoding and update of the base URL in case of
3363 * redirection. It also checks for HTTP errors in which case the input
3364 * is cleanly freed up and an appropriate error is raised in context
3365 *
3366 * Returns the input or NULL in case of HTTP error.
3367 */
3368xmlParserInputPtr
3369xmlCheckHTTPInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr ret) {
3370#ifdef LIBXML_HTTP_ENABLED
3371 if ((ret != NULL) && (ret->buf != NULL) &&
3372 (ret->buf->readcallback == xmlIOHTTPRead) &&
3373 (ret->buf->context != NULL)) {
3374 const char *encoding;
3375 const char *redir;
3376 const char *mime;
3377 int code;
3378
3379 code = xmlNanoHTTPReturnCode(ret->buf->context);
3380 if (code >= 400) {
3381 /* fatal error */
3382 if (ret->filename != NULL)
Daniel Veillarde8039df2003-10-27 11:25:13 +00003383 __xmlLoaderErr(ctxt, "failed to load HTTP resource \"%s\"\n",
Daniel Veillarda840b692003-10-19 13:35:37 +00003384 (const char *) ret->filename);
3385 else
Daniel Veillarde8039df2003-10-27 11:25:13 +00003386 __xmlLoaderErr(ctxt, "failed to load HTTP resource\n", NULL);
Daniel Veillarda840b692003-10-19 13:35:37 +00003387 xmlFreeInputStream(ret);
3388 ret = NULL;
3389 } else {
3390
3391 mime = xmlNanoHTTPMimeType(ret->buf->context);
3392 if ((xmlStrstr(BAD_CAST mime, BAD_CAST "/xml")) ||
3393 (xmlStrstr(BAD_CAST mime, BAD_CAST "+xml"))) {
3394 encoding = xmlNanoHTTPEncoding(ret->buf->context);
3395 if (encoding != NULL) {
3396 xmlCharEncodingHandlerPtr handler;
3397
3398 handler = xmlFindCharEncodingHandler(encoding);
3399 if (handler != NULL) {
3400 xmlSwitchInputEncoding(ctxt, ret, handler);
3401 } else {
3402 __xmlErrEncoding(ctxt, XML_ERR_UNKNOWN_ENCODING,
3403 "Unknown encoding %s",
3404 BAD_CAST encoding, NULL);
3405 }
3406 if (ret->encoding == NULL)
3407 ret->encoding = xmlStrdup(BAD_CAST encoding);
3408 }
3409#if 0
3410 } else if (xmlStrstr(BAD_CAST mime, BAD_CAST "html")) {
3411#endif
3412 }
3413 redir = xmlNanoHTTPRedir(ret->buf->context);
3414 if (redir != NULL) {
3415 if (ret->filename != NULL)
3416 xmlFree((xmlChar *) ret->filename);
3417 if (ret->directory != NULL) {
3418 xmlFree((xmlChar *) ret->directory);
3419 ret->directory = NULL;
3420 }
3421 ret->filename =
3422 (char *) xmlStrdup((const xmlChar *) redir);
3423 }
3424 }
3425 }
3426#endif
3427 return(ret);
3428}
3429
Daniel Veillard561b7f82002-03-20 21:55:57 +00003430static int xmlSysIDExists(const char *URL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003431#ifdef HAVE_STAT
3432 int ret;
3433 struct stat info;
3434 const char *path;
3435
3436 if (URL == NULL)
3437 return(0);
3438
Daniel Veillardf4862f02002-09-10 11:13:43 +00003439 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003440#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00003441 path = &URL[17];
3442#else
Daniel Veillard6990bf32001-08-23 21:17:48 +00003443 path = &URL[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00003444#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003445 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003446#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard6990bf32001-08-23 21:17:48 +00003447 path = &URL[8];
3448#else
3449 path = &URL[7];
3450#endif
3451 } else
3452 path = URL;
3453 ret = stat(path, &info);
Daniel Veillard561b7f82002-03-20 21:55:57 +00003454 if (ret == 0)
3455 return(1);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003456#endif
Daniel Veillard561b7f82002-03-20 21:55:57 +00003457 return(0);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003458}
Daniel Veillard6990bf32001-08-23 21:17:48 +00003459
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003460/**
Owen Taylor3473f882001-02-23 17:55:21 +00003461 * xmlDefaultExternalEntityLoader:
3462 * @URL: the URL for the entity to load
3463 * @ID: the System ID for the entity to load
3464 * @ctxt: the context in which the entity is called or NULL
3465 *
3466 * By default we don't load external entitites, yet.
3467 *
3468 * Returns a new allocated xmlParserInputPtr, or NULL.
3469 */
Daniel Veillarda840b692003-10-19 13:35:37 +00003470static xmlParserInputPtr
Owen Taylor3473f882001-02-23 17:55:21 +00003471xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
Daniel Veillarda840b692003-10-19 13:35:37 +00003472 xmlParserCtxtPtr ctxt)
3473{
Owen Taylor3473f882001-02-23 17:55:21 +00003474 xmlParserInputPtr ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003475 xmlChar *resource = NULL;
Daniel Veillarda840b692003-10-19 13:35:37 +00003476
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003477#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003478 xmlCatalogAllow pref;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003479#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003480
3481#ifdef DEBUG_EXTERNAL_ENTITIES
3482 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda840b692003-10-19 13:35:37 +00003483 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00003484#endif
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003485#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillard61b93382003-11-03 14:28:31 +00003486 if ((ctxt != NULL) && (ctxt->options & XML_PARSE_NONET)) {
3487 int options = ctxt->options;
3488
3489 ctxt->options -= XML_PARSE_NONET;
3490 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
3491 ctxt->options = options;
3492 return(ret);
3493 }
3494
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003495 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003496 * If the resource doesn't exists as a file,
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003497 * try to load it from the resource pointed in the catalogs
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003498 */
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003499 pref = xmlCatalogGetDefaults();
3500
Daniel Veillard561b7f82002-03-20 21:55:57 +00003501 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlSysIDExists(URL))) {
Daniel Veillarda840b692003-10-19 13:35:37 +00003502 /*
3503 * Do a local lookup
3504 */
Daniel Veillard42595322004-11-08 10:52:06 +00003505 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
Daniel Veillarda840b692003-10-19 13:35:37 +00003506 ((pref == XML_CATA_ALLOW_ALL) ||
3507 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3508 resource = xmlCatalogLocalResolve(ctxt->catalogs,
3509 (const xmlChar *) ID,
3510 (const xmlChar *) URL);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003511 }
Daniel Veillarda840b692003-10-19 13:35:37 +00003512 /*
3513 * Try a global lookup
3514 */
3515 if ((resource == NULL) &&
3516 ((pref == XML_CATA_ALLOW_ALL) ||
3517 (pref == XML_CATA_ALLOW_GLOBAL))) {
3518 resource = xmlCatalogResolve((const xmlChar *) ID,
3519 (const xmlChar *) URL);
3520 }
3521 if ((resource == NULL) && (URL != NULL))
3522 resource = xmlStrdup((const xmlChar *) URL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003523
Daniel Veillarda840b692003-10-19 13:35:37 +00003524 /*
3525 * TODO: do an URI lookup on the reference
3526 */
3527 if ((resource != NULL)
3528 && (!xmlSysIDExists((const char *) resource))) {
3529 xmlChar *tmp = NULL;
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003530
Daniel Veillard42595322004-11-08 10:52:06 +00003531 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
Daniel Veillarda840b692003-10-19 13:35:37 +00003532 ((pref == XML_CATA_ALLOW_ALL) ||
3533 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3534 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
3535 }
3536 if ((tmp == NULL) &&
3537 ((pref == XML_CATA_ALLOW_ALL) ||
3538 (pref == XML_CATA_ALLOW_GLOBAL))) {
3539 tmp = xmlCatalogResolveURI(resource);
3540 }
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003541
Daniel Veillarda840b692003-10-19 13:35:37 +00003542 if (tmp != NULL) {
3543 xmlFree(resource);
3544 resource = tmp;
3545 }
3546 }
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003547 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003548#endif
3549
3550 if (resource == NULL)
Daniel Veillarda840b692003-10-19 13:35:37 +00003551 resource = (xmlChar *) URL;
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003552
3553 if (resource == NULL) {
Daniel Veillarda840b692003-10-19 13:35:37 +00003554 if (ID == NULL)
3555 ID = "NULL";
Daniel Veillarde8039df2003-10-27 11:25:13 +00003556 __xmlLoaderErr(ctxt, "failed to load external entity \"%s\"\n", ID);
Daniel Veillarda840b692003-10-19 13:35:37 +00003557 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003558 }
Daniel Veillarda840b692003-10-19 13:35:37 +00003559 ret = xmlNewInputFromFile(ctxt, (const char *) resource);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003560 if ((resource != NULL) && (resource != (xmlChar *) URL))
Daniel Veillarda840b692003-10-19 13:35:37 +00003561 xmlFree(resource);
3562 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003563}
3564
3565static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
3566 xmlDefaultExternalEntityLoader;
3567
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003568/**
Owen Taylor3473f882001-02-23 17:55:21 +00003569 * xmlSetExternalEntityLoader:
3570 * @f: the new entity resolver function
3571 *
3572 * Changes the defaultexternal entity resolver function for the application
3573 */
3574void
3575xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
3576 xmlCurrentExternalEntityLoader = f;
3577}
3578
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003579/**
Owen Taylor3473f882001-02-23 17:55:21 +00003580 * xmlGetExternalEntityLoader:
3581 *
3582 * Get the default external entity resolver function for the application
3583 *
3584 * Returns the xmlExternalEntityLoader function pointer
3585 */
3586xmlExternalEntityLoader
3587xmlGetExternalEntityLoader(void) {
3588 return(xmlCurrentExternalEntityLoader);
3589}
3590
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003591/**
Owen Taylor3473f882001-02-23 17:55:21 +00003592 * xmlLoadExternalEntity:
3593 * @URL: the URL for the entity to load
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00003594 * @ID: the Public ID for the entity to load
Owen Taylor3473f882001-02-23 17:55:21 +00003595 * @ctxt: the context in which the entity is called or NULL
3596 *
3597 * Load an external entity, note that the use of this function for
3598 * unparsed entities may generate problems
Owen Taylor3473f882001-02-23 17:55:21 +00003599 *
3600 * Returns the xmlParserInputPtr or NULL
3601 */
3602xmlParserInputPtr
3603xmlLoadExternalEntity(const char *URL, const char *ID,
3604 xmlParserCtxtPtr ctxt) {
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00003605 if ((URL != NULL) && (xmlSysIDExists(URL) == 0)) {
3606 char *canonicFilename;
3607 xmlParserInputPtr ret;
3608
3609 canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL);
3610 if (canonicFilename == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003611 xmlIOErrMemory("building canonical path\n");
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00003612 return(NULL);
3613 }
3614
3615 ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt);
3616 xmlFree(canonicFilename);
3617 return(ret);
3618 }
Owen Taylor3473f882001-02-23 17:55:21 +00003619 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
3620}
3621
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003622/************************************************************************
3623 * *
3624 * Disabling Network access *
3625 * *
3626 ************************************************************************/
3627
3628#ifdef LIBXML_CATALOG_ENABLED
3629static int
3630xmlNoNetExists(const char *URL)
3631{
3632#ifdef HAVE_STAT
3633 int ret;
3634 struct stat info;
3635 const char *path;
3636
3637 if (URL == NULL)
3638 return (0);
3639
Daniel Veillardf4862f02002-09-10 11:13:43 +00003640 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003641#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00003642 path = &URL[17];
3643#else
3644 path = &URL[16];
3645#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003646 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003647#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003648 path = &URL[8];
3649#else
3650 path = &URL[7];
3651#endif
3652 } else
3653 path = URL;
3654 ret = stat(path, &info);
3655 if (ret == 0)
3656 return (1);
3657#endif
3658 return (0);
3659}
3660#endif
3661
3662/**
3663 * xmlNoNetExternalEntityLoader:
3664 * @URL: the URL for the entity to load
3665 * @ID: the System ID for the entity to load
3666 * @ctxt: the context in which the entity is called or NULL
3667 *
3668 * A specific entity loader disabling network accesses, though still
3669 * allowing local catalog accesses for resolution.
3670 *
3671 * Returns a new allocated xmlParserInputPtr, or NULL.
3672 */
3673xmlParserInputPtr
3674xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
3675 xmlParserCtxtPtr ctxt) {
3676 xmlParserInputPtr input = NULL;
3677 xmlChar *resource = NULL;
3678
3679#ifdef LIBXML_CATALOG_ENABLED
3680 xmlCatalogAllow pref;
3681
3682 /*
3683 * If the resource doesn't exists as a file,
3684 * try to load it from the resource pointed in the catalogs
3685 */
3686 pref = xmlCatalogGetDefaults();
3687
3688 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
3689 /*
3690 * Do a local lookup
3691 */
Daniel Veillard42595322004-11-08 10:52:06 +00003692 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003693 ((pref == XML_CATA_ALLOW_ALL) ||
3694 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3695 resource = xmlCatalogLocalResolve(ctxt->catalogs,
3696 (const xmlChar *)ID,
3697 (const xmlChar *)URL);
3698 }
3699 /*
3700 * Try a global lookup
3701 */
3702 if ((resource == NULL) &&
3703 ((pref == XML_CATA_ALLOW_ALL) ||
3704 (pref == XML_CATA_ALLOW_GLOBAL))) {
3705 resource = xmlCatalogResolve((const xmlChar *)ID,
3706 (const xmlChar *)URL);
3707 }
3708 if ((resource == NULL) && (URL != NULL))
3709 resource = xmlStrdup((const xmlChar *) URL);
3710
3711 /*
3712 * TODO: do an URI lookup on the reference
3713 */
3714 if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
3715 xmlChar *tmp = NULL;
3716
Daniel Veillard42595322004-11-08 10:52:06 +00003717 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003718 ((pref == XML_CATA_ALLOW_ALL) ||
3719 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3720 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
3721 }
3722 if ((tmp == NULL) &&
3723 ((pref == XML_CATA_ALLOW_ALL) ||
3724 (pref == XML_CATA_ALLOW_GLOBAL))) {
3725 tmp = xmlCatalogResolveURI(resource);
3726 }
3727
3728 if (tmp != NULL) {
3729 xmlFree(resource);
3730 resource = tmp;
3731 }
3732 }
3733 }
3734#endif
3735 if (resource == NULL)
3736 resource = (xmlChar *) URL;
3737
3738 if (resource != NULL) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003739 if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
3740 (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003741 xmlIOErr(XML_IO_NETWORK_ATTEMPT, (const char *) resource);
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003742 if (resource != (xmlChar *) URL)
3743 xmlFree(resource);
3744 return(NULL);
3745 }
3746 }
3747 input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
3748 if (resource != (xmlChar *) URL)
3749 xmlFree(resource);
3750 return(input);
3751}
3752
Daniel Veillard5d4644e2005-04-01 13:11:58 +00003753#define bottom_xmlIO
3754#include "elfgcchack.h"