blob: 29d057dfd64990e8027ce89d75745c99295714d4 [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 Veillard05d987b2003-10-08 11:54:57 +0000613 int ret;
614
615 ret = write((int) (long) context, &buffer[0], len);
616 if (ret < 0) xmlIOErr(0, "write()");
617 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000618}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000619#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000620
621/**
622 * xmlFdClose:
623 * @context: the I/O context
624 *
625 * Close an I/O channel
Daniel Veillardf012a642001-07-23 19:10:52 +0000626 *
627 * Returns 0 in case of success and error code otherwise
Owen Taylor3473f882001-02-23 17:55:21 +0000628 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000629static int
Owen Taylor3473f882001-02-23 17:55:21 +0000630xmlFdClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000631 int ret;
632 ret = close((int) (long) context);
633 if (ret < 0) xmlIOErr(0, "close()");
634 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000635}
636
637/**
638 * xmlFileMatch:
639 * @filename: the URI for matching
640 *
641 * input from FILE *
642 *
643 * Returns 1 if matches, 0 otherwise
644 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000645int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000646xmlFileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000647 return(1);
648}
649
650/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000651 * xmlFileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +0000652 * @filename: the URI for matching
653 *
654 * input from FILE *, supports compressed input
655 * if @filename is " " then the standard input is used
656 *
657 * Returns an I/O context or NULL in case of error
658 */
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000659static void *
660xmlFileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +0000661 const char *path = NULL;
662 FILE *fd;
663
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000664 if (filename == NULL)
665 return(NULL);
666
Owen Taylor3473f882001-02-23 17:55:21 +0000667 if (!strcmp(filename, "-")) {
668 fd = stdin;
669 return((void *) fd);
670 }
671
Daniel Veillardf4862f02002-09-10 11:13:43 +0000672 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000673#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000674 path = &filename[17];
675#else
Owen Taylor3473f882001-02-23 17:55:21 +0000676 path = &filename[16];
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000677#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000678 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000679#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000680 path = &filename[8];
681#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000682 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000683#endif
684 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000685 path = filename;
686
687 if (path == NULL)
688 return(NULL);
689 if (!xmlCheckFilename(path))
690 return(NULL);
691
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000692#if defined(WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
Owen Taylor3473f882001-02-23 17:55:21 +0000693 fd = fopen(path, "rb");
694#else
695 fd = fopen(path, "r");
696#endif /* WIN32 */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000697 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +0000698 return((void *) fd);
699}
700
701/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000702 * xmlFileOpen:
703 * @filename: the URI for matching
704 *
705 * Wrapper around xmlFileOpen_real that try it with an unescaped
706 * version of @filename, if this fails fallback to @filename
Daniel Veillard71531f32003-02-05 13:19:53 +0000707 *
708 * Returns a handler or NULL in case or failure
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000709 */
710void *
711xmlFileOpen (const char *filename) {
712 char *unescaped;
713 void *retval;
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000714
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000715 unescaped = xmlURIUnescapeString(filename, 0, NULL);
716 if (unescaped != NULL) {
717 retval = xmlFileOpen_real(unescaped);
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000718 xmlFree(unescaped);
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000719 } else {
720 retval = xmlFileOpen_real(filename);
721 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000722 return retval;
723}
724
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000725#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000726/**
Owen Taylor3473f882001-02-23 17:55:21 +0000727 * xmlFileOpenW:
728 * @filename: the URI for matching
729 *
730 * output to from FILE *,
731 * if @filename is "-" then the standard output is used
732 *
733 * Returns an I/O context or NULL in case of error
734 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000735static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000736xmlFileOpenW (const char *filename) {
737 const char *path = NULL;
738 FILE *fd;
739
740 if (!strcmp(filename, "-")) {
741 fd = stdout;
742 return((void *) fd);
743 }
744
Daniel Veillardf4862f02002-09-10 11:13:43 +0000745 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000746#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000747 path = &filename[17];
748#else
Owen Taylor3473f882001-02-23 17:55:21 +0000749 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000750#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000751 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000752#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000753 path = &filename[8];
754#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000755 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000756#endif
757 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000758 path = filename;
759
760 if (path == NULL)
761 return(NULL);
762
Daniel Veillardcbbd78d2003-07-20 15:21:30 +0000763 fd = fopen(path, "wb");
Daniel Veillard05d987b2003-10-08 11:54:57 +0000764 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +0000765 return((void *) fd);
766}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000767#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000768
769/**
770 * xmlFileRead:
771 * @context: the I/O context
772 * @buffer: where to drop data
773 * @len: number of bytes to write
774 *
775 * Read @len bytes to @buffer from the I/O channel.
776 *
Daniel Veillardce682bc2004-11-05 17:22:25 +0000777 * Returns the number of bytes written or < 0 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +0000778 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000779int
Owen Taylor3473f882001-02-23 17:55:21 +0000780xmlFileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000781 int ret;
Daniel Veillardce682bc2004-11-05 17:22:25 +0000782 if ((context == NULL) || (buffer == NULL))
783 return(-1);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000784 ret = fread(&buffer[0], 1, len, (FILE *) context);
785 if (ret < 0) xmlIOErr(0, "fread()");
786 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000787}
788
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000789#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000790/**
791 * xmlFileWrite:
792 * @context: the I/O context
793 * @buffer: where to drop data
794 * @len: number of bytes to write
795 *
796 * Write @len bytes from @buffer to the I/O channel.
797 *
798 * Returns the number of bytes written
799 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000800static int
Owen Taylor3473f882001-02-23 17:55:21 +0000801xmlFileWrite (void * context, const char * buffer, int len) {
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000802 int items;
803
Daniel Veillardce682bc2004-11-05 17:22:25 +0000804 if ((context == NULL) || (buffer == NULL))
805 return(-1);
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000806 items = fwrite(&buffer[0], len, 1, (FILE *) context);
Daniel Veillard97bf4d02003-10-08 18:58:28 +0000807 if ((items == 0) && (ferror((FILE *) context))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000808 xmlIOErr(0, "fwrite()");
Daniel Veillard97bf4d02003-10-08 18:58:28 +0000809 return(-1);
810 }
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000811 return(items * len);
Owen Taylor3473f882001-02-23 17:55:21 +0000812}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000813#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000814
815/**
816 * xmlFileClose:
817 * @context: the I/O context
818 *
819 * Close an I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000820 *
821 * Returns 0 or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +0000822 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000823int
Owen Taylor3473f882001-02-23 17:55:21 +0000824xmlFileClose (void * context) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000825 FILE *fil;
Daniel Veillard05d987b2003-10-08 11:54:57 +0000826 int ret;
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000827
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000828 if (context == NULL)
829 return(-1);
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000830 fil = (FILE *) context;
Daniel Veillard500a1de2004-03-22 15:22:58 +0000831 if ((fil == stdout) || (fil == stderr)) {
832 ret = fflush(fil);
833 if (ret < 0)
834 xmlIOErr(0, "fflush()");
835 return(0);
836 }
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000837 if (fil == stdin)
838 return(0);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000839 ret = ( fclose((FILE *) context) == EOF ) ? -1 : 0;
840 if (ret < 0)
841 xmlIOErr(0, "fclose()");
842 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000843}
844
845/**
846 * xmlFileFlush:
847 * @context: the I/O context
848 *
849 * Flush an I/O channel
850 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000851static int
Owen Taylor3473f882001-02-23 17:55:21 +0000852xmlFileFlush (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000853 int ret;
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000854
855 if (context == NULL)
856 return(-1);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000857 ret = ( fflush((FILE *) context) == EOF ) ? -1 : 0;
858 if (ret < 0)
859 xmlIOErr(0, "fflush()");
860 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000861}
862
863#ifdef HAVE_ZLIB_H
864/************************************************************************
865 * *
866 * I/O for compressed file accesses *
867 * *
868 ************************************************************************/
869/**
870 * xmlGzfileMatch:
871 * @filename: the URI for matching
872 *
873 * input from compressed file test
874 *
875 * Returns 1 if matches, 0 otherwise
876 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000877static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000878xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000879 return(1);
880}
881
882/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000883 * xmlGzfileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +0000884 * @filename: the URI for matching
885 *
886 * input from compressed file open
887 * if @filename is " " then the standard input is used
888 *
889 * Returns an I/O context or NULL in case of error
890 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000891static void *
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000892xmlGzfileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +0000893 const char *path = NULL;
894 gzFile fd;
895
896 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000897 fd = gzdopen(dup(0), "rb");
Owen Taylor3473f882001-02-23 17:55:21 +0000898 return((void *) fd);
899 }
900
Daniel Veillardf4862f02002-09-10 11:13:43 +0000901 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000902#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000903 path = &filename[17];
904#else
Owen Taylor3473f882001-02-23 17:55:21 +0000905 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000906#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000907 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000908#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000909 path = &filename[8];
910#else
Owen Taylor3473f882001-02-23 17:55:21 +0000911 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000912#endif
913 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000914 path = filename;
915
916 if (path == NULL)
917 return(NULL);
918 if (!xmlCheckFilename(path))
919 return(NULL);
920
921 fd = gzopen(path, "rb");
922 return((void *) fd);
923}
924
925/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000926 * xmlGzfileOpen:
927 * @filename: the URI for matching
928 *
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +0000929 * Wrapper around xmlGzfileOpen if the open fais, it will
930 * try to unescape @filename
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000931 */
932static void *
933xmlGzfileOpen (const char *filename) {
934 char *unescaped;
935 void *retval;
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +0000936
937 retval = xmlGzfileOpen_real(filename);
938 if (retval == NULL) {
939 unescaped = xmlURIUnescapeString(filename, 0, NULL);
940 if (unescaped != NULL) {
941 retval = xmlGzfileOpen_real(unescaped);
942 }
943 xmlFree(unescaped);
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000944 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000945 return retval;
946}
947
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000948#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000949/**
Owen Taylor3473f882001-02-23 17:55:21 +0000950 * xmlGzfileOpenW:
951 * @filename: the URI for matching
952 * @compression: the compression factor (0 - 9 included)
953 *
954 * input from compressed file open
955 * if @filename is " " then the standard input is used
956 *
957 * Returns an I/O context or NULL in case of error
958 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000959static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000960xmlGzfileOpenW (const char *filename, int compression) {
961 const char *path = NULL;
962 char mode[15];
963 gzFile fd;
964
Aleksey Sanin49cc9752002-06-14 17:07:10 +0000965 snprintf(mode, sizeof(mode), "wb%d", compression);
Owen Taylor3473f882001-02-23 17:55:21 +0000966 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000967 fd = gzdopen(dup(1), mode);
Owen Taylor3473f882001-02-23 17:55:21 +0000968 return((void *) fd);
969 }
970
Daniel Veillardf4862f02002-09-10 11:13:43 +0000971 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000972#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000973 path = &filename[17];
974#else
Owen Taylor3473f882001-02-23 17:55:21 +0000975 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000976#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000977 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000978#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000979 path = &filename[8];
980#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000981 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000982#endif
983 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000984 path = filename;
985
986 if (path == NULL)
987 return(NULL);
988
989 fd = gzopen(path, mode);
990 return((void *) fd);
991}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000992#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000993
994/**
995 * xmlGzfileRead:
996 * @context: the I/O context
997 * @buffer: where to drop data
998 * @len: number of bytes to write
999 *
1000 * Read @len bytes to @buffer from the compressed I/O channel.
1001 *
1002 * Returns the number of bytes written
1003 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001004static int
Owen Taylor3473f882001-02-23 17:55:21 +00001005xmlGzfileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001006 int ret;
1007
1008 ret = gzread((gzFile) context, &buffer[0], len);
1009 if (ret < 0) xmlIOErr(0, "gzread()");
1010 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001011}
1012
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001013#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001014/**
1015 * xmlGzfileWrite:
1016 * @context: the I/O context
1017 * @buffer: where to drop data
1018 * @len: number of bytes to write
1019 *
1020 * Write @len bytes from @buffer to the compressed I/O channel.
1021 *
1022 * Returns the number of bytes written
1023 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001024static int
Owen Taylor3473f882001-02-23 17:55:21 +00001025xmlGzfileWrite (void * context, const char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001026 int ret;
1027
1028 ret = gzwrite((gzFile) context, (char *) &buffer[0], len);
1029 if (ret < 0) xmlIOErr(0, "gzwrite()");
1030 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001031}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001032#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001033
1034/**
1035 * xmlGzfileClose:
1036 * @context: the I/O context
1037 *
1038 * Close a compressed I/O channel
1039 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001040static int
Owen Taylor3473f882001-02-23 17:55:21 +00001041xmlGzfileClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001042 int ret;
1043
1044 ret = (gzclose((gzFile) context) == Z_OK ) ? 0 : -1;
1045 if (ret < 0) xmlIOErr(0, "gzclose()");
1046 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001047}
1048#endif /* HAVE_ZLIB_H */
1049
1050#ifdef LIBXML_HTTP_ENABLED
1051/************************************************************************
1052 * *
1053 * I/O for HTTP file accesses *
1054 * *
1055 ************************************************************************/
Daniel Veillardf012a642001-07-23 19:10:52 +00001056
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001057#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001058typedef struct xmlIOHTTPWriteCtxt_
1059{
1060 int compression;
1061
1062 char * uri;
1063
1064 void * doc_buff;
1065
1066} xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr;
1067
1068#ifdef HAVE_ZLIB_H
1069
1070#define DFLT_WBITS ( -15 )
1071#define DFLT_MEM_LVL ( 8 )
1072#define GZ_MAGIC1 ( 0x1f )
1073#define GZ_MAGIC2 ( 0x8b )
1074#define LXML_ZLIB_OS_CODE ( 0x03 )
1075#define INIT_HTTP_BUFF_SIZE ( 32768 )
1076#define DFLT_ZLIB_RATIO ( 5 )
1077
1078/*
1079** Data structure and functions to work with sending compressed data
1080** via HTTP.
1081*/
1082
1083typedef struct xmlZMemBuff_
1084{
1085 unsigned long size;
1086 unsigned long crc;
1087
1088 unsigned char * zbuff;
1089 z_stream zctrl;
1090
1091} xmlZMemBuff, *xmlZMemBuffPtr;
1092
1093/**
1094 * append_reverse_ulong
1095 * @buff: Compressed memory buffer
1096 * @data: Unsigned long to append
1097 *
1098 * Append a unsigned long in reverse byte order to the end of the
1099 * memory buffer.
1100 */
1101static void
1102append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) {
1103
1104 int idx;
1105
1106 if ( buff == NULL )
1107 return;
1108
1109 /*
1110 ** This is plagiarized from putLong in gzio.c (zlib source) where
1111 ** the number "4" is hardcoded. If zlib is ever patched to
1112 ** support 64 bit file sizes, this code would need to be patched
1113 ** as well.
1114 */
1115
1116 for ( idx = 0; idx < 4; idx++ ) {
1117 *buff->zctrl.next_out = ( data & 0xff );
1118 data >>= 8;
1119 buff->zctrl.next_out++;
1120 }
1121
1122 return;
1123}
1124
1125/**
1126 *
1127 * xmlFreeZMemBuff
1128 * @buff: The memory buffer context to clear
1129 *
1130 * Release all the resources associated with the compressed memory buffer.
1131 */
1132static void
1133xmlFreeZMemBuff( xmlZMemBuffPtr buff ) {
William M. Brack78637da2003-07-31 14:47:38 +00001134
1135#ifdef DEBUG_HTTP
Daniel Veillardf012a642001-07-23 19:10:52 +00001136 int z_err;
William M. Brack78637da2003-07-31 14:47:38 +00001137#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001138
1139 if ( buff == NULL )
1140 return;
1141
1142 xmlFree( buff->zbuff );
Daniel Veillardf012a642001-07-23 19:10:52 +00001143#ifdef DEBUG_HTTP
William M. Brack78637da2003-07-31 14:47:38 +00001144 z_err = deflateEnd( &buff->zctrl );
Daniel Veillardf012a642001-07-23 19:10:52 +00001145 if ( z_err != Z_OK )
1146 xmlGenericError( xmlGenericErrorContext,
1147 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
1148 z_err );
William M. Brack78637da2003-07-31 14:47:38 +00001149#else
1150 deflateEnd( &buff->zctrl );
William M. Brack779af002003-08-01 15:55:39 +00001151#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001152
1153 xmlFree( buff );
1154 return;
1155}
1156
1157/**
1158 * xmlCreateZMemBuff
1159 *@compression: Compression value to use
1160 *
1161 * Create a memory buffer to hold the compressed XML document. The
1162 * compressed document in memory will end up being identical to what
1163 * would be created if gzopen/gzwrite/gzclose were being used to
1164 * write the document to disk. The code for the header/trailer data to
1165 * the compression is plagiarized from the zlib source files.
1166 */
1167static void *
1168xmlCreateZMemBuff( int compression ) {
1169
1170 int z_err;
1171 int hdr_lgth;
1172 xmlZMemBuffPtr buff = NULL;
1173
1174 if ( ( compression < 1 ) || ( compression > 9 ) )
1175 return ( NULL );
1176
1177 /* Create the control and data areas */
1178
1179 buff = xmlMalloc( sizeof( xmlZMemBuff ) );
1180 if ( buff == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001181 xmlIOErrMemory("creating buffer context");
Daniel Veillardf012a642001-07-23 19:10:52 +00001182 return ( NULL );
1183 }
1184
1185 (void)memset( buff, 0, sizeof( xmlZMemBuff ) );
1186 buff->size = INIT_HTTP_BUFF_SIZE;
1187 buff->zbuff = xmlMalloc( buff->size );
1188 if ( buff->zbuff == NULL ) {
1189 xmlFreeZMemBuff( buff );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001190 xmlIOErrMemory("creating buffer");
Daniel Veillardf012a642001-07-23 19:10:52 +00001191 return ( NULL );
1192 }
1193
1194 z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
1195 DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
1196 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001197 xmlChar msg[500];
Daniel Veillardf012a642001-07-23 19:10:52 +00001198 xmlFreeZMemBuff( buff );
1199 buff = NULL;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001200 xmlStrPrintf(msg, 500,
1201 (const xmlChar *) "xmlCreateZMemBuff: %s %d\n",
1202 "Error initializing compression context. ZLIB error:",
1203 z_err );
1204 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001205 return ( NULL );
1206 }
1207
1208 /* Set the header data. The CRC will be needed for the trailer */
Daniel Veillardf012a642001-07-23 19:10:52 +00001209 buff->crc = crc32( 0L, Z_NULL, 0 );
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001210 hdr_lgth = snprintf( (char *)buff->zbuff, buff->size,
1211 "%c%c%c%c%c%c%c%c%c%c",
Daniel Veillardf012a642001-07-23 19:10:52 +00001212 GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED,
1213 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE );
1214 buff->zctrl.next_out = buff->zbuff + hdr_lgth;
1215 buff->zctrl.avail_out = buff->size - hdr_lgth;
1216
1217 return ( buff );
1218}
1219
1220/**
1221 * xmlZMemBuffExtend
1222 * @buff: Buffer used to compress and consolidate data.
1223 * @ext_amt: Number of bytes to extend the buffer.
1224 *
1225 * Extend the internal buffer used to store the compressed data by the
1226 * specified amount.
1227 *
1228 * Returns 0 on success or -1 on failure to extend the buffer. On failure
1229 * the original buffer still exists at the original size.
1230 */
1231static int
1232xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) {
1233
1234 int rc = -1;
1235 size_t new_size;
1236 size_t cur_used;
1237
1238 unsigned char * tmp_ptr = NULL;
1239
1240 if ( buff == NULL )
1241 return ( -1 );
1242
1243 else if ( ext_amt == 0 )
1244 return ( 0 );
1245
1246 cur_used = buff->zctrl.next_out - buff->zbuff;
1247 new_size = buff->size + ext_amt;
1248
1249#ifdef DEBUG_HTTP
1250 if ( cur_used > new_size )
1251 xmlGenericError( xmlGenericErrorContext,
1252 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
1253 "Buffer overwrite detected during compressed memory",
1254 "buffer extension. Overflowed by",
1255 (cur_used - new_size ) );
1256#endif
1257
1258 tmp_ptr = xmlRealloc( buff->zbuff, new_size );
1259 if ( tmp_ptr != NULL ) {
1260 rc = 0;
1261 buff->size = new_size;
1262 buff->zbuff = tmp_ptr;
1263 buff->zctrl.next_out = tmp_ptr + cur_used;
1264 buff->zctrl.avail_out = new_size - cur_used;
1265 }
1266 else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001267 xmlChar msg[500];
1268 xmlStrPrintf(msg, 500,
1269 (const xmlChar *) "xmlZMemBuffExtend: %s %lu bytes.\n",
1270 "Allocation failure extending output buffer to",
1271 new_size );
1272 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001273 }
1274
1275 return ( rc );
1276}
1277
1278/**
1279 * xmlZMemBuffAppend
1280 * @buff: Buffer used to compress and consolidate data
1281 * @src: Uncompressed source content to append to buffer
1282 * @len: Length of source data to append to buffer
1283 *
1284 * Compress and append data to the internal buffer. The data buffer
1285 * will be expanded if needed to store the additional data.
1286 *
1287 * Returns the number of bytes appended to the buffer or -1 on error.
1288 */
1289static int
1290xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) {
1291
1292 int z_err;
1293 size_t min_accept;
1294
1295 if ( ( buff == NULL ) || ( src == NULL ) )
1296 return ( -1 );
1297
1298 buff->zctrl.avail_in = len;
1299 buff->zctrl.next_in = (unsigned char *)src;
1300 while ( buff->zctrl.avail_in > 0 ) {
1301 /*
1302 ** Extend the buffer prior to deflate call if a reasonable amount
1303 ** of output buffer space is not available.
1304 */
1305 min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO;
1306 if ( buff->zctrl.avail_out <= min_accept ) {
1307 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1308 return ( -1 );
1309 }
1310
1311 z_err = deflate( &buff->zctrl, Z_NO_FLUSH );
1312 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001313 xmlChar msg[500];
1314 xmlStrPrintf(msg, 500,
1315 (const xmlChar *) "xmlZMemBuffAppend: %s %d %s - %d",
Daniel Veillardf012a642001-07-23 19:10:52 +00001316 "Compression error while appending",
1317 len, "bytes to buffer. ZLIB error", z_err );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001318 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001319 return ( -1 );
1320 }
1321 }
1322
1323 buff->crc = crc32( buff->crc, (unsigned char *)src, len );
1324
1325 return ( len );
1326}
1327
1328/**
1329 * xmlZMemBuffGetContent
1330 * @buff: Compressed memory content buffer
1331 * @data_ref: Pointer reference to point to compressed content
1332 *
1333 * Flushes the compression buffers, appends gzip file trailers and
1334 * returns the compressed content and length of the compressed data.
1335 * NOTE: The gzip trailer code here is plagiarized from zlib source.
1336 *
1337 * Returns the length of the compressed data or -1 on error.
1338 */
1339static int
1340xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) {
1341
1342 int zlgth = -1;
1343 int z_err;
1344
1345 if ( ( buff == NULL ) || ( data_ref == NULL ) )
1346 return ( -1 );
1347
1348 /* Need to loop until compression output buffers are flushed */
1349
1350 do
1351 {
1352 z_err = deflate( &buff->zctrl, Z_FINISH );
1353 if ( z_err == Z_OK ) {
1354 /* In this case Z_OK means more buffer space needed */
1355
1356 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1357 return ( -1 );
1358 }
1359 }
1360 while ( z_err == Z_OK );
1361
1362 /* If the compression state is not Z_STREAM_END, some error occurred */
1363
1364 if ( z_err == Z_STREAM_END ) {
1365
1366 /* Need to append the gzip data trailer */
1367
1368 if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) {
1369 if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 )
1370 return ( -1 );
1371 }
1372
1373 /*
1374 ** For whatever reason, the CRC and length data are pushed out
1375 ** in reverse byte order. So a memcpy can't be used here.
1376 */
1377
1378 append_reverse_ulong( buff, buff->crc );
1379 append_reverse_ulong( buff, buff->zctrl.total_in );
1380
1381 zlgth = buff->zctrl.next_out - buff->zbuff;
1382 *data_ref = (char *)buff->zbuff;
1383 }
1384
Daniel Veillard05d987b2003-10-08 11:54:57 +00001385 else {
1386 xmlChar msg[500];
1387 xmlStrPrintf(msg, 500,
1388 (const xmlChar *) "xmlZMemBuffGetContent: %s - %d\n",
1389 "Error flushing zlib buffers. Error code", z_err );
1390 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1391 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001392
1393 return ( zlgth );
1394}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001395#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001396#endif /* HAVE_ZLIB_H */
1397
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001398#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001399/**
1400 * xmlFreeHTTPWriteCtxt
1401 * @ctxt: Context to cleanup
1402 *
1403 * Free allocated memory and reclaim system resources.
1404 *
1405 * No return value.
1406 */
1407static void
1408xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt )
1409{
1410 if ( ctxt->uri != NULL )
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001411 xmlFree( ctxt->uri );
Daniel Veillardf012a642001-07-23 19:10:52 +00001412
1413 if ( ctxt->doc_buff != NULL ) {
1414
1415#ifdef HAVE_ZLIB_H
1416 if ( ctxt->compression > 0 ) {
1417 xmlFreeZMemBuff( ctxt->doc_buff );
1418 }
1419 else
1420#endif
1421 {
1422 xmlOutputBufferClose( ctxt->doc_buff );
1423 }
1424 }
1425
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001426 xmlFree( ctxt );
Daniel Veillardf012a642001-07-23 19:10:52 +00001427 return;
1428}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001429#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001430
1431
Owen Taylor3473f882001-02-23 17:55:21 +00001432/**
1433 * xmlIOHTTPMatch:
1434 * @filename: the URI for matching
1435 *
1436 * check if the URI matches an HTTP one
1437 *
1438 * Returns 1 if matches, 0 otherwise
1439 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001440int
Owen Taylor3473f882001-02-23 17:55:21 +00001441xmlIOHTTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001442 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "http://", 7))
Owen Taylor3473f882001-02-23 17:55:21 +00001443 return(1);
1444 return(0);
1445}
1446
1447/**
1448 * xmlIOHTTPOpen:
1449 * @filename: the URI for matching
1450 *
1451 * open an HTTP I/O channel
1452 *
1453 * Returns an I/O context or NULL in case of error
1454 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001455void *
Owen Taylor3473f882001-02-23 17:55:21 +00001456xmlIOHTTPOpen (const char *filename) {
1457 return(xmlNanoHTTPOpen(filename, NULL));
1458}
1459
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001460#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001461/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001462 * xmlIOHTTPOpenW:
Daniel Veillardf012a642001-07-23 19:10:52 +00001463 * @post_uri: The destination URI for the document
1464 * @compression: The compression desired for the document.
1465 *
1466 * Open a temporary buffer to collect the document for a subsequent HTTP POST
1467 * request. Non-static as is called from the output buffer creation routine.
1468 *
1469 * Returns an I/O context or NULL in case of error.
1470 */
1471
1472void *
Daniel Veillard572577e2002-01-18 16:23:55 +00001473xmlIOHTTPOpenW(const char *post_uri, int compression)
1474{
Daniel Veillardf012a642001-07-23 19:10:52 +00001475
Daniel Veillard572577e2002-01-18 16:23:55 +00001476 xmlIOHTTPWriteCtxtPtr ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001477
Daniel Veillard572577e2002-01-18 16:23:55 +00001478 if (post_uri == NULL)
1479 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001480
Daniel Veillard572577e2002-01-18 16:23:55 +00001481 ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt));
1482 if (ctxt == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001483 xmlIOErrMemory("creating HTTP output context");
Daniel Veillard572577e2002-01-18 16:23:55 +00001484 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001485 }
1486
Daniel Veillard572577e2002-01-18 16:23:55 +00001487 (void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt));
Daniel Veillardf012a642001-07-23 19:10:52 +00001488
Daniel Veillard572577e2002-01-18 16:23:55 +00001489 ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri);
1490 if (ctxt->uri == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001491 xmlIOErrMemory("copying URI");
Daniel Veillard572577e2002-01-18 16:23:55 +00001492 xmlFreeHTTPWriteCtxt(ctxt);
1493 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001494 }
1495
1496 /*
Daniel Veillard572577e2002-01-18 16:23:55 +00001497 * ** Since the document length is required for an HTTP post,
1498 * ** need to put the document into a buffer. A memory buffer
1499 * ** is being used to avoid pushing the data to disk and back.
1500 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001501
1502#ifdef HAVE_ZLIB_H
Daniel Veillard572577e2002-01-18 16:23:55 +00001503 if ((compression > 0) && (compression <= 9)) {
1504
1505 ctxt->compression = compression;
1506 ctxt->doc_buff = xmlCreateZMemBuff(compression);
1507 } else
Daniel Veillardf012a642001-07-23 19:10:52 +00001508#endif
1509 {
Daniel Veillard572577e2002-01-18 16:23:55 +00001510 /* Any character conversions should have been done before this */
Daniel Veillardf012a642001-07-23 19:10:52 +00001511
Daniel Veillard572577e2002-01-18 16:23:55 +00001512 ctxt->doc_buff = xmlAllocOutputBuffer(NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001513 }
1514
Daniel Veillard572577e2002-01-18 16:23:55 +00001515 if (ctxt->doc_buff == NULL) {
1516 xmlFreeHTTPWriteCtxt(ctxt);
1517 ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001518 }
1519
Daniel Veillard572577e2002-01-18 16:23:55 +00001520 return (ctxt);
Daniel Veillardf012a642001-07-23 19:10:52 +00001521}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001522#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001523
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001524#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001525/**
1526 * xmlIOHTTPDfltOpenW
1527 * @post_uri: The destination URI for this document.
1528 *
1529 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
1530 * HTTP post command. This function should generally not be used as
1531 * the open callback is short circuited in xmlOutputBufferCreateFile.
1532 *
1533 * Returns a pointer to the new IO context.
1534 */
1535static void *
1536xmlIOHTTPDfltOpenW( const char * post_uri ) {
1537 return ( xmlIOHTTPOpenW( post_uri, 0 ) );
1538}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001539#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001540
1541/**
Owen Taylor3473f882001-02-23 17:55:21 +00001542 * xmlIOHTTPRead:
1543 * @context: the I/O context
1544 * @buffer: where to drop data
1545 * @len: number of bytes to write
1546 *
1547 * Read @len bytes to @buffer from the I/O channel.
1548 *
1549 * Returns the number of bytes written
1550 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001551int
Owen Taylor3473f882001-02-23 17:55:21 +00001552xmlIOHTTPRead(void * context, char * buffer, int len) {
Daniel Veillard5ea30d72004-11-08 11:54:28 +00001553 if ((buffer == NULL) || (len < 0)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001554 return(xmlNanoHTTPRead(context, &buffer[0], len));
1555}
1556
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001557#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001558/**
Daniel Veillardf012a642001-07-23 19:10:52 +00001559 * xmlIOHTTPWrite
1560 * @context: previously opened writing context
1561 * @buffer: data to output to temporary buffer
1562 * @len: bytes to output
1563 *
1564 * Collect data from memory buffer into a temporary file for later
1565 * processing.
1566 *
1567 * Returns number of bytes written.
1568 */
1569
1570static int
1571xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
1572
1573 xmlIOHTTPWriteCtxtPtr ctxt = context;
1574
1575 if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
1576 return ( -1 );
1577
1578 if ( len > 0 ) {
1579
1580 /* Use gzwrite or fwrite as previously setup in the open call */
1581
1582#ifdef HAVE_ZLIB_H
1583 if ( ctxt->compression > 0 )
1584 len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len );
1585
1586 else
1587#endif
1588 len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
1589
1590 if ( len < 0 ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001591 xmlChar msg[500];
1592 xmlStrPrintf(msg, 500,
1593 (const xmlChar *) "xmlIOHTTPWrite: %s\n%s '%s'.\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001594 "Error appending to internal buffer.",
1595 "Error sending document to URI",
1596 ctxt->uri );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001597 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001598 }
1599 }
1600
1601 return ( len );
1602}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001603#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001604
1605
1606/**
Owen Taylor3473f882001-02-23 17:55:21 +00001607 * xmlIOHTTPClose:
1608 * @context: the I/O context
1609 *
1610 * Close an HTTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001611 *
1612 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00001613 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001614int
Owen Taylor3473f882001-02-23 17:55:21 +00001615xmlIOHTTPClose (void * context) {
1616 xmlNanoHTTPClose(context);
Daniel Veillardf012a642001-07-23 19:10:52 +00001617 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001618}
Daniel Veillardf012a642001-07-23 19:10:52 +00001619
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001620#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001621/**
1622 * xmlIOHTTCloseWrite
1623 * @context: The I/O context
1624 * @http_mthd: The HTTP method to be used when sending the data
1625 *
1626 * Close the transmit HTTP I/O channel and actually send the data.
1627 */
1628static int
1629xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
1630
1631 int close_rc = -1;
1632 int http_rtn = 0;
1633 int content_lgth = 0;
1634 xmlIOHTTPWriteCtxtPtr ctxt = context;
1635
1636 char * http_content = NULL;
1637 char * content_encoding = NULL;
1638 char * content_type = (char *) "text/xml";
1639 void * http_ctxt = NULL;
1640
1641 if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
1642 return ( -1 );
1643
1644 /* Retrieve the content from the appropriate buffer */
1645
1646#ifdef HAVE_ZLIB_H
1647
1648 if ( ctxt->compression > 0 ) {
1649 content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
1650 content_encoding = (char *) "Content-Encoding: gzip";
1651 }
1652 else
1653#endif
1654 {
1655 /* Pull the data out of the memory output buffer */
1656
1657 xmlOutputBufferPtr dctxt = ctxt->doc_buff;
1658 http_content = (char *)dctxt->buffer->content;
1659 content_lgth = dctxt->buffer->use;
1660 }
1661
1662 if ( http_content == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001663 xmlChar msg[500];
1664 xmlStrPrintf(msg, 500,
1665 (const xmlChar *) "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
1666 "Error retrieving content.\nUnable to",
1667 http_mthd, "data to URI", ctxt->uri );
1668 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001669 }
1670
1671 else {
1672
1673 http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
1674 &content_type, content_encoding,
1675 content_lgth );
1676
1677 if ( http_ctxt != NULL ) {
1678#ifdef DEBUG_HTTP
1679 /* If testing/debugging - dump reply with request content */
1680
1681 FILE * tst_file = NULL;
1682 char buffer[ 4096 ];
1683 char * dump_name = NULL;
1684 int avail;
1685
1686 xmlGenericError( xmlGenericErrorContext,
1687 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
1688 http_mthd, ctxt->uri,
1689 xmlNanoHTTPReturnCode( http_ctxt ) );
1690
1691 /*
1692 ** Since either content or reply may be gzipped,
1693 ** dump them to separate files instead of the
1694 ** standard error context.
1695 */
1696
1697 dump_name = tempnam( NULL, "lxml" );
1698 if ( dump_name != NULL ) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001699 (void)snprintf( buffer, sizeof(buffer), "%s.content", dump_name );
Daniel Veillardf012a642001-07-23 19:10:52 +00001700
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00001701 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00001702 if ( tst_file != NULL ) {
1703 xmlGenericError( xmlGenericErrorContext,
1704 "Transmitted content saved in file: %s\n", buffer );
1705
1706 fwrite( http_content, sizeof( char ),
1707 content_lgth, tst_file );
1708 fclose( tst_file );
1709 }
1710
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001711 (void)snprintf( buffer, sizeof(buffer), "%s.reply", dump_name );
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00001712 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00001713 if ( tst_file != NULL ) {
1714 xmlGenericError( xmlGenericErrorContext,
1715 "Reply content saved in file: %s\n", buffer );
1716
1717
1718 while ( (avail = xmlNanoHTTPRead( http_ctxt,
1719 buffer, sizeof( buffer ) )) > 0 ) {
1720
1721 fwrite( buffer, sizeof( char ), avail, tst_file );
1722 }
1723
1724 fclose( tst_file );
1725 }
1726
1727 free( dump_name );
1728 }
1729#endif /* DEBUG_HTTP */
1730
1731 http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
1732 if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
1733 close_rc = 0;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001734 else {
1735 xmlChar msg[500];
1736 xmlStrPrintf(msg, 500,
1737 (const xmlChar *) "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001738 http_mthd, content_lgth,
1739 "bytes to URI", ctxt->uri,
1740 "failed. HTTP return code:", http_rtn );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001741 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1742 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001743
1744 xmlNanoHTTPClose( http_ctxt );
1745 xmlFree( content_type );
1746 }
1747 }
1748
1749 /* Final cleanups */
1750
1751 xmlFreeHTTPWriteCtxt( ctxt );
1752
1753 return ( close_rc );
1754}
1755
1756/**
1757 * xmlIOHTTPClosePut
1758 *
1759 * @context: The I/O context
1760 *
1761 * Close the transmit HTTP I/O channel and actually send data using a PUT
1762 * HTTP method.
1763 */
1764static int
1765xmlIOHTTPClosePut( void * ctxt ) {
1766 return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
1767}
1768
1769
1770/**
1771 * xmlIOHTTPClosePost
1772 *
1773 * @context: The I/O context
1774 *
1775 * Close the transmit HTTP I/O channel and actually send data using a POST
1776 * HTTP method.
1777 */
1778static int
1779xmlIOHTTPClosePost( void * ctxt ) {
1780 return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
1781}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001782#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001783
Owen Taylor3473f882001-02-23 17:55:21 +00001784#endif /* LIBXML_HTTP_ENABLED */
1785
1786#ifdef LIBXML_FTP_ENABLED
1787/************************************************************************
1788 * *
1789 * I/O for FTP file accesses *
1790 * *
1791 ************************************************************************/
1792/**
1793 * xmlIOFTPMatch:
1794 * @filename: the URI for matching
1795 *
1796 * check if the URI matches an FTP one
1797 *
1798 * Returns 1 if matches, 0 otherwise
1799 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001800int
Owen Taylor3473f882001-02-23 17:55:21 +00001801xmlIOFTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001802 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "ftp://", 6))
Owen Taylor3473f882001-02-23 17:55:21 +00001803 return(1);
1804 return(0);
1805}
1806
1807/**
1808 * xmlIOFTPOpen:
1809 * @filename: the URI for matching
1810 *
1811 * open an FTP I/O channel
1812 *
1813 * Returns an I/O context or NULL in case of error
1814 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001815void *
Owen Taylor3473f882001-02-23 17:55:21 +00001816xmlIOFTPOpen (const char *filename) {
1817 return(xmlNanoFTPOpen(filename));
1818}
1819
1820/**
1821 * xmlIOFTPRead:
1822 * @context: the I/O context
1823 * @buffer: where to drop data
1824 * @len: number of bytes to write
1825 *
1826 * Read @len bytes to @buffer from the I/O channel.
1827 *
1828 * Returns the number of bytes written
1829 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001830int
Owen Taylor3473f882001-02-23 17:55:21 +00001831xmlIOFTPRead(void * context, char * buffer, int len) {
Daniel Veillard5ea30d72004-11-08 11:54:28 +00001832 if ((buffer == NULL) || (len < 0)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001833 return(xmlNanoFTPRead(context, &buffer[0], len));
1834}
1835
1836/**
1837 * xmlIOFTPClose:
1838 * @context: the I/O context
1839 *
1840 * Close an FTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001841 *
1842 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00001843 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001844int
Owen Taylor3473f882001-02-23 17:55:21 +00001845xmlIOFTPClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001846 return ( xmlNanoFTPClose(context) );
Owen Taylor3473f882001-02-23 17:55:21 +00001847}
1848#endif /* LIBXML_FTP_ENABLED */
1849
1850
1851/**
1852 * xmlRegisterInputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001853 * @matchFunc: the xmlInputMatchCallback
1854 * @openFunc: the xmlInputOpenCallback
1855 * @readFunc: the xmlInputReadCallback
1856 * @closeFunc: the xmlInputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001857 *
1858 * Register a new set of I/O callback for handling parser input.
1859 *
1860 * Returns the registered handler number or -1 in case of error
1861 */
1862int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001863xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
1864 xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
1865 xmlInputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001866 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
1867 return(-1);
1868 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001869 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
1870 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
1871 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
1872 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00001873 xmlInputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00001874 return(xmlInputCallbackNr++);
1875}
1876
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001877#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001878/**
1879 * xmlRegisterOutputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001880 * @matchFunc: the xmlOutputMatchCallback
1881 * @openFunc: the xmlOutputOpenCallback
1882 * @writeFunc: the xmlOutputWriteCallback
1883 * @closeFunc: the xmlOutputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001884 *
1885 * Register a new set of I/O callback for handling output.
1886 *
1887 * Returns the registered handler number or -1 in case of error
1888 */
1889int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001890xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
1891 xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
1892 xmlOutputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001893 if (xmlOutputCallbackNr >= MAX_INPUT_CALLBACK) {
1894 return(-1);
1895 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001896 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
1897 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
1898 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
1899 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00001900 xmlOutputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00001901 return(xmlOutputCallbackNr++);
1902}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001903#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001904
1905/**
1906 * xmlRegisterDefaultInputCallbacks:
1907 *
1908 * Registers the default compiled-in I/O handlers.
1909 */
1910void
Owen Taylor3473f882001-02-23 17:55:21 +00001911xmlRegisterDefaultInputCallbacks
Owen Taylor3473f882001-02-23 17:55:21 +00001912(void) {
1913 if (xmlInputCallbackInitialized)
1914 return;
1915
1916 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
1917 xmlFileRead, xmlFileClose);
1918#ifdef HAVE_ZLIB_H
1919 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1920 xmlGzfileRead, xmlGzfileClose);
1921#endif /* HAVE_ZLIB_H */
1922
1923#ifdef LIBXML_HTTP_ENABLED
1924 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
1925 xmlIOHTTPRead, xmlIOHTTPClose);
1926#endif /* LIBXML_HTTP_ENABLED */
1927
1928#ifdef LIBXML_FTP_ENABLED
1929 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1930 xmlIOFTPRead, xmlIOFTPClose);
1931#endif /* LIBXML_FTP_ENABLED */
1932 xmlInputCallbackInitialized = 1;
1933}
1934
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001935#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001936/**
1937 * xmlRegisterDefaultOutputCallbacks:
1938 *
1939 * Registers the default compiled-in I/O handlers.
1940 */
1941void
Owen Taylor3473f882001-02-23 17:55:21 +00001942xmlRegisterDefaultOutputCallbacks
Owen Taylor3473f882001-02-23 17:55:21 +00001943(void) {
1944 if (xmlOutputCallbackInitialized)
1945 return;
1946
1947 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
1948 xmlFileWrite, xmlFileClose);
Daniel Veillardf012a642001-07-23 19:10:52 +00001949
1950#ifdef LIBXML_HTTP_ENABLED
1951 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
1952 xmlIOHTTPWrite, xmlIOHTTPClosePut);
1953#endif
1954
Owen Taylor3473f882001-02-23 17:55:21 +00001955/*********************************
1956 No way a-priori to distinguish between gzipped files from
1957 uncompressed ones except opening if existing then closing
1958 and saving with same compression ratio ... a pain.
1959
1960#ifdef HAVE_ZLIB_H
1961 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1962 xmlGzfileWrite, xmlGzfileClose);
1963#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001964
1965 Nor FTP PUT ....
1966#ifdef LIBXML_FTP_ENABLED
1967 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1968 xmlIOFTPWrite, xmlIOFTPClose);
1969#endif
1970 **********************************/
1971 xmlOutputCallbackInitialized = 1;
1972}
1973
Daniel Veillardf012a642001-07-23 19:10:52 +00001974#ifdef LIBXML_HTTP_ENABLED
1975/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001976 * xmlRegisterHTTPPostCallbacks:
Daniel Veillardf012a642001-07-23 19:10:52 +00001977 *
1978 * By default, libxml submits HTTP output requests using the "PUT" method.
1979 * Calling this method changes the HTTP output method to use the "POST"
1980 * method instead.
1981 *
1982 */
1983void
1984xmlRegisterHTTPPostCallbacks( void ) {
1985
1986 /* Register defaults if not done previously */
1987
1988 if ( xmlOutputCallbackInitialized == 0 )
1989 xmlRegisterDefaultOutputCallbacks( );
1990
1991 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
1992 xmlIOHTTPWrite, xmlIOHTTPClosePost);
1993 return;
1994}
1995#endif
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001996#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001997
Owen Taylor3473f882001-02-23 17:55:21 +00001998/**
1999 * xmlAllocParserInputBuffer:
2000 * @enc: the charset encoding if known
2001 *
2002 * Create a buffered parser input for progressive parsing
2003 *
2004 * Returns the new parser input or NULL
2005 */
2006xmlParserInputBufferPtr
2007xmlAllocParserInputBuffer(xmlCharEncoding enc) {
2008 xmlParserInputBufferPtr ret;
2009
2010 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2011 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002012 xmlIOErrMemory("creating input buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00002013 return(NULL);
2014 }
2015 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002016 ret->buffer = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00002017 if (ret->buffer == NULL) {
2018 xmlFree(ret);
2019 return(NULL);
2020 }
2021 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
2022 ret->encoder = xmlGetCharEncodingHandler(enc);
2023 if (ret->encoder != NULL)
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002024 ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00002025 else
2026 ret->raw = NULL;
2027 ret->readcallback = NULL;
2028 ret->closecallback = NULL;
2029 ret->context = NULL;
William M. Brackc07329e2003-09-08 01:57:30 +00002030 ret->compressed = -1;
Daniel Veillard36711902004-02-11 13:25:26 +00002031 ret->rawconsumed = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002032
2033 return(ret);
2034}
2035
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002036#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002037/**
2038 * xmlAllocOutputBuffer:
2039 * @encoder: the encoding converter or NULL
2040 *
2041 * Create a buffered parser output
2042 *
2043 * Returns the new parser output or NULL
2044 */
2045xmlOutputBufferPtr
2046xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
2047 xmlOutputBufferPtr ret;
2048
2049 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
2050 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002051 xmlIOErrMemory("creating output buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00002052 return(NULL);
2053 }
2054 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
2055 ret->buffer = xmlBufferCreate();
2056 if (ret->buffer == NULL) {
2057 xmlFree(ret);
2058 return(NULL);
2059 }
2060 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
2061 ret->encoder = encoder;
2062 if (encoder != NULL) {
2063 ret->conv = xmlBufferCreateSize(4000);
2064 /*
2065 * This call is designed to initiate the encoder state
2066 */
2067 xmlCharEncOutFunc(encoder, ret->conv, NULL);
2068 } else
2069 ret->conv = NULL;
2070 ret->writecallback = NULL;
2071 ret->closecallback = NULL;
2072 ret->context = NULL;
2073 ret->written = 0;
2074
2075 return(ret);
2076}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002077#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002078
2079/**
2080 * xmlFreeParserInputBuffer:
2081 * @in: a buffered parser input
2082 *
2083 * Free up the memory used by a buffered parser input
2084 */
2085void
2086xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
Daniel Veillard8d8bf2c2003-09-17 19:36:25 +00002087 if (in == NULL) return;
2088
Owen Taylor3473f882001-02-23 17:55:21 +00002089 if (in->raw) {
2090 xmlBufferFree(in->raw);
2091 in->raw = NULL;
2092 }
2093 if (in->encoder != NULL) {
2094 xmlCharEncCloseFunc(in->encoder);
2095 }
2096 if (in->closecallback != NULL) {
2097 in->closecallback(in->context);
2098 }
2099 if (in->buffer != NULL) {
2100 xmlBufferFree(in->buffer);
2101 in->buffer = NULL;
2102 }
2103
Owen Taylor3473f882001-02-23 17:55:21 +00002104 xmlFree(in);
2105}
2106
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002107#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002108/**
2109 * xmlOutputBufferClose:
2110 * @out: a buffered output
2111 *
2112 * flushes and close the output I/O channel
2113 * and free up all the associated resources
2114 *
2115 * Returns the number of byte written or -1 in case of error.
2116 */
2117int
Daniel Veillard828ce832003-10-08 19:19:10 +00002118xmlOutputBufferClose(xmlOutputBufferPtr out)
2119{
Owen Taylor3473f882001-02-23 17:55:21 +00002120 int written;
Daniel Veillardf012a642001-07-23 19:10:52 +00002121 int err_rc = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002122
2123 if (out == NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002124 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002125 if (out->writecallback != NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002126 xmlOutputBufferFlush(out);
Owen Taylor3473f882001-02-23 17:55:21 +00002127 if (out->closecallback != NULL) {
Daniel Veillard828ce832003-10-08 19:19:10 +00002128 err_rc = out->closecallback(out->context);
Owen Taylor3473f882001-02-23 17:55:21 +00002129 }
2130 written = out->written;
2131 if (out->conv) {
2132 xmlBufferFree(out->conv);
Daniel Veillard828ce832003-10-08 19:19:10 +00002133 out->conv = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002134 }
2135 if (out->encoder != NULL) {
2136 xmlCharEncCloseFunc(out->encoder);
2137 }
2138 if (out->buffer != NULL) {
2139 xmlBufferFree(out->buffer);
Daniel Veillard828ce832003-10-08 19:19:10 +00002140 out->buffer = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002141 }
2142
Daniel Veillard828ce832003-10-08 19:19:10 +00002143 if (out->error)
2144 err_rc = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00002145 xmlFree(out);
Daniel Veillard828ce832003-10-08 19:19:10 +00002146 return ((err_rc == 0) ? written : err_rc);
Owen Taylor3473f882001-02-23 17:55:21 +00002147}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002148#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002149
Daniel Veillard1b243b42004-06-08 10:16:42 +00002150xmlParserInputBufferPtr
Daniel Veillard0335a842004-06-02 16:18:40 +00002151__xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002152 xmlParserInputBufferPtr ret;
Daniel Veillard388236f2001-07-08 18:35:48 +00002153 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002154 void *context = NULL;
2155
2156 if (xmlInputCallbackInitialized == 0)
2157 xmlRegisterDefaultInputCallbacks();
2158
2159 if (URI == NULL) return(NULL);
2160
2161 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002162 * Try to find one of the input accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002163 * Go in reverse to give precedence to user defined handlers.
Daniel Veillard388236f2001-07-08 18:35:48 +00002164 */
2165 if (context == NULL) {
2166 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
2167 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
2168 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002169 context = xmlInputCallbackTable[i].opencallback(URI);
Daniel Veillard847332a2003-10-18 11:29:40 +00002170 if (context != NULL) {
Daniel Veillard388236f2001-07-08 18:35:48 +00002171 break;
Daniel Veillard847332a2003-10-18 11:29:40 +00002172 }
Daniel Veillard388236f2001-07-08 18:35:48 +00002173 }
Owen Taylor3473f882001-02-23 17:55:21 +00002174 }
2175 }
2176 if (context == NULL) {
2177 return(NULL);
2178 }
2179
2180 /*
2181 * Allocate the Input buffer front-end.
2182 */
2183 ret = xmlAllocParserInputBuffer(enc);
2184 if (ret != NULL) {
2185 ret->context = context;
2186 ret->readcallback = xmlInputCallbackTable[i].readcallback;
2187 ret->closecallback = xmlInputCallbackTable[i].closecallback;
William M. Brackc07329e2003-09-08 01:57:30 +00002188#ifdef HAVE_ZLIB_H
William M. Brackc5cbf992003-10-29 22:15:13 +00002189 if ((xmlInputCallbackTable[i].opencallback == xmlGzfileOpen) &&
2190 (strcmp(URI, "-") != 0)) {
William M. Brackc07329e2003-09-08 01:57:30 +00002191 if (((z_stream *)context)->avail_in > 4) {
2192 char *cptr, buff4[4];
Daniel Veillard07cb8222003-09-10 10:51:05 +00002193 cptr = (char *) ((z_stream *)context)->next_in;
William M. Brackc07329e2003-09-08 01:57:30 +00002194 if (gzread(context, buff4, 4) == 4) {
2195 if (strncmp(buff4, cptr, 4) == 0)
2196 ret->compressed = 0;
2197 else
2198 ret->compressed = 1;
2199 gzrewind(context);
2200 }
2201 }
2202 }
2203#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002204 }
William M. Brack42331a92004-07-29 07:07:16 +00002205 else
2206 xmlInputCallbackTable[i].closecallback (context);
2207
Owen Taylor3473f882001-02-23 17:55:21 +00002208 return(ret);
2209}
2210
2211/**
Daniel Veillard0335a842004-06-02 16:18:40 +00002212 * xmlParserInputBufferCreateFilename:
Owen Taylor3473f882001-02-23 17:55:21 +00002213 * @URI: a C string containing the URI or filename
Daniel Veillard0335a842004-06-02 16:18:40 +00002214 * @enc: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002215 *
Daniel Veillard0335a842004-06-02 16:18:40 +00002216 * Create a buffered parser input for the progressive parsing of a file
2217 * If filename is "-' then we use stdin as the input.
Owen Taylor3473f882001-02-23 17:55:21 +00002218 * Automatic support for ZLIB/Compress compressed document is provided
2219 * by default if found at compile-time.
Daniel Veillard0335a842004-06-02 16:18:40 +00002220 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
Owen Taylor3473f882001-02-23 17:55:21 +00002221 *
Daniel Veillard0335a842004-06-02 16:18:40 +00002222 * Returns the new parser input or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00002223 */
Daniel Veillard0335a842004-06-02 16:18:40 +00002224xmlParserInputBufferPtr
2225xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
2226 if ((xmlParserInputBufferCreateFilenameValue)) {
2227 return xmlParserInputBufferCreateFilenameValue(URI, enc);
2228 }
2229 return __xmlParserInputBufferCreateFilename(URI, enc);
2230}
2231
2232#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard1b243b42004-06-08 10:16:42 +00002233xmlOutputBufferPtr
Daniel Veillard0335a842004-06-02 16:18:40 +00002234__xmlOutputBufferCreateFilename(const char *URI,
Owen Taylor3473f882001-02-23 17:55:21 +00002235 xmlCharEncodingHandlerPtr encoder,
Daniel Veillard0335a842004-06-02 16:18:40 +00002236 int compression ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00002237 xmlOutputBufferPtr ret;
Daniel Veillard966a31e2004-05-09 02:58:44 +00002238 xmlURIPtr puri;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002239 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002240 void *context = NULL;
Daniel Veillard966a31e2004-05-09 02:58:44 +00002241 char *unescaped = NULL;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002242#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002243 int is_file_uri = 1;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002244#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00002245
Owen Taylor3473f882001-02-23 17:55:21 +00002246 if (xmlOutputCallbackInitialized == 0)
2247 xmlRegisterDefaultOutputCallbacks();
2248
2249 if (URI == NULL) return(NULL);
2250
Daniel Veillard966a31e2004-05-09 02:58:44 +00002251 puri = xmlParseURI(URI);
2252 if (puri != NULL) {
Daniel Veillard18a65092004-05-11 15:57:42 +00002253 if ((puri->scheme != NULL) &&
2254 (!xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002255#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002256 is_file_uri = 0;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002257#endif
Daniel Veillard966a31e2004-05-09 02:58:44 +00002258 /*
2259 * try to limit the damages of the URI unescaping code.
2260 */
2261 if (puri->scheme != NULL)
2262 unescaped = xmlURIUnescapeString(URI, 0, NULL);
2263 xmlFreeURI(puri);
2264 }
Owen Taylor3473f882001-02-23 17:55:21 +00002265
2266 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002267 * Try to find one of the output accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002268 * Go in reverse to give precedence to user defined handlers.
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002269 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00002270 */
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002271 if (unescaped != NULL) {
2272#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002273 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002274 context = xmlGzfileOpenW(unescaped, compression);
2275 if (context != NULL) {
2276 ret = xmlAllocOutputBuffer(encoder);
2277 if (ret != NULL) {
2278 ret->context = context;
2279 ret->writecallback = xmlGzfileWrite;
2280 ret->closecallback = xmlGzfileClose;
2281 }
2282 xmlFree(unescaped);
2283 return(ret);
2284 }
2285 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002286#endif
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002287 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2288 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
2289 (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
2290#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2291 /* Need to pass compression parameter into HTTP open calls */
2292 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2293 context = xmlIOHTTPOpenW(unescaped, compression);
2294 else
2295#endif
2296 context = xmlOutputCallbackTable[i].opencallback(unescaped);
2297 if (context != NULL)
2298 break;
2299 }
2300 }
2301 xmlFree(unescaped);
2302 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002303
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002304 /*
2305 * If this failed try with a non-escaped URI this may be a strange
2306 * filename
2307 */
2308 if (context == NULL) {
2309#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002310 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002311 context = xmlGzfileOpenW(URI, compression);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002312 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 return(ret);
2320 }
2321 }
2322#endif
2323 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2324 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002325 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002326#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2327 /* Need to pass compression parameter into HTTP open calls */
2328 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2329 context = xmlIOHTTPOpenW(URI, compression);
2330 else
2331#endif
2332 context = xmlOutputCallbackTable[i].opencallback(URI);
2333 if (context != NULL)
2334 break;
2335 }
Owen Taylor3473f882001-02-23 17:55:21 +00002336 }
2337 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002338
Owen Taylor3473f882001-02-23 17:55:21 +00002339 if (context == NULL) {
2340 return(NULL);
2341 }
2342
2343 /*
2344 * Allocate the Output buffer front-end.
2345 */
2346 ret = xmlAllocOutputBuffer(encoder);
2347 if (ret != NULL) {
2348 ret->context = context;
2349 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
2350 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
2351 }
2352 return(ret);
2353}
Daniel Veillard0335a842004-06-02 16:18:40 +00002354
2355/**
2356 * xmlOutputBufferCreateFilename:
2357 * @URI: a C string containing the URI or filename
2358 * @encoder: the encoding converter or NULL
2359 * @compression: the compression ration (0 none, 9 max).
2360 *
2361 * Create a buffered output for the progressive saving of a file
2362 * If filename is "-' then we use stdout as the output.
2363 * Automatic support for ZLIB/Compress compressed document is provided
2364 * by default if found at compile-time.
2365 * TODO: currently if compression is set, the library only support
2366 * writing to a local file.
2367 *
2368 * Returns the new output or NULL
2369 */
2370xmlOutputBufferPtr
2371xmlOutputBufferCreateFilename(const char *URI,
2372 xmlCharEncodingHandlerPtr encoder,
2373 int compression ATTRIBUTE_UNUSED) {
2374 if ((xmlOutputBufferCreateFilenameValue)) {
2375 return xmlOutputBufferCreateFilenameValue(URI, encoder, compression);
2376 }
2377 return __xmlOutputBufferCreateFilename(URI, encoder, compression);
2378}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002379#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002380
2381/**
2382 * xmlParserInputBufferCreateFile:
2383 * @file: a FILE*
2384 * @enc: the charset encoding if known
2385 *
2386 * Create a buffered parser input for the progressive parsing of a FILE *
2387 * buffered C I/O
2388 *
2389 * Returns the new parser input or NULL
2390 */
2391xmlParserInputBufferPtr
2392xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
2393 xmlParserInputBufferPtr ret;
2394
2395 if (xmlInputCallbackInitialized == 0)
2396 xmlRegisterDefaultInputCallbacks();
2397
2398 if (file == NULL) return(NULL);
2399
2400 ret = xmlAllocParserInputBuffer(enc);
2401 if (ret != NULL) {
2402 ret->context = file;
2403 ret->readcallback = xmlFileRead;
2404 ret->closecallback = xmlFileFlush;
2405 }
2406
2407 return(ret);
2408}
2409
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002410#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002411/**
2412 * xmlOutputBufferCreateFile:
2413 * @file: a FILE*
2414 * @encoder: the encoding converter or NULL
2415 *
2416 * Create a buffered output for the progressive saving to a FILE *
2417 * buffered C I/O
2418 *
2419 * Returns the new parser output or NULL
2420 */
2421xmlOutputBufferPtr
2422xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
2423 xmlOutputBufferPtr ret;
2424
2425 if (xmlOutputCallbackInitialized == 0)
2426 xmlRegisterDefaultOutputCallbacks();
2427
2428 if (file == NULL) return(NULL);
2429
2430 ret = xmlAllocOutputBuffer(encoder);
2431 if (ret != NULL) {
2432 ret->context = file;
2433 ret->writecallback = xmlFileWrite;
2434 ret->closecallback = xmlFileFlush;
2435 }
2436
2437 return(ret);
2438}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002439#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002440
2441/**
2442 * xmlParserInputBufferCreateFd:
2443 * @fd: a file descriptor number
2444 * @enc: the charset encoding if known
2445 *
2446 * Create a buffered parser input for the progressive parsing for the input
2447 * from a file descriptor
2448 *
2449 * Returns the new parser input or NULL
2450 */
2451xmlParserInputBufferPtr
2452xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
2453 xmlParserInputBufferPtr ret;
2454
2455 if (fd < 0) return(NULL);
2456
2457 ret = xmlAllocParserInputBuffer(enc);
2458 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002459 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002460 ret->readcallback = xmlFdRead;
2461 ret->closecallback = xmlFdClose;
2462 }
2463
2464 return(ret);
2465}
2466
2467/**
2468 * xmlParserInputBufferCreateMem:
2469 * @mem: the memory input
2470 * @size: the length of the memory block
2471 * @enc: the charset encoding if known
2472 *
2473 * Create a buffered parser input for the progressive parsing for the input
2474 * from a memory area.
2475 *
2476 * Returns the new parser input or NULL
2477 */
2478xmlParserInputBufferPtr
2479xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
2480 xmlParserInputBufferPtr ret;
William M. Bracka3215c72004-07-31 16:24:01 +00002481 int errcode;
Owen Taylor3473f882001-02-23 17:55:21 +00002482
2483 if (size <= 0) return(NULL);
2484 if (mem == NULL) return(NULL);
2485
2486 ret = xmlAllocParserInputBuffer(enc);
2487 if (ret != NULL) {
2488 ret->context = (void *) mem;
2489 ret->readcallback = (xmlInputReadCallback) xmlNop;
2490 ret->closecallback = NULL;
William M. Bracka3215c72004-07-31 16:24:01 +00002491 errcode = xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size);
2492 if (errcode != 0) {
2493 xmlFree(ret);
2494 return(NULL);
2495 }
Owen Taylor3473f882001-02-23 17:55:21 +00002496 }
2497
2498 return(ret);
2499}
2500
2501/**
Daniel Veillard53350552003-09-18 13:35:51 +00002502 * xmlParserInputBufferCreateStatic:
2503 * @mem: the memory input
2504 * @size: the length of the memory block
2505 * @enc: the charset encoding if known
2506 *
2507 * Create a buffered parser input for the progressive parsing for the input
2508 * from an immutable memory area. This will not copy the memory area to
2509 * the buffer, but the memory is expected to be available until the end of
2510 * the parsing, this is useful for example when using mmap'ed file.
2511 *
2512 * Returns the new parser input or NULL
2513 */
2514xmlParserInputBufferPtr
2515xmlParserInputBufferCreateStatic(const char *mem, int size,
2516 xmlCharEncoding enc) {
2517 xmlParserInputBufferPtr ret;
2518
2519 if (size <= 0) return(NULL);
2520 if (mem == NULL) return(NULL);
2521
2522 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2523 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002524 xmlIOErrMemory("creating input buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00002525 return(NULL);
2526 }
2527 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillarde72c5082003-09-19 12:44:05 +00002528 ret->buffer = xmlBufferCreateStatic((void *)mem, (size_t) size);
Daniel Veillard53350552003-09-18 13:35:51 +00002529 if (ret->buffer == NULL) {
2530 xmlFree(ret);
2531 return(NULL);
2532 }
2533 ret->encoder = xmlGetCharEncodingHandler(enc);
2534 if (ret->encoder != NULL)
2535 ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
2536 else
2537 ret->raw = NULL;
2538 ret->compressed = -1;
2539 ret->context = (void *) mem;
2540 ret->readcallback = NULL;
2541 ret->closecallback = NULL;
2542
2543 return(ret);
2544}
2545
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002546#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard53350552003-09-18 13:35:51 +00002547/**
Owen Taylor3473f882001-02-23 17:55:21 +00002548 * xmlOutputBufferCreateFd:
2549 * @fd: a file descriptor number
2550 * @encoder: the encoding converter or NULL
2551 *
2552 * Create a buffered output for the progressive saving
2553 * to a file descriptor
2554 *
2555 * Returns the new parser output or NULL
2556 */
2557xmlOutputBufferPtr
2558xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
2559 xmlOutputBufferPtr ret;
2560
2561 if (fd < 0) return(NULL);
2562
2563 ret = xmlAllocOutputBuffer(encoder);
2564 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002565 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002566 ret->writecallback = xmlFdWrite;
Daniel Veillard7db38712002-02-07 16:39:11 +00002567 ret->closecallback = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002568 }
2569
2570 return(ret);
2571}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002572#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002573
2574/**
2575 * xmlParserInputBufferCreateIO:
2576 * @ioread: an I/O read function
2577 * @ioclose: an I/O close function
2578 * @ioctx: an I/O handler
2579 * @enc: the charset encoding if known
2580 *
2581 * Create a buffered parser input for the progressive parsing for the input
2582 * from an I/O handler
2583 *
2584 * Returns the new parser input or NULL
2585 */
2586xmlParserInputBufferPtr
2587xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
2588 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
2589 xmlParserInputBufferPtr ret;
2590
2591 if (ioread == NULL) return(NULL);
2592
2593 ret = xmlAllocParserInputBuffer(enc);
2594 if (ret != NULL) {
2595 ret->context = (void *) ioctx;
2596 ret->readcallback = ioread;
2597 ret->closecallback = ioclose;
2598 }
2599
2600 return(ret);
2601}
2602
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002603#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002604/**
2605 * xmlOutputBufferCreateIO:
2606 * @iowrite: an I/O write function
2607 * @ioclose: an I/O close function
2608 * @ioctx: an I/O handler
Daniel Veillard9d06d302002-01-22 18:15:52 +00002609 * @encoder: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002610 *
2611 * Create a buffered output for the progressive saving
2612 * to an I/O handler
2613 *
2614 * Returns the new parser output or NULL
2615 */
2616xmlOutputBufferPtr
2617xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
2618 xmlOutputCloseCallback ioclose, void *ioctx,
2619 xmlCharEncodingHandlerPtr encoder) {
2620 xmlOutputBufferPtr ret;
2621
2622 if (iowrite == NULL) return(NULL);
2623
2624 ret = xmlAllocOutputBuffer(encoder);
2625 if (ret != NULL) {
2626 ret->context = (void *) ioctx;
2627 ret->writecallback = iowrite;
2628 ret->closecallback = ioclose;
2629 }
2630
2631 return(ret);
2632}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002633#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002634
2635/**
Daniel Veillard1b243b42004-06-08 10:16:42 +00002636 * xmlParserInputBufferCreateFilenameDefault:
2637 * @func: function pointer to the new ParserInputBufferCreateFilenameFunc
2638 *
2639 * Registers a callback for URI input file handling
2640 *
2641 * Returns the old value of the registration function
2642 */
2643xmlParserInputBufferCreateFilenameFunc
2644xmlParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func)
2645{
2646 xmlParserInputBufferCreateFilenameFunc old = xmlParserInputBufferCreateFilenameValue;
2647 if (old == NULL) {
2648 old = __xmlParserInputBufferCreateFilename;
2649 }
2650
2651 xmlParserInputBufferCreateFilenameValue = func;
2652 return(old);
2653}
2654
2655/**
2656 * xmlOutputBufferCreateFilenameDefault:
2657 * @func: function pointer to the new OutputBufferCreateFilenameFunc
2658 *
2659 * Registers a callback for URI output file handling
2660 *
2661 * Returns the old value of the registration function
2662 */
2663xmlOutputBufferCreateFilenameFunc
2664xmlOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func)
2665{
2666 xmlOutputBufferCreateFilenameFunc old = xmlOutputBufferCreateFilenameValue;
2667#ifdef LIBXML_OUTPUT_ENABLED
2668 if (old == NULL) {
2669 old = __xmlOutputBufferCreateFilename;
2670 }
2671#endif
2672 xmlOutputBufferCreateFilenameValue = func;
2673 return(old);
2674}
2675
2676/**
Owen Taylor3473f882001-02-23 17:55:21 +00002677 * xmlParserInputBufferPush:
2678 * @in: a buffered parser input
2679 * @len: the size in bytes of the array.
2680 * @buf: an char array
2681 *
2682 * Push the content of the arry in the input buffer
2683 * This routine handle the I18N transcoding to internal UTF-8
2684 * This is used when operating the parser in progressive (push) mode.
2685 *
2686 * Returns the number of chars read and stored in the buffer, or -1
2687 * in case of error.
2688 */
2689int
2690xmlParserInputBufferPush(xmlParserInputBufferPtr in,
2691 int len, const char *buf) {
2692 int nbchars = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00002693 int ret;
Owen Taylor3473f882001-02-23 17:55:21 +00002694
2695 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002696 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002697 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00002698 unsigned int use;
2699
Owen Taylor3473f882001-02-23 17:55:21 +00002700 /*
2701 * Store the data in the incoming raw buffer
2702 */
2703 if (in->raw == NULL) {
2704 in->raw = xmlBufferCreate();
2705 }
William M. Bracka3215c72004-07-31 16:24:01 +00002706 ret = xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
2707 if (ret != 0)
2708 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002709
2710 /*
2711 * convert as much as possible to the parser reading buffer.
2712 */
Daniel Veillard36711902004-02-11 13:25:26 +00002713 use = in->raw->use;
Owen Taylor3473f882001-02-23 17:55:21 +00002714 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2715 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002716 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002717 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002718 return(-1);
2719 }
Daniel Veillard36711902004-02-11 13:25:26 +00002720 in->rawconsumed += (use - in->raw->use);
Owen Taylor3473f882001-02-23 17:55:21 +00002721 } else {
2722 nbchars = len;
William M. Bracka3215c72004-07-31 16:24:01 +00002723 ret = xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
2724 if (ret != 0)
2725 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002726 }
2727#ifdef DEBUG_INPUT
2728 xmlGenericError(xmlGenericErrorContext,
2729 "I/O: pushed %d chars, buffer %d/%d\n",
2730 nbchars, in->buffer->use, in->buffer->size);
2731#endif
2732 return(nbchars);
2733}
2734
2735/**
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002736 * endOfInput:
2737 *
2738 * When reading from an Input channel indicated end of file or error
2739 * don't reread from it again.
2740 */
2741static int
2742endOfInput (void * context ATTRIBUTE_UNUSED,
2743 char * buffer ATTRIBUTE_UNUSED,
2744 int len ATTRIBUTE_UNUSED) {
2745 return(0);
2746}
2747
2748/**
Owen Taylor3473f882001-02-23 17:55:21 +00002749 * xmlParserInputBufferGrow:
2750 * @in: a buffered parser input
2751 * @len: indicative value of the amount of chars to read
2752 *
2753 * Grow up the content of the input buffer, the old data are preserved
2754 * This routine handle the I18N transcoding to internal UTF-8
2755 * This routine is used when operating the parser in normal (pull) mode
2756 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002757 * TODO: one should be able to remove one extra copy by copying directly
Owen Taylor3473f882001-02-23 17:55:21 +00002758 * onto in->buffer or in->raw
2759 *
2760 * Returns the number of chars read and stored in the buffer, or -1
2761 * in case of error.
2762 */
2763int
2764xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
2765 char *buffer = NULL;
2766 int res = 0;
2767 int nbchars = 0;
2768 int buffree;
Daniel Veillard9e412302002-06-10 15:59:44 +00002769 unsigned int needSize;
Owen Taylor3473f882001-02-23 17:55:21 +00002770
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002771 if ((in == NULL) || (in->error)) return(-1);
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002772 if ((len <= MINLEN) && (len != 4))
Owen Taylor3473f882001-02-23 17:55:21 +00002773 len = MINLEN;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002774
Owen Taylor3473f882001-02-23 17:55:21 +00002775 buffree = in->buffer->size - in->buffer->use;
2776 if (buffree <= 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002777 xmlIOErr(XML_IO_BUFFER_FULL, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002778 in->error = XML_IO_BUFFER_FULL;
William M. Bracka3215c72004-07-31 16:24:01 +00002779 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002780 }
Owen Taylor3473f882001-02-23 17:55:21 +00002781
Daniel Veillarde5354492002-05-16 08:43:22 +00002782 needSize = in->buffer->use + len + 1;
2783 if (needSize > in->buffer->size){
2784 if (!xmlBufferResize(in->buffer, needSize)){
Daniel Veillard05d987b2003-10-08 11:54:57 +00002785 xmlIOErrMemory("growing input buffer");
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002786 in->error = XML_ERR_NO_MEMORY;
William M. Bracka3215c72004-07-31 16:24:01 +00002787 return(-1);
Daniel Veillarde5354492002-05-16 08:43:22 +00002788 }
Owen Taylor3473f882001-02-23 17:55:21 +00002789 }
Daniel Veillarde5354492002-05-16 08:43:22 +00002790 buffer = (char *)&in->buffer->content[in->buffer->use];
Owen Taylor3473f882001-02-23 17:55:21 +00002791
2792 /*
2793 * Call the read method for this I/O type.
2794 */
2795 if (in->readcallback != NULL) {
2796 res = in->readcallback(in->context, &buffer[0], len);
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002797 if (res <= 0)
2798 in->readcallback = endOfInput;
Owen Taylor3473f882001-02-23 17:55:21 +00002799 } else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002800 xmlIOErr(XML_IO_NO_INPUT, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002801 in->error = XML_IO_NO_INPUT;
Owen Taylor3473f882001-02-23 17:55:21 +00002802 return(-1);
2803 }
2804 if (res < 0) {
Owen Taylor3473f882001-02-23 17:55:21 +00002805 return(-1);
2806 }
2807 len = res;
2808 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00002809 unsigned int use;
2810
Owen Taylor3473f882001-02-23 17:55:21 +00002811 /*
2812 * Store the data in the incoming raw buffer
2813 */
2814 if (in->raw == NULL) {
2815 in->raw = xmlBufferCreate();
2816 }
William M. Bracka3215c72004-07-31 16:24:01 +00002817 res = xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
2818 if (res != 0)
2819 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002820
2821 /*
2822 * convert as much as possible to the parser reading buffer.
2823 */
Daniel Veillard36711902004-02-11 13:25:26 +00002824 use = in->raw->use;
Owen Taylor3473f882001-02-23 17:55:21 +00002825 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2826 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002827 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002828 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002829 return(-1);
2830 }
Daniel Veillard36711902004-02-11 13:25:26 +00002831 in->rawconsumed += (use - in->raw->use);
Owen Taylor3473f882001-02-23 17:55:21 +00002832 } else {
2833 nbchars = len;
Daniel Veillarde5354492002-05-16 08:43:22 +00002834 in->buffer->use += nbchars;
2835 buffer[nbchars] = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002836 }
2837#ifdef DEBUG_INPUT
2838 xmlGenericError(xmlGenericErrorContext,
2839 "I/O: read %d chars, buffer %d/%d\n",
2840 nbchars, in->buffer->use, in->buffer->size);
2841#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002842 return(nbchars);
2843}
2844
2845/**
2846 * xmlParserInputBufferRead:
2847 * @in: a buffered parser input
2848 * @len: indicative value of the amount of chars to read
2849 *
2850 * Refresh the content of the input buffer, the old data are considered
2851 * consumed
2852 * This routine handle the I18N transcoding to internal UTF-8
2853 *
2854 * Returns the number of chars read and stored in the buffer, or -1
2855 * in case of error.
2856 */
2857int
2858xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002859 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002860 if (in->readcallback != NULL)
2861 return(xmlParserInputBufferGrow(in, len));
Daniel Veillard53350552003-09-18 13:35:51 +00002862 else if ((in->buffer != NULL) &&
2863 (in->buffer->alloc == XML_BUFFER_ALLOC_IMMUTABLE))
2864 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002865 else
2866 return(-1);
2867}
2868
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002869#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002870/**
2871 * xmlOutputBufferWrite:
2872 * @out: a buffered parser output
2873 * @len: the size in bytes of the array.
2874 * @buf: an char array
2875 *
2876 * Write the content of the array in the output I/O buffer
2877 * This routine handle the I18N transcoding from internal UTF-8
2878 * The buffer is lossless, i.e. will store in case of partial
2879 * or delayed writes.
2880 *
2881 * Returns the number of chars immediately written, or -1
2882 * in case of error.
2883 */
2884int
2885xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
2886 int nbchars = 0; /* number of chars to output to I/O */
2887 int ret; /* return from function call */
2888 int written = 0; /* number of char written to I/O so far */
2889 int chunk; /* number of byte curreent processed from buf */
2890
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002891 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002892 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002893 if (out->error) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002894
2895 do {
2896 chunk = len;
2897 if (chunk > 4 * MINLEN)
2898 chunk = 4 * MINLEN;
2899
2900 /*
2901 * first handle encoding stuff.
2902 */
2903 if (out->encoder != NULL) {
2904 /*
2905 * Store the data in the incoming raw buffer
2906 */
2907 if (out->conv == NULL) {
2908 out->conv = xmlBufferCreate();
2909 }
William M. Bracka3215c72004-07-31 16:24:01 +00002910 ret = xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2911 if (ret != 0)
2912 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002913
2914 if ((out->buffer->use < MINLEN) && (chunk == len))
2915 goto done;
2916
2917 /*
2918 * convert as much as possible to the parser reading buffer.
2919 */
2920 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
Daniel Veillard809faa52003-02-10 15:43:53 +00002921 if ((ret < 0) && (ret != -3)) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002922 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002923 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002924 return(-1);
2925 }
2926 nbchars = out->conv->use;
2927 } else {
William M. Bracka3215c72004-07-31 16:24:01 +00002928 ret = xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2929 if (ret != 0)
2930 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002931 nbchars = out->buffer->use;
2932 }
2933 buf += chunk;
2934 len -= chunk;
2935
2936 if ((nbchars < MINLEN) && (len <= 0))
2937 goto done;
2938
2939 if (out->writecallback) {
2940 /*
2941 * second write the stuff to the I/O channel
2942 */
2943 if (out->encoder != NULL) {
2944 ret = out->writecallback(out->context,
2945 (const char *)out->conv->content, nbchars);
2946 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002947 xmlBufferShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002948 } else {
2949 ret = out->writecallback(out->context,
2950 (const char *)out->buffer->content, nbchars);
2951 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002952 xmlBufferShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002953 }
2954 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002955 xmlIOErr(XML_IO_WRITE, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002956 out->error = XML_IO_WRITE;
Owen Taylor3473f882001-02-23 17:55:21 +00002957 return(ret);
2958 }
2959 out->written += ret;
2960 }
2961 written += nbchars;
2962 } while (len > 0);
2963
2964done:
2965#ifdef DEBUG_INPUT
2966 xmlGenericError(xmlGenericErrorContext,
2967 "I/O: wrote %d chars\n", written);
2968#endif
2969 return(written);
2970}
2971
2972/**
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00002973 * xmlEscapeContent:
2974 * @out: a pointer to an array of bytes to store the result
2975 * @outlen: the length of @out
2976 * @in: a pointer to an array of unescaped UTF-8 bytes
2977 * @inlen: the length of @in
2978 *
2979 * Take a block of UTF-8 chars in and escape them.
2980 * Returns 0 if success, or -1 otherwise
2981 * The value of @inlen after return is the number of octets consumed
2982 * if the return value is positive, else unpredictable.
2983 * The value of @outlen after return is the number of octets consumed.
2984 */
2985static int
2986xmlEscapeContent(unsigned char* out, int *outlen,
2987 const xmlChar* in, int *inlen) {
2988 unsigned char* outstart = out;
2989 const unsigned char* base = in;
2990 unsigned char* outend = out + *outlen;
2991 const unsigned char* inend;
2992
2993 inend = in + (*inlen);
2994
2995 while ((in < inend) && (out < outend)) {
2996 if (*in == '<') {
2997 if (outend - out < 4) break;
2998 *out++ = '&';
2999 *out++ = 'l';
3000 *out++ = 't';
3001 *out++ = ';';
3002 } else if (*in == '>') {
3003 if (outend - out < 4) break;
3004 *out++ = '&';
3005 *out++ = 'g';
3006 *out++ = 't';
3007 *out++ = ';';
3008 } else if (*in == '&') {
3009 if (outend - out < 5) break;
3010 *out++ = '&';
3011 *out++ = 'a';
3012 *out++ = 'm';
3013 *out++ = 'p';
3014 *out++ = ';';
3015 } else if (*in == '\r') {
3016 if (outend - out < 5) break;
3017 *out++ = '&';
3018 *out++ = '#';
3019 *out++ = '1';
3020 *out++ = '3';
3021 *out++ = ';';
3022 } else {
3023 *out++ = (unsigned char) *in;
3024 }
3025 ++in;
3026 }
3027 *outlen = out - outstart;
3028 *inlen = in - base;
3029 return(0);
3030}
3031
3032/**
3033 * xmlOutputBufferWriteEscape:
3034 * @out: a buffered parser output
3035 * @str: a zero terminated UTF-8 string
Daniel Veillardee8960b2004-05-14 03:25:14 +00003036 * @escaping: an optional escaping function (or NULL)
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003037 *
3038 * Write the content of the string in the output I/O buffer
3039 * This routine escapes the caracters and then handle the I18N
3040 * transcoding from internal UTF-8
3041 * The buffer is lossless, i.e. will store in case of partial
3042 * or delayed writes.
3043 *
3044 * Returns the number of chars immediately written, or -1
3045 * in case of error.
3046 */
3047int
Daniel Veillardee8960b2004-05-14 03:25:14 +00003048xmlOutputBufferWriteEscape(xmlOutputBufferPtr out, const xmlChar *str,
3049 xmlCharEncodingOutputFunc escaping) {
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003050 int nbchars = 0; /* number of chars to output to I/O */
3051 int ret; /* return from function call */
3052 int written = 0; /* number of char written to I/O so far */
Daniel Veillard71b95632004-08-31 12:15:36 +00003053 int oldwritten=0;/* loop guard */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003054 int chunk; /* number of byte currently processed from str */
3055 int len; /* number of bytes in str */
3056 int cons; /* byte from str consumed */
3057
Daniel Veillardce244ad2004-11-05 10:03:46 +00003058 if ((out == NULL) || (out->error) || (str == NULL) ||
3059 (out->buffer == NULL) ||
3060 (out->buffer->alloc == XML_BUFFER_ALLOC_IMMUTABLE)) return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003061 len = strlen((const char *)str);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003062 if (len < 0) return(0);
3063 if (out->error) return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003064 if (escaping == NULL) escaping = xmlEscapeContent;
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003065
3066 do {
Daniel Veillard71b95632004-08-31 12:15:36 +00003067 oldwritten = written;
3068
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003069 /*
3070 * how many bytes to consume and how many bytes to store.
3071 */
3072 cons = len;
3073 chunk = (out->buffer->size - out->buffer->use) - 1;
3074
3075 /*
3076 * first handle encoding stuff.
3077 */
3078 if (out->encoder != NULL) {
3079 /*
3080 * Store the data in the incoming raw buffer
3081 */
3082 if (out->conv == NULL) {
3083 out->conv = xmlBufferCreate();
3084 }
Daniel Veillardee8960b2004-05-14 03:25:14 +00003085 ret = escaping(out->buffer->content + out->buffer->use ,
3086 &chunk, str, &cons);
William M. Brack66e40b12004-11-26 15:45:19 +00003087 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003088 return(-1);
3089 out->buffer->use += chunk;
3090 out->buffer->content[out->buffer->use] = 0;
3091
3092 if ((out->buffer->use < MINLEN) && (cons == len))
3093 goto done;
3094
3095 /*
3096 * convert as much as possible to the output buffer.
3097 */
3098 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
3099 if ((ret < 0) && (ret != -3)) {
3100 xmlIOErr(XML_IO_ENCODER, NULL);
3101 out->error = XML_IO_ENCODER;
3102 return(-1);
3103 }
3104 nbchars = out->conv->use;
3105 } else {
Daniel Veillardee8960b2004-05-14 03:25:14 +00003106 ret = escaping(out->buffer->content + out->buffer->use ,
3107 &chunk, str, &cons);
William M. Brack66e40b12004-11-26 15:45:19 +00003108 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003109 return(-1);
3110 out->buffer->use += chunk;
3111 out->buffer->content[out->buffer->use] = 0;
3112 nbchars = out->buffer->use;
3113 }
3114 str += cons;
3115 len -= cons;
3116
3117 if ((nbchars < MINLEN) && (len <= 0))
3118 goto done;
3119
3120 if (out->writecallback) {
3121 /*
3122 * second write the stuff to the I/O channel
3123 */
3124 if (out->encoder != NULL) {
3125 ret = out->writecallback(out->context,
3126 (const char *)out->conv->content, nbchars);
3127 if (ret >= 0)
3128 xmlBufferShrink(out->conv, ret);
3129 } else {
3130 ret = out->writecallback(out->context,
3131 (const char *)out->buffer->content, nbchars);
3132 if (ret >= 0)
3133 xmlBufferShrink(out->buffer, ret);
3134 }
3135 if (ret < 0) {
3136 xmlIOErr(XML_IO_WRITE, NULL);
3137 out->error = XML_IO_WRITE;
3138 return(ret);
3139 }
3140 out->written += ret;
Daniel Veillard83a75e02004-05-14 21:50:42 +00003141 } else if (out->buffer->size - out->buffer->use < MINLEN) {
3142 xmlBufferResize(out->buffer, out->buffer->size + MINLEN);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003143 }
3144 written += nbchars;
Daniel Veillard71b95632004-08-31 12:15:36 +00003145 } while ((len > 0) && (oldwritten != written));
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003146
3147done:
3148#ifdef DEBUG_INPUT
3149 xmlGenericError(xmlGenericErrorContext,
3150 "I/O: wrote %d chars\n", written);
3151#endif
3152 return(written);
3153}
3154
3155/**
Owen Taylor3473f882001-02-23 17:55:21 +00003156 * xmlOutputBufferWriteString:
3157 * @out: a buffered parser output
3158 * @str: a zero terminated C string
3159 *
3160 * Write the content of the string in the output I/O buffer
3161 * This routine handle the I18N transcoding from internal UTF-8
3162 * The buffer is lossless, i.e. will store in case of partial
3163 * or delayed writes.
3164 *
3165 * Returns the number of chars immediately written, or -1
3166 * in case of error.
3167 */
3168int
3169xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
3170 int len;
3171
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003172 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003173 if (str == NULL)
3174 return(-1);
3175 len = strlen(str);
3176
3177 if (len > 0)
3178 return(xmlOutputBufferWrite(out, len, str));
3179 return(len);
3180}
3181
3182/**
3183 * xmlOutputBufferFlush:
3184 * @out: a buffered output
3185 *
3186 * flushes the output I/O channel
3187 *
3188 * Returns the number of byte written or -1 in case of error.
3189 */
3190int
3191xmlOutputBufferFlush(xmlOutputBufferPtr out) {
3192 int nbchars = 0, ret = 0;
3193
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003194 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003195 /*
3196 * first handle encoding stuff.
3197 */
3198 if ((out->conv != NULL) && (out->encoder != NULL)) {
3199 /*
3200 * convert as much as possible to the parser reading buffer.
3201 */
3202 nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
3203 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003204 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003205 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003206 return(-1);
3207 }
3208 }
3209
3210 /*
3211 * second flush the stuff to the I/O channel
3212 */
3213 if ((out->conv != NULL) && (out->encoder != NULL) &&
3214 (out->writecallback != NULL)) {
3215 ret = out->writecallback(out->context,
3216 (const char *)out->conv->content, out->conv->use);
3217 if (ret >= 0)
3218 xmlBufferShrink(out->conv, ret);
3219 } else if (out->writecallback != NULL) {
3220 ret = out->writecallback(out->context,
3221 (const char *)out->buffer->content, out->buffer->use);
3222 if (ret >= 0)
3223 xmlBufferShrink(out->buffer, ret);
3224 }
3225 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003226 xmlIOErr(XML_IO_FLUSH, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003227 out->error = XML_IO_FLUSH;
Owen Taylor3473f882001-02-23 17:55:21 +00003228 return(ret);
3229 }
3230 out->written += ret;
3231
3232#ifdef DEBUG_INPUT
3233 xmlGenericError(xmlGenericErrorContext,
3234 "I/O: flushed %d chars\n", ret);
3235#endif
3236 return(ret);
3237}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003238#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003239
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003240/**
Owen Taylor3473f882001-02-23 17:55:21 +00003241 * xmlParserGetDirectory:
3242 * @filename: the path to a file
3243 *
3244 * lookup the directory for that file
3245 *
3246 * Returns a new allocated string containing the directory, or NULL.
3247 */
3248char *
3249xmlParserGetDirectory(const char *filename) {
3250 char *ret = NULL;
3251 char dir[1024];
3252 char *cur;
3253 char sep = '/';
3254
Igor Zlatkovic9181cc02002-09-29 17:51:06 +00003255#ifdef _WIN32_WCE /* easy way by now ... wince does not have dirs! */
3256 return NULL;
3257#endif
3258
Owen Taylor3473f882001-02-23 17:55:21 +00003259 if (xmlInputCallbackInitialized == 0)
3260 xmlRegisterDefaultInputCallbacks();
3261
3262 if (filename == NULL) return(NULL);
Daniel Veillard3c5ed912002-01-08 10:36:16 +00003263#if defined(WIN32) && !defined(__CYGWIN__)
Owen Taylor3473f882001-02-23 17:55:21 +00003264 sep = '\\';
3265#endif
3266
3267 strncpy(dir, filename, 1023);
3268 dir[1023] = 0;
3269 cur = &dir[strlen(dir)];
3270 while (cur > dir) {
3271 if (*cur == sep) break;
3272 cur --;
3273 }
3274 if (*cur == sep) {
3275 if (cur == dir) dir[1] = 0;
3276 else *cur = 0;
3277 ret = xmlMemStrdup(dir);
3278 } else {
3279 if (getcwd(dir, 1024) != NULL) {
3280 dir[1023] = 0;
3281 ret = xmlMemStrdup(dir);
3282 }
3283 }
3284 return(ret);
3285}
3286
3287/****************************************************************
3288 * *
3289 * External entities loading *
3290 * *
3291 ****************************************************************/
3292
Daniel Veillarda840b692003-10-19 13:35:37 +00003293/**
3294 * xmlCheckHTTPInput:
3295 * @ctxt: an XML parser context
3296 * @ret: an XML parser input
3297 *
3298 * Check an input in case it was created from an HTTP stream, in that
3299 * case it will handle encoding and update of the base URL in case of
3300 * redirection. It also checks for HTTP errors in which case the input
3301 * is cleanly freed up and an appropriate error is raised in context
3302 *
3303 * Returns the input or NULL in case of HTTP error.
3304 */
3305xmlParserInputPtr
3306xmlCheckHTTPInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr ret) {
3307#ifdef LIBXML_HTTP_ENABLED
3308 if ((ret != NULL) && (ret->buf != NULL) &&
3309 (ret->buf->readcallback == xmlIOHTTPRead) &&
3310 (ret->buf->context != NULL)) {
3311 const char *encoding;
3312 const char *redir;
3313 const char *mime;
3314 int code;
3315
3316 code = xmlNanoHTTPReturnCode(ret->buf->context);
3317 if (code >= 400) {
3318 /* fatal error */
3319 if (ret->filename != NULL)
Daniel Veillarde8039df2003-10-27 11:25:13 +00003320 __xmlLoaderErr(ctxt, "failed to load HTTP resource \"%s\"\n",
Daniel Veillarda840b692003-10-19 13:35:37 +00003321 (const char *) ret->filename);
3322 else
Daniel Veillarde8039df2003-10-27 11:25:13 +00003323 __xmlLoaderErr(ctxt, "failed to load HTTP resource\n", NULL);
Daniel Veillarda840b692003-10-19 13:35:37 +00003324 xmlFreeInputStream(ret);
3325 ret = NULL;
3326 } else {
3327
3328 mime = xmlNanoHTTPMimeType(ret->buf->context);
3329 if ((xmlStrstr(BAD_CAST mime, BAD_CAST "/xml")) ||
3330 (xmlStrstr(BAD_CAST mime, BAD_CAST "+xml"))) {
3331 encoding = xmlNanoHTTPEncoding(ret->buf->context);
3332 if (encoding != NULL) {
3333 xmlCharEncodingHandlerPtr handler;
3334
3335 handler = xmlFindCharEncodingHandler(encoding);
3336 if (handler != NULL) {
3337 xmlSwitchInputEncoding(ctxt, ret, handler);
3338 } else {
3339 __xmlErrEncoding(ctxt, XML_ERR_UNKNOWN_ENCODING,
3340 "Unknown encoding %s",
3341 BAD_CAST encoding, NULL);
3342 }
3343 if (ret->encoding == NULL)
3344 ret->encoding = xmlStrdup(BAD_CAST encoding);
3345 }
3346#if 0
3347 } else if (xmlStrstr(BAD_CAST mime, BAD_CAST "html")) {
3348#endif
3349 }
3350 redir = xmlNanoHTTPRedir(ret->buf->context);
3351 if (redir != NULL) {
3352 if (ret->filename != NULL)
3353 xmlFree((xmlChar *) ret->filename);
3354 if (ret->directory != NULL) {
3355 xmlFree((xmlChar *) ret->directory);
3356 ret->directory = NULL;
3357 }
3358 ret->filename =
3359 (char *) xmlStrdup((const xmlChar *) redir);
3360 }
3361 }
3362 }
3363#endif
3364 return(ret);
3365}
3366
Daniel Veillard561b7f82002-03-20 21:55:57 +00003367static int xmlSysIDExists(const char *URL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003368#ifdef HAVE_STAT
3369 int ret;
3370 struct stat info;
3371 const char *path;
3372
3373 if (URL == NULL)
3374 return(0);
3375
Daniel Veillardf4862f02002-09-10 11:13:43 +00003376 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003377#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00003378 path = &URL[17];
3379#else
Daniel Veillard6990bf32001-08-23 21:17:48 +00003380 path = &URL[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00003381#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003382 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003383#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard6990bf32001-08-23 21:17:48 +00003384 path = &URL[8];
3385#else
3386 path = &URL[7];
3387#endif
3388 } else
3389 path = URL;
3390 ret = stat(path, &info);
Daniel Veillard561b7f82002-03-20 21:55:57 +00003391 if (ret == 0)
3392 return(1);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003393#endif
Daniel Veillard561b7f82002-03-20 21:55:57 +00003394 return(0);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003395}
Daniel Veillard6990bf32001-08-23 21:17:48 +00003396
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003397/**
Owen Taylor3473f882001-02-23 17:55:21 +00003398 * xmlDefaultExternalEntityLoader:
3399 * @URL: the URL for the entity to load
3400 * @ID: the System ID for the entity to load
3401 * @ctxt: the context in which the entity is called or NULL
3402 *
3403 * By default we don't load external entitites, yet.
3404 *
3405 * Returns a new allocated xmlParserInputPtr, or NULL.
3406 */
Daniel Veillarda840b692003-10-19 13:35:37 +00003407static xmlParserInputPtr
Owen Taylor3473f882001-02-23 17:55:21 +00003408xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
Daniel Veillarda840b692003-10-19 13:35:37 +00003409 xmlParserCtxtPtr ctxt)
3410{
Owen Taylor3473f882001-02-23 17:55:21 +00003411 xmlParserInputPtr ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003412 xmlChar *resource = NULL;
Daniel Veillarda840b692003-10-19 13:35:37 +00003413
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003414#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003415 xmlCatalogAllow pref;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003416#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003417
3418#ifdef DEBUG_EXTERNAL_ENTITIES
3419 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda840b692003-10-19 13:35:37 +00003420 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00003421#endif
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003422#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillard61b93382003-11-03 14:28:31 +00003423 if ((ctxt != NULL) && (ctxt->options & XML_PARSE_NONET)) {
3424 int options = ctxt->options;
3425
3426 ctxt->options -= XML_PARSE_NONET;
3427 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
3428 ctxt->options = options;
3429 return(ret);
3430 }
3431
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003432 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003433 * If the resource doesn't exists as a file,
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003434 * try to load it from the resource pointed in the catalogs
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003435 */
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003436 pref = xmlCatalogGetDefaults();
3437
Daniel Veillard561b7f82002-03-20 21:55:57 +00003438 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlSysIDExists(URL))) {
Daniel Veillarda840b692003-10-19 13:35:37 +00003439 /*
3440 * Do a local lookup
3441 */
Daniel Veillard42595322004-11-08 10:52:06 +00003442 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
Daniel Veillarda840b692003-10-19 13:35:37 +00003443 ((pref == XML_CATA_ALLOW_ALL) ||
3444 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3445 resource = xmlCatalogLocalResolve(ctxt->catalogs,
3446 (const xmlChar *) ID,
3447 (const xmlChar *) URL);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003448 }
Daniel Veillarda840b692003-10-19 13:35:37 +00003449 /*
3450 * Try a global lookup
3451 */
3452 if ((resource == NULL) &&
3453 ((pref == XML_CATA_ALLOW_ALL) ||
3454 (pref == XML_CATA_ALLOW_GLOBAL))) {
3455 resource = xmlCatalogResolve((const xmlChar *) ID,
3456 (const xmlChar *) URL);
3457 }
3458 if ((resource == NULL) && (URL != NULL))
3459 resource = xmlStrdup((const xmlChar *) URL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003460
Daniel Veillarda840b692003-10-19 13:35:37 +00003461 /*
3462 * TODO: do an URI lookup on the reference
3463 */
3464 if ((resource != NULL)
3465 && (!xmlSysIDExists((const char *) resource))) {
3466 xmlChar *tmp = NULL;
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003467
Daniel Veillard42595322004-11-08 10:52:06 +00003468 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
Daniel Veillarda840b692003-10-19 13:35:37 +00003469 ((pref == XML_CATA_ALLOW_ALL) ||
3470 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3471 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
3472 }
3473 if ((tmp == NULL) &&
3474 ((pref == XML_CATA_ALLOW_ALL) ||
3475 (pref == XML_CATA_ALLOW_GLOBAL))) {
3476 tmp = xmlCatalogResolveURI(resource);
3477 }
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003478
Daniel Veillarda840b692003-10-19 13:35:37 +00003479 if (tmp != NULL) {
3480 xmlFree(resource);
3481 resource = tmp;
3482 }
3483 }
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003484 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003485#endif
3486
3487 if (resource == NULL)
Daniel Veillarda840b692003-10-19 13:35:37 +00003488 resource = (xmlChar *) URL;
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003489
3490 if (resource == NULL) {
Daniel Veillarda840b692003-10-19 13:35:37 +00003491 if (ID == NULL)
3492 ID = "NULL";
Daniel Veillarde8039df2003-10-27 11:25:13 +00003493 __xmlLoaderErr(ctxt, "failed to load external entity \"%s\"\n", ID);
Daniel Veillarda840b692003-10-19 13:35:37 +00003494 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003495 }
Daniel Veillarda840b692003-10-19 13:35:37 +00003496 ret = xmlNewInputFromFile(ctxt, (const char *) resource);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003497 if ((resource != NULL) && (resource != (xmlChar *) URL))
Daniel Veillarda840b692003-10-19 13:35:37 +00003498 xmlFree(resource);
3499 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003500}
3501
3502static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
3503 xmlDefaultExternalEntityLoader;
3504
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003505/**
Owen Taylor3473f882001-02-23 17:55:21 +00003506 * xmlSetExternalEntityLoader:
3507 * @f: the new entity resolver function
3508 *
3509 * Changes the defaultexternal entity resolver function for the application
3510 */
3511void
3512xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
3513 xmlCurrentExternalEntityLoader = f;
3514}
3515
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003516/**
Owen Taylor3473f882001-02-23 17:55:21 +00003517 * xmlGetExternalEntityLoader:
3518 *
3519 * Get the default external entity resolver function for the application
3520 *
3521 * Returns the xmlExternalEntityLoader function pointer
3522 */
3523xmlExternalEntityLoader
3524xmlGetExternalEntityLoader(void) {
3525 return(xmlCurrentExternalEntityLoader);
3526}
3527
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003528/**
Owen Taylor3473f882001-02-23 17:55:21 +00003529 * xmlLoadExternalEntity:
3530 * @URL: the URL for the entity to load
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00003531 * @ID: the Public ID for the entity to load
Owen Taylor3473f882001-02-23 17:55:21 +00003532 * @ctxt: the context in which the entity is called or NULL
3533 *
3534 * Load an external entity, note that the use of this function for
3535 * unparsed entities may generate problems
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003536 * TODO: a more generic External entity API must be designed
Owen Taylor3473f882001-02-23 17:55:21 +00003537 *
3538 * Returns the xmlParserInputPtr or NULL
3539 */
3540xmlParserInputPtr
3541xmlLoadExternalEntity(const char *URL, const char *ID,
3542 xmlParserCtxtPtr ctxt) {
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00003543 if ((URL != NULL) && (xmlSysIDExists(URL) == 0)) {
3544 char *canonicFilename;
3545 xmlParserInputPtr ret;
3546
3547 canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL);
3548 if (canonicFilename == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003549 xmlIOErrMemory("building canonical path\n");
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00003550 return(NULL);
3551 }
3552
3553 ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt);
3554 xmlFree(canonicFilename);
3555 return(ret);
3556 }
Owen Taylor3473f882001-02-23 17:55:21 +00003557 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
3558}
3559
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003560/************************************************************************
3561 * *
3562 * Disabling Network access *
3563 * *
3564 ************************************************************************/
3565
3566#ifdef LIBXML_CATALOG_ENABLED
3567static int
3568xmlNoNetExists(const char *URL)
3569{
3570#ifdef HAVE_STAT
3571 int ret;
3572 struct stat info;
3573 const char *path;
3574
3575 if (URL == NULL)
3576 return (0);
3577
Daniel Veillardf4862f02002-09-10 11:13:43 +00003578 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003579#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00003580 path = &URL[17];
3581#else
3582 path = &URL[16];
3583#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003584 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003585#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003586 path = &URL[8];
3587#else
3588 path = &URL[7];
3589#endif
3590 } else
3591 path = URL;
3592 ret = stat(path, &info);
3593 if (ret == 0)
3594 return (1);
3595#endif
3596 return (0);
3597}
3598#endif
3599
3600/**
3601 * xmlNoNetExternalEntityLoader:
3602 * @URL: the URL for the entity to load
3603 * @ID: the System ID for the entity to load
3604 * @ctxt: the context in which the entity is called or NULL
3605 *
3606 * A specific entity loader disabling network accesses, though still
3607 * allowing local catalog accesses for resolution.
3608 *
3609 * Returns a new allocated xmlParserInputPtr, or NULL.
3610 */
3611xmlParserInputPtr
3612xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
3613 xmlParserCtxtPtr ctxt) {
3614 xmlParserInputPtr input = NULL;
3615 xmlChar *resource = NULL;
3616
3617#ifdef LIBXML_CATALOG_ENABLED
3618 xmlCatalogAllow pref;
3619
3620 /*
3621 * If the resource doesn't exists as a file,
3622 * try to load it from the resource pointed in the catalogs
3623 */
3624 pref = xmlCatalogGetDefaults();
3625
3626 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
3627 /*
3628 * Do a local lookup
3629 */
Daniel Veillard42595322004-11-08 10:52:06 +00003630 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003631 ((pref == XML_CATA_ALLOW_ALL) ||
3632 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3633 resource = xmlCatalogLocalResolve(ctxt->catalogs,
3634 (const xmlChar *)ID,
3635 (const xmlChar *)URL);
3636 }
3637 /*
3638 * Try a global lookup
3639 */
3640 if ((resource == NULL) &&
3641 ((pref == XML_CATA_ALLOW_ALL) ||
3642 (pref == XML_CATA_ALLOW_GLOBAL))) {
3643 resource = xmlCatalogResolve((const xmlChar *)ID,
3644 (const xmlChar *)URL);
3645 }
3646 if ((resource == NULL) && (URL != NULL))
3647 resource = xmlStrdup((const xmlChar *) URL);
3648
3649 /*
3650 * TODO: do an URI lookup on the reference
3651 */
3652 if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
3653 xmlChar *tmp = NULL;
3654
Daniel Veillard42595322004-11-08 10:52:06 +00003655 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003656 ((pref == XML_CATA_ALLOW_ALL) ||
3657 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3658 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
3659 }
3660 if ((tmp == NULL) &&
3661 ((pref == XML_CATA_ALLOW_ALL) ||
3662 (pref == XML_CATA_ALLOW_GLOBAL))) {
3663 tmp = xmlCatalogResolveURI(resource);
3664 }
3665
3666 if (tmp != NULL) {
3667 xmlFree(resource);
3668 resource = tmp;
3669 }
3670 }
3671 }
3672#endif
3673 if (resource == NULL)
3674 resource = (xmlChar *) URL;
3675
3676 if (resource != NULL) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003677 if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
3678 (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003679 xmlIOErr(XML_IO_NETWORK_ATTEMPT, (const char *) resource);
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003680 if (resource != (xmlChar *) URL)
3681 xmlFree(resource);
3682 return(NULL);
3683 }
3684 }
3685 input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
3686 if (resource != (xmlChar *) URL)
3687 xmlFree(resource);
3688 return(input);
3689}
3690
Daniel Veillard5d4644e2005-04-01 13:11:58 +00003691#define bottom_xmlIO
3692#include "elfgcchack.h"