blob: 9e302aee5c091d4908e051b5d3f4275c26f25c63 [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
2493 ret = xmlAllocOutputBuffer(encoder);
2494 if (ret != NULL) {
2495 ret->context = buffer;
2496 ret->writecallback = xmlBufferWrite;
2497 ret->closecallback = xmlBufferClose;
2498 }
2499
2500 return(ret);
2501}
2502
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002503#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002504
2505/**
2506 * xmlParserInputBufferCreateFd:
2507 * @fd: a file descriptor number
2508 * @enc: the charset encoding if known
2509 *
2510 * Create a buffered parser input for the progressive parsing for the input
2511 * from a file descriptor
2512 *
2513 * Returns the new parser input or NULL
2514 */
2515xmlParserInputBufferPtr
2516xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
2517 xmlParserInputBufferPtr ret;
2518
2519 if (fd < 0) return(NULL);
2520
2521 ret = xmlAllocParserInputBuffer(enc);
2522 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002523 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002524 ret->readcallback = xmlFdRead;
2525 ret->closecallback = xmlFdClose;
2526 }
2527
2528 return(ret);
2529}
2530
2531/**
2532 * xmlParserInputBufferCreateMem:
2533 * @mem: the memory input
2534 * @size: the length of the memory block
2535 * @enc: the charset encoding if known
2536 *
2537 * Create a buffered parser input for the progressive parsing for the input
2538 * from a memory area.
2539 *
2540 * Returns the new parser input or NULL
2541 */
2542xmlParserInputBufferPtr
2543xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
2544 xmlParserInputBufferPtr ret;
William M. Bracka3215c72004-07-31 16:24:01 +00002545 int errcode;
Owen Taylor3473f882001-02-23 17:55:21 +00002546
2547 if (size <= 0) return(NULL);
2548 if (mem == NULL) return(NULL);
2549
2550 ret = xmlAllocParserInputBuffer(enc);
2551 if (ret != NULL) {
2552 ret->context = (void *) mem;
2553 ret->readcallback = (xmlInputReadCallback) xmlNop;
2554 ret->closecallback = NULL;
William M. Bracka3215c72004-07-31 16:24:01 +00002555 errcode = xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size);
2556 if (errcode != 0) {
2557 xmlFree(ret);
2558 return(NULL);
2559 }
Owen Taylor3473f882001-02-23 17:55:21 +00002560 }
2561
2562 return(ret);
2563}
2564
2565/**
Daniel Veillard53350552003-09-18 13:35:51 +00002566 * xmlParserInputBufferCreateStatic:
2567 * @mem: the memory input
2568 * @size: the length of the memory block
2569 * @enc: the charset encoding if known
2570 *
2571 * Create a buffered parser input for the progressive parsing for the input
2572 * from an immutable memory area. This will not copy the memory area to
2573 * the buffer, but the memory is expected to be available until the end of
2574 * the parsing, this is useful for example when using mmap'ed file.
2575 *
2576 * Returns the new parser input or NULL
2577 */
2578xmlParserInputBufferPtr
2579xmlParserInputBufferCreateStatic(const char *mem, int size,
2580 xmlCharEncoding enc) {
2581 xmlParserInputBufferPtr ret;
2582
2583 if (size <= 0) return(NULL);
2584 if (mem == NULL) return(NULL);
2585
2586 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2587 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002588 xmlIOErrMemory("creating input buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00002589 return(NULL);
2590 }
2591 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillarde72c5082003-09-19 12:44:05 +00002592 ret->buffer = xmlBufferCreateStatic((void *)mem, (size_t) size);
Daniel Veillard53350552003-09-18 13:35:51 +00002593 if (ret->buffer == NULL) {
2594 xmlFree(ret);
2595 return(NULL);
2596 }
2597 ret->encoder = xmlGetCharEncodingHandler(enc);
2598 if (ret->encoder != NULL)
2599 ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
2600 else
2601 ret->raw = NULL;
2602 ret->compressed = -1;
2603 ret->context = (void *) mem;
2604 ret->readcallback = NULL;
2605 ret->closecallback = NULL;
2606
2607 return(ret);
2608}
2609
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002610#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard53350552003-09-18 13:35:51 +00002611/**
Owen Taylor3473f882001-02-23 17:55:21 +00002612 * xmlOutputBufferCreateFd:
2613 * @fd: a file descriptor number
2614 * @encoder: the encoding converter or NULL
2615 *
2616 * Create a buffered output for the progressive saving
2617 * to a file descriptor
2618 *
2619 * Returns the new parser output or NULL
2620 */
2621xmlOutputBufferPtr
2622xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
2623 xmlOutputBufferPtr ret;
2624
2625 if (fd < 0) return(NULL);
2626
2627 ret = xmlAllocOutputBuffer(encoder);
2628 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002629 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002630 ret->writecallback = xmlFdWrite;
Daniel Veillard7db38712002-02-07 16:39:11 +00002631 ret->closecallback = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002632 }
2633
2634 return(ret);
2635}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002636#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002637
2638/**
2639 * xmlParserInputBufferCreateIO:
2640 * @ioread: an I/O read function
2641 * @ioclose: an I/O close function
2642 * @ioctx: an I/O handler
2643 * @enc: the charset encoding if known
2644 *
2645 * Create a buffered parser input for the progressive parsing for the input
2646 * from an I/O handler
2647 *
2648 * Returns the new parser input or NULL
2649 */
2650xmlParserInputBufferPtr
2651xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
2652 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
2653 xmlParserInputBufferPtr ret;
2654
2655 if (ioread == NULL) return(NULL);
2656
2657 ret = xmlAllocParserInputBuffer(enc);
2658 if (ret != NULL) {
2659 ret->context = (void *) ioctx;
2660 ret->readcallback = ioread;
2661 ret->closecallback = ioclose;
2662 }
2663
2664 return(ret);
2665}
2666
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002667#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002668/**
2669 * xmlOutputBufferCreateIO:
2670 * @iowrite: an I/O write function
2671 * @ioclose: an I/O close function
2672 * @ioctx: an I/O handler
Daniel Veillard9d06d302002-01-22 18:15:52 +00002673 * @encoder: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002674 *
2675 * Create a buffered output for the progressive saving
2676 * to an I/O handler
2677 *
2678 * Returns the new parser output or NULL
2679 */
2680xmlOutputBufferPtr
2681xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
2682 xmlOutputCloseCallback ioclose, void *ioctx,
2683 xmlCharEncodingHandlerPtr encoder) {
2684 xmlOutputBufferPtr ret;
2685
2686 if (iowrite == NULL) return(NULL);
2687
2688 ret = xmlAllocOutputBuffer(encoder);
2689 if (ret != NULL) {
2690 ret->context = (void *) ioctx;
2691 ret->writecallback = iowrite;
2692 ret->closecallback = ioclose;
2693 }
2694
2695 return(ret);
2696}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002697#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002698
2699/**
Daniel Veillard1b243b42004-06-08 10:16:42 +00002700 * xmlParserInputBufferCreateFilenameDefault:
2701 * @func: function pointer to the new ParserInputBufferCreateFilenameFunc
2702 *
2703 * Registers a callback for URI input file handling
2704 *
2705 * Returns the old value of the registration function
2706 */
2707xmlParserInputBufferCreateFilenameFunc
2708xmlParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func)
2709{
2710 xmlParserInputBufferCreateFilenameFunc old = xmlParserInputBufferCreateFilenameValue;
2711 if (old == NULL) {
2712 old = __xmlParserInputBufferCreateFilename;
2713 }
2714
2715 xmlParserInputBufferCreateFilenameValue = func;
2716 return(old);
2717}
2718
2719/**
2720 * xmlOutputBufferCreateFilenameDefault:
2721 * @func: function pointer to the new OutputBufferCreateFilenameFunc
2722 *
2723 * Registers a callback for URI output file handling
2724 *
2725 * Returns the old value of the registration function
2726 */
2727xmlOutputBufferCreateFilenameFunc
2728xmlOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func)
2729{
2730 xmlOutputBufferCreateFilenameFunc old = xmlOutputBufferCreateFilenameValue;
2731#ifdef LIBXML_OUTPUT_ENABLED
2732 if (old == NULL) {
2733 old = __xmlOutputBufferCreateFilename;
2734 }
2735#endif
2736 xmlOutputBufferCreateFilenameValue = func;
2737 return(old);
2738}
2739
2740/**
Owen Taylor3473f882001-02-23 17:55:21 +00002741 * xmlParserInputBufferPush:
2742 * @in: a buffered parser input
2743 * @len: the size in bytes of the array.
2744 * @buf: an char array
2745 *
2746 * Push the content of the arry in the input buffer
2747 * This routine handle the I18N transcoding to internal UTF-8
2748 * This is used when operating the parser in progressive (push) mode.
2749 *
2750 * Returns the number of chars read and stored in the buffer, or -1
2751 * in case of error.
2752 */
2753int
2754xmlParserInputBufferPush(xmlParserInputBufferPtr in,
2755 int len, const char *buf) {
2756 int nbchars = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00002757 int ret;
Owen Taylor3473f882001-02-23 17:55:21 +00002758
2759 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002760 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002761 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00002762 unsigned int use;
2763
Owen Taylor3473f882001-02-23 17:55:21 +00002764 /*
2765 * Store the data in the incoming raw buffer
2766 */
2767 if (in->raw == NULL) {
2768 in->raw = xmlBufferCreate();
2769 }
William M. Bracka3215c72004-07-31 16:24:01 +00002770 ret = xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
2771 if (ret != 0)
2772 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002773
2774 /*
2775 * convert as much as possible to the parser reading buffer.
2776 */
Daniel Veillard36711902004-02-11 13:25:26 +00002777 use = in->raw->use;
Owen Taylor3473f882001-02-23 17:55:21 +00002778 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2779 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002780 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002781 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002782 return(-1);
2783 }
Daniel Veillard36711902004-02-11 13:25:26 +00002784 in->rawconsumed += (use - in->raw->use);
Owen Taylor3473f882001-02-23 17:55:21 +00002785 } else {
2786 nbchars = len;
William M. Bracka3215c72004-07-31 16:24:01 +00002787 ret = xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
2788 if (ret != 0)
2789 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002790 }
2791#ifdef DEBUG_INPUT
2792 xmlGenericError(xmlGenericErrorContext,
2793 "I/O: pushed %d chars, buffer %d/%d\n",
2794 nbchars, in->buffer->use, in->buffer->size);
2795#endif
2796 return(nbchars);
2797}
2798
2799/**
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002800 * endOfInput:
2801 *
2802 * When reading from an Input channel indicated end of file or error
2803 * don't reread from it again.
2804 */
2805static int
2806endOfInput (void * context ATTRIBUTE_UNUSED,
2807 char * buffer ATTRIBUTE_UNUSED,
2808 int len ATTRIBUTE_UNUSED) {
2809 return(0);
2810}
2811
2812/**
Owen Taylor3473f882001-02-23 17:55:21 +00002813 * xmlParserInputBufferGrow:
2814 * @in: a buffered parser input
2815 * @len: indicative value of the amount of chars to read
2816 *
2817 * Grow up the content of the input buffer, the old data are preserved
2818 * This routine handle the I18N transcoding to internal UTF-8
2819 * This routine is used when operating the parser in normal (pull) mode
2820 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002821 * TODO: one should be able to remove one extra copy by copying directly
Owen Taylor3473f882001-02-23 17:55:21 +00002822 * onto in->buffer or in->raw
2823 *
2824 * Returns the number of chars read and stored in the buffer, or -1
2825 * in case of error.
2826 */
2827int
2828xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
2829 char *buffer = NULL;
2830 int res = 0;
2831 int nbchars = 0;
2832 int buffree;
Daniel Veillard9e412302002-06-10 15:59:44 +00002833 unsigned int needSize;
Owen Taylor3473f882001-02-23 17:55:21 +00002834
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002835 if ((in == NULL) || (in->error)) return(-1);
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002836 if ((len <= MINLEN) && (len != 4))
Owen Taylor3473f882001-02-23 17:55:21 +00002837 len = MINLEN;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002838
Owen Taylor3473f882001-02-23 17:55:21 +00002839 buffree = in->buffer->size - in->buffer->use;
2840 if (buffree <= 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002841 xmlIOErr(XML_IO_BUFFER_FULL, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002842 in->error = XML_IO_BUFFER_FULL;
William M. Bracka3215c72004-07-31 16:24:01 +00002843 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002844 }
Owen Taylor3473f882001-02-23 17:55:21 +00002845
Daniel Veillarde5354492002-05-16 08:43:22 +00002846 needSize = in->buffer->use + len + 1;
2847 if (needSize > in->buffer->size){
2848 if (!xmlBufferResize(in->buffer, needSize)){
Daniel Veillard05d987b2003-10-08 11:54:57 +00002849 xmlIOErrMemory("growing input buffer");
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002850 in->error = XML_ERR_NO_MEMORY;
William M. Bracka3215c72004-07-31 16:24:01 +00002851 return(-1);
Daniel Veillarde5354492002-05-16 08:43:22 +00002852 }
Owen Taylor3473f882001-02-23 17:55:21 +00002853 }
Daniel Veillarde5354492002-05-16 08:43:22 +00002854 buffer = (char *)&in->buffer->content[in->buffer->use];
Owen Taylor3473f882001-02-23 17:55:21 +00002855
2856 /*
2857 * Call the read method for this I/O type.
2858 */
2859 if (in->readcallback != NULL) {
2860 res = in->readcallback(in->context, &buffer[0], len);
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002861 if (res <= 0)
2862 in->readcallback = endOfInput;
Owen Taylor3473f882001-02-23 17:55:21 +00002863 } else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002864 xmlIOErr(XML_IO_NO_INPUT, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002865 in->error = XML_IO_NO_INPUT;
Owen Taylor3473f882001-02-23 17:55:21 +00002866 return(-1);
2867 }
2868 if (res < 0) {
Owen Taylor3473f882001-02-23 17:55:21 +00002869 return(-1);
2870 }
2871 len = res;
2872 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00002873 unsigned int use;
2874
Owen Taylor3473f882001-02-23 17:55:21 +00002875 /*
2876 * Store the data in the incoming raw buffer
2877 */
2878 if (in->raw == NULL) {
2879 in->raw = xmlBufferCreate();
2880 }
William M. Bracka3215c72004-07-31 16:24:01 +00002881 res = xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
2882 if (res != 0)
2883 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002884
2885 /*
2886 * convert as much as possible to the parser reading buffer.
2887 */
Daniel Veillard36711902004-02-11 13:25:26 +00002888 use = in->raw->use;
Owen Taylor3473f882001-02-23 17:55:21 +00002889 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2890 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002891 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002892 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002893 return(-1);
2894 }
Daniel Veillard36711902004-02-11 13:25:26 +00002895 in->rawconsumed += (use - in->raw->use);
Owen Taylor3473f882001-02-23 17:55:21 +00002896 } else {
2897 nbchars = len;
Daniel Veillarde5354492002-05-16 08:43:22 +00002898 in->buffer->use += nbchars;
2899 buffer[nbchars] = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002900 }
2901#ifdef DEBUG_INPUT
2902 xmlGenericError(xmlGenericErrorContext,
2903 "I/O: read %d chars, buffer %d/%d\n",
2904 nbchars, in->buffer->use, in->buffer->size);
2905#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002906 return(nbchars);
2907}
2908
2909/**
2910 * xmlParserInputBufferRead:
2911 * @in: a buffered parser input
2912 * @len: indicative value of the amount of chars to read
2913 *
2914 * Refresh the content of the input buffer, the old data are considered
2915 * consumed
2916 * This routine handle the I18N transcoding to internal UTF-8
2917 *
2918 * Returns the number of chars read and stored in the buffer, or -1
2919 * in case of error.
2920 */
2921int
2922xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002923 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002924 if (in->readcallback != NULL)
2925 return(xmlParserInputBufferGrow(in, len));
Daniel Veillard53350552003-09-18 13:35:51 +00002926 else if ((in->buffer != NULL) &&
2927 (in->buffer->alloc == XML_BUFFER_ALLOC_IMMUTABLE))
2928 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002929 else
2930 return(-1);
2931}
2932
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002933#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002934/**
2935 * xmlOutputBufferWrite:
2936 * @out: a buffered parser output
2937 * @len: the size in bytes of the array.
2938 * @buf: an char array
2939 *
2940 * Write the content of the array in the output I/O buffer
2941 * This routine handle the I18N transcoding from internal UTF-8
2942 * The buffer is lossless, i.e. will store in case of partial
2943 * or delayed writes.
2944 *
2945 * Returns the number of chars immediately written, or -1
2946 * in case of error.
2947 */
2948int
2949xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
2950 int nbchars = 0; /* number of chars to output to I/O */
2951 int ret; /* return from function call */
2952 int written = 0; /* number of char written to I/O so far */
2953 int chunk; /* number of byte curreent processed from buf */
2954
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002955 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002956 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002957 if (out->error) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002958
2959 do {
2960 chunk = len;
2961 if (chunk > 4 * MINLEN)
2962 chunk = 4 * MINLEN;
2963
2964 /*
2965 * first handle encoding stuff.
2966 */
2967 if (out->encoder != NULL) {
2968 /*
2969 * Store the data in the incoming raw buffer
2970 */
2971 if (out->conv == NULL) {
2972 out->conv = xmlBufferCreate();
2973 }
William M. Bracka3215c72004-07-31 16:24:01 +00002974 ret = xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2975 if (ret != 0)
2976 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002977
2978 if ((out->buffer->use < MINLEN) && (chunk == len))
2979 goto done;
2980
2981 /*
2982 * convert as much as possible to the parser reading buffer.
2983 */
2984 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
Daniel Veillard809faa52003-02-10 15:43:53 +00002985 if ((ret < 0) && (ret != -3)) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002986 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002987 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002988 return(-1);
2989 }
2990 nbchars = out->conv->use;
2991 } else {
William M. Bracka3215c72004-07-31 16:24:01 +00002992 ret = xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2993 if (ret != 0)
2994 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002995 nbchars = out->buffer->use;
2996 }
2997 buf += chunk;
2998 len -= chunk;
2999
3000 if ((nbchars < MINLEN) && (len <= 0))
3001 goto done;
3002
3003 if (out->writecallback) {
3004 /*
3005 * second write the stuff to the I/O channel
3006 */
3007 if (out->encoder != NULL) {
3008 ret = out->writecallback(out->context,
3009 (const char *)out->conv->content, nbchars);
3010 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00003011 xmlBufferShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003012 } else {
3013 ret = out->writecallback(out->context,
3014 (const char *)out->buffer->content, nbchars);
3015 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00003016 xmlBufferShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003017 }
3018 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003019 xmlIOErr(XML_IO_WRITE, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003020 out->error = XML_IO_WRITE;
Owen Taylor3473f882001-02-23 17:55:21 +00003021 return(ret);
3022 }
3023 out->written += ret;
3024 }
3025 written += nbchars;
3026 } while (len > 0);
3027
3028done:
3029#ifdef DEBUG_INPUT
3030 xmlGenericError(xmlGenericErrorContext,
3031 "I/O: wrote %d chars\n", written);
3032#endif
3033 return(written);
3034}
3035
3036/**
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003037 * xmlEscapeContent:
3038 * @out: a pointer to an array of bytes to store the result
3039 * @outlen: the length of @out
3040 * @in: a pointer to an array of unescaped UTF-8 bytes
3041 * @inlen: the length of @in
3042 *
3043 * Take a block of UTF-8 chars in and escape them.
3044 * Returns 0 if success, or -1 otherwise
3045 * The value of @inlen after return is the number of octets consumed
3046 * if the return value is positive, else unpredictable.
3047 * The value of @outlen after return is the number of octets consumed.
3048 */
3049static int
3050xmlEscapeContent(unsigned char* out, int *outlen,
3051 const xmlChar* in, int *inlen) {
3052 unsigned char* outstart = out;
3053 const unsigned char* base = in;
3054 unsigned char* outend = out + *outlen;
3055 const unsigned char* inend;
3056
3057 inend = in + (*inlen);
3058
3059 while ((in < inend) && (out < outend)) {
3060 if (*in == '<') {
3061 if (outend - out < 4) break;
3062 *out++ = '&';
3063 *out++ = 'l';
3064 *out++ = 't';
3065 *out++ = ';';
3066 } else if (*in == '>') {
3067 if (outend - out < 4) break;
3068 *out++ = '&';
3069 *out++ = 'g';
3070 *out++ = 't';
3071 *out++ = ';';
3072 } else if (*in == '&') {
3073 if (outend - out < 5) break;
3074 *out++ = '&';
3075 *out++ = 'a';
3076 *out++ = 'm';
3077 *out++ = 'p';
3078 *out++ = ';';
3079 } else if (*in == '\r') {
3080 if (outend - out < 5) break;
3081 *out++ = '&';
3082 *out++ = '#';
3083 *out++ = '1';
3084 *out++ = '3';
3085 *out++ = ';';
3086 } else {
3087 *out++ = (unsigned char) *in;
3088 }
3089 ++in;
3090 }
3091 *outlen = out - outstart;
3092 *inlen = in - base;
3093 return(0);
3094}
3095
3096/**
3097 * xmlOutputBufferWriteEscape:
3098 * @out: a buffered parser output
3099 * @str: a zero terminated UTF-8 string
Daniel Veillardee8960b2004-05-14 03:25:14 +00003100 * @escaping: an optional escaping function (or NULL)
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003101 *
3102 * Write the content of the string in the output I/O buffer
3103 * This routine escapes the caracters and then handle the I18N
3104 * transcoding from internal UTF-8
3105 * The buffer is lossless, i.e. will store in case of partial
3106 * or delayed writes.
3107 *
3108 * Returns the number of chars immediately written, or -1
3109 * in case of error.
3110 */
3111int
Daniel Veillardee8960b2004-05-14 03:25:14 +00003112xmlOutputBufferWriteEscape(xmlOutputBufferPtr out, const xmlChar *str,
3113 xmlCharEncodingOutputFunc escaping) {
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003114 int nbchars = 0; /* number of chars to output to I/O */
3115 int ret; /* return from function call */
3116 int written = 0; /* number of char written to I/O so far */
Daniel Veillard71b95632004-08-31 12:15:36 +00003117 int oldwritten=0;/* loop guard */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003118 int chunk; /* number of byte currently processed from str */
3119 int len; /* number of bytes in str */
3120 int cons; /* byte from str consumed */
3121
Daniel Veillardce244ad2004-11-05 10:03:46 +00003122 if ((out == NULL) || (out->error) || (str == NULL) ||
3123 (out->buffer == NULL) ||
3124 (out->buffer->alloc == XML_BUFFER_ALLOC_IMMUTABLE)) return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003125 len = strlen((const char *)str);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003126 if (len < 0) return(0);
3127 if (out->error) return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003128 if (escaping == NULL) escaping = xmlEscapeContent;
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003129
3130 do {
Daniel Veillard71b95632004-08-31 12:15:36 +00003131 oldwritten = written;
3132
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003133 /*
3134 * how many bytes to consume and how many bytes to store.
3135 */
3136 cons = len;
3137 chunk = (out->buffer->size - out->buffer->use) - 1;
3138
3139 /*
3140 * first handle encoding stuff.
3141 */
3142 if (out->encoder != NULL) {
3143 /*
3144 * Store the data in the incoming raw buffer
3145 */
3146 if (out->conv == NULL) {
3147 out->conv = xmlBufferCreate();
3148 }
Daniel Veillardee8960b2004-05-14 03:25:14 +00003149 ret = escaping(out->buffer->content + out->buffer->use ,
3150 &chunk, str, &cons);
William M. Brack66e40b12004-11-26 15:45:19 +00003151 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003152 return(-1);
3153 out->buffer->use += chunk;
3154 out->buffer->content[out->buffer->use] = 0;
3155
3156 if ((out->buffer->use < MINLEN) && (cons == len))
3157 goto done;
3158
3159 /*
3160 * convert as much as possible to the output buffer.
3161 */
3162 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
3163 if ((ret < 0) && (ret != -3)) {
3164 xmlIOErr(XML_IO_ENCODER, NULL);
3165 out->error = XML_IO_ENCODER;
3166 return(-1);
3167 }
3168 nbchars = out->conv->use;
3169 } else {
Daniel Veillardee8960b2004-05-14 03:25:14 +00003170 ret = escaping(out->buffer->content + out->buffer->use ,
3171 &chunk, str, &cons);
William M. Brack66e40b12004-11-26 15:45:19 +00003172 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003173 return(-1);
3174 out->buffer->use += chunk;
3175 out->buffer->content[out->buffer->use] = 0;
3176 nbchars = out->buffer->use;
3177 }
3178 str += cons;
3179 len -= cons;
3180
3181 if ((nbchars < MINLEN) && (len <= 0))
3182 goto done;
3183
3184 if (out->writecallback) {
3185 /*
3186 * second write the stuff to the I/O channel
3187 */
3188 if (out->encoder != NULL) {
3189 ret = out->writecallback(out->context,
3190 (const char *)out->conv->content, nbchars);
3191 if (ret >= 0)
3192 xmlBufferShrink(out->conv, ret);
3193 } else {
3194 ret = out->writecallback(out->context,
3195 (const char *)out->buffer->content, nbchars);
3196 if (ret >= 0)
3197 xmlBufferShrink(out->buffer, ret);
3198 }
3199 if (ret < 0) {
3200 xmlIOErr(XML_IO_WRITE, NULL);
3201 out->error = XML_IO_WRITE;
3202 return(ret);
3203 }
3204 out->written += ret;
Daniel Veillard83a75e02004-05-14 21:50:42 +00003205 } else if (out->buffer->size - out->buffer->use < MINLEN) {
3206 xmlBufferResize(out->buffer, out->buffer->size + MINLEN);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003207 }
3208 written += nbchars;
Daniel Veillard71b95632004-08-31 12:15:36 +00003209 } while ((len > 0) && (oldwritten != written));
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003210
3211done:
3212#ifdef DEBUG_INPUT
3213 xmlGenericError(xmlGenericErrorContext,
3214 "I/O: wrote %d chars\n", written);
3215#endif
3216 return(written);
3217}
3218
3219/**
Owen Taylor3473f882001-02-23 17:55:21 +00003220 * xmlOutputBufferWriteString:
3221 * @out: a buffered parser output
3222 * @str: a zero terminated C string
3223 *
3224 * Write the content of the string in the output I/O buffer
3225 * This routine handle the I18N transcoding from internal UTF-8
3226 * The buffer is lossless, i.e. will store in case of partial
3227 * or delayed writes.
3228 *
3229 * Returns the number of chars immediately written, or -1
3230 * in case of error.
3231 */
3232int
3233xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
3234 int len;
3235
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003236 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003237 if (str == NULL)
3238 return(-1);
3239 len = strlen(str);
3240
3241 if (len > 0)
3242 return(xmlOutputBufferWrite(out, len, str));
3243 return(len);
3244}
3245
3246/**
3247 * xmlOutputBufferFlush:
3248 * @out: a buffered output
3249 *
3250 * flushes the output I/O channel
3251 *
3252 * Returns the number of byte written or -1 in case of error.
3253 */
3254int
3255xmlOutputBufferFlush(xmlOutputBufferPtr out) {
3256 int nbchars = 0, ret = 0;
3257
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003258 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003259 /*
3260 * first handle encoding stuff.
3261 */
3262 if ((out->conv != NULL) && (out->encoder != NULL)) {
3263 /*
3264 * convert as much as possible to the parser reading buffer.
3265 */
3266 nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
3267 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003268 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003269 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003270 return(-1);
3271 }
3272 }
3273
3274 /*
3275 * second flush the stuff to the I/O channel
3276 */
3277 if ((out->conv != NULL) && (out->encoder != NULL) &&
3278 (out->writecallback != NULL)) {
3279 ret = out->writecallback(out->context,
3280 (const char *)out->conv->content, out->conv->use);
3281 if (ret >= 0)
3282 xmlBufferShrink(out->conv, ret);
3283 } else if (out->writecallback != NULL) {
3284 ret = out->writecallback(out->context,
3285 (const char *)out->buffer->content, out->buffer->use);
3286 if (ret >= 0)
3287 xmlBufferShrink(out->buffer, ret);
3288 }
3289 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003290 xmlIOErr(XML_IO_FLUSH, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003291 out->error = XML_IO_FLUSH;
Owen Taylor3473f882001-02-23 17:55:21 +00003292 return(ret);
3293 }
3294 out->written += ret;
3295
3296#ifdef DEBUG_INPUT
3297 xmlGenericError(xmlGenericErrorContext,
3298 "I/O: flushed %d chars\n", ret);
3299#endif
3300 return(ret);
3301}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003302#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003303
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003304/**
Owen Taylor3473f882001-02-23 17:55:21 +00003305 * xmlParserGetDirectory:
3306 * @filename: the path to a file
3307 *
3308 * lookup the directory for that file
3309 *
3310 * Returns a new allocated string containing the directory, or NULL.
3311 */
3312char *
3313xmlParserGetDirectory(const char *filename) {
3314 char *ret = NULL;
3315 char dir[1024];
3316 char *cur;
3317 char sep = '/';
3318
Igor Zlatkovic9181cc02002-09-29 17:51:06 +00003319#ifdef _WIN32_WCE /* easy way by now ... wince does not have dirs! */
3320 return NULL;
3321#endif
3322
Owen Taylor3473f882001-02-23 17:55:21 +00003323 if (xmlInputCallbackInitialized == 0)
3324 xmlRegisterDefaultInputCallbacks();
3325
3326 if (filename == NULL) return(NULL);
Daniel Veillard3c5ed912002-01-08 10:36:16 +00003327#if defined(WIN32) && !defined(__CYGWIN__)
Owen Taylor3473f882001-02-23 17:55:21 +00003328 sep = '\\';
3329#endif
3330
3331 strncpy(dir, filename, 1023);
3332 dir[1023] = 0;
3333 cur = &dir[strlen(dir)];
3334 while (cur > dir) {
3335 if (*cur == sep) break;
3336 cur --;
3337 }
3338 if (*cur == sep) {
3339 if (cur == dir) dir[1] = 0;
3340 else *cur = 0;
3341 ret = xmlMemStrdup(dir);
3342 } else {
3343 if (getcwd(dir, 1024) != NULL) {
3344 dir[1023] = 0;
3345 ret = xmlMemStrdup(dir);
3346 }
3347 }
3348 return(ret);
3349}
3350
3351/****************************************************************
3352 * *
3353 * External entities loading *
3354 * *
3355 ****************************************************************/
3356
Daniel Veillarda840b692003-10-19 13:35:37 +00003357/**
3358 * xmlCheckHTTPInput:
3359 * @ctxt: an XML parser context
3360 * @ret: an XML parser input
3361 *
3362 * Check an input in case it was created from an HTTP stream, in that
3363 * case it will handle encoding and update of the base URL in case of
3364 * redirection. It also checks for HTTP errors in which case the input
3365 * is cleanly freed up and an appropriate error is raised in context
3366 *
3367 * Returns the input or NULL in case of HTTP error.
3368 */
3369xmlParserInputPtr
3370xmlCheckHTTPInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr ret) {
3371#ifdef LIBXML_HTTP_ENABLED
3372 if ((ret != NULL) && (ret->buf != NULL) &&
3373 (ret->buf->readcallback == xmlIOHTTPRead) &&
3374 (ret->buf->context != NULL)) {
3375 const char *encoding;
3376 const char *redir;
3377 const char *mime;
3378 int code;
3379
3380 code = xmlNanoHTTPReturnCode(ret->buf->context);
3381 if (code >= 400) {
3382 /* fatal error */
3383 if (ret->filename != NULL)
Daniel Veillarde8039df2003-10-27 11:25:13 +00003384 __xmlLoaderErr(ctxt, "failed to load HTTP resource \"%s\"\n",
Daniel Veillarda840b692003-10-19 13:35:37 +00003385 (const char *) ret->filename);
3386 else
Daniel Veillarde8039df2003-10-27 11:25:13 +00003387 __xmlLoaderErr(ctxt, "failed to load HTTP resource\n", NULL);
Daniel Veillarda840b692003-10-19 13:35:37 +00003388 xmlFreeInputStream(ret);
3389 ret = NULL;
3390 } else {
3391
3392 mime = xmlNanoHTTPMimeType(ret->buf->context);
3393 if ((xmlStrstr(BAD_CAST mime, BAD_CAST "/xml")) ||
3394 (xmlStrstr(BAD_CAST mime, BAD_CAST "+xml"))) {
3395 encoding = xmlNanoHTTPEncoding(ret->buf->context);
3396 if (encoding != NULL) {
3397 xmlCharEncodingHandlerPtr handler;
3398
3399 handler = xmlFindCharEncodingHandler(encoding);
3400 if (handler != NULL) {
3401 xmlSwitchInputEncoding(ctxt, ret, handler);
3402 } else {
3403 __xmlErrEncoding(ctxt, XML_ERR_UNKNOWN_ENCODING,
3404 "Unknown encoding %s",
3405 BAD_CAST encoding, NULL);
3406 }
3407 if (ret->encoding == NULL)
3408 ret->encoding = xmlStrdup(BAD_CAST encoding);
3409 }
3410#if 0
3411 } else if (xmlStrstr(BAD_CAST mime, BAD_CAST "html")) {
3412#endif
3413 }
3414 redir = xmlNanoHTTPRedir(ret->buf->context);
3415 if (redir != NULL) {
3416 if (ret->filename != NULL)
3417 xmlFree((xmlChar *) ret->filename);
3418 if (ret->directory != NULL) {
3419 xmlFree((xmlChar *) ret->directory);
3420 ret->directory = NULL;
3421 }
3422 ret->filename =
3423 (char *) xmlStrdup((const xmlChar *) redir);
3424 }
3425 }
3426 }
3427#endif
3428 return(ret);
3429}
3430
Daniel Veillard561b7f82002-03-20 21:55:57 +00003431static int xmlSysIDExists(const char *URL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003432#ifdef HAVE_STAT
3433 int ret;
3434 struct stat info;
3435 const char *path;
3436
3437 if (URL == NULL)
3438 return(0);
3439
Daniel Veillardf4862f02002-09-10 11:13:43 +00003440 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003441#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00003442 path = &URL[17];
3443#else
Daniel Veillard6990bf32001-08-23 21:17:48 +00003444 path = &URL[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00003445#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003446 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003447#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard6990bf32001-08-23 21:17:48 +00003448 path = &URL[8];
3449#else
3450 path = &URL[7];
3451#endif
3452 } else
3453 path = URL;
3454 ret = stat(path, &info);
Daniel Veillard561b7f82002-03-20 21:55:57 +00003455 if (ret == 0)
3456 return(1);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003457#endif
Daniel Veillard561b7f82002-03-20 21:55:57 +00003458 return(0);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003459}
Daniel Veillard6990bf32001-08-23 21:17:48 +00003460
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003461/**
Owen Taylor3473f882001-02-23 17:55:21 +00003462 * xmlDefaultExternalEntityLoader:
3463 * @URL: the URL for the entity to load
3464 * @ID: the System ID for the entity to load
3465 * @ctxt: the context in which the entity is called or NULL
3466 *
3467 * By default we don't load external entitites, yet.
3468 *
3469 * Returns a new allocated xmlParserInputPtr, or NULL.
3470 */
Daniel Veillarda840b692003-10-19 13:35:37 +00003471static xmlParserInputPtr
Owen Taylor3473f882001-02-23 17:55:21 +00003472xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
Daniel Veillarda840b692003-10-19 13:35:37 +00003473 xmlParserCtxtPtr ctxt)
3474{
Owen Taylor3473f882001-02-23 17:55:21 +00003475 xmlParserInputPtr ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003476 xmlChar *resource = NULL;
Daniel Veillarda840b692003-10-19 13:35:37 +00003477
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003478#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003479 xmlCatalogAllow pref;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003480#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003481
3482#ifdef DEBUG_EXTERNAL_ENTITIES
3483 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda840b692003-10-19 13:35:37 +00003484 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00003485#endif
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003486#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillard61b93382003-11-03 14:28:31 +00003487 if ((ctxt != NULL) && (ctxt->options & XML_PARSE_NONET)) {
3488 int options = ctxt->options;
3489
3490 ctxt->options -= XML_PARSE_NONET;
3491 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
3492 ctxt->options = options;
3493 return(ret);
3494 }
3495
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003496 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003497 * If the resource doesn't exists as a file,
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003498 * try to load it from the resource pointed in the catalogs
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003499 */
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003500 pref = xmlCatalogGetDefaults();
3501
Daniel Veillard561b7f82002-03-20 21:55:57 +00003502 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlSysIDExists(URL))) {
Daniel Veillarda840b692003-10-19 13:35:37 +00003503 /*
3504 * Do a local lookup
3505 */
Daniel Veillard42595322004-11-08 10:52:06 +00003506 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
Daniel Veillarda840b692003-10-19 13:35:37 +00003507 ((pref == XML_CATA_ALLOW_ALL) ||
3508 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3509 resource = xmlCatalogLocalResolve(ctxt->catalogs,
3510 (const xmlChar *) ID,
3511 (const xmlChar *) URL);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003512 }
Daniel Veillarda840b692003-10-19 13:35:37 +00003513 /*
3514 * Try a global lookup
3515 */
3516 if ((resource == NULL) &&
3517 ((pref == XML_CATA_ALLOW_ALL) ||
3518 (pref == XML_CATA_ALLOW_GLOBAL))) {
3519 resource = xmlCatalogResolve((const xmlChar *) ID,
3520 (const xmlChar *) URL);
3521 }
3522 if ((resource == NULL) && (URL != NULL))
3523 resource = xmlStrdup((const xmlChar *) URL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003524
Daniel Veillarda840b692003-10-19 13:35:37 +00003525 /*
3526 * TODO: do an URI lookup on the reference
3527 */
3528 if ((resource != NULL)
3529 && (!xmlSysIDExists((const char *) resource))) {
3530 xmlChar *tmp = NULL;
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003531
Daniel Veillard42595322004-11-08 10:52:06 +00003532 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
Daniel Veillarda840b692003-10-19 13:35:37 +00003533 ((pref == XML_CATA_ALLOW_ALL) ||
3534 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3535 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
3536 }
3537 if ((tmp == NULL) &&
3538 ((pref == XML_CATA_ALLOW_ALL) ||
3539 (pref == XML_CATA_ALLOW_GLOBAL))) {
3540 tmp = xmlCatalogResolveURI(resource);
3541 }
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003542
Daniel Veillarda840b692003-10-19 13:35:37 +00003543 if (tmp != NULL) {
3544 xmlFree(resource);
3545 resource = tmp;
3546 }
3547 }
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003548 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003549#endif
3550
3551 if (resource == NULL)
Daniel Veillarda840b692003-10-19 13:35:37 +00003552 resource = (xmlChar *) URL;
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003553
3554 if (resource == NULL) {
Daniel Veillarda840b692003-10-19 13:35:37 +00003555 if (ID == NULL)
3556 ID = "NULL";
Daniel Veillarde8039df2003-10-27 11:25:13 +00003557 __xmlLoaderErr(ctxt, "failed to load external entity \"%s\"\n", ID);
Daniel Veillarda840b692003-10-19 13:35:37 +00003558 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003559 }
Daniel Veillarda840b692003-10-19 13:35:37 +00003560 ret = xmlNewInputFromFile(ctxt, (const char *) resource);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003561 if ((resource != NULL) && (resource != (xmlChar *) URL))
Daniel Veillarda840b692003-10-19 13:35:37 +00003562 xmlFree(resource);
3563 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003564}
3565
3566static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
3567 xmlDefaultExternalEntityLoader;
3568
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003569/**
Owen Taylor3473f882001-02-23 17:55:21 +00003570 * xmlSetExternalEntityLoader:
3571 * @f: the new entity resolver function
3572 *
3573 * Changes the defaultexternal entity resolver function for the application
3574 */
3575void
3576xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
3577 xmlCurrentExternalEntityLoader = f;
3578}
3579
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003580/**
Owen Taylor3473f882001-02-23 17:55:21 +00003581 * xmlGetExternalEntityLoader:
3582 *
3583 * Get the default external entity resolver function for the application
3584 *
3585 * Returns the xmlExternalEntityLoader function pointer
3586 */
3587xmlExternalEntityLoader
3588xmlGetExternalEntityLoader(void) {
3589 return(xmlCurrentExternalEntityLoader);
3590}
3591
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003592/**
Owen Taylor3473f882001-02-23 17:55:21 +00003593 * xmlLoadExternalEntity:
3594 * @URL: the URL for the entity to load
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00003595 * @ID: the Public ID for the entity to load
Owen Taylor3473f882001-02-23 17:55:21 +00003596 * @ctxt: the context in which the entity is called or NULL
3597 *
3598 * Load an external entity, note that the use of this function for
3599 * unparsed entities may generate problems
Owen Taylor3473f882001-02-23 17:55:21 +00003600 *
3601 * Returns the xmlParserInputPtr or NULL
3602 */
3603xmlParserInputPtr
3604xmlLoadExternalEntity(const char *URL, const char *ID,
3605 xmlParserCtxtPtr ctxt) {
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00003606 if ((URL != NULL) && (xmlSysIDExists(URL) == 0)) {
3607 char *canonicFilename;
3608 xmlParserInputPtr ret;
3609
3610 canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL);
3611 if (canonicFilename == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003612 xmlIOErrMemory("building canonical path\n");
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00003613 return(NULL);
3614 }
3615
3616 ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt);
3617 xmlFree(canonicFilename);
3618 return(ret);
3619 }
Owen Taylor3473f882001-02-23 17:55:21 +00003620 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
3621}
3622
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003623/************************************************************************
3624 * *
3625 * Disabling Network access *
3626 * *
3627 ************************************************************************/
3628
3629#ifdef LIBXML_CATALOG_ENABLED
3630static int
3631xmlNoNetExists(const char *URL)
3632{
3633#ifdef HAVE_STAT
3634 int ret;
3635 struct stat info;
3636 const char *path;
3637
3638 if (URL == NULL)
3639 return (0);
3640
Daniel Veillardf4862f02002-09-10 11:13:43 +00003641 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003642#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00003643 path = &URL[17];
3644#else
3645 path = &URL[16];
3646#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003647 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003648#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003649 path = &URL[8];
3650#else
3651 path = &URL[7];
3652#endif
3653 } else
3654 path = URL;
3655 ret = stat(path, &info);
3656 if (ret == 0)
3657 return (1);
3658#endif
3659 return (0);
3660}
3661#endif
3662
3663/**
3664 * xmlNoNetExternalEntityLoader:
3665 * @URL: the URL for the entity to load
3666 * @ID: the System ID for the entity to load
3667 * @ctxt: the context in which the entity is called or NULL
3668 *
3669 * A specific entity loader disabling network accesses, though still
3670 * allowing local catalog accesses for resolution.
3671 *
3672 * Returns a new allocated xmlParserInputPtr, or NULL.
3673 */
3674xmlParserInputPtr
3675xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
3676 xmlParserCtxtPtr ctxt) {
3677 xmlParserInputPtr input = NULL;
3678 xmlChar *resource = NULL;
3679
3680#ifdef LIBXML_CATALOG_ENABLED
3681 xmlCatalogAllow pref;
3682
3683 /*
3684 * If the resource doesn't exists as a file,
3685 * try to load it from the resource pointed in the catalogs
3686 */
3687 pref = xmlCatalogGetDefaults();
3688
3689 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
3690 /*
3691 * Do a local lookup
3692 */
Daniel Veillard42595322004-11-08 10:52:06 +00003693 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003694 ((pref == XML_CATA_ALLOW_ALL) ||
3695 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3696 resource = xmlCatalogLocalResolve(ctxt->catalogs,
3697 (const xmlChar *)ID,
3698 (const xmlChar *)URL);
3699 }
3700 /*
3701 * Try a global lookup
3702 */
3703 if ((resource == NULL) &&
3704 ((pref == XML_CATA_ALLOW_ALL) ||
3705 (pref == XML_CATA_ALLOW_GLOBAL))) {
3706 resource = xmlCatalogResolve((const xmlChar *)ID,
3707 (const xmlChar *)URL);
3708 }
3709 if ((resource == NULL) && (URL != NULL))
3710 resource = xmlStrdup((const xmlChar *) URL);
3711
3712 /*
3713 * TODO: do an URI lookup on the reference
3714 */
3715 if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
3716 xmlChar *tmp = NULL;
3717
Daniel Veillard42595322004-11-08 10:52:06 +00003718 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003719 ((pref == XML_CATA_ALLOW_ALL) ||
3720 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3721 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
3722 }
3723 if ((tmp == NULL) &&
3724 ((pref == XML_CATA_ALLOW_ALL) ||
3725 (pref == XML_CATA_ALLOW_GLOBAL))) {
3726 tmp = xmlCatalogResolveURI(resource);
3727 }
3728
3729 if (tmp != NULL) {
3730 xmlFree(resource);
3731 resource = tmp;
3732 }
3733 }
3734 }
3735#endif
3736 if (resource == NULL)
3737 resource = (xmlChar *) URL;
3738
3739 if (resource != NULL) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003740 if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
3741 (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003742 xmlIOErr(XML_IO_NETWORK_ATTEMPT, (const char *) resource);
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003743 if (resource != (xmlChar *) URL)
3744 xmlFree(resource);
3745 return(NULL);
3746 }
3747 }
3748 input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
3749 if (resource != (xmlChar *) URL)
3750 xmlFree(resource);
3751 return(input);
3752}
3753
Daniel Veillard5d4644e2005-04-01 13:11:58 +00003754#define bottom_xmlIO
3755#include "elfgcchack.h"