blob: 1dffa279e69dc5bab2b842c7c2517fbe5dc85e4b [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
2 * xmlIO.c : implementation of the I/O interfaces used by the parser
3 *
4 * See Copyright for the status of this software.
5 *
Daniel Veillard344cee72001-08-20 00:08:40 +00006 * daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +00007 *
8 * 14 Nov 2000 ht - for VMS, truncated name of long functions to under 32 char
9 */
10
Daniel Veillard34ce8be2002-03-18 19:37:11 +000011#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000012#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000013
Owen Taylor3473f882001-02-23 17:55:21 +000014#include <string.h>
Daniel Veillard92727042002-09-17 17:59:20 +000015#ifdef HAVE_ERRNO_H
Owen Taylor3473f882001-02-23 17:55:21 +000016#include <errno.h>
Daniel Veillard92727042002-09-17 17:59:20 +000017#endif
18
Owen Taylor3473f882001-02-23 17:55:21 +000019
20#ifdef HAVE_SYS_TYPES_H
21#include <sys/types.h>
22#endif
23#ifdef HAVE_SYS_STAT_H
24#include <sys/stat.h>
25#endif
26#ifdef HAVE_FCNTL_H
27#include <fcntl.h>
28#endif
29#ifdef HAVE_UNISTD_H
30#include <unistd.h>
31#endif
32#ifdef HAVE_STDLIB_H
33#include <stdlib.h>
34#endif
35#ifdef HAVE_ZLIB_H
36#include <zlib.h>
37#endif
38
39/* Figure a portable way to know if a file is a directory. */
40#ifndef HAVE_STAT
41# ifdef HAVE__STAT
Daniel Veillard50f34372001-08-03 12:06:36 +000042 /* MS C library seems to define stat and _stat. The definition
43 is identical. Still, mapping them to each other causes a warning. */
44# ifndef _MSC_VER
45# define stat(x,y) _stat(x,y)
46# endif
Owen Taylor3473f882001-02-23 17:55:21 +000047# define HAVE_STAT
48# endif
49#endif
50#ifdef HAVE_STAT
51# ifndef S_ISDIR
52# ifdef _S_ISDIR
53# define S_ISDIR(x) _S_ISDIR(x)
54# else
55# ifdef S_IFDIR
56# ifndef S_IFMT
57# ifdef _S_IFMT
58# define S_IFMT _S_IFMT
59# endif
60# endif
61# ifdef S_IFMT
62# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
63# endif
64# endif
65# endif
66# endif
67#endif
68
69#include <libxml/xmlmemory.h>
70#include <libxml/parser.h>
71#include <libxml/parserInternals.h>
72#include <libxml/xmlIO.h>
Daniel Veillard388236f2001-07-08 18:35:48 +000073#include <libxml/uri.h>
Owen Taylor3473f882001-02-23 17:55:21 +000074#include <libxml/nanohttp.h>
75#include <libxml/nanoftp.h>
76#include <libxml/xmlerror.h>
Daniel Veillard7d6fd212001-05-10 15:34:11 +000077#ifdef LIBXML_CATALOG_ENABLED
78#include <libxml/catalog.h>
79#endif
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000080#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000081
Daniel Veillardf012a642001-07-23 19:10:52 +000082/* #define VERBOSE_FAILURE */
Daniel Veillard1fd36d22001-07-04 22:54:28 +000083/* #define DEBUG_EXTERNAL_ENTITIES */
Owen Taylor3473f882001-02-23 17:55:21 +000084/* #define DEBUG_INPUT */
85
86#ifdef DEBUG_INPUT
87#define MINLEN 40
88#else
89#define MINLEN 4000
90#endif
91
92/*
93 * Input I/O callback sets
94 */
95typedef struct _xmlInputCallback {
96 xmlInputMatchCallback matchcallback;
97 xmlInputOpenCallback opencallback;
98 xmlInputReadCallback readcallback;
99 xmlInputCloseCallback closecallback;
100} xmlInputCallback;
101
102#define MAX_INPUT_CALLBACK 15
103
Daniel Veillard22090732001-07-16 00:06:07 +0000104static xmlInputCallback xmlInputCallbackTable[MAX_INPUT_CALLBACK];
105static int xmlInputCallbackNr = 0;
106static int xmlInputCallbackInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000107
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000108#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000109/*
110 * Output I/O callback sets
111 */
112typedef struct _xmlOutputCallback {
113 xmlOutputMatchCallback matchcallback;
114 xmlOutputOpenCallback opencallback;
115 xmlOutputWriteCallback writecallback;
116 xmlOutputCloseCallback closecallback;
117} xmlOutputCallback;
118
119#define MAX_OUTPUT_CALLBACK 15
120
Daniel Veillard22090732001-07-16 00:06:07 +0000121static xmlOutputCallback xmlOutputCallbackTable[MAX_OUTPUT_CALLBACK];
122static int xmlOutputCallbackNr = 0;
123static int xmlOutputCallbackInitialized = 0;
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000124#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000125
Daniel Veillard05d987b2003-10-08 11:54:57 +0000126/************************************************************************
127 * *
128 * Tree memory error handler *
129 * *
130 ************************************************************************/
Daniel Veillardf4862f02002-09-10 11:13:43 +0000131
Daniel Veillard05d987b2003-10-08 11:54:57 +0000132static const char *IOerr[] = {
Daniel Veillarda8856222003-10-08 19:26:03 +0000133 "Unknown IO error", /* UNKNOWN */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000134 "Permission denied", /* EACCES */
135 "Resource temporarily unavailable",/* EAGAIN */
136 "Bad file descriptor", /* EBADF */
137 "Bad message", /* EBADMSG */
138 "Resource busy", /* EBUSY */
139 "Operation canceled", /* ECANCELED */
140 "No child processes", /* ECHILD */
141 "Resource deadlock avoided",/* EDEADLK */
142 "Domain error", /* EDOM */
143 "File exists", /* EEXIST */
144 "Bad address", /* EFAULT */
145 "File too large", /* EFBIG */
146 "Operation in progress", /* EINPROGRESS */
147 "Interrupted function call",/* EINTR */
148 "Invalid argument", /* EINVAL */
149 "Input/output error", /* EIO */
150 "Is a directory", /* EISDIR */
151 "Too many open files", /* EMFILE */
152 "Too many links", /* EMLINK */
153 "Inappropriate message buffer length",/* EMSGSIZE */
154 "Filename too long", /* ENAMETOOLONG */
155 "Too many open files in system",/* ENFILE */
156 "No such device", /* ENODEV */
157 "No such file or directory",/* ENOENT */
158 "Exec format error", /* ENOEXEC */
159 "No locks available", /* ENOLCK */
160 "Not enough space", /* ENOMEM */
161 "No space left on device", /* ENOSPC */
162 "Function not implemented", /* ENOSYS */
163 "Not a directory", /* ENOTDIR */
164 "Directory not empty", /* ENOTEMPTY */
165 "Not supported", /* ENOTSUP */
166 "Inappropriate I/O control operation",/* ENOTTY */
167 "No such device or address",/* ENXIO */
168 "Operation not permitted", /* EPERM */
169 "Broken pipe", /* EPIPE */
170 "Result too large", /* ERANGE */
171 "Read-only file system", /* EROFS */
172 "Invalid seek", /* ESPIPE */
173 "No such process", /* ESRCH */
174 "Operation timed out", /* ETIMEDOUT */
175 "Improper link", /* EXDEV */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000176 "Attempt to load network entity %s", /* XML_IO_NETWORK_ATTEMPT */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000177 "encoder error", /* XML_IO_ENCODER */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000178 "flush error",
179 "write error",
180 "no input",
181 "buffer full",
182 "loading error",
183 "not a socket", /* ENOTSOCK */
184 "already connected", /* EISCONN */
Daniel Veillard29b17482004-08-16 00:39:03 +0000185 "connection refused", /* ECONNREFUSED */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000186 "unreachable network", /* ENETUNREACH */
187 "adddress in use", /* EADDRINUSE */
188 "already in use", /* EALREADY */
189 "unknown address familly", /* EAFNOSUPPORT */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000190};
191
192/**
193 * xmlIOErrMemory:
194 * @extra: extra informations
195 *
196 * Handle an out of memory condition
197 */
198static void
199xmlIOErrMemory(const char *extra)
200{
201 __xmlSimpleError(XML_FROM_IO, XML_ERR_NO_MEMORY, NULL, NULL, extra);
202}
203
204/**
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000205 * __xmlIOErr:
Daniel Veillard05d987b2003-10-08 11:54:57 +0000206 * @code: the error number
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000207 * @
Daniel Veillard05d987b2003-10-08 11:54:57 +0000208 * @extra: extra informations
209 *
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000210 * Handle an I/O error
Daniel Veillard05d987b2003-10-08 11:54:57 +0000211 */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000212void
213__xmlIOErr(int domain, int code, const char *extra)
Daniel Veillard05d987b2003-10-08 11:54:57 +0000214{
215 unsigned int idx;
216
217 if (code == 0) {
218#ifdef HAVE_ERRNO_H
219 if (errno == 0) code = 0;
220#ifdef EACCES
221 else if (errno == EACCES) code = XML_IO_EACCES;
222#endif
223#ifdef EAGAIN
224 else if (errno == EAGAIN) code = XML_IO_EAGAIN;
225#endif
226#ifdef EBADF
227 else if (errno == EBADF) code = XML_IO_EBADF;
228#endif
229#ifdef EBADMSG
230 else if (errno == EBADMSG) code = XML_IO_EBADMSG;
231#endif
232#ifdef EBUSY
233 else if (errno == EBUSY) code = XML_IO_EBUSY;
234#endif
235#ifdef ECANCELED
236 else if (errno == ECANCELED) code = XML_IO_ECANCELED;
237#endif
238#ifdef ECHILD
239 else if (errno == ECHILD) code = XML_IO_ECHILD;
240#endif
241#ifdef EDEADLK
242 else if (errno == EDEADLK) code = XML_IO_EDEADLK;
243#endif
244#ifdef EDOM
245 else if (errno == EDOM) code = XML_IO_EDOM;
246#endif
247#ifdef EEXIST
248 else if (errno == EEXIST) code = XML_IO_EEXIST;
249#endif
250#ifdef EFAULT
251 else if (errno == EFAULT) code = XML_IO_EFAULT;
252#endif
253#ifdef EFBIG
254 else if (errno == EFBIG) code = XML_IO_EFBIG;
255#endif
256#ifdef EINPROGRESS
257 else if (errno == EINPROGRESS) code = XML_IO_EINPROGRESS;
258#endif
259#ifdef EINTR
260 else if (errno == EINTR) code = XML_IO_EINTR;
261#endif
262#ifdef EINVAL
263 else if (errno == EINVAL) code = XML_IO_EINVAL;
264#endif
265#ifdef EIO
266 else if (errno == EIO) code = XML_IO_EIO;
267#endif
268#ifdef EISDIR
269 else if (errno == EISDIR) code = XML_IO_EISDIR;
270#endif
271#ifdef EMFILE
272 else if (errno == EMFILE) code = XML_IO_EMFILE;
273#endif
274#ifdef EMLINK
275 else if (errno == EMLINK) code = XML_IO_EMLINK;
276#endif
277#ifdef EMSGSIZE
278 else if (errno == EMSGSIZE) code = XML_IO_EMSGSIZE;
279#endif
280#ifdef ENAMETOOLONG
281 else if (errno == ENAMETOOLONG) code = XML_IO_ENAMETOOLONG;
282#endif
283#ifdef ENFILE
284 else if (errno == ENFILE) code = XML_IO_ENFILE;
285#endif
286#ifdef ENODEV
287 else if (errno == ENODEV) code = XML_IO_ENODEV;
288#endif
289#ifdef ENOENT
290 else if (errno == ENOENT) code = XML_IO_ENOENT;
291#endif
292#ifdef ENOEXEC
293 else if (errno == ENOEXEC) code = XML_IO_ENOEXEC;
294#endif
295#ifdef ENOLCK
296 else if (errno == ENOLCK) code = XML_IO_ENOLCK;
297#endif
298#ifdef ENOMEM
299 else if (errno == ENOMEM) code = XML_IO_ENOMEM;
300#endif
301#ifdef ENOSPC
302 else if (errno == ENOSPC) code = XML_IO_ENOSPC;
303#endif
304#ifdef ENOSYS
305 else if (errno == ENOSYS) code = XML_IO_ENOSYS;
306#endif
307#ifdef ENOTDIR
308 else if (errno == ENOTDIR) code = XML_IO_ENOTDIR;
309#endif
310#ifdef ENOTEMPTY
311 else if (errno == ENOTEMPTY) code = XML_IO_ENOTEMPTY;
312#endif
313#ifdef ENOTSUP
314 else if (errno == ENOTSUP) code = XML_IO_ENOTSUP;
315#endif
316#ifdef ENOTTY
317 else if (errno == ENOTTY) code = XML_IO_ENOTTY;
318#endif
319#ifdef ENXIO
320 else if (errno == ENXIO) code = XML_IO_ENXIO;
321#endif
322#ifdef EPERM
323 else if (errno == EPERM) code = XML_IO_EPERM;
324#endif
325#ifdef EPIPE
326 else if (errno == EPIPE) code = XML_IO_EPIPE;
327#endif
328#ifdef ERANGE
329 else if (errno == ERANGE) code = XML_IO_ERANGE;
330#endif
331#ifdef EROFS
332 else if (errno == EROFS) code = XML_IO_EROFS;
333#endif
334#ifdef ESPIPE
335 else if (errno == ESPIPE) code = XML_IO_ESPIPE;
336#endif
337#ifdef ESRCH
338 else if (errno == ESRCH) code = XML_IO_ESRCH;
339#endif
340#ifdef ETIMEDOUT
341 else if (errno == ETIMEDOUT) code = XML_IO_ETIMEDOUT;
342#endif
343#ifdef EXDEV
344 else if (errno == EXDEV) code = XML_IO_EXDEV;
345#endif
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000346#ifdef ENOTSOCK
347 else if (errno == ENOTSOCK) code = XML_IO_ENOTSOCK;
348#endif
349#ifdef EISCONN
350 else if (errno == EISCONN) code = XML_IO_EISCONN;
351#endif
352#ifdef ECONNREFUSED
353 else if (errno == ECONNREFUSED) code = XML_IO_ECONNREFUSED;
354#endif
355#ifdef ETIMEDOUT
356 else if (errno == ETIMEDOUT) code = XML_IO_ETIMEDOUT;
357#endif
358#ifdef ENETUNREACH
359 else if (errno == ENETUNREACH) code = XML_IO_ENETUNREACH;
360#endif
361#ifdef EADDRINUSE
362 else if (errno == EADDRINUSE) code = XML_IO_EADDRINUSE;
363#endif
364#ifdef EINPROGRESS
365 else if (errno == EINPROGRESS) code = XML_IO_EINPROGRESS;
366#endif
367#ifdef EALREADY
368 else if (errno == EALREADY) code = XML_IO_EALREADY;
369#endif
370#ifdef EAFNOSUPPORT
371 else if (errno == EAFNOSUPPORT) code = XML_IO_EAFNOSUPPORT;
372#endif
Daniel Veillard05d987b2003-10-08 11:54:57 +0000373 else code = XML_IO_UNKNOWN;
374#endif /* HAVE_ERRNO_H */
375 }
376 idx = 0;
377 if (code >= XML_IO_UNKNOWN) idx = code - XML_IO_UNKNOWN;
378 if (idx >= (sizeof(IOerr) / sizeof(IOerr[0]))) idx = 0;
379
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000380 __xmlSimpleError(domain, code, NULL, IOerr[idx], extra);
381}
382
383/**
384 * xmlIOErr:
385 * @code: the error number
386 * @extra: extra informations
387 *
388 * Handle an I/O error
389 */
390static void
391xmlIOErr(int code, const char *extra)
392{
393 __xmlIOErr(XML_FROM_IO, code, extra);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000394}
395
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000396/**
Daniel Veillarde8039df2003-10-27 11:25:13 +0000397 * __xmlLoaderErr:
398 * @ctx: the parser context
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000399 * @extra: extra informations
400 *
401 * Handle a resource access error
402 */
Daniel Veillarde8039df2003-10-27 11:25:13 +0000403void
404__xmlLoaderErr(void *ctx, const char *msg, const char *filename)
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000405{
Daniel Veillarde8039df2003-10-27 11:25:13 +0000406 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000407 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000408 xmlGenericErrorFunc channel = NULL;
409 void *data = NULL;
410 xmlErrorLevel level = XML_ERR_ERROR;
411
Daniel Veillard157fee02003-10-31 10:36:03 +0000412 if ((ctxt != NULL) && (ctxt->disableSAX != 0) &&
413 (ctxt->instate == XML_PARSER_EOF))
414 return;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000415 if ((ctxt != NULL) && (ctxt->sax != NULL)) {
416 if (ctxt->validate) {
417 channel = ctxt->sax->error;
418 level = XML_ERR_ERROR;
419 } else {
420 channel = ctxt->sax->warning;
421 level = XML_ERR_WARNING;
422 }
Daniel Veillard5ea30d72004-11-08 11:54:28 +0000423 if (ctxt->sax->initialized == XML_SAX2_MAGIC)
424 schannel = ctxt->sax->serror;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000425 data = ctxt->userData;
426 }
Daniel Veillard659e71e2003-10-10 14:10:40 +0000427 __xmlRaiseError(schannel, channel, data, ctxt, NULL, XML_FROM_IO,
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000428 XML_IO_LOAD_ERROR, level, NULL, 0,
429 filename, NULL, NULL, 0, 0,
430 msg, filename);
431
432}
433
Daniel Veillard05d987b2003-10-08 11:54:57 +0000434/************************************************************************
435 * *
436 * Tree memory error handler *
437 * *
438 ************************************************************************/
Daniel Veillardf4862f02002-09-10 11:13:43 +0000439/**
Daniel Veillard01c13b52002-12-10 15:19:08 +0000440 * xmlNormalizeWindowsPath:
Daniel Veillard33300b42003-04-17 09:09:19 +0000441 * @path: the input file path
Daniel Veillardf4862f02002-09-10 11:13:43 +0000442 *
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +0000443 * This function is obsolete. Please see xmlURIFromPath in uri.c for
444 * a better solution.
Daniel Veillard33300b42003-04-17 09:09:19 +0000445 *
446 * Returns a canonicalized version of the path
Daniel Veillardf4862f02002-09-10 11:13:43 +0000447 */
448xmlChar *
449xmlNormalizeWindowsPath(const xmlChar *path)
450{
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +0000451 return xmlCanonicPath(path);
Daniel Veillardf4862f02002-09-10 11:13:43 +0000452}
453
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000454/**
455 * xmlCleanupInputCallbacks:
456 *
457 * clears the entire input callback table. this includes the
458 * compiled-in I/O.
459 */
460void
461xmlCleanupInputCallbacks(void)
462{
463 int i;
464
465 if (!xmlInputCallbackInitialized)
466 return;
467
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000468 for (i = xmlInputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000469 xmlInputCallbackTable[i].matchcallback = NULL;
470 xmlInputCallbackTable[i].opencallback = NULL;
471 xmlInputCallbackTable[i].readcallback = NULL;
472 xmlInputCallbackTable[i].closecallback = NULL;
473 }
474
475 xmlInputCallbackNr = 0;
Aleksey Sanin9c45ba82002-06-06 21:46:13 +0000476 xmlInputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000477}
478
Daniel Veillardaecc0dc2004-05-08 02:32:07 +0000479/**
William M. Brack4e3a9fa2004-08-03 22:41:11 +0000480 * xmlPopInputCallbacks:
Daniel Veillardaecc0dc2004-05-08 02:32:07 +0000481 *
482 * Clear the top input callback from the input stack. this includes the
483 * compiled-in I/O.
484 *
485 * Returns the number of input callback registered or -1 in case of error.
486 */
487int
488xmlPopInputCallbacks(void)
489{
490 if (!xmlInputCallbackInitialized)
491 return(-1);
492
493 if (xmlInputCallbackNr <= 0)
494 return(-1);
495
496 xmlInputCallbackNr--;
497 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = NULL;
498 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = NULL;
499 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = NULL;
500 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = NULL;
501
502 return(xmlInputCallbackNr);
503}
504
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000505#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000506/**
507 * xmlCleanupOutputCallbacks:
508 *
509 * clears the entire output callback table. this includes the
510 * compiled-in I/O callbacks.
511 */
512void
513xmlCleanupOutputCallbacks(void)
514{
515 int i;
516
517 if (!xmlOutputCallbackInitialized)
518 return;
519
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000520 for (i = xmlOutputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000521 xmlOutputCallbackTable[i].matchcallback = NULL;
522 xmlOutputCallbackTable[i].opencallback = NULL;
523 xmlOutputCallbackTable[i].writecallback = NULL;
524 xmlOutputCallbackTable[i].closecallback = NULL;
525 }
526
527 xmlOutputCallbackNr = 0;
Aleksey Sanin9c45ba82002-06-06 21:46:13 +0000528 xmlOutputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000529}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000530#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000531
Owen Taylor3473f882001-02-23 17:55:21 +0000532/************************************************************************
533 * *
534 * Standard I/O for file accesses *
535 * *
536 ************************************************************************/
537
538/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000539 * xmlCheckFilename:
Owen Taylor3473f882001-02-23 17:55:21 +0000540 * @path: the path to check
541 *
542 * function checks to see if @path is a valid source
543 * (file, socket...) for XML.
544 *
545 * if stat is not available on the target machine,
546 * returns 1. if stat fails, returns 0 (if calling
547 * stat on the filename fails, it can't be right).
548 * if stat succeeds and the file is a directory,
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000549 * returns 2. otherwise returns 1.
Owen Taylor3473f882001-02-23 17:55:21 +0000550 */
551
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000552int
Owen Taylor3473f882001-02-23 17:55:21 +0000553xmlCheckFilename (const char *path)
554{
555#ifdef HAVE_STAT
Owen Taylor3473f882001-02-23 17:55:21 +0000556 struct stat stat_buffer;
557
Daniel Veillard34099b42004-11-04 17:34:35 +0000558 if (path == NULL)
559 return(0);
560
Owen Taylor3473f882001-02-23 17:55:21 +0000561 if (stat(path, &stat_buffer) == -1)
562 return 0;
563
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000564#ifdef S_ISDIR
Owen Taylor3473f882001-02-23 17:55:21 +0000565 if (S_ISDIR(stat_buffer.st_mode)) {
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000566 return 2;
Owen Taylor3473f882001-02-23 17:55:21 +0000567 }
Owen Taylor3473f882001-02-23 17:55:21 +0000568#endif
569#endif
Daniel Veillard34099b42004-11-04 17:34:35 +0000570 if (path == NULL)
571 return(0);
572
Owen Taylor3473f882001-02-23 17:55:21 +0000573 return 1;
574}
575
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000576static int
Owen Taylor3473f882001-02-23 17:55:21 +0000577xmlNop(void) {
578 return(0);
579}
580
581/**
Owen Taylor3473f882001-02-23 17:55:21 +0000582 * xmlFdRead:
583 * @context: the I/O context
584 * @buffer: where to drop data
585 * @len: number of bytes to read
586 *
587 * Read @len bytes to @buffer from the I/O channel.
588 *
589 * Returns the number of bytes written
590 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000591static int
Owen Taylor3473f882001-02-23 17:55:21 +0000592xmlFdRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000593 int ret;
594
595 ret = read((int) (long) context, &buffer[0], len);
596 if (ret < 0) xmlIOErr(0, "read()");
597 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000598}
599
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000600#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000601/**
602 * xmlFdWrite:
603 * @context: the I/O context
604 * @buffer: where to get data
605 * @len: number of bytes to write
606 *
607 * Write @len bytes from @buffer to the I/O channel.
608 *
609 * Returns the number of bytes written
610 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000611static int
Owen Taylor3473f882001-02-23 17:55:21 +0000612xmlFdWrite (void * context, const char * buffer, int len) {
Daniel Veillard9b693b42005-10-28 14:54:17 +0000613 int ret = 0;
Daniel Veillard05d987b2003-10-08 11:54:57 +0000614
Daniel Veillard9b693b42005-10-28 14:54:17 +0000615 if (len > 0) {
616 ret = write((int) (long) context, &buffer[0], len);
617 if (ret < 0) xmlIOErr(0, "write()");
618 }
Daniel Veillard05d987b2003-10-08 11:54:57 +0000619 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000620}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000621#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000622
623/**
624 * xmlFdClose:
625 * @context: the I/O context
626 *
627 * Close an I/O channel
Daniel Veillardf012a642001-07-23 19:10:52 +0000628 *
629 * Returns 0 in case of success and error code otherwise
Owen Taylor3473f882001-02-23 17:55:21 +0000630 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000631static int
Owen Taylor3473f882001-02-23 17:55:21 +0000632xmlFdClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000633 int ret;
634 ret = close((int) (long) context);
635 if (ret < 0) xmlIOErr(0, "close()");
636 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000637}
638
639/**
640 * xmlFileMatch:
641 * @filename: the URI for matching
642 *
643 * input from FILE *
644 *
645 * Returns 1 if matches, 0 otherwise
646 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000647int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000648xmlFileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000649 return(1);
650}
651
652/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000653 * xmlFileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +0000654 * @filename: the URI for matching
655 *
656 * input from FILE *, supports compressed input
657 * if @filename is " " then the standard input is used
658 *
659 * Returns an I/O context or NULL in case of error
660 */
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000661static void *
662xmlFileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +0000663 const char *path = NULL;
664 FILE *fd;
665
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000666 if (filename == NULL)
667 return(NULL);
668
Owen Taylor3473f882001-02-23 17:55:21 +0000669 if (!strcmp(filename, "-")) {
670 fd = stdin;
671 return((void *) fd);
672 }
673
Daniel Veillardf4862f02002-09-10 11:13:43 +0000674 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000675#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000676 path = &filename[17];
677#else
Owen Taylor3473f882001-02-23 17:55:21 +0000678 path = &filename[16];
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000679#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000680 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000681#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000682 path = &filename[8];
683#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000684 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000685#endif
686 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000687 path = filename;
688
689 if (path == NULL)
690 return(NULL);
691 if (!xmlCheckFilename(path))
692 return(NULL);
693
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000694#if defined(WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
Owen Taylor3473f882001-02-23 17:55:21 +0000695 fd = fopen(path, "rb");
696#else
697 fd = fopen(path, "r");
698#endif /* WIN32 */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000699 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +0000700 return((void *) fd);
701}
702
703/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000704 * xmlFileOpen:
705 * @filename: the URI for matching
706 *
707 * Wrapper around xmlFileOpen_real that try it with an unescaped
708 * version of @filename, if this fails fallback to @filename
Daniel Veillard71531f32003-02-05 13:19:53 +0000709 *
710 * Returns a handler or NULL in case or failure
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000711 */
712void *
713xmlFileOpen (const char *filename) {
714 char *unescaped;
715 void *retval;
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000716
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000717 unescaped = xmlURIUnescapeString(filename, 0, NULL);
718 if (unescaped != NULL) {
719 retval = xmlFileOpen_real(unescaped);
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000720 xmlFree(unescaped);
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000721 } else {
722 retval = xmlFileOpen_real(filename);
723 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000724 return retval;
725}
726
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000727#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000728/**
Owen Taylor3473f882001-02-23 17:55:21 +0000729 * xmlFileOpenW:
730 * @filename: the URI for matching
731 *
732 * output to from FILE *,
733 * if @filename is "-" then the standard output is used
734 *
735 * Returns an I/O context or NULL in case of error
736 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000737static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000738xmlFileOpenW (const char *filename) {
739 const char *path = NULL;
740 FILE *fd;
741
742 if (!strcmp(filename, "-")) {
743 fd = stdout;
744 return((void *) fd);
745 }
746
Daniel Veillardf4862f02002-09-10 11:13:43 +0000747 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000748#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000749 path = &filename[17];
750#else
Owen Taylor3473f882001-02-23 17:55:21 +0000751 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000752#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000753 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000754#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000755 path = &filename[8];
756#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000757 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000758#endif
759 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000760 path = filename;
761
762 if (path == NULL)
763 return(NULL);
764
Daniel Veillardcbbd78d2003-07-20 15:21:30 +0000765 fd = fopen(path, "wb");
Daniel Veillard05d987b2003-10-08 11:54:57 +0000766 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +0000767 return((void *) fd);
768}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000769#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000770
771/**
772 * xmlFileRead:
773 * @context: the I/O context
774 * @buffer: where to drop data
775 * @len: number of bytes to write
776 *
777 * Read @len bytes to @buffer from the I/O channel.
778 *
Daniel Veillardce682bc2004-11-05 17:22:25 +0000779 * Returns the number of bytes written or < 0 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +0000780 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000781int
Owen Taylor3473f882001-02-23 17:55:21 +0000782xmlFileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000783 int ret;
Daniel Veillardce682bc2004-11-05 17:22:25 +0000784 if ((context == NULL) || (buffer == NULL))
785 return(-1);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000786 ret = fread(&buffer[0], 1, len, (FILE *) context);
787 if (ret < 0) xmlIOErr(0, "fread()");
788 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000789}
790
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000791#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000792/**
793 * xmlFileWrite:
794 * @context: the I/O context
795 * @buffer: where to drop data
796 * @len: number of bytes to write
797 *
798 * Write @len bytes from @buffer to the I/O channel.
799 *
800 * Returns the number of bytes written
801 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000802static int
Owen Taylor3473f882001-02-23 17:55:21 +0000803xmlFileWrite (void * context, const char * buffer, int len) {
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000804 int items;
805
Daniel Veillardce682bc2004-11-05 17:22:25 +0000806 if ((context == NULL) || (buffer == NULL))
807 return(-1);
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000808 items = fwrite(&buffer[0], len, 1, (FILE *) context);
Daniel Veillard97bf4d02003-10-08 18:58:28 +0000809 if ((items == 0) && (ferror((FILE *) context))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000810 xmlIOErr(0, "fwrite()");
Daniel Veillard97bf4d02003-10-08 18:58:28 +0000811 return(-1);
812 }
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000813 return(items * len);
Owen Taylor3473f882001-02-23 17:55:21 +0000814}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000815#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000816
817/**
818 * xmlFileClose:
819 * @context: the I/O context
820 *
821 * Close an I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000822 *
823 * Returns 0 or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +0000824 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000825int
Owen Taylor3473f882001-02-23 17:55:21 +0000826xmlFileClose (void * context) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000827 FILE *fil;
Daniel Veillard05d987b2003-10-08 11:54:57 +0000828 int ret;
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000829
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000830 if (context == NULL)
831 return(-1);
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000832 fil = (FILE *) context;
Daniel Veillard500a1de2004-03-22 15:22:58 +0000833 if ((fil == stdout) || (fil == stderr)) {
834 ret = fflush(fil);
835 if (ret < 0)
836 xmlIOErr(0, "fflush()");
837 return(0);
838 }
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000839 if (fil == stdin)
840 return(0);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000841 ret = ( fclose((FILE *) context) == EOF ) ? -1 : 0;
842 if (ret < 0)
843 xmlIOErr(0, "fclose()");
844 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000845}
846
847/**
848 * xmlFileFlush:
849 * @context: the I/O context
850 *
851 * Flush an I/O channel
852 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000853static int
Owen Taylor3473f882001-02-23 17:55:21 +0000854xmlFileFlush (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000855 int ret;
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000856
857 if (context == NULL)
858 return(-1);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000859 ret = ( fflush((FILE *) context) == EOF ) ? -1 : 0;
860 if (ret < 0)
861 xmlIOErr(0, "fflush()");
862 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000863}
864
865#ifdef HAVE_ZLIB_H
866/************************************************************************
867 * *
868 * I/O for compressed file accesses *
869 * *
870 ************************************************************************/
871/**
872 * xmlGzfileMatch:
873 * @filename: the URI for matching
874 *
875 * input from compressed file test
876 *
877 * Returns 1 if matches, 0 otherwise
878 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000879static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000880xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000881 return(1);
882}
883
884/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000885 * xmlGzfileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +0000886 * @filename: the URI for matching
887 *
888 * input from compressed file open
889 * if @filename is " " then the standard input is used
890 *
891 * Returns an I/O context or NULL in case of error
892 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000893static void *
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000894xmlGzfileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +0000895 const char *path = NULL;
896 gzFile fd;
897
898 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000899 fd = gzdopen(dup(0), "rb");
Owen Taylor3473f882001-02-23 17:55:21 +0000900 return((void *) fd);
901 }
902
Daniel Veillardf4862f02002-09-10 11:13:43 +0000903 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000904#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000905 path = &filename[17];
906#else
Owen Taylor3473f882001-02-23 17:55:21 +0000907 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000908#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000909 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000910#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000911 path = &filename[8];
912#else
Owen Taylor3473f882001-02-23 17:55:21 +0000913 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000914#endif
915 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000916 path = filename;
917
918 if (path == NULL)
919 return(NULL);
920 if (!xmlCheckFilename(path))
921 return(NULL);
922
923 fd = gzopen(path, "rb");
924 return((void *) fd);
925}
926
927/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000928 * xmlGzfileOpen:
929 * @filename: the URI for matching
930 *
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +0000931 * Wrapper around xmlGzfileOpen if the open fais, it will
932 * try to unescape @filename
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000933 */
934static void *
935xmlGzfileOpen (const char *filename) {
936 char *unescaped;
937 void *retval;
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +0000938
939 retval = xmlGzfileOpen_real(filename);
940 if (retval == NULL) {
941 unescaped = xmlURIUnescapeString(filename, 0, NULL);
942 if (unescaped != NULL) {
943 retval = xmlGzfileOpen_real(unescaped);
944 }
945 xmlFree(unescaped);
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000946 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000947 return retval;
948}
949
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000950#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000951/**
Owen Taylor3473f882001-02-23 17:55:21 +0000952 * xmlGzfileOpenW:
953 * @filename: the URI for matching
954 * @compression: the compression factor (0 - 9 included)
955 *
956 * input from compressed file open
957 * if @filename is " " then the standard input is used
958 *
959 * Returns an I/O context or NULL in case of error
960 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000961static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000962xmlGzfileOpenW (const char *filename, int compression) {
963 const char *path = NULL;
964 char mode[15];
965 gzFile fd;
966
Aleksey Sanin49cc9752002-06-14 17:07:10 +0000967 snprintf(mode, sizeof(mode), "wb%d", compression);
Owen Taylor3473f882001-02-23 17:55:21 +0000968 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000969 fd = gzdopen(dup(1), mode);
Owen Taylor3473f882001-02-23 17:55:21 +0000970 return((void *) fd);
971 }
972
Daniel Veillardf4862f02002-09-10 11:13:43 +0000973 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000974#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000975 path = &filename[17];
976#else
Owen Taylor3473f882001-02-23 17:55:21 +0000977 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000978#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000979 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000980#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000981 path = &filename[8];
982#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000983 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000984#endif
985 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000986 path = filename;
987
988 if (path == NULL)
989 return(NULL);
990
991 fd = gzopen(path, mode);
992 return((void *) fd);
993}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000994#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000995
996/**
997 * xmlGzfileRead:
998 * @context: the I/O context
999 * @buffer: where to drop data
1000 * @len: number of bytes to write
1001 *
1002 * Read @len bytes to @buffer from the compressed I/O channel.
1003 *
1004 * Returns the number of bytes written
1005 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001006static int
Owen Taylor3473f882001-02-23 17:55:21 +00001007xmlGzfileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001008 int ret;
1009
1010 ret = gzread((gzFile) context, &buffer[0], len);
1011 if (ret < 0) xmlIOErr(0, "gzread()");
1012 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001013}
1014
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001015#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001016/**
1017 * xmlGzfileWrite:
1018 * @context: the I/O context
1019 * @buffer: where to drop data
1020 * @len: number of bytes to write
1021 *
1022 * Write @len bytes from @buffer to the compressed I/O channel.
1023 *
1024 * Returns the number of bytes written
1025 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001026static int
Owen Taylor3473f882001-02-23 17:55:21 +00001027xmlGzfileWrite (void * context, const char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001028 int ret;
1029
1030 ret = gzwrite((gzFile) context, (char *) &buffer[0], len);
1031 if (ret < 0) xmlIOErr(0, "gzwrite()");
1032 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001033}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001034#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001035
1036/**
1037 * xmlGzfileClose:
1038 * @context: the I/O context
1039 *
1040 * Close a compressed I/O channel
1041 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001042static int
Owen Taylor3473f882001-02-23 17:55:21 +00001043xmlGzfileClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001044 int ret;
1045
1046 ret = (gzclose((gzFile) context) == Z_OK ) ? 0 : -1;
1047 if (ret < 0) xmlIOErr(0, "gzclose()");
1048 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001049}
1050#endif /* HAVE_ZLIB_H */
1051
1052#ifdef LIBXML_HTTP_ENABLED
1053/************************************************************************
1054 * *
1055 * I/O for HTTP file accesses *
1056 * *
1057 ************************************************************************/
Daniel Veillardf012a642001-07-23 19:10:52 +00001058
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001059#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001060typedef struct xmlIOHTTPWriteCtxt_
1061{
1062 int compression;
1063
1064 char * uri;
1065
1066 void * doc_buff;
1067
1068} xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr;
1069
1070#ifdef HAVE_ZLIB_H
1071
1072#define DFLT_WBITS ( -15 )
1073#define DFLT_MEM_LVL ( 8 )
1074#define GZ_MAGIC1 ( 0x1f )
1075#define GZ_MAGIC2 ( 0x8b )
1076#define LXML_ZLIB_OS_CODE ( 0x03 )
1077#define INIT_HTTP_BUFF_SIZE ( 32768 )
1078#define DFLT_ZLIB_RATIO ( 5 )
1079
1080/*
1081** Data structure and functions to work with sending compressed data
1082** via HTTP.
1083*/
1084
1085typedef struct xmlZMemBuff_
1086{
1087 unsigned long size;
1088 unsigned long crc;
1089
1090 unsigned char * zbuff;
1091 z_stream zctrl;
1092
1093} xmlZMemBuff, *xmlZMemBuffPtr;
1094
1095/**
1096 * append_reverse_ulong
1097 * @buff: Compressed memory buffer
1098 * @data: Unsigned long to append
1099 *
1100 * Append a unsigned long in reverse byte order to the end of the
1101 * memory buffer.
1102 */
1103static void
1104append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) {
1105
1106 int idx;
1107
1108 if ( buff == NULL )
1109 return;
1110
1111 /*
1112 ** This is plagiarized from putLong in gzio.c (zlib source) where
1113 ** the number "4" is hardcoded. If zlib is ever patched to
1114 ** support 64 bit file sizes, this code would need to be patched
1115 ** as well.
1116 */
1117
1118 for ( idx = 0; idx < 4; idx++ ) {
1119 *buff->zctrl.next_out = ( data & 0xff );
1120 data >>= 8;
1121 buff->zctrl.next_out++;
1122 }
1123
1124 return;
1125}
1126
1127/**
1128 *
1129 * xmlFreeZMemBuff
1130 * @buff: The memory buffer context to clear
1131 *
1132 * Release all the resources associated with the compressed memory buffer.
1133 */
1134static void
1135xmlFreeZMemBuff( xmlZMemBuffPtr buff ) {
William M. Brack78637da2003-07-31 14:47:38 +00001136
1137#ifdef DEBUG_HTTP
Daniel Veillardf012a642001-07-23 19:10:52 +00001138 int z_err;
William M. Brack78637da2003-07-31 14:47:38 +00001139#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001140
1141 if ( buff == NULL )
1142 return;
1143
1144 xmlFree( buff->zbuff );
Daniel Veillardf012a642001-07-23 19:10:52 +00001145#ifdef DEBUG_HTTP
William M. Brack78637da2003-07-31 14:47:38 +00001146 z_err = deflateEnd( &buff->zctrl );
Daniel Veillardf012a642001-07-23 19:10:52 +00001147 if ( z_err != Z_OK )
1148 xmlGenericError( xmlGenericErrorContext,
1149 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
1150 z_err );
William M. Brack78637da2003-07-31 14:47:38 +00001151#else
1152 deflateEnd( &buff->zctrl );
William M. Brack779af002003-08-01 15:55:39 +00001153#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001154
1155 xmlFree( buff );
1156 return;
1157}
1158
1159/**
1160 * xmlCreateZMemBuff
1161 *@compression: Compression value to use
1162 *
1163 * Create a memory buffer to hold the compressed XML document. The
1164 * compressed document in memory will end up being identical to what
1165 * would be created if gzopen/gzwrite/gzclose were being used to
1166 * write the document to disk. The code for the header/trailer data to
1167 * the compression is plagiarized from the zlib source files.
1168 */
1169static void *
1170xmlCreateZMemBuff( int compression ) {
1171
1172 int z_err;
1173 int hdr_lgth;
1174 xmlZMemBuffPtr buff = NULL;
1175
1176 if ( ( compression < 1 ) || ( compression > 9 ) )
1177 return ( NULL );
1178
1179 /* Create the control and data areas */
1180
1181 buff = xmlMalloc( sizeof( xmlZMemBuff ) );
1182 if ( buff == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001183 xmlIOErrMemory("creating buffer context");
Daniel Veillardf012a642001-07-23 19:10:52 +00001184 return ( NULL );
1185 }
1186
1187 (void)memset( buff, 0, sizeof( xmlZMemBuff ) );
1188 buff->size = INIT_HTTP_BUFF_SIZE;
1189 buff->zbuff = xmlMalloc( buff->size );
1190 if ( buff->zbuff == NULL ) {
1191 xmlFreeZMemBuff( buff );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001192 xmlIOErrMemory("creating buffer");
Daniel Veillardf012a642001-07-23 19:10:52 +00001193 return ( NULL );
1194 }
1195
1196 z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
1197 DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
1198 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001199 xmlChar msg[500];
Daniel Veillardf012a642001-07-23 19:10:52 +00001200 xmlFreeZMemBuff( buff );
1201 buff = NULL;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001202 xmlStrPrintf(msg, 500,
1203 (const xmlChar *) "xmlCreateZMemBuff: %s %d\n",
1204 "Error initializing compression context. ZLIB error:",
1205 z_err );
1206 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001207 return ( NULL );
1208 }
1209
1210 /* Set the header data. The CRC will be needed for the trailer */
Daniel Veillard24505b02005-07-28 23:49:35 +00001211 buff->crc = crc32( 0L, NULL, 0 );
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001212 hdr_lgth = snprintf( (char *)buff->zbuff, buff->size,
1213 "%c%c%c%c%c%c%c%c%c%c",
Daniel Veillardf012a642001-07-23 19:10:52 +00001214 GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED,
1215 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE );
1216 buff->zctrl.next_out = buff->zbuff + hdr_lgth;
1217 buff->zctrl.avail_out = buff->size - hdr_lgth;
1218
1219 return ( buff );
1220}
1221
1222/**
1223 * xmlZMemBuffExtend
1224 * @buff: Buffer used to compress and consolidate data.
1225 * @ext_amt: Number of bytes to extend the buffer.
1226 *
1227 * Extend the internal buffer used to store the compressed data by the
1228 * specified amount.
1229 *
1230 * Returns 0 on success or -1 on failure to extend the buffer. On failure
1231 * the original buffer still exists at the original size.
1232 */
1233static int
1234xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) {
1235
1236 int rc = -1;
1237 size_t new_size;
1238 size_t cur_used;
1239
1240 unsigned char * tmp_ptr = NULL;
1241
1242 if ( buff == NULL )
1243 return ( -1 );
1244
1245 else if ( ext_amt == 0 )
1246 return ( 0 );
1247
1248 cur_used = buff->zctrl.next_out - buff->zbuff;
1249 new_size = buff->size + ext_amt;
1250
1251#ifdef DEBUG_HTTP
1252 if ( cur_used > new_size )
1253 xmlGenericError( xmlGenericErrorContext,
1254 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
1255 "Buffer overwrite detected during compressed memory",
1256 "buffer extension. Overflowed by",
1257 (cur_used - new_size ) );
1258#endif
1259
1260 tmp_ptr = xmlRealloc( buff->zbuff, new_size );
1261 if ( tmp_ptr != NULL ) {
1262 rc = 0;
1263 buff->size = new_size;
1264 buff->zbuff = tmp_ptr;
1265 buff->zctrl.next_out = tmp_ptr + cur_used;
1266 buff->zctrl.avail_out = new_size - cur_used;
1267 }
1268 else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001269 xmlChar msg[500];
1270 xmlStrPrintf(msg, 500,
1271 (const xmlChar *) "xmlZMemBuffExtend: %s %lu bytes.\n",
1272 "Allocation failure extending output buffer to",
1273 new_size );
1274 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001275 }
1276
1277 return ( rc );
1278}
1279
1280/**
1281 * xmlZMemBuffAppend
1282 * @buff: Buffer used to compress and consolidate data
1283 * @src: Uncompressed source content to append to buffer
1284 * @len: Length of source data to append to buffer
1285 *
1286 * Compress and append data to the internal buffer. The data buffer
1287 * will be expanded if needed to store the additional data.
1288 *
1289 * Returns the number of bytes appended to the buffer or -1 on error.
1290 */
1291static int
1292xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) {
1293
1294 int z_err;
1295 size_t min_accept;
1296
1297 if ( ( buff == NULL ) || ( src == NULL ) )
1298 return ( -1 );
1299
1300 buff->zctrl.avail_in = len;
1301 buff->zctrl.next_in = (unsigned char *)src;
1302 while ( buff->zctrl.avail_in > 0 ) {
1303 /*
1304 ** Extend the buffer prior to deflate call if a reasonable amount
1305 ** of output buffer space is not available.
1306 */
1307 min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO;
1308 if ( buff->zctrl.avail_out <= min_accept ) {
1309 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1310 return ( -1 );
1311 }
1312
1313 z_err = deflate( &buff->zctrl, Z_NO_FLUSH );
1314 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001315 xmlChar msg[500];
1316 xmlStrPrintf(msg, 500,
1317 (const xmlChar *) "xmlZMemBuffAppend: %s %d %s - %d",
Daniel Veillardf012a642001-07-23 19:10:52 +00001318 "Compression error while appending",
1319 len, "bytes to buffer. ZLIB error", z_err );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001320 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001321 return ( -1 );
1322 }
1323 }
1324
1325 buff->crc = crc32( buff->crc, (unsigned char *)src, len );
1326
1327 return ( len );
1328}
1329
1330/**
1331 * xmlZMemBuffGetContent
1332 * @buff: Compressed memory content buffer
1333 * @data_ref: Pointer reference to point to compressed content
1334 *
1335 * Flushes the compression buffers, appends gzip file trailers and
1336 * returns the compressed content and length of the compressed data.
1337 * NOTE: The gzip trailer code here is plagiarized from zlib source.
1338 *
1339 * Returns the length of the compressed data or -1 on error.
1340 */
1341static int
1342xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) {
1343
1344 int zlgth = -1;
1345 int z_err;
1346
1347 if ( ( buff == NULL ) || ( data_ref == NULL ) )
1348 return ( -1 );
1349
1350 /* Need to loop until compression output buffers are flushed */
1351
1352 do
1353 {
1354 z_err = deflate( &buff->zctrl, Z_FINISH );
1355 if ( z_err == Z_OK ) {
1356 /* In this case Z_OK means more buffer space needed */
1357
1358 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1359 return ( -1 );
1360 }
1361 }
1362 while ( z_err == Z_OK );
1363
1364 /* If the compression state is not Z_STREAM_END, some error occurred */
1365
1366 if ( z_err == Z_STREAM_END ) {
1367
1368 /* Need to append the gzip data trailer */
1369
1370 if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) {
1371 if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 )
1372 return ( -1 );
1373 }
1374
1375 /*
1376 ** For whatever reason, the CRC and length data are pushed out
1377 ** in reverse byte order. So a memcpy can't be used here.
1378 */
1379
1380 append_reverse_ulong( buff, buff->crc );
1381 append_reverse_ulong( buff, buff->zctrl.total_in );
1382
1383 zlgth = buff->zctrl.next_out - buff->zbuff;
1384 *data_ref = (char *)buff->zbuff;
1385 }
1386
Daniel Veillard05d987b2003-10-08 11:54:57 +00001387 else {
1388 xmlChar msg[500];
1389 xmlStrPrintf(msg, 500,
1390 (const xmlChar *) "xmlZMemBuffGetContent: %s - %d\n",
1391 "Error flushing zlib buffers. Error code", z_err );
1392 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1393 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001394
1395 return ( zlgth );
1396}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001397#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001398#endif /* HAVE_ZLIB_H */
1399
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001400#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001401/**
1402 * xmlFreeHTTPWriteCtxt
1403 * @ctxt: Context to cleanup
1404 *
1405 * Free allocated memory and reclaim system resources.
1406 *
1407 * No return value.
1408 */
1409static void
1410xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt )
1411{
1412 if ( ctxt->uri != NULL )
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001413 xmlFree( ctxt->uri );
Daniel Veillardf012a642001-07-23 19:10:52 +00001414
1415 if ( ctxt->doc_buff != NULL ) {
1416
1417#ifdef HAVE_ZLIB_H
1418 if ( ctxt->compression > 0 ) {
1419 xmlFreeZMemBuff( ctxt->doc_buff );
1420 }
1421 else
1422#endif
1423 {
1424 xmlOutputBufferClose( ctxt->doc_buff );
1425 }
1426 }
1427
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001428 xmlFree( ctxt );
Daniel Veillardf012a642001-07-23 19:10:52 +00001429 return;
1430}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001431#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001432
1433
Owen Taylor3473f882001-02-23 17:55:21 +00001434/**
1435 * xmlIOHTTPMatch:
1436 * @filename: the URI for matching
1437 *
1438 * check if the URI matches an HTTP one
1439 *
1440 * Returns 1 if matches, 0 otherwise
1441 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001442int
Owen Taylor3473f882001-02-23 17:55:21 +00001443xmlIOHTTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001444 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "http://", 7))
Owen Taylor3473f882001-02-23 17:55:21 +00001445 return(1);
1446 return(0);
1447}
1448
1449/**
1450 * xmlIOHTTPOpen:
1451 * @filename: the URI for matching
1452 *
1453 * open an HTTP I/O channel
1454 *
1455 * Returns an I/O context or NULL in case of error
1456 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001457void *
Owen Taylor3473f882001-02-23 17:55:21 +00001458xmlIOHTTPOpen (const char *filename) {
1459 return(xmlNanoHTTPOpen(filename, NULL));
1460}
1461
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001462#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001463/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001464 * xmlIOHTTPOpenW:
Daniel Veillardf012a642001-07-23 19:10:52 +00001465 * @post_uri: The destination URI for the document
1466 * @compression: The compression desired for the document.
1467 *
1468 * Open a temporary buffer to collect the document for a subsequent HTTP POST
1469 * request. Non-static as is called from the output buffer creation routine.
1470 *
1471 * Returns an I/O context or NULL in case of error.
1472 */
1473
1474void *
Daniel Veillard572577e2002-01-18 16:23:55 +00001475xmlIOHTTPOpenW(const char *post_uri, int compression)
1476{
Daniel Veillardf012a642001-07-23 19:10:52 +00001477
Daniel Veillard572577e2002-01-18 16:23:55 +00001478 xmlIOHTTPWriteCtxtPtr ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001479
Daniel Veillard572577e2002-01-18 16:23:55 +00001480 if (post_uri == NULL)
1481 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001482
Daniel Veillard572577e2002-01-18 16:23:55 +00001483 ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt));
1484 if (ctxt == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001485 xmlIOErrMemory("creating HTTP output context");
Daniel Veillard572577e2002-01-18 16:23:55 +00001486 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001487 }
1488
Daniel Veillard572577e2002-01-18 16:23:55 +00001489 (void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt));
Daniel Veillardf012a642001-07-23 19:10:52 +00001490
Daniel Veillard572577e2002-01-18 16:23:55 +00001491 ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri);
1492 if (ctxt->uri == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001493 xmlIOErrMemory("copying URI");
Daniel Veillard572577e2002-01-18 16:23:55 +00001494 xmlFreeHTTPWriteCtxt(ctxt);
1495 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001496 }
1497
1498 /*
Daniel Veillard572577e2002-01-18 16:23:55 +00001499 * ** Since the document length is required for an HTTP post,
1500 * ** need to put the document into a buffer. A memory buffer
1501 * ** is being used to avoid pushing the data to disk and back.
1502 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001503
1504#ifdef HAVE_ZLIB_H
Daniel Veillard572577e2002-01-18 16:23:55 +00001505 if ((compression > 0) && (compression <= 9)) {
1506
1507 ctxt->compression = compression;
1508 ctxt->doc_buff = xmlCreateZMemBuff(compression);
1509 } else
Daniel Veillardf012a642001-07-23 19:10:52 +00001510#endif
1511 {
Daniel Veillard572577e2002-01-18 16:23:55 +00001512 /* Any character conversions should have been done before this */
Daniel Veillardf012a642001-07-23 19:10:52 +00001513
Daniel Veillard572577e2002-01-18 16:23:55 +00001514 ctxt->doc_buff = xmlAllocOutputBuffer(NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001515 }
1516
Daniel Veillard572577e2002-01-18 16:23:55 +00001517 if (ctxt->doc_buff == NULL) {
1518 xmlFreeHTTPWriteCtxt(ctxt);
1519 ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001520 }
1521
Daniel Veillard572577e2002-01-18 16:23:55 +00001522 return (ctxt);
Daniel Veillardf012a642001-07-23 19:10:52 +00001523}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001524#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001525
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001526#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001527/**
1528 * xmlIOHTTPDfltOpenW
1529 * @post_uri: The destination URI for this document.
1530 *
1531 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
1532 * HTTP post command. This function should generally not be used as
1533 * the open callback is short circuited in xmlOutputBufferCreateFile.
1534 *
1535 * Returns a pointer to the new IO context.
1536 */
1537static void *
1538xmlIOHTTPDfltOpenW( const char * post_uri ) {
1539 return ( xmlIOHTTPOpenW( post_uri, 0 ) );
1540}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001541#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001542
1543/**
Owen Taylor3473f882001-02-23 17:55:21 +00001544 * xmlIOHTTPRead:
1545 * @context: the I/O context
1546 * @buffer: where to drop data
1547 * @len: number of bytes to write
1548 *
1549 * Read @len bytes to @buffer from the I/O channel.
1550 *
1551 * Returns the number of bytes written
1552 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001553int
Owen Taylor3473f882001-02-23 17:55:21 +00001554xmlIOHTTPRead(void * context, char * buffer, int len) {
Daniel Veillard5ea30d72004-11-08 11:54:28 +00001555 if ((buffer == NULL) || (len < 0)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001556 return(xmlNanoHTTPRead(context, &buffer[0], len));
1557}
1558
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001559#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001560/**
Daniel Veillardf012a642001-07-23 19:10:52 +00001561 * xmlIOHTTPWrite
1562 * @context: previously opened writing context
1563 * @buffer: data to output to temporary buffer
1564 * @len: bytes to output
1565 *
1566 * Collect data from memory buffer into a temporary file for later
1567 * processing.
1568 *
1569 * Returns number of bytes written.
1570 */
1571
1572static int
1573xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
1574
1575 xmlIOHTTPWriteCtxtPtr ctxt = context;
1576
1577 if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
1578 return ( -1 );
1579
1580 if ( len > 0 ) {
1581
1582 /* Use gzwrite or fwrite as previously setup in the open call */
1583
1584#ifdef HAVE_ZLIB_H
1585 if ( ctxt->compression > 0 )
1586 len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len );
1587
1588 else
1589#endif
1590 len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
1591
1592 if ( len < 0 ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001593 xmlChar msg[500];
1594 xmlStrPrintf(msg, 500,
1595 (const xmlChar *) "xmlIOHTTPWrite: %s\n%s '%s'.\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001596 "Error appending to internal buffer.",
1597 "Error sending document to URI",
1598 ctxt->uri );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001599 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001600 }
1601 }
1602
1603 return ( len );
1604}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001605#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001606
1607
1608/**
Owen Taylor3473f882001-02-23 17:55:21 +00001609 * xmlIOHTTPClose:
1610 * @context: the I/O context
1611 *
1612 * Close an HTTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001613 *
1614 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00001615 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001616int
Owen Taylor3473f882001-02-23 17:55:21 +00001617xmlIOHTTPClose (void * context) {
1618 xmlNanoHTTPClose(context);
Daniel Veillardf012a642001-07-23 19:10:52 +00001619 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001620}
Daniel Veillardf012a642001-07-23 19:10:52 +00001621
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001622#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001623/**
1624 * xmlIOHTTCloseWrite
1625 * @context: The I/O context
1626 * @http_mthd: The HTTP method to be used when sending the data
1627 *
1628 * Close the transmit HTTP I/O channel and actually send the data.
1629 */
1630static int
1631xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
1632
1633 int close_rc = -1;
1634 int http_rtn = 0;
1635 int content_lgth = 0;
1636 xmlIOHTTPWriteCtxtPtr ctxt = context;
1637
1638 char * http_content = NULL;
1639 char * content_encoding = NULL;
1640 char * content_type = (char *) "text/xml";
1641 void * http_ctxt = NULL;
1642
1643 if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
1644 return ( -1 );
1645
1646 /* Retrieve the content from the appropriate buffer */
1647
1648#ifdef HAVE_ZLIB_H
1649
1650 if ( ctxt->compression > 0 ) {
1651 content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
1652 content_encoding = (char *) "Content-Encoding: gzip";
1653 }
1654 else
1655#endif
1656 {
1657 /* Pull the data out of the memory output buffer */
1658
1659 xmlOutputBufferPtr dctxt = ctxt->doc_buff;
1660 http_content = (char *)dctxt->buffer->content;
1661 content_lgth = dctxt->buffer->use;
1662 }
1663
1664 if ( http_content == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001665 xmlChar msg[500];
1666 xmlStrPrintf(msg, 500,
1667 (const xmlChar *) "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
1668 "Error retrieving content.\nUnable to",
1669 http_mthd, "data to URI", ctxt->uri );
1670 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001671 }
1672
1673 else {
1674
1675 http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
1676 &content_type, content_encoding,
1677 content_lgth );
1678
1679 if ( http_ctxt != NULL ) {
1680#ifdef DEBUG_HTTP
1681 /* If testing/debugging - dump reply with request content */
1682
1683 FILE * tst_file = NULL;
1684 char buffer[ 4096 ];
1685 char * dump_name = NULL;
1686 int avail;
1687
1688 xmlGenericError( xmlGenericErrorContext,
1689 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
1690 http_mthd, ctxt->uri,
1691 xmlNanoHTTPReturnCode( http_ctxt ) );
1692
1693 /*
1694 ** Since either content or reply may be gzipped,
1695 ** dump them to separate files instead of the
1696 ** standard error context.
1697 */
1698
1699 dump_name = tempnam( NULL, "lxml" );
1700 if ( dump_name != NULL ) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001701 (void)snprintf( buffer, sizeof(buffer), "%s.content", dump_name );
Daniel Veillardf012a642001-07-23 19:10:52 +00001702
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00001703 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00001704 if ( tst_file != NULL ) {
1705 xmlGenericError( xmlGenericErrorContext,
1706 "Transmitted content saved in file: %s\n", buffer );
1707
1708 fwrite( http_content, sizeof( char ),
1709 content_lgth, tst_file );
1710 fclose( tst_file );
1711 }
1712
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001713 (void)snprintf( buffer, sizeof(buffer), "%s.reply", dump_name );
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00001714 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00001715 if ( tst_file != NULL ) {
1716 xmlGenericError( xmlGenericErrorContext,
1717 "Reply content saved in file: %s\n", buffer );
1718
1719
1720 while ( (avail = xmlNanoHTTPRead( http_ctxt,
1721 buffer, sizeof( buffer ) )) > 0 ) {
1722
1723 fwrite( buffer, sizeof( char ), avail, tst_file );
1724 }
1725
1726 fclose( tst_file );
1727 }
1728
1729 free( dump_name );
1730 }
1731#endif /* DEBUG_HTTP */
1732
1733 http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
1734 if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
1735 close_rc = 0;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001736 else {
1737 xmlChar msg[500];
1738 xmlStrPrintf(msg, 500,
1739 (const xmlChar *) "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001740 http_mthd, content_lgth,
1741 "bytes to URI", ctxt->uri,
1742 "failed. HTTP return code:", http_rtn );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001743 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1744 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001745
1746 xmlNanoHTTPClose( http_ctxt );
1747 xmlFree( content_type );
1748 }
1749 }
1750
1751 /* Final cleanups */
1752
1753 xmlFreeHTTPWriteCtxt( ctxt );
1754
1755 return ( close_rc );
1756}
1757
1758/**
1759 * xmlIOHTTPClosePut
1760 *
1761 * @context: The I/O context
1762 *
1763 * Close the transmit HTTP I/O channel and actually send data using a PUT
1764 * HTTP method.
1765 */
1766static int
1767xmlIOHTTPClosePut( void * ctxt ) {
1768 return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
1769}
1770
1771
1772/**
1773 * xmlIOHTTPClosePost
1774 *
1775 * @context: The I/O context
1776 *
1777 * Close the transmit HTTP I/O channel and actually send data using a POST
1778 * HTTP method.
1779 */
1780static int
1781xmlIOHTTPClosePost( void * ctxt ) {
1782 return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
1783}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001784#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001785
Owen Taylor3473f882001-02-23 17:55:21 +00001786#endif /* LIBXML_HTTP_ENABLED */
1787
1788#ifdef LIBXML_FTP_ENABLED
1789/************************************************************************
1790 * *
1791 * I/O for FTP file accesses *
1792 * *
1793 ************************************************************************/
1794/**
1795 * xmlIOFTPMatch:
1796 * @filename: the URI for matching
1797 *
1798 * check if the URI matches an FTP one
1799 *
1800 * Returns 1 if matches, 0 otherwise
1801 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001802int
Owen Taylor3473f882001-02-23 17:55:21 +00001803xmlIOFTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001804 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "ftp://", 6))
Owen Taylor3473f882001-02-23 17:55:21 +00001805 return(1);
1806 return(0);
1807}
1808
1809/**
1810 * xmlIOFTPOpen:
1811 * @filename: the URI for matching
1812 *
1813 * open an FTP I/O channel
1814 *
1815 * Returns an I/O context or NULL in case of error
1816 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001817void *
Owen Taylor3473f882001-02-23 17:55:21 +00001818xmlIOFTPOpen (const char *filename) {
1819 return(xmlNanoFTPOpen(filename));
1820}
1821
1822/**
1823 * xmlIOFTPRead:
1824 * @context: the I/O context
1825 * @buffer: where to drop data
1826 * @len: number of bytes to write
1827 *
1828 * Read @len bytes to @buffer from the I/O channel.
1829 *
1830 * Returns the number of bytes written
1831 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001832int
Owen Taylor3473f882001-02-23 17:55:21 +00001833xmlIOFTPRead(void * context, char * buffer, int len) {
Daniel Veillard5ea30d72004-11-08 11:54:28 +00001834 if ((buffer == NULL) || (len < 0)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001835 return(xmlNanoFTPRead(context, &buffer[0], len));
1836}
1837
1838/**
1839 * xmlIOFTPClose:
1840 * @context: the I/O context
1841 *
1842 * Close an FTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001843 *
1844 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00001845 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001846int
Owen Taylor3473f882001-02-23 17:55:21 +00001847xmlIOFTPClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001848 return ( xmlNanoFTPClose(context) );
Owen Taylor3473f882001-02-23 17:55:21 +00001849}
1850#endif /* LIBXML_FTP_ENABLED */
1851
1852
1853/**
1854 * xmlRegisterInputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001855 * @matchFunc: the xmlInputMatchCallback
1856 * @openFunc: the xmlInputOpenCallback
1857 * @readFunc: the xmlInputReadCallback
1858 * @closeFunc: the xmlInputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001859 *
1860 * Register a new set of I/O callback for handling parser input.
1861 *
1862 * Returns the registered handler number or -1 in case of error
1863 */
1864int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001865xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
1866 xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
1867 xmlInputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001868 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
1869 return(-1);
1870 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001871 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
1872 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
1873 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
1874 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00001875 xmlInputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00001876 return(xmlInputCallbackNr++);
1877}
1878
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001879#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001880/**
1881 * xmlRegisterOutputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001882 * @matchFunc: the xmlOutputMatchCallback
1883 * @openFunc: the xmlOutputOpenCallback
1884 * @writeFunc: the xmlOutputWriteCallback
1885 * @closeFunc: the xmlOutputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001886 *
1887 * Register a new set of I/O callback for handling output.
1888 *
1889 * Returns the registered handler number or -1 in case of error
1890 */
1891int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001892xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
1893 xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
1894 xmlOutputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001895 if (xmlOutputCallbackNr >= MAX_INPUT_CALLBACK) {
1896 return(-1);
1897 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001898 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
1899 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
1900 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
1901 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00001902 xmlOutputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00001903 return(xmlOutputCallbackNr++);
1904}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001905#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001906
1907/**
1908 * xmlRegisterDefaultInputCallbacks:
1909 *
1910 * Registers the default compiled-in I/O handlers.
1911 */
1912void
Owen Taylor3473f882001-02-23 17:55:21 +00001913xmlRegisterDefaultInputCallbacks
Owen Taylor3473f882001-02-23 17:55:21 +00001914(void) {
1915 if (xmlInputCallbackInitialized)
1916 return;
1917
1918 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
1919 xmlFileRead, xmlFileClose);
1920#ifdef HAVE_ZLIB_H
1921 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1922 xmlGzfileRead, xmlGzfileClose);
1923#endif /* HAVE_ZLIB_H */
1924
1925#ifdef LIBXML_HTTP_ENABLED
1926 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
1927 xmlIOHTTPRead, xmlIOHTTPClose);
1928#endif /* LIBXML_HTTP_ENABLED */
1929
1930#ifdef LIBXML_FTP_ENABLED
1931 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1932 xmlIOFTPRead, xmlIOFTPClose);
1933#endif /* LIBXML_FTP_ENABLED */
1934 xmlInputCallbackInitialized = 1;
1935}
1936
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001937#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001938/**
1939 * xmlRegisterDefaultOutputCallbacks:
1940 *
1941 * Registers the default compiled-in I/O handlers.
1942 */
1943void
Owen Taylor3473f882001-02-23 17:55:21 +00001944xmlRegisterDefaultOutputCallbacks
Owen Taylor3473f882001-02-23 17:55:21 +00001945(void) {
1946 if (xmlOutputCallbackInitialized)
1947 return;
1948
1949 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
1950 xmlFileWrite, xmlFileClose);
Daniel Veillardf012a642001-07-23 19:10:52 +00001951
1952#ifdef LIBXML_HTTP_ENABLED
1953 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
1954 xmlIOHTTPWrite, xmlIOHTTPClosePut);
1955#endif
1956
Owen Taylor3473f882001-02-23 17:55:21 +00001957/*********************************
1958 No way a-priori to distinguish between gzipped files from
1959 uncompressed ones except opening if existing then closing
1960 and saving with same compression ratio ... a pain.
1961
1962#ifdef HAVE_ZLIB_H
1963 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1964 xmlGzfileWrite, xmlGzfileClose);
1965#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001966
1967 Nor FTP PUT ....
1968#ifdef LIBXML_FTP_ENABLED
1969 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1970 xmlIOFTPWrite, xmlIOFTPClose);
1971#endif
1972 **********************************/
1973 xmlOutputCallbackInitialized = 1;
1974}
1975
Daniel Veillardf012a642001-07-23 19:10:52 +00001976#ifdef LIBXML_HTTP_ENABLED
1977/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001978 * xmlRegisterHTTPPostCallbacks:
Daniel Veillardf012a642001-07-23 19:10:52 +00001979 *
1980 * By default, libxml submits HTTP output requests using the "PUT" method.
1981 * Calling this method changes the HTTP output method to use the "POST"
1982 * method instead.
1983 *
1984 */
1985void
1986xmlRegisterHTTPPostCallbacks( void ) {
1987
1988 /* Register defaults if not done previously */
1989
1990 if ( xmlOutputCallbackInitialized == 0 )
1991 xmlRegisterDefaultOutputCallbacks( );
1992
1993 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
1994 xmlIOHTTPWrite, xmlIOHTTPClosePost);
1995 return;
1996}
1997#endif
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001998#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001999
Owen Taylor3473f882001-02-23 17:55:21 +00002000/**
2001 * xmlAllocParserInputBuffer:
2002 * @enc: the charset encoding if known
2003 *
2004 * Create a buffered parser input for progressive parsing
2005 *
2006 * Returns the new parser input or NULL
2007 */
2008xmlParserInputBufferPtr
2009xmlAllocParserInputBuffer(xmlCharEncoding enc) {
2010 xmlParserInputBufferPtr ret;
2011
2012 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2013 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002014 xmlIOErrMemory("creating input buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00002015 return(NULL);
2016 }
2017 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002018 ret->buffer = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00002019 if (ret->buffer == NULL) {
2020 xmlFree(ret);
2021 return(NULL);
2022 }
2023 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
2024 ret->encoder = xmlGetCharEncodingHandler(enc);
2025 if (ret->encoder != NULL)
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002026 ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00002027 else
2028 ret->raw = NULL;
2029 ret->readcallback = NULL;
2030 ret->closecallback = NULL;
2031 ret->context = NULL;
William M. Brackc07329e2003-09-08 01:57:30 +00002032 ret->compressed = -1;
Daniel Veillard36711902004-02-11 13:25:26 +00002033 ret->rawconsumed = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002034
2035 return(ret);
2036}
2037
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002038#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002039/**
2040 * xmlAllocOutputBuffer:
2041 * @encoder: the encoding converter or NULL
2042 *
2043 * Create a buffered parser output
2044 *
2045 * Returns the new parser output or NULL
2046 */
2047xmlOutputBufferPtr
2048xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
2049 xmlOutputBufferPtr ret;
2050
2051 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
2052 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002053 xmlIOErrMemory("creating output buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00002054 return(NULL);
2055 }
2056 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
2057 ret->buffer = xmlBufferCreate();
2058 if (ret->buffer == NULL) {
2059 xmlFree(ret);
2060 return(NULL);
2061 }
2062 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
2063 ret->encoder = encoder;
2064 if (encoder != NULL) {
2065 ret->conv = xmlBufferCreateSize(4000);
2066 /*
2067 * This call is designed to initiate the encoder state
2068 */
2069 xmlCharEncOutFunc(encoder, ret->conv, NULL);
2070 } else
2071 ret->conv = NULL;
2072 ret->writecallback = NULL;
2073 ret->closecallback = NULL;
2074 ret->context = NULL;
2075 ret->written = 0;
2076
2077 return(ret);
2078}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002079#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002080
2081/**
2082 * xmlFreeParserInputBuffer:
2083 * @in: a buffered parser input
2084 *
2085 * Free up the memory used by a buffered parser input
2086 */
2087void
2088xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
Daniel Veillard8d8bf2c2003-09-17 19:36:25 +00002089 if (in == NULL) return;
2090
Owen Taylor3473f882001-02-23 17:55:21 +00002091 if (in->raw) {
2092 xmlBufferFree(in->raw);
2093 in->raw = NULL;
2094 }
2095 if (in->encoder != NULL) {
2096 xmlCharEncCloseFunc(in->encoder);
2097 }
2098 if (in->closecallback != NULL) {
2099 in->closecallback(in->context);
2100 }
2101 if (in->buffer != NULL) {
2102 xmlBufferFree(in->buffer);
2103 in->buffer = NULL;
2104 }
2105
Owen Taylor3473f882001-02-23 17:55:21 +00002106 xmlFree(in);
2107}
2108
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002109#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002110/**
2111 * xmlOutputBufferClose:
2112 * @out: a buffered output
2113 *
2114 * flushes and close the output I/O channel
2115 * and free up all the associated resources
2116 *
2117 * Returns the number of byte written or -1 in case of error.
2118 */
2119int
Daniel Veillard828ce832003-10-08 19:19:10 +00002120xmlOutputBufferClose(xmlOutputBufferPtr out)
2121{
Owen Taylor3473f882001-02-23 17:55:21 +00002122 int written;
Daniel Veillardf012a642001-07-23 19:10:52 +00002123 int err_rc = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002124
2125 if (out == NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002126 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002127 if (out->writecallback != NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002128 xmlOutputBufferFlush(out);
Owen Taylor3473f882001-02-23 17:55:21 +00002129 if (out->closecallback != NULL) {
Daniel Veillard828ce832003-10-08 19:19:10 +00002130 err_rc = out->closecallback(out->context);
Owen Taylor3473f882001-02-23 17:55:21 +00002131 }
2132 written = out->written;
2133 if (out->conv) {
2134 xmlBufferFree(out->conv);
Daniel Veillard828ce832003-10-08 19:19:10 +00002135 out->conv = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002136 }
2137 if (out->encoder != NULL) {
2138 xmlCharEncCloseFunc(out->encoder);
2139 }
2140 if (out->buffer != NULL) {
2141 xmlBufferFree(out->buffer);
Daniel Veillard828ce832003-10-08 19:19:10 +00002142 out->buffer = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002143 }
2144
Daniel Veillard828ce832003-10-08 19:19:10 +00002145 if (out->error)
2146 err_rc = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00002147 xmlFree(out);
Daniel Veillard828ce832003-10-08 19:19:10 +00002148 return ((err_rc == 0) ? written : err_rc);
Owen Taylor3473f882001-02-23 17:55:21 +00002149}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002150#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002151
Daniel Veillard1b243b42004-06-08 10:16:42 +00002152xmlParserInputBufferPtr
Daniel Veillard0335a842004-06-02 16:18:40 +00002153__xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002154 xmlParserInputBufferPtr ret;
Daniel Veillard388236f2001-07-08 18:35:48 +00002155 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002156 void *context = NULL;
2157
2158 if (xmlInputCallbackInitialized == 0)
2159 xmlRegisterDefaultInputCallbacks();
2160
2161 if (URI == NULL) return(NULL);
2162
2163 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002164 * Try to find one of the input accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002165 * Go in reverse to give precedence to user defined handlers.
Daniel Veillard388236f2001-07-08 18:35:48 +00002166 */
2167 if (context == NULL) {
2168 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
2169 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
2170 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002171 context = xmlInputCallbackTable[i].opencallback(URI);
Daniel Veillard847332a2003-10-18 11:29:40 +00002172 if (context != NULL) {
Daniel Veillard388236f2001-07-08 18:35:48 +00002173 break;
Daniel Veillard847332a2003-10-18 11:29:40 +00002174 }
Daniel Veillard388236f2001-07-08 18:35:48 +00002175 }
Owen Taylor3473f882001-02-23 17:55:21 +00002176 }
2177 }
2178 if (context == NULL) {
2179 return(NULL);
2180 }
2181
2182 /*
2183 * Allocate the Input buffer front-end.
2184 */
2185 ret = xmlAllocParserInputBuffer(enc);
2186 if (ret != NULL) {
2187 ret->context = context;
2188 ret->readcallback = xmlInputCallbackTable[i].readcallback;
2189 ret->closecallback = xmlInputCallbackTable[i].closecallback;
William M. Brackc07329e2003-09-08 01:57:30 +00002190#ifdef HAVE_ZLIB_H
William M. Brackc5cbf992003-10-29 22:15:13 +00002191 if ((xmlInputCallbackTable[i].opencallback == xmlGzfileOpen) &&
2192 (strcmp(URI, "-") != 0)) {
William M. Brackc07329e2003-09-08 01:57:30 +00002193 if (((z_stream *)context)->avail_in > 4) {
2194 char *cptr, buff4[4];
Daniel Veillard07cb8222003-09-10 10:51:05 +00002195 cptr = (char *) ((z_stream *)context)->next_in;
William M. Brackc07329e2003-09-08 01:57:30 +00002196 if (gzread(context, buff4, 4) == 4) {
2197 if (strncmp(buff4, cptr, 4) == 0)
2198 ret->compressed = 0;
2199 else
2200 ret->compressed = 1;
2201 gzrewind(context);
2202 }
2203 }
2204 }
2205#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002206 }
William M. Brack42331a92004-07-29 07:07:16 +00002207 else
2208 xmlInputCallbackTable[i].closecallback (context);
2209
Owen Taylor3473f882001-02-23 17:55:21 +00002210 return(ret);
2211}
2212
2213/**
Daniel Veillard0335a842004-06-02 16:18:40 +00002214 * xmlParserInputBufferCreateFilename:
Owen Taylor3473f882001-02-23 17:55:21 +00002215 * @URI: a C string containing the URI or filename
Daniel Veillard0335a842004-06-02 16:18:40 +00002216 * @enc: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002217 *
Daniel Veillard0335a842004-06-02 16:18:40 +00002218 * Create a buffered parser input for the progressive parsing of a file
2219 * If filename is "-' then we use stdin as the input.
Owen Taylor3473f882001-02-23 17:55:21 +00002220 * Automatic support for ZLIB/Compress compressed document is provided
2221 * by default if found at compile-time.
Daniel Veillard0335a842004-06-02 16:18:40 +00002222 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
Owen Taylor3473f882001-02-23 17:55:21 +00002223 *
Daniel Veillard0335a842004-06-02 16:18:40 +00002224 * Returns the new parser input or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00002225 */
Daniel Veillard0335a842004-06-02 16:18:40 +00002226xmlParserInputBufferPtr
2227xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
2228 if ((xmlParserInputBufferCreateFilenameValue)) {
2229 return xmlParserInputBufferCreateFilenameValue(URI, enc);
2230 }
2231 return __xmlParserInputBufferCreateFilename(URI, enc);
2232}
2233
2234#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard1b243b42004-06-08 10:16:42 +00002235xmlOutputBufferPtr
Daniel Veillard0335a842004-06-02 16:18:40 +00002236__xmlOutputBufferCreateFilename(const char *URI,
Owen Taylor3473f882001-02-23 17:55:21 +00002237 xmlCharEncodingHandlerPtr encoder,
Daniel Veillard0335a842004-06-02 16:18:40 +00002238 int compression ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00002239 xmlOutputBufferPtr ret;
Daniel Veillard966a31e2004-05-09 02:58:44 +00002240 xmlURIPtr puri;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002241 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002242 void *context = NULL;
Daniel Veillard966a31e2004-05-09 02:58:44 +00002243 char *unescaped = NULL;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002244#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002245 int is_file_uri = 1;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002246#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00002247
Owen Taylor3473f882001-02-23 17:55:21 +00002248 if (xmlOutputCallbackInitialized == 0)
2249 xmlRegisterDefaultOutputCallbacks();
2250
2251 if (URI == NULL) return(NULL);
2252
Daniel Veillard966a31e2004-05-09 02:58:44 +00002253 puri = xmlParseURI(URI);
2254 if (puri != NULL) {
Daniel Veillard8fcd2ca2005-07-03 14:42:56 +00002255#ifdef HAVE_ZLIB_H
Daniel Veillard18a65092004-05-11 15:57:42 +00002256 if ((puri->scheme != NULL) &&
2257 (!xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
Daniel Veillard966a31e2004-05-09 02:58:44 +00002258 is_file_uri = 0;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002259#endif
Daniel Veillard966a31e2004-05-09 02:58:44 +00002260 /*
2261 * try to limit the damages of the URI unescaping code.
2262 */
2263 if (puri->scheme != NULL)
2264 unescaped = xmlURIUnescapeString(URI, 0, NULL);
2265 xmlFreeURI(puri);
2266 }
Owen Taylor3473f882001-02-23 17:55:21 +00002267
2268 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002269 * Try to find one of the output accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002270 * Go in reverse to give precedence to user defined handlers.
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002271 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00002272 */
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002273 if (unescaped != NULL) {
2274#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002275 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002276 context = xmlGzfileOpenW(unescaped, compression);
2277 if (context != NULL) {
2278 ret = xmlAllocOutputBuffer(encoder);
2279 if (ret != NULL) {
2280 ret->context = context;
2281 ret->writecallback = xmlGzfileWrite;
2282 ret->closecallback = xmlGzfileClose;
2283 }
2284 xmlFree(unescaped);
2285 return(ret);
2286 }
2287 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002288#endif
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002289 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2290 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
2291 (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
2292#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2293 /* Need to pass compression parameter into HTTP open calls */
2294 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2295 context = xmlIOHTTPOpenW(unescaped, compression);
2296 else
2297#endif
2298 context = xmlOutputCallbackTable[i].opencallback(unescaped);
2299 if (context != NULL)
2300 break;
2301 }
2302 }
2303 xmlFree(unescaped);
2304 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002305
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002306 /*
2307 * If this failed try with a non-escaped URI this may be a strange
2308 * filename
2309 */
2310 if (context == NULL) {
2311#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002312 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002313 context = xmlGzfileOpenW(URI, compression);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002314 if (context != NULL) {
2315 ret = xmlAllocOutputBuffer(encoder);
2316 if (ret != NULL) {
2317 ret->context = context;
2318 ret->writecallback = xmlGzfileWrite;
2319 ret->closecallback = xmlGzfileClose;
2320 }
2321 return(ret);
2322 }
2323 }
2324#endif
2325 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2326 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002327 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002328#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2329 /* Need to pass compression parameter into HTTP open calls */
2330 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2331 context = xmlIOHTTPOpenW(URI, compression);
2332 else
2333#endif
2334 context = xmlOutputCallbackTable[i].opencallback(URI);
2335 if (context != NULL)
2336 break;
2337 }
Owen Taylor3473f882001-02-23 17:55:21 +00002338 }
2339 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002340
Owen Taylor3473f882001-02-23 17:55:21 +00002341 if (context == NULL) {
2342 return(NULL);
2343 }
2344
2345 /*
2346 * Allocate the Output buffer front-end.
2347 */
2348 ret = xmlAllocOutputBuffer(encoder);
2349 if (ret != NULL) {
2350 ret->context = context;
2351 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
2352 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
2353 }
2354 return(ret);
2355}
Daniel Veillard0335a842004-06-02 16:18:40 +00002356
2357/**
2358 * xmlOutputBufferCreateFilename:
2359 * @URI: a C string containing the URI or filename
2360 * @encoder: the encoding converter or NULL
2361 * @compression: the compression ration (0 none, 9 max).
2362 *
2363 * Create a buffered output for the progressive saving of a file
2364 * If filename is "-' then we use stdout as the output.
2365 * Automatic support for ZLIB/Compress compressed document is provided
2366 * by default if found at compile-time.
2367 * TODO: currently if compression is set, the library only support
2368 * writing to a local file.
2369 *
2370 * Returns the new output or NULL
2371 */
2372xmlOutputBufferPtr
2373xmlOutputBufferCreateFilename(const char *URI,
2374 xmlCharEncodingHandlerPtr encoder,
2375 int compression ATTRIBUTE_UNUSED) {
2376 if ((xmlOutputBufferCreateFilenameValue)) {
2377 return xmlOutputBufferCreateFilenameValue(URI, encoder, compression);
2378 }
2379 return __xmlOutputBufferCreateFilename(URI, encoder, compression);
2380}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002381#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002382
2383/**
2384 * xmlParserInputBufferCreateFile:
2385 * @file: a FILE*
2386 * @enc: the charset encoding if known
2387 *
2388 * Create a buffered parser input for the progressive parsing of a FILE *
2389 * buffered C I/O
2390 *
2391 * Returns the new parser input or NULL
2392 */
2393xmlParserInputBufferPtr
2394xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
2395 xmlParserInputBufferPtr ret;
2396
2397 if (xmlInputCallbackInitialized == 0)
2398 xmlRegisterDefaultInputCallbacks();
2399
2400 if (file == NULL) return(NULL);
2401
2402 ret = xmlAllocParserInputBuffer(enc);
2403 if (ret != NULL) {
2404 ret->context = file;
2405 ret->readcallback = xmlFileRead;
2406 ret->closecallback = xmlFileFlush;
2407 }
2408
2409 return(ret);
2410}
2411
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002412#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002413/**
2414 * xmlOutputBufferCreateFile:
2415 * @file: a FILE*
2416 * @encoder: the encoding converter or NULL
2417 *
2418 * Create a buffered output for the progressive saving to a FILE *
2419 * buffered C I/O
2420 *
2421 * Returns the new parser output or NULL
2422 */
2423xmlOutputBufferPtr
2424xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
2425 xmlOutputBufferPtr ret;
2426
2427 if (xmlOutputCallbackInitialized == 0)
2428 xmlRegisterDefaultOutputCallbacks();
2429
2430 if (file == NULL) return(NULL);
2431
2432 ret = xmlAllocOutputBuffer(encoder);
2433 if (ret != NULL) {
2434 ret->context = file;
2435 ret->writecallback = xmlFileWrite;
2436 ret->closecallback = xmlFileFlush;
2437 }
2438
2439 return(ret);
2440}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002441#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002442
2443/**
2444 * xmlParserInputBufferCreateFd:
2445 * @fd: a file descriptor number
2446 * @enc: the charset encoding if known
2447 *
2448 * Create a buffered parser input for the progressive parsing for the input
2449 * from a file descriptor
2450 *
2451 * Returns the new parser input or NULL
2452 */
2453xmlParserInputBufferPtr
2454xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
2455 xmlParserInputBufferPtr ret;
2456
2457 if (fd < 0) return(NULL);
2458
2459 ret = xmlAllocParserInputBuffer(enc);
2460 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002461 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002462 ret->readcallback = xmlFdRead;
2463 ret->closecallback = xmlFdClose;
2464 }
2465
2466 return(ret);
2467}
2468
2469/**
2470 * xmlParserInputBufferCreateMem:
2471 * @mem: the memory input
2472 * @size: the length of the memory block
2473 * @enc: the charset encoding if known
2474 *
2475 * Create a buffered parser input for the progressive parsing for the input
2476 * from a memory area.
2477 *
2478 * Returns the new parser input or NULL
2479 */
2480xmlParserInputBufferPtr
2481xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
2482 xmlParserInputBufferPtr ret;
William M. Bracka3215c72004-07-31 16:24:01 +00002483 int errcode;
Owen Taylor3473f882001-02-23 17:55:21 +00002484
2485 if (size <= 0) return(NULL);
2486 if (mem == NULL) return(NULL);
2487
2488 ret = xmlAllocParserInputBuffer(enc);
2489 if (ret != NULL) {
2490 ret->context = (void *) mem;
2491 ret->readcallback = (xmlInputReadCallback) xmlNop;
2492 ret->closecallback = NULL;
William M. Bracka3215c72004-07-31 16:24:01 +00002493 errcode = xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size);
2494 if (errcode != 0) {
2495 xmlFree(ret);
2496 return(NULL);
2497 }
Owen Taylor3473f882001-02-23 17:55:21 +00002498 }
2499
2500 return(ret);
2501}
2502
2503/**
Daniel Veillard53350552003-09-18 13:35:51 +00002504 * xmlParserInputBufferCreateStatic:
2505 * @mem: the memory input
2506 * @size: the length of the memory block
2507 * @enc: the charset encoding if known
2508 *
2509 * Create a buffered parser input for the progressive parsing for the input
2510 * from an immutable memory area. This will not copy the memory area to
2511 * the buffer, but the memory is expected to be available until the end of
2512 * the parsing, this is useful for example when using mmap'ed file.
2513 *
2514 * Returns the new parser input or NULL
2515 */
2516xmlParserInputBufferPtr
2517xmlParserInputBufferCreateStatic(const char *mem, int size,
2518 xmlCharEncoding enc) {
2519 xmlParserInputBufferPtr ret;
2520
2521 if (size <= 0) return(NULL);
2522 if (mem == NULL) return(NULL);
2523
2524 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2525 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002526 xmlIOErrMemory("creating input buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00002527 return(NULL);
2528 }
2529 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillarde72c5082003-09-19 12:44:05 +00002530 ret->buffer = xmlBufferCreateStatic((void *)mem, (size_t) size);
Daniel Veillard53350552003-09-18 13:35:51 +00002531 if (ret->buffer == NULL) {
2532 xmlFree(ret);
2533 return(NULL);
2534 }
2535 ret->encoder = xmlGetCharEncodingHandler(enc);
2536 if (ret->encoder != NULL)
2537 ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
2538 else
2539 ret->raw = NULL;
2540 ret->compressed = -1;
2541 ret->context = (void *) mem;
2542 ret->readcallback = NULL;
2543 ret->closecallback = NULL;
2544
2545 return(ret);
2546}
2547
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002548#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard53350552003-09-18 13:35:51 +00002549/**
Owen Taylor3473f882001-02-23 17:55:21 +00002550 * xmlOutputBufferCreateFd:
2551 * @fd: a file descriptor number
2552 * @encoder: the encoding converter or NULL
2553 *
2554 * Create a buffered output for the progressive saving
2555 * to a file descriptor
2556 *
2557 * Returns the new parser output or NULL
2558 */
2559xmlOutputBufferPtr
2560xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
2561 xmlOutputBufferPtr ret;
2562
2563 if (fd < 0) return(NULL);
2564
2565 ret = xmlAllocOutputBuffer(encoder);
2566 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002567 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002568 ret->writecallback = xmlFdWrite;
Daniel Veillard7db38712002-02-07 16:39:11 +00002569 ret->closecallback = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002570 }
2571
2572 return(ret);
2573}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002574#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002575
2576/**
2577 * xmlParserInputBufferCreateIO:
2578 * @ioread: an I/O read function
2579 * @ioclose: an I/O close function
2580 * @ioctx: an I/O handler
2581 * @enc: the charset encoding if known
2582 *
2583 * Create a buffered parser input for the progressive parsing for the input
2584 * from an I/O handler
2585 *
2586 * Returns the new parser input or NULL
2587 */
2588xmlParserInputBufferPtr
2589xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
2590 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
2591 xmlParserInputBufferPtr ret;
2592
2593 if (ioread == NULL) return(NULL);
2594
2595 ret = xmlAllocParserInputBuffer(enc);
2596 if (ret != NULL) {
2597 ret->context = (void *) ioctx;
2598 ret->readcallback = ioread;
2599 ret->closecallback = ioclose;
2600 }
2601
2602 return(ret);
2603}
2604
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002605#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002606/**
2607 * xmlOutputBufferCreateIO:
2608 * @iowrite: an I/O write function
2609 * @ioclose: an I/O close function
2610 * @ioctx: an I/O handler
Daniel Veillard9d06d302002-01-22 18:15:52 +00002611 * @encoder: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002612 *
2613 * Create a buffered output for the progressive saving
2614 * to an I/O handler
2615 *
2616 * Returns the new parser output or NULL
2617 */
2618xmlOutputBufferPtr
2619xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
2620 xmlOutputCloseCallback ioclose, void *ioctx,
2621 xmlCharEncodingHandlerPtr encoder) {
2622 xmlOutputBufferPtr ret;
2623
2624 if (iowrite == NULL) return(NULL);
2625
2626 ret = xmlAllocOutputBuffer(encoder);
2627 if (ret != NULL) {
2628 ret->context = (void *) ioctx;
2629 ret->writecallback = iowrite;
2630 ret->closecallback = ioclose;
2631 }
2632
2633 return(ret);
2634}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002635#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002636
2637/**
Daniel Veillard1b243b42004-06-08 10:16:42 +00002638 * xmlParserInputBufferCreateFilenameDefault:
2639 * @func: function pointer to the new ParserInputBufferCreateFilenameFunc
2640 *
2641 * Registers a callback for URI input file handling
2642 *
2643 * Returns the old value of the registration function
2644 */
2645xmlParserInputBufferCreateFilenameFunc
2646xmlParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func)
2647{
2648 xmlParserInputBufferCreateFilenameFunc old = xmlParserInputBufferCreateFilenameValue;
2649 if (old == NULL) {
2650 old = __xmlParserInputBufferCreateFilename;
2651 }
2652
2653 xmlParserInputBufferCreateFilenameValue = func;
2654 return(old);
2655}
2656
2657/**
2658 * xmlOutputBufferCreateFilenameDefault:
2659 * @func: function pointer to the new OutputBufferCreateFilenameFunc
2660 *
2661 * Registers a callback for URI output file handling
2662 *
2663 * Returns the old value of the registration function
2664 */
2665xmlOutputBufferCreateFilenameFunc
2666xmlOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func)
2667{
2668 xmlOutputBufferCreateFilenameFunc old = xmlOutputBufferCreateFilenameValue;
2669#ifdef LIBXML_OUTPUT_ENABLED
2670 if (old == NULL) {
2671 old = __xmlOutputBufferCreateFilename;
2672 }
2673#endif
2674 xmlOutputBufferCreateFilenameValue = func;
2675 return(old);
2676}
2677
2678/**
Owen Taylor3473f882001-02-23 17:55:21 +00002679 * xmlParserInputBufferPush:
2680 * @in: a buffered parser input
2681 * @len: the size in bytes of the array.
2682 * @buf: an char array
2683 *
2684 * Push the content of the arry in the input buffer
2685 * This routine handle the I18N transcoding to internal UTF-8
2686 * This is used when operating the parser in progressive (push) mode.
2687 *
2688 * Returns the number of chars read and stored in the buffer, or -1
2689 * in case of error.
2690 */
2691int
2692xmlParserInputBufferPush(xmlParserInputBufferPtr in,
2693 int len, const char *buf) {
2694 int nbchars = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00002695 int ret;
Owen Taylor3473f882001-02-23 17:55:21 +00002696
2697 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002698 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002699 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00002700 unsigned int use;
2701
Owen Taylor3473f882001-02-23 17:55:21 +00002702 /*
2703 * Store the data in the incoming raw buffer
2704 */
2705 if (in->raw == NULL) {
2706 in->raw = xmlBufferCreate();
2707 }
William M. Bracka3215c72004-07-31 16:24:01 +00002708 ret = xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
2709 if (ret != 0)
2710 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002711
2712 /*
2713 * convert as much as possible to the parser reading buffer.
2714 */
Daniel Veillard36711902004-02-11 13:25:26 +00002715 use = in->raw->use;
Owen Taylor3473f882001-02-23 17:55:21 +00002716 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2717 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002718 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002719 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002720 return(-1);
2721 }
Daniel Veillard36711902004-02-11 13:25:26 +00002722 in->rawconsumed += (use - in->raw->use);
Owen Taylor3473f882001-02-23 17:55:21 +00002723 } else {
2724 nbchars = len;
William M. Bracka3215c72004-07-31 16:24:01 +00002725 ret = xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
2726 if (ret != 0)
2727 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002728 }
2729#ifdef DEBUG_INPUT
2730 xmlGenericError(xmlGenericErrorContext,
2731 "I/O: pushed %d chars, buffer %d/%d\n",
2732 nbchars, in->buffer->use, in->buffer->size);
2733#endif
2734 return(nbchars);
2735}
2736
2737/**
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002738 * endOfInput:
2739 *
2740 * When reading from an Input channel indicated end of file or error
2741 * don't reread from it again.
2742 */
2743static int
2744endOfInput (void * context ATTRIBUTE_UNUSED,
2745 char * buffer ATTRIBUTE_UNUSED,
2746 int len ATTRIBUTE_UNUSED) {
2747 return(0);
2748}
2749
2750/**
Owen Taylor3473f882001-02-23 17:55:21 +00002751 * xmlParserInputBufferGrow:
2752 * @in: a buffered parser input
2753 * @len: indicative value of the amount of chars to read
2754 *
2755 * Grow up the content of the input buffer, the old data are preserved
2756 * This routine handle the I18N transcoding to internal UTF-8
2757 * This routine is used when operating the parser in normal (pull) mode
2758 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002759 * TODO: one should be able to remove one extra copy by copying directly
Owen Taylor3473f882001-02-23 17:55:21 +00002760 * onto in->buffer or in->raw
2761 *
2762 * Returns the number of chars read and stored in the buffer, or -1
2763 * in case of error.
2764 */
2765int
2766xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
2767 char *buffer = NULL;
2768 int res = 0;
2769 int nbchars = 0;
2770 int buffree;
Daniel Veillard9e412302002-06-10 15:59:44 +00002771 unsigned int needSize;
Owen Taylor3473f882001-02-23 17:55:21 +00002772
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002773 if ((in == NULL) || (in->error)) return(-1);
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002774 if ((len <= MINLEN) && (len != 4))
Owen Taylor3473f882001-02-23 17:55:21 +00002775 len = MINLEN;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002776
Owen Taylor3473f882001-02-23 17:55:21 +00002777 buffree = in->buffer->size - in->buffer->use;
2778 if (buffree <= 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002779 xmlIOErr(XML_IO_BUFFER_FULL, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002780 in->error = XML_IO_BUFFER_FULL;
William M. Bracka3215c72004-07-31 16:24:01 +00002781 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002782 }
Owen Taylor3473f882001-02-23 17:55:21 +00002783
Daniel Veillarde5354492002-05-16 08:43:22 +00002784 needSize = in->buffer->use + len + 1;
2785 if (needSize > in->buffer->size){
2786 if (!xmlBufferResize(in->buffer, needSize)){
Daniel Veillard05d987b2003-10-08 11:54:57 +00002787 xmlIOErrMemory("growing input buffer");
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002788 in->error = XML_ERR_NO_MEMORY;
William M. Bracka3215c72004-07-31 16:24:01 +00002789 return(-1);
Daniel Veillarde5354492002-05-16 08:43:22 +00002790 }
Owen Taylor3473f882001-02-23 17:55:21 +00002791 }
Daniel Veillarde5354492002-05-16 08:43:22 +00002792 buffer = (char *)&in->buffer->content[in->buffer->use];
Owen Taylor3473f882001-02-23 17:55:21 +00002793
2794 /*
2795 * Call the read method for this I/O type.
2796 */
2797 if (in->readcallback != NULL) {
2798 res = in->readcallback(in->context, &buffer[0], len);
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002799 if (res <= 0)
2800 in->readcallback = endOfInput;
Owen Taylor3473f882001-02-23 17:55:21 +00002801 } else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002802 xmlIOErr(XML_IO_NO_INPUT, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002803 in->error = XML_IO_NO_INPUT;
Owen Taylor3473f882001-02-23 17:55:21 +00002804 return(-1);
2805 }
2806 if (res < 0) {
Owen Taylor3473f882001-02-23 17:55:21 +00002807 return(-1);
2808 }
2809 len = res;
2810 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00002811 unsigned int use;
2812
Owen Taylor3473f882001-02-23 17:55:21 +00002813 /*
2814 * Store the data in the incoming raw buffer
2815 */
2816 if (in->raw == NULL) {
2817 in->raw = xmlBufferCreate();
2818 }
William M. Bracka3215c72004-07-31 16:24:01 +00002819 res = xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
2820 if (res != 0)
2821 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002822
2823 /*
2824 * convert as much as possible to the parser reading buffer.
2825 */
Daniel Veillard36711902004-02-11 13:25:26 +00002826 use = in->raw->use;
Owen Taylor3473f882001-02-23 17:55:21 +00002827 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2828 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002829 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002830 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002831 return(-1);
2832 }
Daniel Veillard36711902004-02-11 13:25:26 +00002833 in->rawconsumed += (use - in->raw->use);
Owen Taylor3473f882001-02-23 17:55:21 +00002834 } else {
2835 nbchars = len;
Daniel Veillarde5354492002-05-16 08:43:22 +00002836 in->buffer->use += nbchars;
2837 buffer[nbchars] = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002838 }
2839#ifdef DEBUG_INPUT
2840 xmlGenericError(xmlGenericErrorContext,
2841 "I/O: read %d chars, buffer %d/%d\n",
2842 nbchars, in->buffer->use, in->buffer->size);
2843#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002844 return(nbchars);
2845}
2846
2847/**
2848 * xmlParserInputBufferRead:
2849 * @in: a buffered parser input
2850 * @len: indicative value of the amount of chars to read
2851 *
2852 * Refresh the content of the input buffer, the old data are considered
2853 * consumed
2854 * This routine handle the I18N transcoding to internal UTF-8
2855 *
2856 * Returns the number of chars read and stored in the buffer, or -1
2857 * in case of error.
2858 */
2859int
2860xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002861 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002862 if (in->readcallback != NULL)
2863 return(xmlParserInputBufferGrow(in, len));
Daniel Veillard53350552003-09-18 13:35:51 +00002864 else if ((in->buffer != NULL) &&
2865 (in->buffer->alloc == XML_BUFFER_ALLOC_IMMUTABLE))
2866 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002867 else
2868 return(-1);
2869}
2870
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002871#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002872/**
2873 * xmlOutputBufferWrite:
2874 * @out: a buffered parser output
2875 * @len: the size in bytes of the array.
2876 * @buf: an char array
2877 *
2878 * Write the content of the array in the output I/O buffer
2879 * This routine handle the I18N transcoding from internal UTF-8
2880 * The buffer is lossless, i.e. will store in case of partial
2881 * or delayed writes.
2882 *
2883 * Returns the number of chars immediately written, or -1
2884 * in case of error.
2885 */
2886int
2887xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
2888 int nbchars = 0; /* number of chars to output to I/O */
2889 int ret; /* return from function call */
2890 int written = 0; /* number of char written to I/O so far */
2891 int chunk; /* number of byte curreent processed from buf */
2892
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002893 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002894 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002895 if (out->error) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002896
2897 do {
2898 chunk = len;
2899 if (chunk > 4 * MINLEN)
2900 chunk = 4 * MINLEN;
2901
2902 /*
2903 * first handle encoding stuff.
2904 */
2905 if (out->encoder != NULL) {
2906 /*
2907 * Store the data in the incoming raw buffer
2908 */
2909 if (out->conv == NULL) {
2910 out->conv = xmlBufferCreate();
2911 }
William M. Bracka3215c72004-07-31 16:24:01 +00002912 ret = xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2913 if (ret != 0)
2914 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002915
2916 if ((out->buffer->use < MINLEN) && (chunk == len))
2917 goto done;
2918
2919 /*
2920 * convert as much as possible to the parser reading buffer.
2921 */
2922 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
Daniel Veillard809faa52003-02-10 15:43:53 +00002923 if ((ret < 0) && (ret != -3)) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002924 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002925 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002926 return(-1);
2927 }
2928 nbchars = out->conv->use;
2929 } else {
William M. Bracka3215c72004-07-31 16:24:01 +00002930 ret = xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2931 if (ret != 0)
2932 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002933 nbchars = out->buffer->use;
2934 }
2935 buf += chunk;
2936 len -= chunk;
2937
2938 if ((nbchars < MINLEN) && (len <= 0))
2939 goto done;
2940
2941 if (out->writecallback) {
2942 /*
2943 * second write the stuff to the I/O channel
2944 */
2945 if (out->encoder != NULL) {
2946 ret = out->writecallback(out->context,
2947 (const char *)out->conv->content, nbchars);
2948 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002949 xmlBufferShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002950 } else {
2951 ret = out->writecallback(out->context,
2952 (const char *)out->buffer->content, nbchars);
2953 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002954 xmlBufferShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002955 }
2956 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002957 xmlIOErr(XML_IO_WRITE, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002958 out->error = XML_IO_WRITE;
Owen Taylor3473f882001-02-23 17:55:21 +00002959 return(ret);
2960 }
2961 out->written += ret;
2962 }
2963 written += nbchars;
2964 } while (len > 0);
2965
2966done:
2967#ifdef DEBUG_INPUT
2968 xmlGenericError(xmlGenericErrorContext,
2969 "I/O: wrote %d chars\n", written);
2970#endif
2971 return(written);
2972}
2973
2974/**
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00002975 * xmlEscapeContent:
2976 * @out: a pointer to an array of bytes to store the result
2977 * @outlen: the length of @out
2978 * @in: a pointer to an array of unescaped UTF-8 bytes
2979 * @inlen: the length of @in
2980 *
2981 * Take a block of UTF-8 chars in and escape them.
2982 * Returns 0 if success, or -1 otherwise
2983 * The value of @inlen after return is the number of octets consumed
2984 * if the return value is positive, else unpredictable.
2985 * The value of @outlen after return is the number of octets consumed.
2986 */
2987static int
2988xmlEscapeContent(unsigned char* out, int *outlen,
2989 const xmlChar* in, int *inlen) {
2990 unsigned char* outstart = out;
2991 const unsigned char* base = in;
2992 unsigned char* outend = out + *outlen;
2993 const unsigned char* inend;
2994
2995 inend = in + (*inlen);
2996
2997 while ((in < inend) && (out < outend)) {
2998 if (*in == '<') {
2999 if (outend - out < 4) break;
3000 *out++ = '&';
3001 *out++ = 'l';
3002 *out++ = 't';
3003 *out++ = ';';
3004 } else if (*in == '>') {
3005 if (outend - out < 4) break;
3006 *out++ = '&';
3007 *out++ = 'g';
3008 *out++ = 't';
3009 *out++ = ';';
3010 } else if (*in == '&') {
3011 if (outend - out < 5) break;
3012 *out++ = '&';
3013 *out++ = 'a';
3014 *out++ = 'm';
3015 *out++ = 'p';
3016 *out++ = ';';
3017 } else if (*in == '\r') {
3018 if (outend - out < 5) break;
3019 *out++ = '&';
3020 *out++ = '#';
3021 *out++ = '1';
3022 *out++ = '3';
3023 *out++ = ';';
3024 } else {
3025 *out++ = (unsigned char) *in;
3026 }
3027 ++in;
3028 }
3029 *outlen = out - outstart;
3030 *inlen = in - base;
3031 return(0);
3032}
3033
3034/**
3035 * xmlOutputBufferWriteEscape:
3036 * @out: a buffered parser output
3037 * @str: a zero terminated UTF-8 string
Daniel Veillardee8960b2004-05-14 03:25:14 +00003038 * @escaping: an optional escaping function (or NULL)
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003039 *
3040 * Write the content of the string in the output I/O buffer
3041 * This routine escapes the caracters and then handle the I18N
3042 * transcoding from internal UTF-8
3043 * The buffer is lossless, i.e. will store in case of partial
3044 * or delayed writes.
3045 *
3046 * Returns the number of chars immediately written, or -1
3047 * in case of error.
3048 */
3049int
Daniel Veillardee8960b2004-05-14 03:25:14 +00003050xmlOutputBufferWriteEscape(xmlOutputBufferPtr out, const xmlChar *str,
3051 xmlCharEncodingOutputFunc escaping) {
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003052 int nbchars = 0; /* number of chars to output to I/O */
3053 int ret; /* return from function call */
3054 int written = 0; /* number of char written to I/O so far */
Daniel Veillard71b95632004-08-31 12:15:36 +00003055 int oldwritten=0;/* loop guard */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003056 int chunk; /* number of byte currently processed from str */
3057 int len; /* number of bytes in str */
3058 int cons; /* byte from str consumed */
3059
Daniel Veillardce244ad2004-11-05 10:03:46 +00003060 if ((out == NULL) || (out->error) || (str == NULL) ||
3061 (out->buffer == NULL) ||
3062 (out->buffer->alloc == XML_BUFFER_ALLOC_IMMUTABLE)) return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003063 len = strlen((const char *)str);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003064 if (len < 0) return(0);
3065 if (out->error) return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003066 if (escaping == NULL) escaping = xmlEscapeContent;
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003067
3068 do {
Daniel Veillard71b95632004-08-31 12:15:36 +00003069 oldwritten = written;
3070
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003071 /*
3072 * how many bytes to consume and how many bytes to store.
3073 */
3074 cons = len;
3075 chunk = (out->buffer->size - out->buffer->use) - 1;
3076
3077 /*
3078 * first handle encoding stuff.
3079 */
3080 if (out->encoder != NULL) {
3081 /*
3082 * Store the data in the incoming raw buffer
3083 */
3084 if (out->conv == NULL) {
3085 out->conv = xmlBufferCreate();
3086 }
Daniel Veillardee8960b2004-05-14 03:25:14 +00003087 ret = escaping(out->buffer->content + out->buffer->use ,
3088 &chunk, str, &cons);
William M. Brack66e40b12004-11-26 15:45:19 +00003089 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003090 return(-1);
3091 out->buffer->use += chunk;
3092 out->buffer->content[out->buffer->use] = 0;
3093
3094 if ((out->buffer->use < MINLEN) && (cons == len))
3095 goto done;
3096
3097 /*
3098 * convert as much as possible to the output buffer.
3099 */
3100 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
3101 if ((ret < 0) && (ret != -3)) {
3102 xmlIOErr(XML_IO_ENCODER, NULL);
3103 out->error = XML_IO_ENCODER;
3104 return(-1);
3105 }
3106 nbchars = out->conv->use;
3107 } else {
Daniel Veillardee8960b2004-05-14 03:25:14 +00003108 ret = escaping(out->buffer->content + out->buffer->use ,
3109 &chunk, str, &cons);
William M. Brack66e40b12004-11-26 15:45:19 +00003110 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003111 return(-1);
3112 out->buffer->use += chunk;
3113 out->buffer->content[out->buffer->use] = 0;
3114 nbchars = out->buffer->use;
3115 }
3116 str += cons;
3117 len -= cons;
3118
3119 if ((nbchars < MINLEN) && (len <= 0))
3120 goto done;
3121
3122 if (out->writecallback) {
3123 /*
3124 * second write the stuff to the I/O channel
3125 */
3126 if (out->encoder != NULL) {
3127 ret = out->writecallback(out->context,
3128 (const char *)out->conv->content, nbchars);
3129 if (ret >= 0)
3130 xmlBufferShrink(out->conv, ret);
3131 } else {
3132 ret = out->writecallback(out->context,
3133 (const char *)out->buffer->content, nbchars);
3134 if (ret >= 0)
3135 xmlBufferShrink(out->buffer, ret);
3136 }
3137 if (ret < 0) {
3138 xmlIOErr(XML_IO_WRITE, NULL);
3139 out->error = XML_IO_WRITE;
3140 return(ret);
3141 }
3142 out->written += ret;
Daniel Veillard83a75e02004-05-14 21:50:42 +00003143 } else if (out->buffer->size - out->buffer->use < MINLEN) {
3144 xmlBufferResize(out->buffer, out->buffer->size + MINLEN);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003145 }
3146 written += nbchars;
Daniel Veillard71b95632004-08-31 12:15:36 +00003147 } while ((len > 0) && (oldwritten != written));
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003148
3149done:
3150#ifdef DEBUG_INPUT
3151 xmlGenericError(xmlGenericErrorContext,
3152 "I/O: wrote %d chars\n", written);
3153#endif
3154 return(written);
3155}
3156
3157/**
Owen Taylor3473f882001-02-23 17:55:21 +00003158 * xmlOutputBufferWriteString:
3159 * @out: a buffered parser output
3160 * @str: a zero terminated C string
3161 *
3162 * Write the content of the string in the output I/O buffer
3163 * This routine handle the I18N transcoding from internal UTF-8
3164 * The buffer is lossless, i.e. will store in case of partial
3165 * or delayed writes.
3166 *
3167 * Returns the number of chars immediately written, or -1
3168 * in case of error.
3169 */
3170int
3171xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
3172 int len;
3173
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003174 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003175 if (str == NULL)
3176 return(-1);
3177 len = strlen(str);
3178
3179 if (len > 0)
3180 return(xmlOutputBufferWrite(out, len, str));
3181 return(len);
3182}
3183
3184/**
3185 * xmlOutputBufferFlush:
3186 * @out: a buffered output
3187 *
3188 * flushes the output I/O channel
3189 *
3190 * Returns the number of byte written or -1 in case of error.
3191 */
3192int
3193xmlOutputBufferFlush(xmlOutputBufferPtr out) {
3194 int nbchars = 0, ret = 0;
3195
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003196 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003197 /*
3198 * first handle encoding stuff.
3199 */
3200 if ((out->conv != NULL) && (out->encoder != NULL)) {
3201 /*
3202 * convert as much as possible to the parser reading buffer.
3203 */
3204 nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
3205 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003206 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003207 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003208 return(-1);
3209 }
3210 }
3211
3212 /*
3213 * second flush the stuff to the I/O channel
3214 */
3215 if ((out->conv != NULL) && (out->encoder != NULL) &&
3216 (out->writecallback != NULL)) {
3217 ret = out->writecallback(out->context,
3218 (const char *)out->conv->content, out->conv->use);
3219 if (ret >= 0)
3220 xmlBufferShrink(out->conv, ret);
3221 } else if (out->writecallback != NULL) {
3222 ret = out->writecallback(out->context,
3223 (const char *)out->buffer->content, out->buffer->use);
3224 if (ret >= 0)
3225 xmlBufferShrink(out->buffer, ret);
3226 }
3227 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003228 xmlIOErr(XML_IO_FLUSH, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003229 out->error = XML_IO_FLUSH;
Owen Taylor3473f882001-02-23 17:55:21 +00003230 return(ret);
3231 }
3232 out->written += ret;
3233
3234#ifdef DEBUG_INPUT
3235 xmlGenericError(xmlGenericErrorContext,
3236 "I/O: flushed %d chars\n", ret);
3237#endif
3238 return(ret);
3239}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003240#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003241
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003242/**
Owen Taylor3473f882001-02-23 17:55:21 +00003243 * xmlParserGetDirectory:
3244 * @filename: the path to a file
3245 *
3246 * lookup the directory for that file
3247 *
3248 * Returns a new allocated string containing the directory, or NULL.
3249 */
3250char *
3251xmlParserGetDirectory(const char *filename) {
3252 char *ret = NULL;
3253 char dir[1024];
3254 char *cur;
3255 char sep = '/';
3256
Igor Zlatkovic9181cc02002-09-29 17:51:06 +00003257#ifdef _WIN32_WCE /* easy way by now ... wince does not have dirs! */
3258 return NULL;
3259#endif
3260
Owen Taylor3473f882001-02-23 17:55:21 +00003261 if (xmlInputCallbackInitialized == 0)
3262 xmlRegisterDefaultInputCallbacks();
3263
3264 if (filename == NULL) return(NULL);
Daniel Veillard3c5ed912002-01-08 10:36:16 +00003265#if defined(WIN32) && !defined(__CYGWIN__)
Owen Taylor3473f882001-02-23 17:55:21 +00003266 sep = '\\';
3267#endif
3268
3269 strncpy(dir, filename, 1023);
3270 dir[1023] = 0;
3271 cur = &dir[strlen(dir)];
3272 while (cur > dir) {
3273 if (*cur == sep) break;
3274 cur --;
3275 }
3276 if (*cur == sep) {
3277 if (cur == dir) dir[1] = 0;
3278 else *cur = 0;
3279 ret = xmlMemStrdup(dir);
3280 } else {
3281 if (getcwd(dir, 1024) != NULL) {
3282 dir[1023] = 0;
3283 ret = xmlMemStrdup(dir);
3284 }
3285 }
3286 return(ret);
3287}
3288
3289/****************************************************************
3290 * *
3291 * External entities loading *
3292 * *
3293 ****************************************************************/
3294
Daniel Veillarda840b692003-10-19 13:35:37 +00003295/**
3296 * xmlCheckHTTPInput:
3297 * @ctxt: an XML parser context
3298 * @ret: an XML parser input
3299 *
3300 * Check an input in case it was created from an HTTP stream, in that
3301 * case it will handle encoding and update of the base URL in case of
3302 * redirection. It also checks for HTTP errors in which case the input
3303 * is cleanly freed up and an appropriate error is raised in context
3304 *
3305 * Returns the input or NULL in case of HTTP error.
3306 */
3307xmlParserInputPtr
3308xmlCheckHTTPInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr ret) {
3309#ifdef LIBXML_HTTP_ENABLED
3310 if ((ret != NULL) && (ret->buf != NULL) &&
3311 (ret->buf->readcallback == xmlIOHTTPRead) &&
3312 (ret->buf->context != NULL)) {
3313 const char *encoding;
3314 const char *redir;
3315 const char *mime;
3316 int code;
3317
3318 code = xmlNanoHTTPReturnCode(ret->buf->context);
3319 if (code >= 400) {
3320 /* fatal error */
3321 if (ret->filename != NULL)
Daniel Veillarde8039df2003-10-27 11:25:13 +00003322 __xmlLoaderErr(ctxt, "failed to load HTTP resource \"%s\"\n",
Daniel Veillarda840b692003-10-19 13:35:37 +00003323 (const char *) ret->filename);
3324 else
Daniel Veillarde8039df2003-10-27 11:25:13 +00003325 __xmlLoaderErr(ctxt, "failed to load HTTP resource\n", NULL);
Daniel Veillarda840b692003-10-19 13:35:37 +00003326 xmlFreeInputStream(ret);
3327 ret = NULL;
3328 } else {
3329
3330 mime = xmlNanoHTTPMimeType(ret->buf->context);
3331 if ((xmlStrstr(BAD_CAST mime, BAD_CAST "/xml")) ||
3332 (xmlStrstr(BAD_CAST mime, BAD_CAST "+xml"))) {
3333 encoding = xmlNanoHTTPEncoding(ret->buf->context);
3334 if (encoding != NULL) {
3335 xmlCharEncodingHandlerPtr handler;
3336
3337 handler = xmlFindCharEncodingHandler(encoding);
3338 if (handler != NULL) {
3339 xmlSwitchInputEncoding(ctxt, ret, handler);
3340 } else {
3341 __xmlErrEncoding(ctxt, XML_ERR_UNKNOWN_ENCODING,
3342 "Unknown encoding %s",
3343 BAD_CAST encoding, NULL);
3344 }
3345 if (ret->encoding == NULL)
3346 ret->encoding = xmlStrdup(BAD_CAST encoding);
3347 }
3348#if 0
3349 } else if (xmlStrstr(BAD_CAST mime, BAD_CAST "html")) {
3350#endif
3351 }
3352 redir = xmlNanoHTTPRedir(ret->buf->context);
3353 if (redir != NULL) {
3354 if (ret->filename != NULL)
3355 xmlFree((xmlChar *) ret->filename);
3356 if (ret->directory != NULL) {
3357 xmlFree((xmlChar *) ret->directory);
3358 ret->directory = NULL;
3359 }
3360 ret->filename =
3361 (char *) xmlStrdup((const xmlChar *) redir);
3362 }
3363 }
3364 }
3365#endif
3366 return(ret);
3367}
3368
Daniel Veillard561b7f82002-03-20 21:55:57 +00003369static int xmlSysIDExists(const char *URL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003370#ifdef HAVE_STAT
3371 int ret;
3372 struct stat info;
3373 const char *path;
3374
3375 if (URL == NULL)
3376 return(0);
3377
Daniel Veillardf4862f02002-09-10 11:13:43 +00003378 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003379#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00003380 path = &URL[17];
3381#else
Daniel Veillard6990bf32001-08-23 21:17:48 +00003382 path = &URL[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00003383#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003384 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003385#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard6990bf32001-08-23 21:17:48 +00003386 path = &URL[8];
3387#else
3388 path = &URL[7];
3389#endif
3390 } else
3391 path = URL;
3392 ret = stat(path, &info);
Daniel Veillard561b7f82002-03-20 21:55:57 +00003393 if (ret == 0)
3394 return(1);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003395#endif
Daniel Veillard561b7f82002-03-20 21:55:57 +00003396 return(0);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003397}
Daniel Veillard6990bf32001-08-23 21:17:48 +00003398
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003399/**
Owen Taylor3473f882001-02-23 17:55:21 +00003400 * xmlDefaultExternalEntityLoader:
3401 * @URL: the URL for the entity to load
3402 * @ID: the System ID for the entity to load
3403 * @ctxt: the context in which the entity is called or NULL
3404 *
3405 * By default we don't load external entitites, yet.
3406 *
3407 * Returns a new allocated xmlParserInputPtr, or NULL.
3408 */
Daniel Veillarda840b692003-10-19 13:35:37 +00003409static xmlParserInputPtr
Owen Taylor3473f882001-02-23 17:55:21 +00003410xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
Daniel Veillarda840b692003-10-19 13:35:37 +00003411 xmlParserCtxtPtr ctxt)
3412{
Owen Taylor3473f882001-02-23 17:55:21 +00003413 xmlParserInputPtr ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003414 xmlChar *resource = NULL;
Daniel Veillarda840b692003-10-19 13:35:37 +00003415
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003416#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003417 xmlCatalogAllow pref;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003418#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003419
3420#ifdef DEBUG_EXTERNAL_ENTITIES
3421 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda840b692003-10-19 13:35:37 +00003422 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00003423#endif
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003424#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillard61b93382003-11-03 14:28:31 +00003425 if ((ctxt != NULL) && (ctxt->options & XML_PARSE_NONET)) {
3426 int options = ctxt->options;
3427
3428 ctxt->options -= XML_PARSE_NONET;
3429 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
3430 ctxt->options = options;
3431 return(ret);
3432 }
3433
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003434 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003435 * If the resource doesn't exists as a file,
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003436 * try to load it from the resource pointed in the catalogs
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003437 */
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003438 pref = xmlCatalogGetDefaults();
3439
Daniel Veillard561b7f82002-03-20 21:55:57 +00003440 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlSysIDExists(URL))) {
Daniel Veillarda840b692003-10-19 13:35:37 +00003441 /*
3442 * Do a local lookup
3443 */
Daniel Veillard42595322004-11-08 10:52:06 +00003444 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
Daniel Veillarda840b692003-10-19 13:35:37 +00003445 ((pref == XML_CATA_ALLOW_ALL) ||
3446 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3447 resource = xmlCatalogLocalResolve(ctxt->catalogs,
3448 (const xmlChar *) ID,
3449 (const xmlChar *) URL);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003450 }
Daniel Veillarda840b692003-10-19 13:35:37 +00003451 /*
3452 * Try a global lookup
3453 */
3454 if ((resource == NULL) &&
3455 ((pref == XML_CATA_ALLOW_ALL) ||
3456 (pref == XML_CATA_ALLOW_GLOBAL))) {
3457 resource = xmlCatalogResolve((const xmlChar *) ID,
3458 (const xmlChar *) URL);
3459 }
3460 if ((resource == NULL) && (URL != NULL))
3461 resource = xmlStrdup((const xmlChar *) URL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003462
Daniel Veillarda840b692003-10-19 13:35:37 +00003463 /*
3464 * TODO: do an URI lookup on the reference
3465 */
3466 if ((resource != NULL)
3467 && (!xmlSysIDExists((const char *) resource))) {
3468 xmlChar *tmp = NULL;
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003469
Daniel Veillard42595322004-11-08 10:52:06 +00003470 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
Daniel Veillarda840b692003-10-19 13:35:37 +00003471 ((pref == XML_CATA_ALLOW_ALL) ||
3472 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3473 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
3474 }
3475 if ((tmp == NULL) &&
3476 ((pref == XML_CATA_ALLOW_ALL) ||
3477 (pref == XML_CATA_ALLOW_GLOBAL))) {
3478 tmp = xmlCatalogResolveURI(resource);
3479 }
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003480
Daniel Veillarda840b692003-10-19 13:35:37 +00003481 if (tmp != NULL) {
3482 xmlFree(resource);
3483 resource = tmp;
3484 }
3485 }
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003486 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003487#endif
3488
3489 if (resource == NULL)
Daniel Veillarda840b692003-10-19 13:35:37 +00003490 resource = (xmlChar *) URL;
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003491
3492 if (resource == NULL) {
Daniel Veillarda840b692003-10-19 13:35:37 +00003493 if (ID == NULL)
3494 ID = "NULL";
Daniel Veillarde8039df2003-10-27 11:25:13 +00003495 __xmlLoaderErr(ctxt, "failed to load external entity \"%s\"\n", ID);
Daniel Veillarda840b692003-10-19 13:35:37 +00003496 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003497 }
Daniel Veillarda840b692003-10-19 13:35:37 +00003498 ret = xmlNewInputFromFile(ctxt, (const char *) resource);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003499 if ((resource != NULL) && (resource != (xmlChar *) URL))
Daniel Veillarda840b692003-10-19 13:35:37 +00003500 xmlFree(resource);
3501 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003502}
3503
3504static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
3505 xmlDefaultExternalEntityLoader;
3506
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003507/**
Owen Taylor3473f882001-02-23 17:55:21 +00003508 * xmlSetExternalEntityLoader:
3509 * @f: the new entity resolver function
3510 *
3511 * Changes the defaultexternal entity resolver function for the application
3512 */
3513void
3514xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
3515 xmlCurrentExternalEntityLoader = f;
3516}
3517
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003518/**
Owen Taylor3473f882001-02-23 17:55:21 +00003519 * xmlGetExternalEntityLoader:
3520 *
3521 * Get the default external entity resolver function for the application
3522 *
3523 * Returns the xmlExternalEntityLoader function pointer
3524 */
3525xmlExternalEntityLoader
3526xmlGetExternalEntityLoader(void) {
3527 return(xmlCurrentExternalEntityLoader);
3528}
3529
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003530/**
Owen Taylor3473f882001-02-23 17:55:21 +00003531 * xmlLoadExternalEntity:
3532 * @URL: the URL for the entity to load
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00003533 * @ID: the Public ID for the entity to load
Owen Taylor3473f882001-02-23 17:55:21 +00003534 * @ctxt: the context in which the entity is called or NULL
3535 *
3536 * Load an external entity, note that the use of this function for
3537 * unparsed entities may generate problems
Owen Taylor3473f882001-02-23 17:55:21 +00003538 *
3539 * Returns the xmlParserInputPtr or NULL
3540 */
3541xmlParserInputPtr
3542xmlLoadExternalEntity(const char *URL, const char *ID,
3543 xmlParserCtxtPtr ctxt) {
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00003544 if ((URL != NULL) && (xmlSysIDExists(URL) == 0)) {
3545 char *canonicFilename;
3546 xmlParserInputPtr ret;
3547
3548 canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL);
3549 if (canonicFilename == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003550 xmlIOErrMemory("building canonical path\n");
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00003551 return(NULL);
3552 }
3553
3554 ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt);
3555 xmlFree(canonicFilename);
3556 return(ret);
3557 }
Owen Taylor3473f882001-02-23 17:55:21 +00003558 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
3559}
3560
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003561/************************************************************************
3562 * *
3563 * Disabling Network access *
3564 * *
3565 ************************************************************************/
3566
3567#ifdef LIBXML_CATALOG_ENABLED
3568static int
3569xmlNoNetExists(const char *URL)
3570{
3571#ifdef HAVE_STAT
3572 int ret;
3573 struct stat info;
3574 const char *path;
3575
3576 if (URL == NULL)
3577 return (0);
3578
Daniel Veillardf4862f02002-09-10 11:13:43 +00003579 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003580#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00003581 path = &URL[17];
3582#else
3583 path = &URL[16];
3584#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003585 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003586#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003587 path = &URL[8];
3588#else
3589 path = &URL[7];
3590#endif
3591 } else
3592 path = URL;
3593 ret = stat(path, &info);
3594 if (ret == 0)
3595 return (1);
3596#endif
3597 return (0);
3598}
3599#endif
3600
3601/**
3602 * xmlNoNetExternalEntityLoader:
3603 * @URL: the URL for the entity to load
3604 * @ID: the System ID for the entity to load
3605 * @ctxt: the context in which the entity is called or NULL
3606 *
3607 * A specific entity loader disabling network accesses, though still
3608 * allowing local catalog accesses for resolution.
3609 *
3610 * Returns a new allocated xmlParserInputPtr, or NULL.
3611 */
3612xmlParserInputPtr
3613xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
3614 xmlParserCtxtPtr ctxt) {
3615 xmlParserInputPtr input = NULL;
3616 xmlChar *resource = NULL;
3617
3618#ifdef LIBXML_CATALOG_ENABLED
3619 xmlCatalogAllow pref;
3620
3621 /*
3622 * If the resource doesn't exists as a file,
3623 * try to load it from the resource pointed in the catalogs
3624 */
3625 pref = xmlCatalogGetDefaults();
3626
3627 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
3628 /*
3629 * Do a local lookup
3630 */
Daniel Veillard42595322004-11-08 10:52:06 +00003631 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003632 ((pref == XML_CATA_ALLOW_ALL) ||
3633 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3634 resource = xmlCatalogLocalResolve(ctxt->catalogs,
3635 (const xmlChar *)ID,
3636 (const xmlChar *)URL);
3637 }
3638 /*
3639 * Try a global lookup
3640 */
3641 if ((resource == NULL) &&
3642 ((pref == XML_CATA_ALLOW_ALL) ||
3643 (pref == XML_CATA_ALLOW_GLOBAL))) {
3644 resource = xmlCatalogResolve((const xmlChar *)ID,
3645 (const xmlChar *)URL);
3646 }
3647 if ((resource == NULL) && (URL != NULL))
3648 resource = xmlStrdup((const xmlChar *) URL);
3649
3650 /*
3651 * TODO: do an URI lookup on the reference
3652 */
3653 if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
3654 xmlChar *tmp = NULL;
3655
Daniel Veillard42595322004-11-08 10:52:06 +00003656 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003657 ((pref == XML_CATA_ALLOW_ALL) ||
3658 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3659 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
3660 }
3661 if ((tmp == NULL) &&
3662 ((pref == XML_CATA_ALLOW_ALL) ||
3663 (pref == XML_CATA_ALLOW_GLOBAL))) {
3664 tmp = xmlCatalogResolveURI(resource);
3665 }
3666
3667 if (tmp != NULL) {
3668 xmlFree(resource);
3669 resource = tmp;
3670 }
3671 }
3672 }
3673#endif
3674 if (resource == NULL)
3675 resource = (xmlChar *) URL;
3676
3677 if (resource != NULL) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003678 if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
3679 (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003680 xmlIOErr(XML_IO_NETWORK_ATTEMPT, (const char *) resource);
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003681 if (resource != (xmlChar *) URL)
3682 xmlFree(resource);
3683 return(NULL);
3684 }
3685 }
3686 input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
3687 if (resource != (xmlChar *) URL)
3688 xmlFree(resource);
3689 return(input);
3690}
3691
Daniel Veillard5d4644e2005-04-01 13:11:58 +00003692#define bottom_xmlIO
3693#include "elfgcchack.h"