blob: 85281948d77450013a42d1e38e04d522dacf9f04 [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 Veillard659e71e2003-10-10 14:10:40 +0000423 schannel = ctxt->sax->serror;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000424 data = ctxt->userData;
425 }
Daniel Veillard659e71e2003-10-10 14:10:40 +0000426 __xmlRaiseError(schannel, channel, data, ctxt, NULL, XML_FROM_IO,
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000427 XML_IO_LOAD_ERROR, level, NULL, 0,
428 filename, NULL, NULL, 0, 0,
429 msg, filename);
430
431}
432
Daniel Veillard05d987b2003-10-08 11:54:57 +0000433/************************************************************************
434 * *
435 * Tree memory error handler *
436 * *
437 ************************************************************************/
Daniel Veillardf4862f02002-09-10 11:13:43 +0000438/**
Daniel Veillard01c13b52002-12-10 15:19:08 +0000439 * xmlNormalizeWindowsPath:
Daniel Veillard33300b42003-04-17 09:09:19 +0000440 * @path: the input file path
Daniel Veillardf4862f02002-09-10 11:13:43 +0000441 *
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +0000442 * This function is obsolete. Please see xmlURIFromPath in uri.c for
443 * a better solution.
Daniel Veillard33300b42003-04-17 09:09:19 +0000444 *
445 * Returns a canonicalized version of the path
Daniel Veillardf4862f02002-09-10 11:13:43 +0000446 */
447xmlChar *
448xmlNormalizeWindowsPath(const xmlChar *path)
449{
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +0000450 return xmlCanonicPath(path);
Daniel Veillardf4862f02002-09-10 11:13:43 +0000451}
452
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000453/**
454 * xmlCleanupInputCallbacks:
455 *
456 * clears the entire input callback table. this includes the
457 * compiled-in I/O.
458 */
459void
460xmlCleanupInputCallbacks(void)
461{
462 int i;
463
464 if (!xmlInputCallbackInitialized)
465 return;
466
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000467 for (i = xmlInputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000468 xmlInputCallbackTable[i].matchcallback = NULL;
469 xmlInputCallbackTable[i].opencallback = NULL;
470 xmlInputCallbackTable[i].readcallback = NULL;
471 xmlInputCallbackTable[i].closecallback = NULL;
472 }
473
474 xmlInputCallbackNr = 0;
Aleksey Sanin9c45ba82002-06-06 21:46:13 +0000475 xmlInputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000476}
477
Daniel Veillardaecc0dc2004-05-08 02:32:07 +0000478/**
William M. Brack4e3a9fa2004-08-03 22:41:11 +0000479 * xmlPopInputCallbacks:
Daniel Veillardaecc0dc2004-05-08 02:32:07 +0000480 *
481 * Clear the top input callback from the input stack. this includes the
482 * compiled-in I/O.
483 *
484 * Returns the number of input callback registered or -1 in case of error.
485 */
486int
487xmlPopInputCallbacks(void)
488{
489 if (!xmlInputCallbackInitialized)
490 return(-1);
491
492 if (xmlInputCallbackNr <= 0)
493 return(-1);
494
495 xmlInputCallbackNr--;
496 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = NULL;
497 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = NULL;
498 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = NULL;
499 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = NULL;
500
501 return(xmlInputCallbackNr);
502}
503
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000504#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000505/**
506 * xmlCleanupOutputCallbacks:
507 *
508 * clears the entire output callback table. this includes the
509 * compiled-in I/O callbacks.
510 */
511void
512xmlCleanupOutputCallbacks(void)
513{
514 int i;
515
516 if (!xmlOutputCallbackInitialized)
517 return;
518
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000519 for (i = xmlOutputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000520 xmlOutputCallbackTable[i].matchcallback = NULL;
521 xmlOutputCallbackTable[i].opencallback = NULL;
522 xmlOutputCallbackTable[i].writecallback = NULL;
523 xmlOutputCallbackTable[i].closecallback = NULL;
524 }
525
526 xmlOutputCallbackNr = 0;
Aleksey Sanin9c45ba82002-06-06 21:46:13 +0000527 xmlOutputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000528}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000529#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000530
Owen Taylor3473f882001-02-23 17:55:21 +0000531/************************************************************************
532 * *
533 * Standard I/O for file accesses *
534 * *
535 ************************************************************************/
536
537/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000538 * xmlCheckFilename:
Owen Taylor3473f882001-02-23 17:55:21 +0000539 * @path: the path to check
540 *
541 * function checks to see if @path is a valid source
542 * (file, socket...) for XML.
543 *
544 * if stat is not available on the target machine,
545 * returns 1. if stat fails, returns 0 (if calling
546 * stat on the filename fails, it can't be right).
547 * if stat succeeds and the file is a directory,
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000548 * returns 2. otherwise returns 1.
Owen Taylor3473f882001-02-23 17:55:21 +0000549 */
550
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000551int
Owen Taylor3473f882001-02-23 17:55:21 +0000552xmlCheckFilename (const char *path)
553{
554#ifdef HAVE_STAT
Owen Taylor3473f882001-02-23 17:55:21 +0000555 struct stat stat_buffer;
556
Daniel Veillard34099b42004-11-04 17:34:35 +0000557 if (path == NULL)
558 return(0);
559
Owen Taylor3473f882001-02-23 17:55:21 +0000560 if (stat(path, &stat_buffer) == -1)
561 return 0;
562
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000563#ifdef S_ISDIR
Owen Taylor3473f882001-02-23 17:55:21 +0000564 if (S_ISDIR(stat_buffer.st_mode)) {
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000565 return 2;
Owen Taylor3473f882001-02-23 17:55:21 +0000566 }
Owen Taylor3473f882001-02-23 17:55:21 +0000567#endif
568#endif
Daniel Veillard34099b42004-11-04 17:34:35 +0000569 if (path == NULL)
570 return(0);
571
Owen Taylor3473f882001-02-23 17:55:21 +0000572 return 1;
573}
574
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000575static int
Owen Taylor3473f882001-02-23 17:55:21 +0000576xmlNop(void) {
577 return(0);
578}
579
580/**
Owen Taylor3473f882001-02-23 17:55:21 +0000581 * xmlFdRead:
582 * @context: the I/O context
583 * @buffer: where to drop data
584 * @len: number of bytes to read
585 *
586 * Read @len bytes to @buffer from the I/O channel.
587 *
588 * Returns the number of bytes written
589 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000590static int
Owen Taylor3473f882001-02-23 17:55:21 +0000591xmlFdRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000592 int ret;
593
594 ret = read((int) (long) context, &buffer[0], len);
595 if (ret < 0) xmlIOErr(0, "read()");
596 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000597}
598
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000599#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000600/**
601 * xmlFdWrite:
602 * @context: the I/O context
603 * @buffer: where to get data
604 * @len: number of bytes to write
605 *
606 * Write @len bytes from @buffer to the I/O channel.
607 *
608 * Returns the number of bytes written
609 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000610static int
Owen Taylor3473f882001-02-23 17:55:21 +0000611xmlFdWrite (void * context, const char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000612 int ret;
613
614 ret = write((int) (long) context, &buffer[0], len);
615 if (ret < 0) xmlIOErr(0, "write()");
616 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000617}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000618#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000619
620/**
621 * xmlFdClose:
622 * @context: the I/O context
623 *
624 * Close an I/O channel
Daniel Veillardf012a642001-07-23 19:10:52 +0000625 *
626 * Returns 0 in case of success and error code otherwise
Owen Taylor3473f882001-02-23 17:55:21 +0000627 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000628static int
Owen Taylor3473f882001-02-23 17:55:21 +0000629xmlFdClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000630 int ret;
631 ret = close((int) (long) context);
632 if (ret < 0) xmlIOErr(0, "close()");
633 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000634}
635
636/**
637 * xmlFileMatch:
638 * @filename: the URI for matching
639 *
640 * input from FILE *
641 *
642 * Returns 1 if matches, 0 otherwise
643 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000644int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000645xmlFileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000646 return(1);
647}
648
649/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000650 * xmlFileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +0000651 * @filename: the URI for matching
652 *
653 * input from FILE *, supports compressed input
654 * if @filename is " " then the standard input is used
655 *
656 * Returns an I/O context or NULL in case of error
657 */
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000658static void *
659xmlFileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +0000660 const char *path = NULL;
661 FILE *fd;
662
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000663 if (filename == NULL)
664 return(NULL);
665
Owen Taylor3473f882001-02-23 17:55:21 +0000666 if (!strcmp(filename, "-")) {
667 fd = stdin;
668 return((void *) fd);
669 }
670
Daniel Veillardf4862f02002-09-10 11:13:43 +0000671 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000672#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000673 path = &filename[17];
674#else
Owen Taylor3473f882001-02-23 17:55:21 +0000675 path = &filename[16];
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000676#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000677 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000678#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000679 path = &filename[8];
680#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000681 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000682#endif
683 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000684 path = filename;
685
686 if (path == NULL)
687 return(NULL);
688 if (!xmlCheckFilename(path))
689 return(NULL);
690
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000691#if defined(WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
Owen Taylor3473f882001-02-23 17:55:21 +0000692 fd = fopen(path, "rb");
693#else
694 fd = fopen(path, "r");
695#endif /* WIN32 */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000696 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +0000697 return((void *) fd);
698}
699
700/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000701 * xmlFileOpen:
702 * @filename: the URI for matching
703 *
704 * Wrapper around xmlFileOpen_real that try it with an unescaped
705 * version of @filename, if this fails fallback to @filename
Daniel Veillard71531f32003-02-05 13:19:53 +0000706 *
707 * Returns a handler or NULL in case or failure
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000708 */
709void *
710xmlFileOpen (const char *filename) {
711 char *unescaped;
712 void *retval;
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000713
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000714 unescaped = xmlURIUnescapeString(filename, 0, NULL);
715 if (unescaped != NULL) {
716 retval = xmlFileOpen_real(unescaped);
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000717 xmlFree(unescaped);
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000718 } else {
719 retval = xmlFileOpen_real(filename);
720 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000721 return retval;
722}
723
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000724#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000725/**
Owen Taylor3473f882001-02-23 17:55:21 +0000726 * xmlFileOpenW:
727 * @filename: the URI for matching
728 *
729 * output to from FILE *,
730 * if @filename is "-" then the standard output is used
731 *
732 * Returns an I/O context or NULL in case of error
733 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000734static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000735xmlFileOpenW (const char *filename) {
736 const char *path = NULL;
737 FILE *fd;
738
739 if (!strcmp(filename, "-")) {
740 fd = stdout;
741 return((void *) fd);
742 }
743
Daniel Veillardf4862f02002-09-10 11:13:43 +0000744 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000745#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000746 path = &filename[17];
747#else
Owen Taylor3473f882001-02-23 17:55:21 +0000748 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000749#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000750 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000751#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000752 path = &filename[8];
753#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000754 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000755#endif
756 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000757 path = filename;
758
759 if (path == NULL)
760 return(NULL);
761
Daniel Veillardcbbd78d2003-07-20 15:21:30 +0000762 fd = fopen(path, "wb");
Daniel Veillard05d987b2003-10-08 11:54:57 +0000763 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +0000764 return((void *) fd);
765}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000766#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000767
768/**
769 * xmlFileRead:
770 * @context: the I/O context
771 * @buffer: where to drop data
772 * @len: number of bytes to write
773 *
774 * Read @len bytes to @buffer from the I/O channel.
775 *
Daniel Veillardce682bc2004-11-05 17:22:25 +0000776 * Returns the number of bytes written or < 0 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +0000777 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000778int
Owen Taylor3473f882001-02-23 17:55:21 +0000779xmlFileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000780 int ret;
Daniel Veillardce682bc2004-11-05 17:22:25 +0000781 if ((context == NULL) || (buffer == NULL))
782 return(-1);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000783 ret = fread(&buffer[0], 1, len, (FILE *) context);
784 if (ret < 0) xmlIOErr(0, "fread()");
785 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000786}
787
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000788#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000789/**
790 * xmlFileWrite:
791 * @context: the I/O context
792 * @buffer: where to drop data
793 * @len: number of bytes to write
794 *
795 * Write @len bytes from @buffer to the I/O channel.
796 *
797 * Returns the number of bytes written
798 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000799static int
Owen Taylor3473f882001-02-23 17:55:21 +0000800xmlFileWrite (void * context, const char * buffer, int len) {
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000801 int items;
802
Daniel Veillardce682bc2004-11-05 17:22:25 +0000803 if ((context == NULL) || (buffer == NULL))
804 return(-1);
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000805 items = fwrite(&buffer[0], len, 1, (FILE *) context);
Daniel Veillard97bf4d02003-10-08 18:58:28 +0000806 if ((items == 0) && (ferror((FILE *) context))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000807 xmlIOErr(0, "fwrite()");
Daniel Veillard97bf4d02003-10-08 18:58:28 +0000808 return(-1);
809 }
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000810 return(items * len);
Owen Taylor3473f882001-02-23 17:55:21 +0000811}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000812#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000813
814/**
815 * xmlFileClose:
816 * @context: the I/O context
817 *
818 * Close an I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000819 *
820 * Returns 0 or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +0000821 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000822int
Owen Taylor3473f882001-02-23 17:55:21 +0000823xmlFileClose (void * context) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000824 FILE *fil;
Daniel Veillard05d987b2003-10-08 11:54:57 +0000825 int ret;
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000826
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000827 if (context == NULL)
828 return(-1);
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000829 fil = (FILE *) context;
Daniel Veillard500a1de2004-03-22 15:22:58 +0000830 if ((fil == stdout) || (fil == stderr)) {
831 ret = fflush(fil);
832 if (ret < 0)
833 xmlIOErr(0, "fflush()");
834 return(0);
835 }
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000836 if (fil == stdin)
837 return(0);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000838 ret = ( fclose((FILE *) context) == EOF ) ? -1 : 0;
839 if (ret < 0)
840 xmlIOErr(0, "fclose()");
841 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000842}
843
844/**
845 * xmlFileFlush:
846 * @context: the I/O context
847 *
848 * Flush an I/O channel
849 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000850static int
Owen Taylor3473f882001-02-23 17:55:21 +0000851xmlFileFlush (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000852 int ret;
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000853
854 if (context == NULL)
855 return(-1);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000856 ret = ( fflush((FILE *) context) == EOF ) ? -1 : 0;
857 if (ret < 0)
858 xmlIOErr(0, "fflush()");
859 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000860}
861
862#ifdef HAVE_ZLIB_H
863/************************************************************************
864 * *
865 * I/O for compressed file accesses *
866 * *
867 ************************************************************************/
868/**
869 * xmlGzfileMatch:
870 * @filename: the URI for matching
871 *
872 * input from compressed file test
873 *
874 * Returns 1 if matches, 0 otherwise
875 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000876static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000877xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000878 return(1);
879}
880
881/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000882 * xmlGzfileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +0000883 * @filename: the URI for matching
884 *
885 * input from compressed file open
886 * if @filename is " " then the standard input is used
887 *
888 * Returns an I/O context or NULL in case of error
889 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000890static void *
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000891xmlGzfileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +0000892 const char *path = NULL;
893 gzFile fd;
894
895 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000896 fd = gzdopen(dup(0), "rb");
Owen Taylor3473f882001-02-23 17:55:21 +0000897 return((void *) fd);
898 }
899
Daniel Veillardf4862f02002-09-10 11:13:43 +0000900 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000901#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000902 path = &filename[17];
903#else
Owen Taylor3473f882001-02-23 17:55:21 +0000904 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000905#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000906 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000907#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000908 path = &filename[8];
909#else
Owen Taylor3473f882001-02-23 17:55:21 +0000910 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000911#endif
912 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000913 path = filename;
914
915 if (path == NULL)
916 return(NULL);
917 if (!xmlCheckFilename(path))
918 return(NULL);
919
920 fd = gzopen(path, "rb");
921 return((void *) fd);
922}
923
924/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000925 * xmlGzfileOpen:
926 * @filename: the URI for matching
927 *
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +0000928 * Wrapper around xmlGzfileOpen if the open fais, it will
929 * try to unescape @filename
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000930 */
931static void *
932xmlGzfileOpen (const char *filename) {
933 char *unescaped;
934 void *retval;
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +0000935
936 retval = xmlGzfileOpen_real(filename);
937 if (retval == NULL) {
938 unescaped = xmlURIUnescapeString(filename, 0, NULL);
939 if (unescaped != NULL) {
940 retval = xmlGzfileOpen_real(unescaped);
941 }
942 xmlFree(unescaped);
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000943 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000944 return retval;
945}
946
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000947#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000948/**
Owen Taylor3473f882001-02-23 17:55:21 +0000949 * xmlGzfileOpenW:
950 * @filename: the URI for matching
951 * @compression: the compression factor (0 - 9 included)
952 *
953 * input from compressed file open
954 * if @filename is " " then the standard input is used
955 *
956 * Returns an I/O context or NULL in case of error
957 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000958static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000959xmlGzfileOpenW (const char *filename, int compression) {
960 const char *path = NULL;
961 char mode[15];
962 gzFile fd;
963
Aleksey Sanin49cc9752002-06-14 17:07:10 +0000964 snprintf(mode, sizeof(mode), "wb%d", compression);
Owen Taylor3473f882001-02-23 17:55:21 +0000965 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000966 fd = gzdopen(dup(1), mode);
Owen Taylor3473f882001-02-23 17:55:21 +0000967 return((void *) fd);
968 }
969
Daniel Veillardf4862f02002-09-10 11:13:43 +0000970 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000971#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000972 path = &filename[17];
973#else
Owen Taylor3473f882001-02-23 17:55:21 +0000974 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000975#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000976 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000977#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000978 path = &filename[8];
979#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000980 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000981#endif
982 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000983 path = filename;
984
985 if (path == NULL)
986 return(NULL);
987
988 fd = gzopen(path, mode);
989 return((void *) fd);
990}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000991#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000992
993/**
994 * xmlGzfileRead:
995 * @context: the I/O context
996 * @buffer: where to drop data
997 * @len: number of bytes to write
998 *
999 * Read @len bytes to @buffer from the compressed I/O channel.
1000 *
1001 * Returns the number of bytes written
1002 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001003static int
Owen Taylor3473f882001-02-23 17:55:21 +00001004xmlGzfileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001005 int ret;
1006
1007 ret = gzread((gzFile) context, &buffer[0], len);
1008 if (ret < 0) xmlIOErr(0, "gzread()");
1009 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001010}
1011
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001012#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001013/**
1014 * xmlGzfileWrite:
1015 * @context: the I/O context
1016 * @buffer: where to drop data
1017 * @len: number of bytes to write
1018 *
1019 * Write @len bytes from @buffer to the compressed I/O channel.
1020 *
1021 * Returns the number of bytes written
1022 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001023static int
Owen Taylor3473f882001-02-23 17:55:21 +00001024xmlGzfileWrite (void * context, const char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001025 int ret;
1026
1027 ret = gzwrite((gzFile) context, (char *) &buffer[0], len);
1028 if (ret < 0) xmlIOErr(0, "gzwrite()");
1029 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001030}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001031#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001032
1033/**
1034 * xmlGzfileClose:
1035 * @context: the I/O context
1036 *
1037 * Close a compressed I/O channel
1038 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001039static int
Owen Taylor3473f882001-02-23 17:55:21 +00001040xmlGzfileClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001041 int ret;
1042
1043 ret = (gzclose((gzFile) context) == Z_OK ) ? 0 : -1;
1044 if (ret < 0) xmlIOErr(0, "gzclose()");
1045 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001046}
1047#endif /* HAVE_ZLIB_H */
1048
1049#ifdef LIBXML_HTTP_ENABLED
1050/************************************************************************
1051 * *
1052 * I/O for HTTP file accesses *
1053 * *
1054 ************************************************************************/
Daniel Veillardf012a642001-07-23 19:10:52 +00001055
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001056#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001057typedef struct xmlIOHTTPWriteCtxt_
1058{
1059 int compression;
1060
1061 char * uri;
1062
1063 void * doc_buff;
1064
1065} xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr;
1066
1067#ifdef HAVE_ZLIB_H
1068
1069#define DFLT_WBITS ( -15 )
1070#define DFLT_MEM_LVL ( 8 )
1071#define GZ_MAGIC1 ( 0x1f )
1072#define GZ_MAGIC2 ( 0x8b )
1073#define LXML_ZLIB_OS_CODE ( 0x03 )
1074#define INIT_HTTP_BUFF_SIZE ( 32768 )
1075#define DFLT_ZLIB_RATIO ( 5 )
1076
1077/*
1078** Data structure and functions to work with sending compressed data
1079** via HTTP.
1080*/
1081
1082typedef struct xmlZMemBuff_
1083{
1084 unsigned long size;
1085 unsigned long crc;
1086
1087 unsigned char * zbuff;
1088 z_stream zctrl;
1089
1090} xmlZMemBuff, *xmlZMemBuffPtr;
1091
1092/**
1093 * append_reverse_ulong
1094 * @buff: Compressed memory buffer
1095 * @data: Unsigned long to append
1096 *
1097 * Append a unsigned long in reverse byte order to the end of the
1098 * memory buffer.
1099 */
1100static void
1101append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) {
1102
1103 int idx;
1104
1105 if ( buff == NULL )
1106 return;
1107
1108 /*
1109 ** This is plagiarized from putLong in gzio.c (zlib source) where
1110 ** the number "4" is hardcoded. If zlib is ever patched to
1111 ** support 64 bit file sizes, this code would need to be patched
1112 ** as well.
1113 */
1114
1115 for ( idx = 0; idx < 4; idx++ ) {
1116 *buff->zctrl.next_out = ( data & 0xff );
1117 data >>= 8;
1118 buff->zctrl.next_out++;
1119 }
1120
1121 return;
1122}
1123
1124/**
1125 *
1126 * xmlFreeZMemBuff
1127 * @buff: The memory buffer context to clear
1128 *
1129 * Release all the resources associated with the compressed memory buffer.
1130 */
1131static void
1132xmlFreeZMemBuff( xmlZMemBuffPtr buff ) {
William M. Brack78637da2003-07-31 14:47:38 +00001133
1134#ifdef DEBUG_HTTP
Daniel Veillardf012a642001-07-23 19:10:52 +00001135 int z_err;
William M. Brack78637da2003-07-31 14:47:38 +00001136#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001137
1138 if ( buff == NULL )
1139 return;
1140
1141 xmlFree( buff->zbuff );
Daniel Veillardf012a642001-07-23 19:10:52 +00001142#ifdef DEBUG_HTTP
William M. Brack78637da2003-07-31 14:47:38 +00001143 z_err = deflateEnd( &buff->zctrl );
Daniel Veillardf012a642001-07-23 19:10:52 +00001144 if ( z_err != Z_OK )
1145 xmlGenericError( xmlGenericErrorContext,
1146 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
1147 z_err );
William M. Brack78637da2003-07-31 14:47:38 +00001148#else
1149 deflateEnd( &buff->zctrl );
William M. Brack779af002003-08-01 15:55:39 +00001150#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001151
1152 xmlFree( buff );
1153 return;
1154}
1155
1156/**
1157 * xmlCreateZMemBuff
1158 *@compression: Compression value to use
1159 *
1160 * Create a memory buffer to hold the compressed XML document. The
1161 * compressed document in memory will end up being identical to what
1162 * would be created if gzopen/gzwrite/gzclose were being used to
1163 * write the document to disk. The code for the header/trailer data to
1164 * the compression is plagiarized from the zlib source files.
1165 */
1166static void *
1167xmlCreateZMemBuff( int compression ) {
1168
1169 int z_err;
1170 int hdr_lgth;
1171 xmlZMemBuffPtr buff = NULL;
1172
1173 if ( ( compression < 1 ) || ( compression > 9 ) )
1174 return ( NULL );
1175
1176 /* Create the control and data areas */
1177
1178 buff = xmlMalloc( sizeof( xmlZMemBuff ) );
1179 if ( buff == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001180 xmlIOErrMemory("creating buffer context");
Daniel Veillardf012a642001-07-23 19:10:52 +00001181 return ( NULL );
1182 }
1183
1184 (void)memset( buff, 0, sizeof( xmlZMemBuff ) );
1185 buff->size = INIT_HTTP_BUFF_SIZE;
1186 buff->zbuff = xmlMalloc( buff->size );
1187 if ( buff->zbuff == NULL ) {
1188 xmlFreeZMemBuff( buff );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001189 xmlIOErrMemory("creating buffer");
Daniel Veillardf012a642001-07-23 19:10:52 +00001190 return ( NULL );
1191 }
1192
1193 z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
1194 DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
1195 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001196 xmlChar msg[500];
Daniel Veillardf012a642001-07-23 19:10:52 +00001197 xmlFreeZMemBuff( buff );
1198 buff = NULL;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001199 xmlStrPrintf(msg, 500,
1200 (const xmlChar *) "xmlCreateZMemBuff: %s %d\n",
1201 "Error initializing compression context. ZLIB error:",
1202 z_err );
1203 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001204 return ( NULL );
1205 }
1206
1207 /* Set the header data. The CRC will be needed for the trailer */
Daniel Veillardf012a642001-07-23 19:10:52 +00001208 buff->crc = crc32( 0L, Z_NULL, 0 );
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001209 hdr_lgth = snprintf( (char *)buff->zbuff, buff->size,
1210 "%c%c%c%c%c%c%c%c%c%c",
Daniel Veillardf012a642001-07-23 19:10:52 +00001211 GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED,
1212 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE );
1213 buff->zctrl.next_out = buff->zbuff + hdr_lgth;
1214 buff->zctrl.avail_out = buff->size - hdr_lgth;
1215
1216 return ( buff );
1217}
1218
1219/**
1220 * xmlZMemBuffExtend
1221 * @buff: Buffer used to compress and consolidate data.
1222 * @ext_amt: Number of bytes to extend the buffer.
1223 *
1224 * Extend the internal buffer used to store the compressed data by the
1225 * specified amount.
1226 *
1227 * Returns 0 on success or -1 on failure to extend the buffer. On failure
1228 * the original buffer still exists at the original size.
1229 */
1230static int
1231xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) {
1232
1233 int rc = -1;
1234 size_t new_size;
1235 size_t cur_used;
1236
1237 unsigned char * tmp_ptr = NULL;
1238
1239 if ( buff == NULL )
1240 return ( -1 );
1241
1242 else if ( ext_amt == 0 )
1243 return ( 0 );
1244
1245 cur_used = buff->zctrl.next_out - buff->zbuff;
1246 new_size = buff->size + ext_amt;
1247
1248#ifdef DEBUG_HTTP
1249 if ( cur_used > new_size )
1250 xmlGenericError( xmlGenericErrorContext,
1251 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
1252 "Buffer overwrite detected during compressed memory",
1253 "buffer extension. Overflowed by",
1254 (cur_used - new_size ) );
1255#endif
1256
1257 tmp_ptr = xmlRealloc( buff->zbuff, new_size );
1258 if ( tmp_ptr != NULL ) {
1259 rc = 0;
1260 buff->size = new_size;
1261 buff->zbuff = tmp_ptr;
1262 buff->zctrl.next_out = tmp_ptr + cur_used;
1263 buff->zctrl.avail_out = new_size - cur_used;
1264 }
1265 else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001266 xmlChar msg[500];
1267 xmlStrPrintf(msg, 500,
1268 (const xmlChar *) "xmlZMemBuffExtend: %s %lu bytes.\n",
1269 "Allocation failure extending output buffer to",
1270 new_size );
1271 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001272 }
1273
1274 return ( rc );
1275}
1276
1277/**
1278 * xmlZMemBuffAppend
1279 * @buff: Buffer used to compress and consolidate data
1280 * @src: Uncompressed source content to append to buffer
1281 * @len: Length of source data to append to buffer
1282 *
1283 * Compress and append data to the internal buffer. The data buffer
1284 * will be expanded if needed to store the additional data.
1285 *
1286 * Returns the number of bytes appended to the buffer or -1 on error.
1287 */
1288static int
1289xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) {
1290
1291 int z_err;
1292 size_t min_accept;
1293
1294 if ( ( buff == NULL ) || ( src == NULL ) )
1295 return ( -1 );
1296
1297 buff->zctrl.avail_in = len;
1298 buff->zctrl.next_in = (unsigned char *)src;
1299 while ( buff->zctrl.avail_in > 0 ) {
1300 /*
1301 ** Extend the buffer prior to deflate call if a reasonable amount
1302 ** of output buffer space is not available.
1303 */
1304 min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO;
1305 if ( buff->zctrl.avail_out <= min_accept ) {
1306 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1307 return ( -1 );
1308 }
1309
1310 z_err = deflate( &buff->zctrl, Z_NO_FLUSH );
1311 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001312 xmlChar msg[500];
1313 xmlStrPrintf(msg, 500,
1314 (const xmlChar *) "xmlZMemBuffAppend: %s %d %s - %d",
Daniel Veillardf012a642001-07-23 19:10:52 +00001315 "Compression error while appending",
1316 len, "bytes to buffer. ZLIB error", z_err );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001317 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001318 return ( -1 );
1319 }
1320 }
1321
1322 buff->crc = crc32( buff->crc, (unsigned char *)src, len );
1323
1324 return ( len );
1325}
1326
1327/**
1328 * xmlZMemBuffGetContent
1329 * @buff: Compressed memory content buffer
1330 * @data_ref: Pointer reference to point to compressed content
1331 *
1332 * Flushes the compression buffers, appends gzip file trailers and
1333 * returns the compressed content and length of the compressed data.
1334 * NOTE: The gzip trailer code here is plagiarized from zlib source.
1335 *
1336 * Returns the length of the compressed data or -1 on error.
1337 */
1338static int
1339xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) {
1340
1341 int zlgth = -1;
1342 int z_err;
1343
1344 if ( ( buff == NULL ) || ( data_ref == NULL ) )
1345 return ( -1 );
1346
1347 /* Need to loop until compression output buffers are flushed */
1348
1349 do
1350 {
1351 z_err = deflate( &buff->zctrl, Z_FINISH );
1352 if ( z_err == Z_OK ) {
1353 /* In this case Z_OK means more buffer space needed */
1354
1355 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1356 return ( -1 );
1357 }
1358 }
1359 while ( z_err == Z_OK );
1360
1361 /* If the compression state is not Z_STREAM_END, some error occurred */
1362
1363 if ( z_err == Z_STREAM_END ) {
1364
1365 /* Need to append the gzip data trailer */
1366
1367 if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) {
1368 if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 )
1369 return ( -1 );
1370 }
1371
1372 /*
1373 ** For whatever reason, the CRC and length data are pushed out
1374 ** in reverse byte order. So a memcpy can't be used here.
1375 */
1376
1377 append_reverse_ulong( buff, buff->crc );
1378 append_reverse_ulong( buff, buff->zctrl.total_in );
1379
1380 zlgth = buff->zctrl.next_out - buff->zbuff;
1381 *data_ref = (char *)buff->zbuff;
1382 }
1383
Daniel Veillard05d987b2003-10-08 11:54:57 +00001384 else {
1385 xmlChar msg[500];
1386 xmlStrPrintf(msg, 500,
1387 (const xmlChar *) "xmlZMemBuffGetContent: %s - %d\n",
1388 "Error flushing zlib buffers. Error code", z_err );
1389 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1390 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001391
1392 return ( zlgth );
1393}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001394#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001395#endif /* HAVE_ZLIB_H */
1396
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001397#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001398/**
1399 * xmlFreeHTTPWriteCtxt
1400 * @ctxt: Context to cleanup
1401 *
1402 * Free allocated memory and reclaim system resources.
1403 *
1404 * No return value.
1405 */
1406static void
1407xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt )
1408{
1409 if ( ctxt->uri != NULL )
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001410 xmlFree( ctxt->uri );
Daniel Veillardf012a642001-07-23 19:10:52 +00001411
1412 if ( ctxt->doc_buff != NULL ) {
1413
1414#ifdef HAVE_ZLIB_H
1415 if ( ctxt->compression > 0 ) {
1416 xmlFreeZMemBuff( ctxt->doc_buff );
1417 }
1418 else
1419#endif
1420 {
1421 xmlOutputBufferClose( ctxt->doc_buff );
1422 }
1423 }
1424
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001425 xmlFree( ctxt );
Daniel Veillardf012a642001-07-23 19:10:52 +00001426 return;
1427}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001428#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001429
1430
Owen Taylor3473f882001-02-23 17:55:21 +00001431/**
1432 * xmlIOHTTPMatch:
1433 * @filename: the URI for matching
1434 *
1435 * check if the URI matches an HTTP one
1436 *
1437 * Returns 1 if matches, 0 otherwise
1438 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001439int
Owen Taylor3473f882001-02-23 17:55:21 +00001440xmlIOHTTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001441 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "http://", 7))
Owen Taylor3473f882001-02-23 17:55:21 +00001442 return(1);
1443 return(0);
1444}
1445
1446/**
1447 * xmlIOHTTPOpen:
1448 * @filename: the URI for matching
1449 *
1450 * open an HTTP I/O channel
1451 *
1452 * Returns an I/O context or NULL in case of error
1453 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001454void *
Owen Taylor3473f882001-02-23 17:55:21 +00001455xmlIOHTTPOpen (const char *filename) {
1456 return(xmlNanoHTTPOpen(filename, NULL));
1457}
1458
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001459#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001460/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001461 * xmlIOHTTPOpenW:
Daniel Veillardf012a642001-07-23 19:10:52 +00001462 * @post_uri: The destination URI for the document
1463 * @compression: The compression desired for the document.
1464 *
1465 * Open a temporary buffer to collect the document for a subsequent HTTP POST
1466 * request. Non-static as is called from the output buffer creation routine.
1467 *
1468 * Returns an I/O context or NULL in case of error.
1469 */
1470
1471void *
Daniel Veillard572577e2002-01-18 16:23:55 +00001472xmlIOHTTPOpenW(const char *post_uri, int compression)
1473{
Daniel Veillardf012a642001-07-23 19:10:52 +00001474
Daniel Veillard572577e2002-01-18 16:23:55 +00001475 xmlIOHTTPWriteCtxtPtr ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001476
Daniel Veillard572577e2002-01-18 16:23:55 +00001477 if (post_uri == NULL)
1478 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001479
Daniel Veillard572577e2002-01-18 16:23:55 +00001480 ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt));
1481 if (ctxt == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001482 xmlIOErrMemory("creating HTTP output context");
Daniel Veillard572577e2002-01-18 16:23:55 +00001483 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001484 }
1485
Daniel Veillard572577e2002-01-18 16:23:55 +00001486 (void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt));
Daniel Veillardf012a642001-07-23 19:10:52 +00001487
Daniel Veillard572577e2002-01-18 16:23:55 +00001488 ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri);
1489 if (ctxt->uri == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001490 xmlIOErrMemory("copying URI");
Daniel Veillard572577e2002-01-18 16:23:55 +00001491 xmlFreeHTTPWriteCtxt(ctxt);
1492 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001493 }
1494
1495 /*
Daniel Veillard572577e2002-01-18 16:23:55 +00001496 * ** Since the document length is required for an HTTP post,
1497 * ** need to put the document into a buffer. A memory buffer
1498 * ** is being used to avoid pushing the data to disk and back.
1499 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001500
1501#ifdef HAVE_ZLIB_H
Daniel Veillard572577e2002-01-18 16:23:55 +00001502 if ((compression > 0) && (compression <= 9)) {
1503
1504 ctxt->compression = compression;
1505 ctxt->doc_buff = xmlCreateZMemBuff(compression);
1506 } else
Daniel Veillardf012a642001-07-23 19:10:52 +00001507#endif
1508 {
Daniel Veillard572577e2002-01-18 16:23:55 +00001509 /* Any character conversions should have been done before this */
Daniel Veillardf012a642001-07-23 19:10:52 +00001510
Daniel Veillard572577e2002-01-18 16:23:55 +00001511 ctxt->doc_buff = xmlAllocOutputBuffer(NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001512 }
1513
Daniel Veillard572577e2002-01-18 16:23:55 +00001514 if (ctxt->doc_buff == NULL) {
1515 xmlFreeHTTPWriteCtxt(ctxt);
1516 ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001517 }
1518
Daniel Veillard572577e2002-01-18 16:23:55 +00001519 return (ctxt);
Daniel Veillardf012a642001-07-23 19:10:52 +00001520}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001521#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001522
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001523#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001524/**
1525 * xmlIOHTTPDfltOpenW
1526 * @post_uri: The destination URI for this document.
1527 *
1528 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
1529 * HTTP post command. This function should generally not be used as
1530 * the open callback is short circuited in xmlOutputBufferCreateFile.
1531 *
1532 * Returns a pointer to the new IO context.
1533 */
1534static void *
1535xmlIOHTTPDfltOpenW( const char * post_uri ) {
1536 return ( xmlIOHTTPOpenW( post_uri, 0 ) );
1537}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001538#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001539
1540/**
Owen Taylor3473f882001-02-23 17:55:21 +00001541 * xmlIOHTTPRead:
1542 * @context: the I/O context
1543 * @buffer: where to drop data
1544 * @len: number of bytes to write
1545 *
1546 * Read @len bytes to @buffer from the I/O channel.
1547 *
1548 * Returns the number of bytes written
1549 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001550int
Owen Taylor3473f882001-02-23 17:55:21 +00001551xmlIOHTTPRead(void * context, char * buffer, int len) {
1552 return(xmlNanoHTTPRead(context, &buffer[0], len));
1553}
1554
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001555#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001556/**
Daniel Veillardf012a642001-07-23 19:10:52 +00001557 * xmlIOHTTPWrite
1558 * @context: previously opened writing context
1559 * @buffer: data to output to temporary buffer
1560 * @len: bytes to output
1561 *
1562 * Collect data from memory buffer into a temporary file for later
1563 * processing.
1564 *
1565 * Returns number of bytes written.
1566 */
1567
1568static int
1569xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
1570
1571 xmlIOHTTPWriteCtxtPtr ctxt = context;
1572
1573 if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
1574 return ( -1 );
1575
1576 if ( len > 0 ) {
1577
1578 /* Use gzwrite or fwrite as previously setup in the open call */
1579
1580#ifdef HAVE_ZLIB_H
1581 if ( ctxt->compression > 0 )
1582 len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len );
1583
1584 else
1585#endif
1586 len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
1587
1588 if ( len < 0 ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001589 xmlChar msg[500];
1590 xmlStrPrintf(msg, 500,
1591 (const xmlChar *) "xmlIOHTTPWrite: %s\n%s '%s'.\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001592 "Error appending to internal buffer.",
1593 "Error sending document to URI",
1594 ctxt->uri );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001595 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001596 }
1597 }
1598
1599 return ( len );
1600}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001601#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001602
1603
1604/**
Owen Taylor3473f882001-02-23 17:55:21 +00001605 * xmlIOHTTPClose:
1606 * @context: the I/O context
1607 *
1608 * Close an HTTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001609 *
1610 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00001611 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001612int
Owen Taylor3473f882001-02-23 17:55:21 +00001613xmlIOHTTPClose (void * context) {
1614 xmlNanoHTTPClose(context);
Daniel Veillardf012a642001-07-23 19:10:52 +00001615 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001616}
Daniel Veillardf012a642001-07-23 19:10:52 +00001617
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001618#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001619/**
1620 * xmlIOHTTCloseWrite
1621 * @context: The I/O context
1622 * @http_mthd: The HTTP method to be used when sending the data
1623 *
1624 * Close the transmit HTTP I/O channel and actually send the data.
1625 */
1626static int
1627xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
1628
1629 int close_rc = -1;
1630 int http_rtn = 0;
1631 int content_lgth = 0;
1632 xmlIOHTTPWriteCtxtPtr ctxt = context;
1633
1634 char * http_content = NULL;
1635 char * content_encoding = NULL;
1636 char * content_type = (char *) "text/xml";
1637 void * http_ctxt = NULL;
1638
1639 if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
1640 return ( -1 );
1641
1642 /* Retrieve the content from the appropriate buffer */
1643
1644#ifdef HAVE_ZLIB_H
1645
1646 if ( ctxt->compression > 0 ) {
1647 content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
1648 content_encoding = (char *) "Content-Encoding: gzip";
1649 }
1650 else
1651#endif
1652 {
1653 /* Pull the data out of the memory output buffer */
1654
1655 xmlOutputBufferPtr dctxt = ctxt->doc_buff;
1656 http_content = (char *)dctxt->buffer->content;
1657 content_lgth = dctxt->buffer->use;
1658 }
1659
1660 if ( http_content == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001661 xmlChar msg[500];
1662 xmlStrPrintf(msg, 500,
1663 (const xmlChar *) "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
1664 "Error retrieving content.\nUnable to",
1665 http_mthd, "data to URI", ctxt->uri );
1666 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001667 }
1668
1669 else {
1670
1671 http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
1672 &content_type, content_encoding,
1673 content_lgth );
1674
1675 if ( http_ctxt != NULL ) {
1676#ifdef DEBUG_HTTP
1677 /* If testing/debugging - dump reply with request content */
1678
1679 FILE * tst_file = NULL;
1680 char buffer[ 4096 ];
1681 char * dump_name = NULL;
1682 int avail;
1683
1684 xmlGenericError( xmlGenericErrorContext,
1685 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
1686 http_mthd, ctxt->uri,
1687 xmlNanoHTTPReturnCode( http_ctxt ) );
1688
1689 /*
1690 ** Since either content or reply may be gzipped,
1691 ** dump them to separate files instead of the
1692 ** standard error context.
1693 */
1694
1695 dump_name = tempnam( NULL, "lxml" );
1696 if ( dump_name != NULL ) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001697 (void)snprintf( buffer, sizeof(buffer), "%s.content", dump_name );
Daniel Veillardf012a642001-07-23 19:10:52 +00001698
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00001699 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00001700 if ( tst_file != NULL ) {
1701 xmlGenericError( xmlGenericErrorContext,
1702 "Transmitted content saved in file: %s\n", buffer );
1703
1704 fwrite( http_content, sizeof( char ),
1705 content_lgth, tst_file );
1706 fclose( tst_file );
1707 }
1708
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001709 (void)snprintf( buffer, sizeof(buffer), "%s.reply", dump_name );
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00001710 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00001711 if ( tst_file != NULL ) {
1712 xmlGenericError( xmlGenericErrorContext,
1713 "Reply content saved in file: %s\n", buffer );
1714
1715
1716 while ( (avail = xmlNanoHTTPRead( http_ctxt,
1717 buffer, sizeof( buffer ) )) > 0 ) {
1718
1719 fwrite( buffer, sizeof( char ), avail, tst_file );
1720 }
1721
1722 fclose( tst_file );
1723 }
1724
1725 free( dump_name );
1726 }
1727#endif /* DEBUG_HTTP */
1728
1729 http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
1730 if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
1731 close_rc = 0;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001732 else {
1733 xmlChar msg[500];
1734 xmlStrPrintf(msg, 500,
1735 (const xmlChar *) "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001736 http_mthd, content_lgth,
1737 "bytes to URI", ctxt->uri,
1738 "failed. HTTP return code:", http_rtn );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001739 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1740 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001741
1742 xmlNanoHTTPClose( http_ctxt );
1743 xmlFree( content_type );
1744 }
1745 }
1746
1747 /* Final cleanups */
1748
1749 xmlFreeHTTPWriteCtxt( ctxt );
1750
1751 return ( close_rc );
1752}
1753
1754/**
1755 * xmlIOHTTPClosePut
1756 *
1757 * @context: The I/O context
1758 *
1759 * Close the transmit HTTP I/O channel and actually send data using a PUT
1760 * HTTP method.
1761 */
1762static int
1763xmlIOHTTPClosePut( void * ctxt ) {
1764 return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
1765}
1766
1767
1768/**
1769 * xmlIOHTTPClosePost
1770 *
1771 * @context: The I/O context
1772 *
1773 * Close the transmit HTTP I/O channel and actually send data using a POST
1774 * HTTP method.
1775 */
1776static int
1777xmlIOHTTPClosePost( void * ctxt ) {
1778 return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
1779}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001780#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001781
Owen Taylor3473f882001-02-23 17:55:21 +00001782#endif /* LIBXML_HTTP_ENABLED */
1783
1784#ifdef LIBXML_FTP_ENABLED
1785/************************************************************************
1786 * *
1787 * I/O for FTP file accesses *
1788 * *
1789 ************************************************************************/
1790/**
1791 * xmlIOFTPMatch:
1792 * @filename: the URI for matching
1793 *
1794 * check if the URI matches an FTP one
1795 *
1796 * Returns 1 if matches, 0 otherwise
1797 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001798int
Owen Taylor3473f882001-02-23 17:55:21 +00001799xmlIOFTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001800 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "ftp://", 6))
Owen Taylor3473f882001-02-23 17:55:21 +00001801 return(1);
1802 return(0);
1803}
1804
1805/**
1806 * xmlIOFTPOpen:
1807 * @filename: the URI for matching
1808 *
1809 * open an FTP I/O channel
1810 *
1811 * Returns an I/O context or NULL in case of error
1812 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001813void *
Owen Taylor3473f882001-02-23 17:55:21 +00001814xmlIOFTPOpen (const char *filename) {
1815 return(xmlNanoFTPOpen(filename));
1816}
1817
1818/**
1819 * xmlIOFTPRead:
1820 * @context: the I/O context
1821 * @buffer: where to drop data
1822 * @len: number of bytes to write
1823 *
1824 * Read @len bytes to @buffer from the I/O channel.
1825 *
1826 * Returns the number of bytes written
1827 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001828int
Owen Taylor3473f882001-02-23 17:55:21 +00001829xmlIOFTPRead(void * context, char * buffer, int len) {
1830 return(xmlNanoFTPRead(context, &buffer[0], len));
1831}
1832
1833/**
1834 * xmlIOFTPClose:
1835 * @context: the I/O context
1836 *
1837 * Close an FTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001838 *
1839 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00001840 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001841int
Owen Taylor3473f882001-02-23 17:55:21 +00001842xmlIOFTPClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001843 return ( xmlNanoFTPClose(context) );
Owen Taylor3473f882001-02-23 17:55:21 +00001844}
1845#endif /* LIBXML_FTP_ENABLED */
1846
1847
1848/**
1849 * xmlRegisterInputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001850 * @matchFunc: the xmlInputMatchCallback
1851 * @openFunc: the xmlInputOpenCallback
1852 * @readFunc: the xmlInputReadCallback
1853 * @closeFunc: the xmlInputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001854 *
1855 * Register a new set of I/O callback for handling parser input.
1856 *
1857 * Returns the registered handler number or -1 in case of error
1858 */
1859int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001860xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
1861 xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
1862 xmlInputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001863 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
1864 return(-1);
1865 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001866 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
1867 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
1868 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
1869 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00001870 xmlInputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00001871 return(xmlInputCallbackNr++);
1872}
1873
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001874#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001875/**
1876 * xmlRegisterOutputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001877 * @matchFunc: the xmlOutputMatchCallback
1878 * @openFunc: the xmlOutputOpenCallback
1879 * @writeFunc: the xmlOutputWriteCallback
1880 * @closeFunc: the xmlOutputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001881 *
1882 * Register a new set of I/O callback for handling output.
1883 *
1884 * Returns the registered handler number or -1 in case of error
1885 */
1886int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001887xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
1888 xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
1889 xmlOutputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001890 if (xmlOutputCallbackNr >= MAX_INPUT_CALLBACK) {
1891 return(-1);
1892 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001893 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
1894 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
1895 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
1896 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00001897 xmlOutputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00001898 return(xmlOutputCallbackNr++);
1899}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001900#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001901
1902/**
1903 * xmlRegisterDefaultInputCallbacks:
1904 *
1905 * Registers the default compiled-in I/O handlers.
1906 */
1907void
Owen Taylor3473f882001-02-23 17:55:21 +00001908xmlRegisterDefaultInputCallbacks
Owen Taylor3473f882001-02-23 17:55:21 +00001909(void) {
1910 if (xmlInputCallbackInitialized)
1911 return;
1912
1913 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
1914 xmlFileRead, xmlFileClose);
1915#ifdef HAVE_ZLIB_H
1916 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1917 xmlGzfileRead, xmlGzfileClose);
1918#endif /* HAVE_ZLIB_H */
1919
1920#ifdef LIBXML_HTTP_ENABLED
1921 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
1922 xmlIOHTTPRead, xmlIOHTTPClose);
1923#endif /* LIBXML_HTTP_ENABLED */
1924
1925#ifdef LIBXML_FTP_ENABLED
1926 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1927 xmlIOFTPRead, xmlIOFTPClose);
1928#endif /* LIBXML_FTP_ENABLED */
1929 xmlInputCallbackInitialized = 1;
1930}
1931
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001932#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001933/**
1934 * xmlRegisterDefaultOutputCallbacks:
1935 *
1936 * Registers the default compiled-in I/O handlers.
1937 */
1938void
Owen Taylor3473f882001-02-23 17:55:21 +00001939xmlRegisterDefaultOutputCallbacks
Owen Taylor3473f882001-02-23 17:55:21 +00001940(void) {
1941 if (xmlOutputCallbackInitialized)
1942 return;
1943
1944 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
1945 xmlFileWrite, xmlFileClose);
Daniel Veillardf012a642001-07-23 19:10:52 +00001946
1947#ifdef LIBXML_HTTP_ENABLED
1948 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
1949 xmlIOHTTPWrite, xmlIOHTTPClosePut);
1950#endif
1951
Owen Taylor3473f882001-02-23 17:55:21 +00001952/*********************************
1953 No way a-priori to distinguish between gzipped files from
1954 uncompressed ones except opening if existing then closing
1955 and saving with same compression ratio ... a pain.
1956
1957#ifdef HAVE_ZLIB_H
1958 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1959 xmlGzfileWrite, xmlGzfileClose);
1960#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001961
1962 Nor FTP PUT ....
1963#ifdef LIBXML_FTP_ENABLED
1964 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1965 xmlIOFTPWrite, xmlIOFTPClose);
1966#endif
1967 **********************************/
1968 xmlOutputCallbackInitialized = 1;
1969}
1970
Daniel Veillardf012a642001-07-23 19:10:52 +00001971#ifdef LIBXML_HTTP_ENABLED
1972/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001973 * xmlRegisterHTTPPostCallbacks:
Daniel Veillardf012a642001-07-23 19:10:52 +00001974 *
1975 * By default, libxml submits HTTP output requests using the "PUT" method.
1976 * Calling this method changes the HTTP output method to use the "POST"
1977 * method instead.
1978 *
1979 */
1980void
1981xmlRegisterHTTPPostCallbacks( void ) {
1982
1983 /* Register defaults if not done previously */
1984
1985 if ( xmlOutputCallbackInitialized == 0 )
1986 xmlRegisterDefaultOutputCallbacks( );
1987
1988 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
1989 xmlIOHTTPWrite, xmlIOHTTPClosePost);
1990 return;
1991}
1992#endif
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001993#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001994
Owen Taylor3473f882001-02-23 17:55:21 +00001995/**
1996 * xmlAllocParserInputBuffer:
1997 * @enc: the charset encoding if known
1998 *
1999 * Create a buffered parser input for progressive parsing
2000 *
2001 * Returns the new parser input or NULL
2002 */
2003xmlParserInputBufferPtr
2004xmlAllocParserInputBuffer(xmlCharEncoding enc) {
2005 xmlParserInputBufferPtr ret;
2006
2007 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2008 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002009 xmlIOErrMemory("creating input buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00002010 return(NULL);
2011 }
2012 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002013 ret->buffer = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00002014 if (ret->buffer == NULL) {
2015 xmlFree(ret);
2016 return(NULL);
2017 }
2018 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
2019 ret->encoder = xmlGetCharEncodingHandler(enc);
2020 if (ret->encoder != NULL)
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002021 ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00002022 else
2023 ret->raw = NULL;
2024 ret->readcallback = NULL;
2025 ret->closecallback = NULL;
2026 ret->context = NULL;
William M. Brackc07329e2003-09-08 01:57:30 +00002027 ret->compressed = -1;
Daniel Veillard36711902004-02-11 13:25:26 +00002028 ret->rawconsumed = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002029
2030 return(ret);
2031}
2032
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002033#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002034/**
2035 * xmlAllocOutputBuffer:
2036 * @encoder: the encoding converter or NULL
2037 *
2038 * Create a buffered parser output
2039 *
2040 * Returns the new parser output or NULL
2041 */
2042xmlOutputBufferPtr
2043xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
2044 xmlOutputBufferPtr ret;
2045
2046 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
2047 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002048 xmlIOErrMemory("creating output buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00002049 return(NULL);
2050 }
2051 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
2052 ret->buffer = xmlBufferCreate();
2053 if (ret->buffer == NULL) {
2054 xmlFree(ret);
2055 return(NULL);
2056 }
2057 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
2058 ret->encoder = encoder;
2059 if (encoder != NULL) {
2060 ret->conv = xmlBufferCreateSize(4000);
2061 /*
2062 * This call is designed to initiate the encoder state
2063 */
2064 xmlCharEncOutFunc(encoder, ret->conv, NULL);
2065 } else
2066 ret->conv = NULL;
2067 ret->writecallback = NULL;
2068 ret->closecallback = NULL;
2069 ret->context = NULL;
2070 ret->written = 0;
2071
2072 return(ret);
2073}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002074#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002075
2076/**
2077 * xmlFreeParserInputBuffer:
2078 * @in: a buffered parser input
2079 *
2080 * Free up the memory used by a buffered parser input
2081 */
2082void
2083xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
Daniel Veillard8d8bf2c2003-09-17 19:36:25 +00002084 if (in == NULL) return;
2085
Owen Taylor3473f882001-02-23 17:55:21 +00002086 if (in->raw) {
2087 xmlBufferFree(in->raw);
2088 in->raw = NULL;
2089 }
2090 if (in->encoder != NULL) {
2091 xmlCharEncCloseFunc(in->encoder);
2092 }
2093 if (in->closecallback != NULL) {
2094 in->closecallback(in->context);
2095 }
2096 if (in->buffer != NULL) {
2097 xmlBufferFree(in->buffer);
2098 in->buffer = NULL;
2099 }
2100
Owen Taylor3473f882001-02-23 17:55:21 +00002101 xmlFree(in);
2102}
2103
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002104#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002105/**
2106 * xmlOutputBufferClose:
2107 * @out: a buffered output
2108 *
2109 * flushes and close the output I/O channel
2110 * and free up all the associated resources
2111 *
2112 * Returns the number of byte written or -1 in case of error.
2113 */
2114int
Daniel Veillard828ce832003-10-08 19:19:10 +00002115xmlOutputBufferClose(xmlOutputBufferPtr out)
2116{
Owen Taylor3473f882001-02-23 17:55:21 +00002117 int written;
Daniel Veillardf012a642001-07-23 19:10:52 +00002118 int err_rc = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002119
2120 if (out == NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002121 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002122 if (out->writecallback != NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002123 xmlOutputBufferFlush(out);
Owen Taylor3473f882001-02-23 17:55:21 +00002124 if (out->closecallback != NULL) {
Daniel Veillard828ce832003-10-08 19:19:10 +00002125 err_rc = out->closecallback(out->context);
Owen Taylor3473f882001-02-23 17:55:21 +00002126 }
2127 written = out->written;
2128 if (out->conv) {
2129 xmlBufferFree(out->conv);
Daniel Veillard828ce832003-10-08 19:19:10 +00002130 out->conv = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002131 }
2132 if (out->encoder != NULL) {
2133 xmlCharEncCloseFunc(out->encoder);
2134 }
2135 if (out->buffer != NULL) {
2136 xmlBufferFree(out->buffer);
Daniel Veillard828ce832003-10-08 19:19:10 +00002137 out->buffer = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002138 }
2139
Daniel Veillard828ce832003-10-08 19:19:10 +00002140 if (out->error)
2141 err_rc = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00002142 xmlFree(out);
Daniel Veillard828ce832003-10-08 19:19:10 +00002143 return ((err_rc == 0) ? written : err_rc);
Owen Taylor3473f882001-02-23 17:55:21 +00002144}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002145#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002146
Daniel Veillard1b243b42004-06-08 10:16:42 +00002147xmlParserInputBufferPtr
Daniel Veillard0335a842004-06-02 16:18:40 +00002148__xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002149 xmlParserInputBufferPtr ret;
Daniel Veillard388236f2001-07-08 18:35:48 +00002150 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002151 void *context = NULL;
2152
2153 if (xmlInputCallbackInitialized == 0)
2154 xmlRegisterDefaultInputCallbacks();
2155
2156 if (URI == NULL) return(NULL);
2157
2158 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002159 * Try to find one of the input accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002160 * Go in reverse to give precedence to user defined handlers.
Daniel Veillard388236f2001-07-08 18:35:48 +00002161 */
2162 if (context == NULL) {
2163 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
2164 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
2165 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002166 context = xmlInputCallbackTable[i].opencallback(URI);
Daniel Veillard847332a2003-10-18 11:29:40 +00002167 if (context != NULL) {
Daniel Veillard388236f2001-07-08 18:35:48 +00002168 break;
Daniel Veillard847332a2003-10-18 11:29:40 +00002169 }
Daniel Veillard388236f2001-07-08 18:35:48 +00002170 }
Owen Taylor3473f882001-02-23 17:55:21 +00002171 }
2172 }
2173 if (context == NULL) {
2174 return(NULL);
2175 }
2176
2177 /*
2178 * Allocate the Input buffer front-end.
2179 */
2180 ret = xmlAllocParserInputBuffer(enc);
2181 if (ret != NULL) {
2182 ret->context = context;
2183 ret->readcallback = xmlInputCallbackTable[i].readcallback;
2184 ret->closecallback = xmlInputCallbackTable[i].closecallback;
William M. Brackc07329e2003-09-08 01:57:30 +00002185#ifdef HAVE_ZLIB_H
William M. Brackc5cbf992003-10-29 22:15:13 +00002186 if ((xmlInputCallbackTable[i].opencallback == xmlGzfileOpen) &&
2187 (strcmp(URI, "-") != 0)) {
William M. Brackc07329e2003-09-08 01:57:30 +00002188 if (((z_stream *)context)->avail_in > 4) {
2189 char *cptr, buff4[4];
Daniel Veillard07cb8222003-09-10 10:51:05 +00002190 cptr = (char *) ((z_stream *)context)->next_in;
William M. Brackc07329e2003-09-08 01:57:30 +00002191 if (gzread(context, buff4, 4) == 4) {
2192 if (strncmp(buff4, cptr, 4) == 0)
2193 ret->compressed = 0;
2194 else
2195 ret->compressed = 1;
2196 gzrewind(context);
2197 }
2198 }
2199 }
2200#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002201 }
William M. Brack42331a92004-07-29 07:07:16 +00002202 else
2203 xmlInputCallbackTable[i].closecallback (context);
2204
Owen Taylor3473f882001-02-23 17:55:21 +00002205 return(ret);
2206}
2207
2208/**
Daniel Veillard0335a842004-06-02 16:18:40 +00002209 * xmlParserInputBufferCreateFilename:
Owen Taylor3473f882001-02-23 17:55:21 +00002210 * @URI: a C string containing the URI or filename
Daniel Veillard0335a842004-06-02 16:18:40 +00002211 * @enc: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002212 *
Daniel Veillard0335a842004-06-02 16:18:40 +00002213 * Create a buffered parser input for the progressive parsing of a file
2214 * If filename is "-' then we use stdin as the input.
Owen Taylor3473f882001-02-23 17:55:21 +00002215 * Automatic support for ZLIB/Compress compressed document is provided
2216 * by default if found at compile-time.
Daniel Veillard0335a842004-06-02 16:18:40 +00002217 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
Owen Taylor3473f882001-02-23 17:55:21 +00002218 *
Daniel Veillard0335a842004-06-02 16:18:40 +00002219 * Returns the new parser input or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00002220 */
Daniel Veillard0335a842004-06-02 16:18:40 +00002221xmlParserInputBufferPtr
2222xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
2223 if ((xmlParserInputBufferCreateFilenameValue)) {
2224 return xmlParserInputBufferCreateFilenameValue(URI, enc);
2225 }
2226 return __xmlParserInputBufferCreateFilename(URI, enc);
2227}
2228
2229#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard1b243b42004-06-08 10:16:42 +00002230xmlOutputBufferPtr
Daniel Veillard0335a842004-06-02 16:18:40 +00002231__xmlOutputBufferCreateFilename(const char *URI,
Owen Taylor3473f882001-02-23 17:55:21 +00002232 xmlCharEncodingHandlerPtr encoder,
Daniel Veillard0335a842004-06-02 16:18:40 +00002233 int compression ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00002234 xmlOutputBufferPtr ret;
Daniel Veillard966a31e2004-05-09 02:58:44 +00002235 xmlURIPtr puri;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002236 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002237 void *context = NULL;
Daniel Veillard966a31e2004-05-09 02:58:44 +00002238 char *unescaped = NULL;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002239#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002240 int is_file_uri = 1;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002241#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00002242
Owen Taylor3473f882001-02-23 17:55:21 +00002243 if (xmlOutputCallbackInitialized == 0)
2244 xmlRegisterDefaultOutputCallbacks();
2245
2246 if (URI == NULL) return(NULL);
2247
Daniel Veillard966a31e2004-05-09 02:58:44 +00002248 puri = xmlParseURI(URI);
2249 if (puri != NULL) {
Daniel Veillard18a65092004-05-11 15:57:42 +00002250 if ((puri->scheme != NULL) &&
2251 (!xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002252#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002253 is_file_uri = 0;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002254#endif
Daniel Veillard966a31e2004-05-09 02:58:44 +00002255 /*
2256 * try to limit the damages of the URI unescaping code.
2257 */
2258 if (puri->scheme != NULL)
2259 unescaped = xmlURIUnescapeString(URI, 0, NULL);
2260 xmlFreeURI(puri);
2261 }
Owen Taylor3473f882001-02-23 17:55:21 +00002262
2263 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002264 * Try to find one of the output accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002265 * Go in reverse to give precedence to user defined handlers.
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002266 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00002267 */
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002268 if (unescaped != NULL) {
2269#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002270 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002271 context = xmlGzfileOpenW(unescaped, compression);
2272 if (context != NULL) {
2273 ret = xmlAllocOutputBuffer(encoder);
2274 if (ret != NULL) {
2275 ret->context = context;
2276 ret->writecallback = xmlGzfileWrite;
2277 ret->closecallback = xmlGzfileClose;
2278 }
2279 xmlFree(unescaped);
2280 return(ret);
2281 }
2282 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002283#endif
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002284 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2285 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
2286 (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
2287#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2288 /* Need to pass compression parameter into HTTP open calls */
2289 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2290 context = xmlIOHTTPOpenW(unescaped, compression);
2291 else
2292#endif
2293 context = xmlOutputCallbackTable[i].opencallback(unescaped);
2294 if (context != NULL)
2295 break;
2296 }
2297 }
2298 xmlFree(unescaped);
2299 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002300
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002301 /*
2302 * If this failed try with a non-escaped URI this may be a strange
2303 * filename
2304 */
2305 if (context == NULL) {
2306#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002307 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002308 context = xmlGzfileOpenW(URI, compression);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002309 if (context != NULL) {
2310 ret = xmlAllocOutputBuffer(encoder);
2311 if (ret != NULL) {
2312 ret->context = context;
2313 ret->writecallback = xmlGzfileWrite;
2314 ret->closecallback = xmlGzfileClose;
2315 }
2316 return(ret);
2317 }
2318 }
2319#endif
2320 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2321 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002322 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002323#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2324 /* Need to pass compression parameter into HTTP open calls */
2325 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2326 context = xmlIOHTTPOpenW(URI, compression);
2327 else
2328#endif
2329 context = xmlOutputCallbackTable[i].opencallback(URI);
2330 if (context != NULL)
2331 break;
2332 }
Owen Taylor3473f882001-02-23 17:55:21 +00002333 }
2334 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002335
Owen Taylor3473f882001-02-23 17:55:21 +00002336 if (context == NULL) {
2337 return(NULL);
2338 }
2339
2340 /*
2341 * Allocate the Output buffer front-end.
2342 */
2343 ret = xmlAllocOutputBuffer(encoder);
2344 if (ret != NULL) {
2345 ret->context = context;
2346 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
2347 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
2348 }
2349 return(ret);
2350}
Daniel Veillard0335a842004-06-02 16:18:40 +00002351
2352/**
2353 * xmlOutputBufferCreateFilename:
2354 * @URI: a C string containing the URI or filename
2355 * @encoder: the encoding converter or NULL
2356 * @compression: the compression ration (0 none, 9 max).
2357 *
2358 * Create a buffered output for the progressive saving of a file
2359 * If filename is "-' then we use stdout as the output.
2360 * Automatic support for ZLIB/Compress compressed document is provided
2361 * by default if found at compile-time.
2362 * TODO: currently if compression is set, the library only support
2363 * writing to a local file.
2364 *
2365 * Returns the new output or NULL
2366 */
2367xmlOutputBufferPtr
2368xmlOutputBufferCreateFilename(const char *URI,
2369 xmlCharEncodingHandlerPtr encoder,
2370 int compression ATTRIBUTE_UNUSED) {
2371 if ((xmlOutputBufferCreateFilenameValue)) {
2372 return xmlOutputBufferCreateFilenameValue(URI, encoder, compression);
2373 }
2374 return __xmlOutputBufferCreateFilename(URI, encoder, compression);
2375}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002376#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002377
2378/**
2379 * xmlParserInputBufferCreateFile:
2380 * @file: a FILE*
2381 * @enc: the charset encoding if known
2382 *
2383 * Create a buffered parser input for the progressive parsing of a FILE *
2384 * buffered C I/O
2385 *
2386 * Returns the new parser input or NULL
2387 */
2388xmlParserInputBufferPtr
2389xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
2390 xmlParserInputBufferPtr ret;
2391
2392 if (xmlInputCallbackInitialized == 0)
2393 xmlRegisterDefaultInputCallbacks();
2394
2395 if (file == NULL) return(NULL);
2396
2397 ret = xmlAllocParserInputBuffer(enc);
2398 if (ret != NULL) {
2399 ret->context = file;
2400 ret->readcallback = xmlFileRead;
2401 ret->closecallback = xmlFileFlush;
2402 }
2403
2404 return(ret);
2405}
2406
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002407#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002408/**
2409 * xmlOutputBufferCreateFile:
2410 * @file: a FILE*
2411 * @encoder: the encoding converter or NULL
2412 *
2413 * Create a buffered output for the progressive saving to a FILE *
2414 * buffered C I/O
2415 *
2416 * Returns the new parser output or NULL
2417 */
2418xmlOutputBufferPtr
2419xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
2420 xmlOutputBufferPtr ret;
2421
2422 if (xmlOutputCallbackInitialized == 0)
2423 xmlRegisterDefaultOutputCallbacks();
2424
2425 if (file == NULL) return(NULL);
2426
2427 ret = xmlAllocOutputBuffer(encoder);
2428 if (ret != NULL) {
2429 ret->context = file;
2430 ret->writecallback = xmlFileWrite;
2431 ret->closecallback = xmlFileFlush;
2432 }
2433
2434 return(ret);
2435}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002436#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002437
2438/**
2439 * xmlParserInputBufferCreateFd:
2440 * @fd: a file descriptor number
2441 * @enc: the charset encoding if known
2442 *
2443 * Create a buffered parser input for the progressive parsing for the input
2444 * from a file descriptor
2445 *
2446 * Returns the new parser input or NULL
2447 */
2448xmlParserInputBufferPtr
2449xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
2450 xmlParserInputBufferPtr ret;
2451
2452 if (fd < 0) return(NULL);
2453
2454 ret = xmlAllocParserInputBuffer(enc);
2455 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002456 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002457 ret->readcallback = xmlFdRead;
2458 ret->closecallback = xmlFdClose;
2459 }
2460
2461 return(ret);
2462}
2463
2464/**
2465 * xmlParserInputBufferCreateMem:
2466 * @mem: the memory input
2467 * @size: the length of the memory block
2468 * @enc: the charset encoding if known
2469 *
2470 * Create a buffered parser input for the progressive parsing for the input
2471 * from a memory area.
2472 *
2473 * Returns the new parser input or NULL
2474 */
2475xmlParserInputBufferPtr
2476xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
2477 xmlParserInputBufferPtr ret;
William M. Bracka3215c72004-07-31 16:24:01 +00002478 int errcode;
Owen Taylor3473f882001-02-23 17:55:21 +00002479
2480 if (size <= 0) return(NULL);
2481 if (mem == NULL) return(NULL);
2482
2483 ret = xmlAllocParserInputBuffer(enc);
2484 if (ret != NULL) {
2485 ret->context = (void *) mem;
2486 ret->readcallback = (xmlInputReadCallback) xmlNop;
2487 ret->closecallback = NULL;
William M. Bracka3215c72004-07-31 16:24:01 +00002488 errcode = xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size);
2489 if (errcode != 0) {
2490 xmlFree(ret);
2491 return(NULL);
2492 }
Owen Taylor3473f882001-02-23 17:55:21 +00002493 }
2494
2495 return(ret);
2496}
2497
2498/**
Daniel Veillard53350552003-09-18 13:35:51 +00002499 * xmlParserInputBufferCreateStatic:
2500 * @mem: the memory input
2501 * @size: the length of the memory block
2502 * @enc: the charset encoding if known
2503 *
2504 * Create a buffered parser input for the progressive parsing for the input
2505 * from an immutable memory area. This will not copy the memory area to
2506 * the buffer, but the memory is expected to be available until the end of
2507 * the parsing, this is useful for example when using mmap'ed file.
2508 *
2509 * Returns the new parser input or NULL
2510 */
2511xmlParserInputBufferPtr
2512xmlParserInputBufferCreateStatic(const char *mem, int size,
2513 xmlCharEncoding enc) {
2514 xmlParserInputBufferPtr ret;
2515
2516 if (size <= 0) return(NULL);
2517 if (mem == NULL) return(NULL);
2518
2519 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2520 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002521 xmlIOErrMemory("creating input buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00002522 return(NULL);
2523 }
2524 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillarde72c5082003-09-19 12:44:05 +00002525 ret->buffer = xmlBufferCreateStatic((void *)mem, (size_t) size);
Daniel Veillard53350552003-09-18 13:35:51 +00002526 if (ret->buffer == NULL) {
2527 xmlFree(ret);
2528 return(NULL);
2529 }
2530 ret->encoder = xmlGetCharEncodingHandler(enc);
2531 if (ret->encoder != NULL)
2532 ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
2533 else
2534 ret->raw = NULL;
2535 ret->compressed = -1;
2536 ret->context = (void *) mem;
2537 ret->readcallback = NULL;
2538 ret->closecallback = NULL;
2539
2540 return(ret);
2541}
2542
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002543#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard53350552003-09-18 13:35:51 +00002544/**
Owen Taylor3473f882001-02-23 17:55:21 +00002545 * xmlOutputBufferCreateFd:
2546 * @fd: a file descriptor number
2547 * @encoder: the encoding converter or NULL
2548 *
2549 * Create a buffered output for the progressive saving
2550 * to a file descriptor
2551 *
2552 * Returns the new parser output or NULL
2553 */
2554xmlOutputBufferPtr
2555xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
2556 xmlOutputBufferPtr ret;
2557
2558 if (fd < 0) return(NULL);
2559
2560 ret = xmlAllocOutputBuffer(encoder);
2561 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002562 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002563 ret->writecallback = xmlFdWrite;
Daniel Veillard7db38712002-02-07 16:39:11 +00002564 ret->closecallback = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002565 }
2566
2567 return(ret);
2568}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002569#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002570
2571/**
2572 * xmlParserInputBufferCreateIO:
2573 * @ioread: an I/O read function
2574 * @ioclose: an I/O close function
2575 * @ioctx: an I/O handler
2576 * @enc: the charset encoding if known
2577 *
2578 * Create a buffered parser input for the progressive parsing for the input
2579 * from an I/O handler
2580 *
2581 * Returns the new parser input or NULL
2582 */
2583xmlParserInputBufferPtr
2584xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
2585 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
2586 xmlParserInputBufferPtr ret;
2587
2588 if (ioread == NULL) return(NULL);
2589
2590 ret = xmlAllocParserInputBuffer(enc);
2591 if (ret != NULL) {
2592 ret->context = (void *) ioctx;
2593 ret->readcallback = ioread;
2594 ret->closecallback = ioclose;
2595 }
2596
2597 return(ret);
2598}
2599
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002600#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002601/**
2602 * xmlOutputBufferCreateIO:
2603 * @iowrite: an I/O write function
2604 * @ioclose: an I/O close function
2605 * @ioctx: an I/O handler
Daniel Veillard9d06d302002-01-22 18:15:52 +00002606 * @encoder: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002607 *
2608 * Create a buffered output for the progressive saving
2609 * to an I/O handler
2610 *
2611 * Returns the new parser output or NULL
2612 */
2613xmlOutputBufferPtr
2614xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
2615 xmlOutputCloseCallback ioclose, void *ioctx,
2616 xmlCharEncodingHandlerPtr encoder) {
2617 xmlOutputBufferPtr ret;
2618
2619 if (iowrite == NULL) return(NULL);
2620
2621 ret = xmlAllocOutputBuffer(encoder);
2622 if (ret != NULL) {
2623 ret->context = (void *) ioctx;
2624 ret->writecallback = iowrite;
2625 ret->closecallback = ioclose;
2626 }
2627
2628 return(ret);
2629}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002630#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002631
2632/**
Daniel Veillard1b243b42004-06-08 10:16:42 +00002633 * xmlParserInputBufferCreateFilenameDefault:
2634 * @func: function pointer to the new ParserInputBufferCreateFilenameFunc
2635 *
2636 * Registers a callback for URI input file handling
2637 *
2638 * Returns the old value of the registration function
2639 */
2640xmlParserInputBufferCreateFilenameFunc
2641xmlParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func)
2642{
2643 xmlParserInputBufferCreateFilenameFunc old = xmlParserInputBufferCreateFilenameValue;
2644 if (old == NULL) {
2645 old = __xmlParserInputBufferCreateFilename;
2646 }
2647
2648 xmlParserInputBufferCreateFilenameValue = func;
2649 return(old);
2650}
2651
2652/**
2653 * xmlOutputBufferCreateFilenameDefault:
2654 * @func: function pointer to the new OutputBufferCreateFilenameFunc
2655 *
2656 * Registers a callback for URI output file handling
2657 *
2658 * Returns the old value of the registration function
2659 */
2660xmlOutputBufferCreateFilenameFunc
2661xmlOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func)
2662{
2663 xmlOutputBufferCreateFilenameFunc old = xmlOutputBufferCreateFilenameValue;
2664#ifdef LIBXML_OUTPUT_ENABLED
2665 if (old == NULL) {
2666 old = __xmlOutputBufferCreateFilename;
2667 }
2668#endif
2669 xmlOutputBufferCreateFilenameValue = func;
2670 return(old);
2671}
2672
2673/**
Owen Taylor3473f882001-02-23 17:55:21 +00002674 * xmlParserInputBufferPush:
2675 * @in: a buffered parser input
2676 * @len: the size in bytes of the array.
2677 * @buf: an char array
2678 *
2679 * Push the content of the arry in the input buffer
2680 * This routine handle the I18N transcoding to internal UTF-8
2681 * This is used when operating the parser in progressive (push) mode.
2682 *
2683 * Returns the number of chars read and stored in the buffer, or -1
2684 * in case of error.
2685 */
2686int
2687xmlParserInputBufferPush(xmlParserInputBufferPtr in,
2688 int len, const char *buf) {
2689 int nbchars = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00002690 int ret;
Owen Taylor3473f882001-02-23 17:55:21 +00002691
2692 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002693 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002694 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00002695 unsigned int use;
2696
Owen Taylor3473f882001-02-23 17:55:21 +00002697 /*
2698 * Store the data in the incoming raw buffer
2699 */
2700 if (in->raw == NULL) {
2701 in->raw = xmlBufferCreate();
2702 }
William M. Bracka3215c72004-07-31 16:24:01 +00002703 ret = xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
2704 if (ret != 0)
2705 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002706
2707 /*
2708 * convert as much as possible to the parser reading buffer.
2709 */
Daniel Veillard36711902004-02-11 13:25:26 +00002710 use = in->raw->use;
Owen Taylor3473f882001-02-23 17:55:21 +00002711 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2712 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002713 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002714 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002715 return(-1);
2716 }
Daniel Veillard36711902004-02-11 13:25:26 +00002717 in->rawconsumed += (use - in->raw->use);
Owen Taylor3473f882001-02-23 17:55:21 +00002718 } else {
2719 nbchars = len;
William M. Bracka3215c72004-07-31 16:24:01 +00002720 ret = xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
2721 if (ret != 0)
2722 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002723 }
2724#ifdef DEBUG_INPUT
2725 xmlGenericError(xmlGenericErrorContext,
2726 "I/O: pushed %d chars, buffer %d/%d\n",
2727 nbchars, in->buffer->use, in->buffer->size);
2728#endif
2729 return(nbchars);
2730}
2731
2732/**
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002733 * endOfInput:
2734 *
2735 * When reading from an Input channel indicated end of file or error
2736 * don't reread from it again.
2737 */
2738static int
2739endOfInput (void * context ATTRIBUTE_UNUSED,
2740 char * buffer ATTRIBUTE_UNUSED,
2741 int len ATTRIBUTE_UNUSED) {
2742 return(0);
2743}
2744
2745/**
Owen Taylor3473f882001-02-23 17:55:21 +00002746 * xmlParserInputBufferGrow:
2747 * @in: a buffered parser input
2748 * @len: indicative value of the amount of chars to read
2749 *
2750 * Grow up the content of the input buffer, the old data are preserved
2751 * This routine handle the I18N transcoding to internal UTF-8
2752 * This routine is used when operating the parser in normal (pull) mode
2753 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002754 * TODO: one should be able to remove one extra copy by copying directly
Owen Taylor3473f882001-02-23 17:55:21 +00002755 * onto in->buffer or in->raw
2756 *
2757 * Returns the number of chars read and stored in the buffer, or -1
2758 * in case of error.
2759 */
2760int
2761xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
2762 char *buffer = NULL;
2763 int res = 0;
2764 int nbchars = 0;
2765 int buffree;
Daniel Veillard9e412302002-06-10 15:59:44 +00002766 unsigned int needSize;
Owen Taylor3473f882001-02-23 17:55:21 +00002767
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002768 if ((in == NULL) || (in->error)) return(-1);
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002769 if ((len <= MINLEN) && (len != 4))
Owen Taylor3473f882001-02-23 17:55:21 +00002770 len = MINLEN;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002771
Owen Taylor3473f882001-02-23 17:55:21 +00002772 buffree = in->buffer->size - in->buffer->use;
2773 if (buffree <= 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002774 xmlIOErr(XML_IO_BUFFER_FULL, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002775 in->error = XML_IO_BUFFER_FULL;
William M. Bracka3215c72004-07-31 16:24:01 +00002776 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002777 }
Owen Taylor3473f882001-02-23 17:55:21 +00002778
Daniel Veillarde5354492002-05-16 08:43:22 +00002779 needSize = in->buffer->use + len + 1;
2780 if (needSize > in->buffer->size){
2781 if (!xmlBufferResize(in->buffer, needSize)){
Daniel Veillard05d987b2003-10-08 11:54:57 +00002782 xmlIOErrMemory("growing input buffer");
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002783 in->error = XML_ERR_NO_MEMORY;
William M. Bracka3215c72004-07-31 16:24:01 +00002784 return(-1);
Daniel Veillarde5354492002-05-16 08:43:22 +00002785 }
Owen Taylor3473f882001-02-23 17:55:21 +00002786 }
Daniel Veillarde5354492002-05-16 08:43:22 +00002787 buffer = (char *)&in->buffer->content[in->buffer->use];
Owen Taylor3473f882001-02-23 17:55:21 +00002788
2789 /*
2790 * Call the read method for this I/O type.
2791 */
2792 if (in->readcallback != NULL) {
2793 res = in->readcallback(in->context, &buffer[0], len);
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002794 if (res <= 0)
2795 in->readcallback = endOfInput;
Owen Taylor3473f882001-02-23 17:55:21 +00002796 } else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002797 xmlIOErr(XML_IO_NO_INPUT, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002798 in->error = XML_IO_NO_INPUT;
Owen Taylor3473f882001-02-23 17:55:21 +00002799 return(-1);
2800 }
2801 if (res < 0) {
Owen Taylor3473f882001-02-23 17:55:21 +00002802 return(-1);
2803 }
2804 len = res;
2805 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00002806 unsigned int use;
2807
Owen Taylor3473f882001-02-23 17:55:21 +00002808 /*
2809 * Store the data in the incoming raw buffer
2810 */
2811 if (in->raw == NULL) {
2812 in->raw = xmlBufferCreate();
2813 }
William M. Bracka3215c72004-07-31 16:24:01 +00002814 res = xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
2815 if (res != 0)
2816 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002817
2818 /*
2819 * convert as much as possible to the parser reading buffer.
2820 */
Daniel Veillard36711902004-02-11 13:25:26 +00002821 use = in->raw->use;
Owen Taylor3473f882001-02-23 17:55:21 +00002822 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2823 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002824 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002825 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002826 return(-1);
2827 }
Daniel Veillard36711902004-02-11 13:25:26 +00002828 in->rawconsumed += (use - in->raw->use);
Owen Taylor3473f882001-02-23 17:55:21 +00002829 } else {
2830 nbchars = len;
Daniel Veillarde5354492002-05-16 08:43:22 +00002831 in->buffer->use += nbchars;
2832 buffer[nbchars] = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002833 }
2834#ifdef DEBUG_INPUT
2835 xmlGenericError(xmlGenericErrorContext,
2836 "I/O: read %d chars, buffer %d/%d\n",
2837 nbchars, in->buffer->use, in->buffer->size);
2838#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002839 return(nbchars);
2840}
2841
2842/**
2843 * xmlParserInputBufferRead:
2844 * @in: a buffered parser input
2845 * @len: indicative value of the amount of chars to read
2846 *
2847 * Refresh the content of the input buffer, the old data are considered
2848 * consumed
2849 * This routine handle the I18N transcoding to internal UTF-8
2850 *
2851 * Returns the number of chars read and stored in the buffer, or -1
2852 * in case of error.
2853 */
2854int
2855xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002856 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002857 if (in->readcallback != NULL)
2858 return(xmlParserInputBufferGrow(in, len));
Daniel Veillard53350552003-09-18 13:35:51 +00002859 else if ((in->buffer != NULL) &&
2860 (in->buffer->alloc == XML_BUFFER_ALLOC_IMMUTABLE))
2861 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002862 else
2863 return(-1);
2864}
2865
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002866#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002867/**
2868 * xmlOutputBufferWrite:
2869 * @out: a buffered parser output
2870 * @len: the size in bytes of the array.
2871 * @buf: an char array
2872 *
2873 * Write the content of the array in the output I/O buffer
2874 * This routine handle the I18N transcoding from internal UTF-8
2875 * The buffer is lossless, i.e. will store in case of partial
2876 * or delayed writes.
2877 *
2878 * Returns the number of chars immediately written, or -1
2879 * in case of error.
2880 */
2881int
2882xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
2883 int nbchars = 0; /* number of chars to output to I/O */
2884 int ret; /* return from function call */
2885 int written = 0; /* number of char written to I/O so far */
2886 int chunk; /* number of byte curreent processed from buf */
2887
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002888 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002889 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002890 if (out->error) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002891
2892 do {
2893 chunk = len;
2894 if (chunk > 4 * MINLEN)
2895 chunk = 4 * MINLEN;
2896
2897 /*
2898 * first handle encoding stuff.
2899 */
2900 if (out->encoder != NULL) {
2901 /*
2902 * Store the data in the incoming raw buffer
2903 */
2904 if (out->conv == NULL) {
2905 out->conv = xmlBufferCreate();
2906 }
William M. Bracka3215c72004-07-31 16:24:01 +00002907 ret = xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2908 if (ret != 0)
2909 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002910
2911 if ((out->buffer->use < MINLEN) && (chunk == len))
2912 goto done;
2913
2914 /*
2915 * convert as much as possible to the parser reading buffer.
2916 */
2917 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
Daniel Veillard809faa52003-02-10 15:43:53 +00002918 if ((ret < 0) && (ret != -3)) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002919 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002920 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002921 return(-1);
2922 }
2923 nbchars = out->conv->use;
2924 } else {
William M. Bracka3215c72004-07-31 16:24:01 +00002925 ret = xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2926 if (ret != 0)
2927 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002928 nbchars = out->buffer->use;
2929 }
2930 buf += chunk;
2931 len -= chunk;
2932
2933 if ((nbchars < MINLEN) && (len <= 0))
2934 goto done;
2935
2936 if (out->writecallback) {
2937 /*
2938 * second write the stuff to the I/O channel
2939 */
2940 if (out->encoder != NULL) {
2941 ret = out->writecallback(out->context,
2942 (const char *)out->conv->content, nbchars);
2943 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002944 xmlBufferShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002945 } else {
2946 ret = out->writecallback(out->context,
2947 (const char *)out->buffer->content, nbchars);
2948 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002949 xmlBufferShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002950 }
2951 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002952 xmlIOErr(XML_IO_WRITE, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002953 out->error = XML_IO_WRITE;
Owen Taylor3473f882001-02-23 17:55:21 +00002954 return(ret);
2955 }
2956 out->written += ret;
2957 }
2958 written += nbchars;
2959 } while (len > 0);
2960
2961done:
2962#ifdef DEBUG_INPUT
2963 xmlGenericError(xmlGenericErrorContext,
2964 "I/O: wrote %d chars\n", written);
2965#endif
2966 return(written);
2967}
2968
2969/**
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00002970 * xmlEscapeContent:
2971 * @out: a pointer to an array of bytes to store the result
2972 * @outlen: the length of @out
2973 * @in: a pointer to an array of unescaped UTF-8 bytes
2974 * @inlen: the length of @in
2975 *
2976 * Take a block of UTF-8 chars in and escape them.
2977 * Returns 0 if success, or -1 otherwise
2978 * The value of @inlen after return is the number of octets consumed
2979 * if the return value is positive, else unpredictable.
2980 * The value of @outlen after return is the number of octets consumed.
2981 */
2982static int
2983xmlEscapeContent(unsigned char* out, int *outlen,
2984 const xmlChar* in, int *inlen) {
2985 unsigned char* outstart = out;
2986 const unsigned char* base = in;
2987 unsigned char* outend = out + *outlen;
2988 const unsigned char* inend;
2989
2990 inend = in + (*inlen);
2991
2992 while ((in < inend) && (out < outend)) {
2993 if (*in == '<') {
2994 if (outend - out < 4) break;
2995 *out++ = '&';
2996 *out++ = 'l';
2997 *out++ = 't';
2998 *out++ = ';';
2999 } else if (*in == '>') {
3000 if (outend - out < 4) break;
3001 *out++ = '&';
3002 *out++ = 'g';
3003 *out++ = 't';
3004 *out++ = ';';
3005 } else if (*in == '&') {
3006 if (outend - out < 5) break;
3007 *out++ = '&';
3008 *out++ = 'a';
3009 *out++ = 'm';
3010 *out++ = 'p';
3011 *out++ = ';';
3012 } else if (*in == '\r') {
3013 if (outend - out < 5) break;
3014 *out++ = '&';
3015 *out++ = '#';
3016 *out++ = '1';
3017 *out++ = '3';
3018 *out++ = ';';
3019 } else {
3020 *out++ = (unsigned char) *in;
3021 }
3022 ++in;
3023 }
3024 *outlen = out - outstart;
3025 *inlen = in - base;
3026 return(0);
3027}
3028
3029/**
3030 * xmlOutputBufferWriteEscape:
3031 * @out: a buffered parser output
3032 * @str: a zero terminated UTF-8 string
Daniel Veillardee8960b2004-05-14 03:25:14 +00003033 * @escaping: an optional escaping function (or NULL)
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003034 *
3035 * Write the content of the string in the output I/O buffer
3036 * This routine escapes the caracters and then handle the I18N
3037 * transcoding from internal UTF-8
3038 * The buffer is lossless, i.e. will store in case of partial
3039 * or delayed writes.
3040 *
3041 * Returns the number of chars immediately written, or -1
3042 * in case of error.
3043 */
3044int
Daniel Veillardee8960b2004-05-14 03:25:14 +00003045xmlOutputBufferWriteEscape(xmlOutputBufferPtr out, const xmlChar *str,
3046 xmlCharEncodingOutputFunc escaping) {
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003047 int nbchars = 0; /* number of chars to output to I/O */
3048 int ret; /* return from function call */
3049 int written = 0; /* number of char written to I/O so far */
Daniel Veillard71b95632004-08-31 12:15:36 +00003050 int oldwritten=0;/* loop guard */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003051 int chunk; /* number of byte currently processed from str */
3052 int len; /* number of bytes in str */
3053 int cons; /* byte from str consumed */
3054
Daniel Veillardce244ad2004-11-05 10:03:46 +00003055 if ((out == NULL) || (out->error) || (str == NULL) ||
3056 (out->buffer == NULL) ||
3057 (out->buffer->alloc == XML_BUFFER_ALLOC_IMMUTABLE)) return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003058 len = strlen((const char *)str);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003059 if (len < 0) return(0);
3060 if (out->error) return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003061 if (escaping == NULL) escaping = xmlEscapeContent;
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003062
3063 do {
Daniel Veillard71b95632004-08-31 12:15:36 +00003064 oldwritten = written;
3065
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003066 /*
3067 * how many bytes to consume and how many bytes to store.
3068 */
3069 cons = len;
3070 chunk = (out->buffer->size - out->buffer->use) - 1;
3071
3072 /*
3073 * first handle encoding stuff.
3074 */
3075 if (out->encoder != NULL) {
3076 /*
3077 * Store the data in the incoming raw buffer
3078 */
3079 if (out->conv == NULL) {
3080 out->conv = xmlBufferCreate();
3081 }
Daniel Veillardee8960b2004-05-14 03:25:14 +00003082 ret = escaping(out->buffer->content + out->buffer->use ,
3083 &chunk, str, &cons);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003084 if (ret < 0)
3085 return(-1);
3086 out->buffer->use += chunk;
3087 out->buffer->content[out->buffer->use] = 0;
3088
3089 if ((out->buffer->use < MINLEN) && (cons == len))
3090 goto done;
3091
3092 /*
3093 * convert as much as possible to the output buffer.
3094 */
3095 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
3096 if ((ret < 0) && (ret != -3)) {
3097 xmlIOErr(XML_IO_ENCODER, NULL);
3098 out->error = XML_IO_ENCODER;
3099 return(-1);
3100 }
3101 nbchars = out->conv->use;
3102 } else {
Daniel Veillardee8960b2004-05-14 03:25:14 +00003103 ret = escaping(out->buffer->content + out->buffer->use ,
3104 &chunk, str, &cons);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003105 if (ret < 0)
3106 return(-1);
3107 out->buffer->use += chunk;
3108 out->buffer->content[out->buffer->use] = 0;
3109 nbchars = out->buffer->use;
3110 }
3111 str += cons;
3112 len -= cons;
3113
3114 if ((nbchars < MINLEN) && (len <= 0))
3115 goto done;
3116
3117 if (out->writecallback) {
3118 /*
3119 * second write the stuff to the I/O channel
3120 */
3121 if (out->encoder != NULL) {
3122 ret = out->writecallback(out->context,
3123 (const char *)out->conv->content, nbchars);
3124 if (ret >= 0)
3125 xmlBufferShrink(out->conv, ret);
3126 } else {
3127 ret = out->writecallback(out->context,
3128 (const char *)out->buffer->content, nbchars);
3129 if (ret >= 0)
3130 xmlBufferShrink(out->buffer, ret);
3131 }
3132 if (ret < 0) {
3133 xmlIOErr(XML_IO_WRITE, NULL);
3134 out->error = XML_IO_WRITE;
3135 return(ret);
3136 }
3137 out->written += ret;
Daniel Veillard83a75e02004-05-14 21:50:42 +00003138 } else if (out->buffer->size - out->buffer->use < MINLEN) {
3139 xmlBufferResize(out->buffer, out->buffer->size + MINLEN);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003140 }
3141 written += nbchars;
Daniel Veillard71b95632004-08-31 12:15:36 +00003142 } while ((len > 0) && (oldwritten != written));
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003143
3144done:
3145#ifdef DEBUG_INPUT
3146 xmlGenericError(xmlGenericErrorContext,
3147 "I/O: wrote %d chars\n", written);
3148#endif
3149 return(written);
3150}
3151
3152/**
Owen Taylor3473f882001-02-23 17:55:21 +00003153 * xmlOutputBufferWriteString:
3154 * @out: a buffered parser output
3155 * @str: a zero terminated C string
3156 *
3157 * Write the content of the string in the output I/O buffer
3158 * This routine handle the I18N transcoding from internal UTF-8
3159 * The buffer is lossless, i.e. will store in case of partial
3160 * or delayed writes.
3161 *
3162 * Returns the number of chars immediately written, or -1
3163 * in case of error.
3164 */
3165int
3166xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
3167 int len;
3168
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003169 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003170 if (str == NULL)
3171 return(-1);
3172 len = strlen(str);
3173
3174 if (len > 0)
3175 return(xmlOutputBufferWrite(out, len, str));
3176 return(len);
3177}
3178
3179/**
3180 * xmlOutputBufferFlush:
3181 * @out: a buffered output
3182 *
3183 * flushes the output I/O channel
3184 *
3185 * Returns the number of byte written or -1 in case of error.
3186 */
3187int
3188xmlOutputBufferFlush(xmlOutputBufferPtr out) {
3189 int nbchars = 0, ret = 0;
3190
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003191 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003192 /*
3193 * first handle encoding stuff.
3194 */
3195 if ((out->conv != NULL) && (out->encoder != NULL)) {
3196 /*
3197 * convert as much as possible to the parser reading buffer.
3198 */
3199 nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
3200 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003201 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003202 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003203 return(-1);
3204 }
3205 }
3206
3207 /*
3208 * second flush the stuff to the I/O channel
3209 */
3210 if ((out->conv != NULL) && (out->encoder != NULL) &&
3211 (out->writecallback != NULL)) {
3212 ret = out->writecallback(out->context,
3213 (const char *)out->conv->content, out->conv->use);
3214 if (ret >= 0)
3215 xmlBufferShrink(out->conv, ret);
3216 } else if (out->writecallback != NULL) {
3217 ret = out->writecallback(out->context,
3218 (const char *)out->buffer->content, out->buffer->use);
3219 if (ret >= 0)
3220 xmlBufferShrink(out->buffer, ret);
3221 }
3222 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003223 xmlIOErr(XML_IO_FLUSH, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003224 out->error = XML_IO_FLUSH;
Owen Taylor3473f882001-02-23 17:55:21 +00003225 return(ret);
3226 }
3227 out->written += ret;
3228
3229#ifdef DEBUG_INPUT
3230 xmlGenericError(xmlGenericErrorContext,
3231 "I/O: flushed %d chars\n", ret);
3232#endif
3233 return(ret);
3234}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003235#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003236
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003237/**
Owen Taylor3473f882001-02-23 17:55:21 +00003238 * xmlParserGetDirectory:
3239 * @filename: the path to a file
3240 *
3241 * lookup the directory for that file
3242 *
3243 * Returns a new allocated string containing the directory, or NULL.
3244 */
3245char *
3246xmlParserGetDirectory(const char *filename) {
3247 char *ret = NULL;
3248 char dir[1024];
3249 char *cur;
3250 char sep = '/';
3251
Igor Zlatkovic9181cc02002-09-29 17:51:06 +00003252#ifdef _WIN32_WCE /* easy way by now ... wince does not have dirs! */
3253 return NULL;
3254#endif
3255
Owen Taylor3473f882001-02-23 17:55:21 +00003256 if (xmlInputCallbackInitialized == 0)
3257 xmlRegisterDefaultInputCallbacks();
3258
3259 if (filename == NULL) return(NULL);
Daniel Veillard3c5ed912002-01-08 10:36:16 +00003260#if defined(WIN32) && !defined(__CYGWIN__)
Owen Taylor3473f882001-02-23 17:55:21 +00003261 sep = '\\';
3262#endif
3263
3264 strncpy(dir, filename, 1023);
3265 dir[1023] = 0;
3266 cur = &dir[strlen(dir)];
3267 while (cur > dir) {
3268 if (*cur == sep) break;
3269 cur --;
3270 }
3271 if (*cur == sep) {
3272 if (cur == dir) dir[1] = 0;
3273 else *cur = 0;
3274 ret = xmlMemStrdup(dir);
3275 } else {
3276 if (getcwd(dir, 1024) != NULL) {
3277 dir[1023] = 0;
3278 ret = xmlMemStrdup(dir);
3279 }
3280 }
3281 return(ret);
3282}
3283
3284/****************************************************************
3285 * *
3286 * External entities loading *
3287 * *
3288 ****************************************************************/
3289
Daniel Veillarda840b692003-10-19 13:35:37 +00003290/**
3291 * xmlCheckHTTPInput:
3292 * @ctxt: an XML parser context
3293 * @ret: an XML parser input
3294 *
3295 * Check an input in case it was created from an HTTP stream, in that
3296 * case it will handle encoding and update of the base URL in case of
3297 * redirection. It also checks for HTTP errors in which case the input
3298 * is cleanly freed up and an appropriate error is raised in context
3299 *
3300 * Returns the input or NULL in case of HTTP error.
3301 */
3302xmlParserInputPtr
3303xmlCheckHTTPInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr ret) {
3304#ifdef LIBXML_HTTP_ENABLED
3305 if ((ret != NULL) && (ret->buf != NULL) &&
3306 (ret->buf->readcallback == xmlIOHTTPRead) &&
3307 (ret->buf->context != NULL)) {
3308 const char *encoding;
3309 const char *redir;
3310 const char *mime;
3311 int code;
3312
3313 code = xmlNanoHTTPReturnCode(ret->buf->context);
3314 if (code >= 400) {
3315 /* fatal error */
3316 if (ret->filename != NULL)
Daniel Veillarde8039df2003-10-27 11:25:13 +00003317 __xmlLoaderErr(ctxt, "failed to load HTTP resource \"%s\"\n",
Daniel Veillarda840b692003-10-19 13:35:37 +00003318 (const char *) ret->filename);
3319 else
Daniel Veillarde8039df2003-10-27 11:25:13 +00003320 __xmlLoaderErr(ctxt, "failed to load HTTP resource\n", NULL);
Daniel Veillarda840b692003-10-19 13:35:37 +00003321 xmlFreeInputStream(ret);
3322 ret = NULL;
3323 } else {
3324
3325 mime = xmlNanoHTTPMimeType(ret->buf->context);
3326 if ((xmlStrstr(BAD_CAST mime, BAD_CAST "/xml")) ||
3327 (xmlStrstr(BAD_CAST mime, BAD_CAST "+xml"))) {
3328 encoding = xmlNanoHTTPEncoding(ret->buf->context);
3329 if (encoding != NULL) {
3330 xmlCharEncodingHandlerPtr handler;
3331
3332 handler = xmlFindCharEncodingHandler(encoding);
3333 if (handler != NULL) {
3334 xmlSwitchInputEncoding(ctxt, ret, handler);
3335 } else {
3336 __xmlErrEncoding(ctxt, XML_ERR_UNKNOWN_ENCODING,
3337 "Unknown encoding %s",
3338 BAD_CAST encoding, NULL);
3339 }
3340 if (ret->encoding == NULL)
3341 ret->encoding = xmlStrdup(BAD_CAST encoding);
3342 }
3343#if 0
3344 } else if (xmlStrstr(BAD_CAST mime, BAD_CAST "html")) {
3345#endif
3346 }
3347 redir = xmlNanoHTTPRedir(ret->buf->context);
3348 if (redir != NULL) {
3349 if (ret->filename != NULL)
3350 xmlFree((xmlChar *) ret->filename);
3351 if (ret->directory != NULL) {
3352 xmlFree((xmlChar *) ret->directory);
3353 ret->directory = NULL;
3354 }
3355 ret->filename =
3356 (char *) xmlStrdup((const xmlChar *) redir);
3357 }
3358 }
3359 }
3360#endif
3361 return(ret);
3362}
3363
Daniel Veillard561b7f82002-03-20 21:55:57 +00003364static int xmlSysIDExists(const char *URL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003365#ifdef HAVE_STAT
3366 int ret;
3367 struct stat info;
3368 const char *path;
3369
3370 if (URL == NULL)
3371 return(0);
3372
Daniel Veillardf4862f02002-09-10 11:13:43 +00003373 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003374#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00003375 path = &URL[17];
3376#else
Daniel Veillard6990bf32001-08-23 21:17:48 +00003377 path = &URL[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00003378#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003379 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003380#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard6990bf32001-08-23 21:17:48 +00003381 path = &URL[8];
3382#else
3383 path = &URL[7];
3384#endif
3385 } else
3386 path = URL;
3387 ret = stat(path, &info);
Daniel Veillard561b7f82002-03-20 21:55:57 +00003388 if (ret == 0)
3389 return(1);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003390#endif
Daniel Veillard561b7f82002-03-20 21:55:57 +00003391 return(0);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003392}
Daniel Veillard6990bf32001-08-23 21:17:48 +00003393
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003394/**
Owen Taylor3473f882001-02-23 17:55:21 +00003395 * xmlDefaultExternalEntityLoader:
3396 * @URL: the URL for the entity to load
3397 * @ID: the System ID for the entity to load
3398 * @ctxt: the context in which the entity is called or NULL
3399 *
3400 * By default we don't load external entitites, yet.
3401 *
3402 * Returns a new allocated xmlParserInputPtr, or NULL.
3403 */
Daniel Veillarda840b692003-10-19 13:35:37 +00003404static xmlParserInputPtr
Owen Taylor3473f882001-02-23 17:55:21 +00003405xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
Daniel Veillarda840b692003-10-19 13:35:37 +00003406 xmlParserCtxtPtr ctxt)
3407{
Owen Taylor3473f882001-02-23 17:55:21 +00003408 xmlParserInputPtr ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003409 xmlChar *resource = NULL;
Daniel Veillarda840b692003-10-19 13:35:37 +00003410
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003411#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003412 xmlCatalogAllow pref;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003413#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003414
3415#ifdef DEBUG_EXTERNAL_ENTITIES
3416 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda840b692003-10-19 13:35:37 +00003417 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00003418#endif
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003419#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillard61b93382003-11-03 14:28:31 +00003420 if ((ctxt != NULL) && (ctxt->options & XML_PARSE_NONET)) {
3421 int options = ctxt->options;
3422
3423 ctxt->options -= XML_PARSE_NONET;
3424 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
3425 ctxt->options = options;
3426 return(ret);
3427 }
3428
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003429 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003430 * If the resource doesn't exists as a file,
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003431 * try to load it from the resource pointed in the catalogs
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003432 */
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003433 pref = xmlCatalogGetDefaults();
3434
Daniel Veillard561b7f82002-03-20 21:55:57 +00003435 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlSysIDExists(URL))) {
Daniel Veillarda840b692003-10-19 13:35:37 +00003436 /*
3437 * Do a local lookup
3438 */
Daniel Veillard42595322004-11-08 10:52:06 +00003439 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
Daniel Veillarda840b692003-10-19 13:35:37 +00003440 ((pref == XML_CATA_ALLOW_ALL) ||
3441 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3442 resource = xmlCatalogLocalResolve(ctxt->catalogs,
3443 (const xmlChar *) ID,
3444 (const xmlChar *) URL);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003445 }
Daniel Veillarda840b692003-10-19 13:35:37 +00003446 /*
3447 * Try a global lookup
3448 */
3449 if ((resource == NULL) &&
3450 ((pref == XML_CATA_ALLOW_ALL) ||
3451 (pref == XML_CATA_ALLOW_GLOBAL))) {
3452 resource = xmlCatalogResolve((const xmlChar *) ID,
3453 (const xmlChar *) URL);
3454 }
3455 if ((resource == NULL) && (URL != NULL))
3456 resource = xmlStrdup((const xmlChar *) URL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003457
Daniel Veillarda840b692003-10-19 13:35:37 +00003458 /*
3459 * TODO: do an URI lookup on the reference
3460 */
3461 if ((resource != NULL)
3462 && (!xmlSysIDExists((const char *) resource))) {
3463 xmlChar *tmp = NULL;
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003464
Daniel Veillard42595322004-11-08 10:52:06 +00003465 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
Daniel Veillarda840b692003-10-19 13:35:37 +00003466 ((pref == XML_CATA_ALLOW_ALL) ||
3467 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3468 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
3469 }
3470 if ((tmp == NULL) &&
3471 ((pref == XML_CATA_ALLOW_ALL) ||
3472 (pref == XML_CATA_ALLOW_GLOBAL))) {
3473 tmp = xmlCatalogResolveURI(resource);
3474 }
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003475
Daniel Veillarda840b692003-10-19 13:35:37 +00003476 if (tmp != NULL) {
3477 xmlFree(resource);
3478 resource = tmp;
3479 }
3480 }
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003481 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003482#endif
3483
3484 if (resource == NULL)
Daniel Veillarda840b692003-10-19 13:35:37 +00003485 resource = (xmlChar *) URL;
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003486
3487 if (resource == NULL) {
Daniel Veillarda840b692003-10-19 13:35:37 +00003488 if (ID == NULL)
3489 ID = "NULL";
Daniel Veillarde8039df2003-10-27 11:25:13 +00003490 __xmlLoaderErr(ctxt, "failed to load external entity \"%s\"\n", ID);
Daniel Veillarda840b692003-10-19 13:35:37 +00003491 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003492 }
Daniel Veillarda840b692003-10-19 13:35:37 +00003493 ret = xmlNewInputFromFile(ctxt, (const char *) resource);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003494 if ((resource != NULL) && (resource != (xmlChar *) URL))
Daniel Veillarda840b692003-10-19 13:35:37 +00003495 xmlFree(resource);
3496 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003497}
3498
3499static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
3500 xmlDefaultExternalEntityLoader;
3501
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003502/**
Owen Taylor3473f882001-02-23 17:55:21 +00003503 * xmlSetExternalEntityLoader:
3504 * @f: the new entity resolver function
3505 *
3506 * Changes the defaultexternal entity resolver function for the application
3507 */
3508void
3509xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
3510 xmlCurrentExternalEntityLoader = f;
3511}
3512
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003513/**
Owen Taylor3473f882001-02-23 17:55:21 +00003514 * xmlGetExternalEntityLoader:
3515 *
3516 * Get the default external entity resolver function for the application
3517 *
3518 * Returns the xmlExternalEntityLoader function pointer
3519 */
3520xmlExternalEntityLoader
3521xmlGetExternalEntityLoader(void) {
3522 return(xmlCurrentExternalEntityLoader);
3523}
3524
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003525/**
Owen Taylor3473f882001-02-23 17:55:21 +00003526 * xmlLoadExternalEntity:
3527 * @URL: the URL for the entity to load
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00003528 * @ID: the Public ID for the entity to load
Owen Taylor3473f882001-02-23 17:55:21 +00003529 * @ctxt: the context in which the entity is called or NULL
3530 *
3531 * Load an external entity, note that the use of this function for
3532 * unparsed entities may generate problems
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003533 * TODO: a more generic External entity API must be designed
Owen Taylor3473f882001-02-23 17:55:21 +00003534 *
3535 * Returns the xmlParserInputPtr or NULL
3536 */
3537xmlParserInputPtr
3538xmlLoadExternalEntity(const char *URL, const char *ID,
3539 xmlParserCtxtPtr ctxt) {
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00003540 if ((URL != NULL) && (xmlSysIDExists(URL) == 0)) {
3541 char *canonicFilename;
3542 xmlParserInputPtr ret;
3543
3544 canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL);
3545 if (canonicFilename == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003546 xmlIOErrMemory("building canonical path\n");
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00003547 return(NULL);
3548 }
3549
3550 ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt);
3551 xmlFree(canonicFilename);
3552 return(ret);
3553 }
Owen Taylor3473f882001-02-23 17:55:21 +00003554 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
3555}
3556
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003557/************************************************************************
3558 * *
3559 * Disabling Network access *
3560 * *
3561 ************************************************************************/
3562
3563#ifdef LIBXML_CATALOG_ENABLED
3564static int
3565xmlNoNetExists(const char *URL)
3566{
3567#ifdef HAVE_STAT
3568 int ret;
3569 struct stat info;
3570 const char *path;
3571
3572 if (URL == NULL)
3573 return (0);
3574
Daniel Veillardf4862f02002-09-10 11:13:43 +00003575 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003576#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00003577 path = &URL[17];
3578#else
3579 path = &URL[16];
3580#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003581 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003582#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003583 path = &URL[8];
3584#else
3585 path = &URL[7];
3586#endif
3587 } else
3588 path = URL;
3589 ret = stat(path, &info);
3590 if (ret == 0)
3591 return (1);
3592#endif
3593 return (0);
3594}
3595#endif
3596
3597/**
3598 * xmlNoNetExternalEntityLoader:
3599 * @URL: the URL for the entity to load
3600 * @ID: the System ID for the entity to load
3601 * @ctxt: the context in which the entity is called or NULL
3602 *
3603 * A specific entity loader disabling network accesses, though still
3604 * allowing local catalog accesses for resolution.
3605 *
3606 * Returns a new allocated xmlParserInputPtr, or NULL.
3607 */
3608xmlParserInputPtr
3609xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
3610 xmlParserCtxtPtr ctxt) {
3611 xmlParserInputPtr input = NULL;
3612 xmlChar *resource = NULL;
3613
3614#ifdef LIBXML_CATALOG_ENABLED
3615 xmlCatalogAllow pref;
3616
3617 /*
3618 * If the resource doesn't exists as a file,
3619 * try to load it from the resource pointed in the catalogs
3620 */
3621 pref = xmlCatalogGetDefaults();
3622
3623 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
3624 /*
3625 * Do a local lookup
3626 */
Daniel Veillard42595322004-11-08 10:52:06 +00003627 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003628 ((pref == XML_CATA_ALLOW_ALL) ||
3629 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3630 resource = xmlCatalogLocalResolve(ctxt->catalogs,
3631 (const xmlChar *)ID,
3632 (const xmlChar *)URL);
3633 }
3634 /*
3635 * Try a global lookup
3636 */
3637 if ((resource == NULL) &&
3638 ((pref == XML_CATA_ALLOW_ALL) ||
3639 (pref == XML_CATA_ALLOW_GLOBAL))) {
3640 resource = xmlCatalogResolve((const xmlChar *)ID,
3641 (const xmlChar *)URL);
3642 }
3643 if ((resource == NULL) && (URL != NULL))
3644 resource = xmlStrdup((const xmlChar *) URL);
3645
3646 /*
3647 * TODO: do an URI lookup on the reference
3648 */
3649 if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
3650 xmlChar *tmp = NULL;
3651
Daniel Veillard42595322004-11-08 10:52:06 +00003652 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003653 ((pref == XML_CATA_ALLOW_ALL) ||
3654 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3655 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
3656 }
3657 if ((tmp == NULL) &&
3658 ((pref == XML_CATA_ALLOW_ALL) ||
3659 (pref == XML_CATA_ALLOW_GLOBAL))) {
3660 tmp = xmlCatalogResolveURI(resource);
3661 }
3662
3663 if (tmp != NULL) {
3664 xmlFree(resource);
3665 resource = tmp;
3666 }
3667 }
3668 }
3669#endif
3670 if (resource == NULL)
3671 resource = (xmlChar *) URL;
3672
3673 if (resource != NULL) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003674 if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
3675 (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003676 xmlIOErr(XML_IO_NETWORK_ATTEMPT, (const char *) resource);
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003677 if (resource != (xmlChar *) URL)
3678 xmlFree(resource);
3679 return(NULL);
3680 }
3681 }
3682 input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
3683 if (resource != (xmlChar *) URL)
3684 xmlFree(resource);
3685 return(input);
3686}
3687