blob: a0701e248d859f55ba41b80b1cd52a7408d16c48 [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{
Daniel Veillard36e5cd52004-11-02 14:52:23 +0000554 if (path == NULL)
555 return(0);
556
Owen Taylor3473f882001-02-23 17:55:21 +0000557#ifdef HAVE_STAT
Owen Taylor3473f882001-02-23 17:55:21 +0000558 struct stat stat_buffer;
559
560 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
569 return 1;
570}
571
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000572static int
Owen Taylor3473f882001-02-23 17:55:21 +0000573xmlNop(void) {
574 return(0);
575}
576
577/**
Owen Taylor3473f882001-02-23 17:55:21 +0000578 * xmlFdRead:
579 * @context: the I/O context
580 * @buffer: where to drop data
581 * @len: number of bytes to read
582 *
583 * Read @len bytes to @buffer from the I/O channel.
584 *
585 * Returns the number of bytes written
586 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000587static int
Owen Taylor3473f882001-02-23 17:55:21 +0000588xmlFdRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000589 int ret;
590
591 ret = read((int) (long) context, &buffer[0], len);
592 if (ret < 0) xmlIOErr(0, "read()");
593 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000594}
595
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000596#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000597/**
598 * xmlFdWrite:
599 * @context: the I/O context
600 * @buffer: where to get data
601 * @len: number of bytes to write
602 *
603 * Write @len bytes from @buffer to the I/O channel.
604 *
605 * Returns the number of bytes written
606 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000607static int
Owen Taylor3473f882001-02-23 17:55:21 +0000608xmlFdWrite (void * context, const char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000609 int ret;
610
611 ret = write((int) (long) context, &buffer[0], len);
612 if (ret < 0) xmlIOErr(0, "write()");
613 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000614}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000615#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000616
617/**
618 * xmlFdClose:
619 * @context: the I/O context
620 *
621 * Close an I/O channel
Daniel Veillardf012a642001-07-23 19:10:52 +0000622 *
623 * Returns 0 in case of success and error code otherwise
Owen Taylor3473f882001-02-23 17:55:21 +0000624 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000625static int
Owen Taylor3473f882001-02-23 17:55:21 +0000626xmlFdClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000627 int ret;
628 ret = close((int) (long) context);
629 if (ret < 0) xmlIOErr(0, "close()");
630 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000631}
632
633/**
634 * xmlFileMatch:
635 * @filename: the URI for matching
636 *
637 * input from FILE *
638 *
639 * Returns 1 if matches, 0 otherwise
640 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000641int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000642xmlFileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000643 return(1);
644}
645
646/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000647 * xmlFileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +0000648 * @filename: the URI for matching
649 *
650 * input from FILE *, supports compressed input
651 * if @filename is " " then the standard input is used
652 *
653 * Returns an I/O context or NULL in case of error
654 */
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000655static void *
656xmlFileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +0000657 const char *path = NULL;
658 FILE *fd;
659
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000660 if (filename == NULL)
661 return(NULL);
662
Owen Taylor3473f882001-02-23 17:55:21 +0000663 if (!strcmp(filename, "-")) {
664 fd = stdin;
665 return((void *) fd);
666 }
667
Daniel Veillardf4862f02002-09-10 11:13:43 +0000668 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000669#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000670 path = &filename[17];
671#else
Owen Taylor3473f882001-02-23 17:55:21 +0000672 path = &filename[16];
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000673#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000674 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000675#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000676 path = &filename[8];
677#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000678 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000679#endif
680 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000681 path = filename;
682
683 if (path == NULL)
684 return(NULL);
685 if (!xmlCheckFilename(path))
686 return(NULL);
687
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000688#if defined(WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
Owen Taylor3473f882001-02-23 17:55:21 +0000689 fd = fopen(path, "rb");
690#else
691 fd = fopen(path, "r");
692#endif /* WIN32 */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000693 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +0000694 return((void *) fd);
695}
696
697/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000698 * xmlFileOpen:
699 * @filename: the URI for matching
700 *
701 * Wrapper around xmlFileOpen_real that try it with an unescaped
702 * version of @filename, if this fails fallback to @filename
Daniel Veillard71531f32003-02-05 13:19:53 +0000703 *
704 * Returns a handler or NULL in case or failure
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000705 */
706void *
707xmlFileOpen (const char *filename) {
708 char *unescaped;
709 void *retval;
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000710
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000711 unescaped = xmlURIUnescapeString(filename, 0, NULL);
712 if (unescaped != NULL) {
713 retval = xmlFileOpen_real(unescaped);
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000714 xmlFree(unescaped);
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000715 } else {
716 retval = xmlFileOpen_real(filename);
717 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000718 return retval;
719}
720
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000721#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000722/**
Owen Taylor3473f882001-02-23 17:55:21 +0000723 * xmlFileOpenW:
724 * @filename: the URI for matching
725 *
726 * output to from FILE *,
727 * if @filename is "-" then the standard output is used
728 *
729 * Returns an I/O context or NULL in case of error
730 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000731static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000732xmlFileOpenW (const char *filename) {
733 const char *path = NULL;
734 FILE *fd;
735
736 if (!strcmp(filename, "-")) {
737 fd = stdout;
738 return((void *) fd);
739 }
740
Daniel Veillardf4862f02002-09-10 11:13:43 +0000741 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000742#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000743 path = &filename[17];
744#else
Owen Taylor3473f882001-02-23 17:55:21 +0000745 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000746#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000747 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000748#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000749 path = &filename[8];
750#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000751 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000752#endif
753 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000754 path = filename;
755
756 if (path == NULL)
757 return(NULL);
758
Daniel Veillardcbbd78d2003-07-20 15:21:30 +0000759 fd = fopen(path, "wb");
Daniel Veillard05d987b2003-10-08 11:54:57 +0000760 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +0000761 return((void *) fd);
762}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000763#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000764
765/**
766 * xmlFileRead:
767 * @context: the I/O context
768 * @buffer: where to drop data
769 * @len: number of bytes to write
770 *
771 * Read @len bytes to @buffer from the I/O channel.
772 *
773 * Returns the number of bytes written
774 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000775int
Owen Taylor3473f882001-02-23 17:55:21 +0000776xmlFileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000777 int ret;
778 ret = fread(&buffer[0], 1, len, (FILE *) context);
779 if (ret < 0) xmlIOErr(0, "fread()");
780 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000781}
782
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000783#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000784/**
785 * xmlFileWrite:
786 * @context: the I/O context
787 * @buffer: where to drop data
788 * @len: number of bytes to write
789 *
790 * Write @len bytes from @buffer to the I/O channel.
791 *
792 * Returns the number of bytes written
793 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000794static int
Owen Taylor3473f882001-02-23 17:55:21 +0000795xmlFileWrite (void * context, const char * buffer, int len) {
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000796 int items;
797
798 items = fwrite(&buffer[0], len, 1, (FILE *) context);
Daniel Veillard97bf4d02003-10-08 18:58:28 +0000799 if ((items == 0) && (ferror((FILE *) context))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000800 xmlIOErr(0, "fwrite()");
Daniel Veillard97bf4d02003-10-08 18:58:28 +0000801 return(-1);
802 }
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000803 return(items * len);
Owen Taylor3473f882001-02-23 17:55:21 +0000804}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000805#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000806
807/**
808 * xmlFileClose:
809 * @context: the I/O context
810 *
811 * Close an I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000812 *
813 * Returns 0 or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +0000814 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000815int
Owen Taylor3473f882001-02-23 17:55:21 +0000816xmlFileClose (void * context) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000817 FILE *fil;
Daniel Veillard05d987b2003-10-08 11:54:57 +0000818 int ret;
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000819
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000820 if (context == NULL)
821 return(-1);
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000822 fil = (FILE *) context;
Daniel Veillard500a1de2004-03-22 15:22:58 +0000823 if ((fil == stdout) || (fil == stderr)) {
824 ret = fflush(fil);
825 if (ret < 0)
826 xmlIOErr(0, "fflush()");
827 return(0);
828 }
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000829 if (fil == stdin)
830 return(0);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000831 ret = ( fclose((FILE *) context) == EOF ) ? -1 : 0;
832 if (ret < 0)
833 xmlIOErr(0, "fclose()");
834 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000835}
836
837/**
838 * xmlFileFlush:
839 * @context: the I/O context
840 *
841 * Flush an I/O channel
842 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000843static int
Owen Taylor3473f882001-02-23 17:55:21 +0000844xmlFileFlush (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000845 int ret;
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000846
847 if (context == NULL)
848 return(-1);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000849 ret = ( fflush((FILE *) context) == EOF ) ? -1 : 0;
850 if (ret < 0)
851 xmlIOErr(0, "fflush()");
852 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000853}
854
855#ifdef HAVE_ZLIB_H
856/************************************************************************
857 * *
858 * I/O for compressed file accesses *
859 * *
860 ************************************************************************/
861/**
862 * xmlGzfileMatch:
863 * @filename: the URI for matching
864 *
865 * input from compressed file test
866 *
867 * Returns 1 if matches, 0 otherwise
868 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000869static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000870xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000871 return(1);
872}
873
874/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000875 * xmlGzfileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +0000876 * @filename: the URI for matching
877 *
878 * input from compressed file open
879 * if @filename is " " then the standard input is used
880 *
881 * Returns an I/O context or NULL in case of error
882 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000883static void *
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000884xmlGzfileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +0000885 const char *path = NULL;
886 gzFile fd;
887
888 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000889 fd = gzdopen(dup(0), "rb");
Owen Taylor3473f882001-02-23 17:55:21 +0000890 return((void *) fd);
891 }
892
Daniel Veillardf4862f02002-09-10 11:13:43 +0000893 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000894#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000895 path = &filename[17];
896#else
Owen Taylor3473f882001-02-23 17:55:21 +0000897 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000898#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000899 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000900#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000901 path = &filename[8];
902#else
Owen Taylor3473f882001-02-23 17:55:21 +0000903 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000904#endif
905 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000906 path = filename;
907
908 if (path == NULL)
909 return(NULL);
910 if (!xmlCheckFilename(path))
911 return(NULL);
912
913 fd = gzopen(path, "rb");
914 return((void *) fd);
915}
916
917/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000918 * xmlGzfileOpen:
919 * @filename: the URI for matching
920 *
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +0000921 * Wrapper around xmlGzfileOpen if the open fais, it will
922 * try to unescape @filename
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000923 */
924static void *
925xmlGzfileOpen (const char *filename) {
926 char *unescaped;
927 void *retval;
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +0000928
929 retval = xmlGzfileOpen_real(filename);
930 if (retval == NULL) {
931 unescaped = xmlURIUnescapeString(filename, 0, NULL);
932 if (unescaped != NULL) {
933 retval = xmlGzfileOpen_real(unescaped);
934 }
935 xmlFree(unescaped);
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000936 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000937 return retval;
938}
939
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000940#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000941/**
Owen Taylor3473f882001-02-23 17:55:21 +0000942 * xmlGzfileOpenW:
943 * @filename: the URI for matching
944 * @compression: the compression factor (0 - 9 included)
945 *
946 * input from compressed file open
947 * if @filename is " " then the standard input is used
948 *
949 * Returns an I/O context or NULL in case of error
950 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000951static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000952xmlGzfileOpenW (const char *filename, int compression) {
953 const char *path = NULL;
954 char mode[15];
955 gzFile fd;
956
Aleksey Sanin49cc9752002-06-14 17:07:10 +0000957 snprintf(mode, sizeof(mode), "wb%d", compression);
Owen Taylor3473f882001-02-23 17:55:21 +0000958 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000959 fd = gzdopen(dup(1), mode);
Owen Taylor3473f882001-02-23 17:55:21 +0000960 return((void *) fd);
961 }
962
Daniel Veillardf4862f02002-09-10 11:13:43 +0000963 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000964#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000965 path = &filename[17];
966#else
Owen Taylor3473f882001-02-23 17:55:21 +0000967 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000968#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000969 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000970#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000971 path = &filename[8];
972#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000973 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000974#endif
975 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000976 path = filename;
977
978 if (path == NULL)
979 return(NULL);
980
981 fd = gzopen(path, mode);
982 return((void *) fd);
983}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000984#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000985
986/**
987 * xmlGzfileRead:
988 * @context: the I/O context
989 * @buffer: where to drop data
990 * @len: number of bytes to write
991 *
992 * Read @len bytes to @buffer from the compressed I/O channel.
993 *
994 * Returns the number of bytes written
995 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000996static int
Owen Taylor3473f882001-02-23 17:55:21 +0000997xmlGzfileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000998 int ret;
999
1000 ret = gzread((gzFile) context, &buffer[0], len);
1001 if (ret < 0) xmlIOErr(0, "gzread()");
1002 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001003}
1004
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001005#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001006/**
1007 * xmlGzfileWrite:
1008 * @context: the I/O context
1009 * @buffer: where to drop data
1010 * @len: number of bytes to write
1011 *
1012 * Write @len bytes from @buffer to the compressed I/O channel.
1013 *
1014 * Returns the number of bytes written
1015 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001016static int
Owen Taylor3473f882001-02-23 17:55:21 +00001017xmlGzfileWrite (void * context, const char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001018 int ret;
1019
1020 ret = gzwrite((gzFile) context, (char *) &buffer[0], len);
1021 if (ret < 0) xmlIOErr(0, "gzwrite()");
1022 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001023}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001024#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001025
1026/**
1027 * xmlGzfileClose:
1028 * @context: the I/O context
1029 *
1030 * Close a compressed I/O channel
1031 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001032static int
Owen Taylor3473f882001-02-23 17:55:21 +00001033xmlGzfileClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001034 int ret;
1035
1036 ret = (gzclose((gzFile) context) == Z_OK ) ? 0 : -1;
1037 if (ret < 0) xmlIOErr(0, "gzclose()");
1038 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001039}
1040#endif /* HAVE_ZLIB_H */
1041
1042#ifdef LIBXML_HTTP_ENABLED
1043/************************************************************************
1044 * *
1045 * I/O for HTTP file accesses *
1046 * *
1047 ************************************************************************/
Daniel Veillardf012a642001-07-23 19:10:52 +00001048
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001049#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001050typedef struct xmlIOHTTPWriteCtxt_
1051{
1052 int compression;
1053
1054 char * uri;
1055
1056 void * doc_buff;
1057
1058} xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr;
1059
1060#ifdef HAVE_ZLIB_H
1061
1062#define DFLT_WBITS ( -15 )
1063#define DFLT_MEM_LVL ( 8 )
1064#define GZ_MAGIC1 ( 0x1f )
1065#define GZ_MAGIC2 ( 0x8b )
1066#define LXML_ZLIB_OS_CODE ( 0x03 )
1067#define INIT_HTTP_BUFF_SIZE ( 32768 )
1068#define DFLT_ZLIB_RATIO ( 5 )
1069
1070/*
1071** Data structure and functions to work with sending compressed data
1072** via HTTP.
1073*/
1074
1075typedef struct xmlZMemBuff_
1076{
1077 unsigned long size;
1078 unsigned long crc;
1079
1080 unsigned char * zbuff;
1081 z_stream zctrl;
1082
1083} xmlZMemBuff, *xmlZMemBuffPtr;
1084
1085/**
1086 * append_reverse_ulong
1087 * @buff: Compressed memory buffer
1088 * @data: Unsigned long to append
1089 *
1090 * Append a unsigned long in reverse byte order to the end of the
1091 * memory buffer.
1092 */
1093static void
1094append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) {
1095
1096 int idx;
1097
1098 if ( buff == NULL )
1099 return;
1100
1101 /*
1102 ** This is plagiarized from putLong in gzio.c (zlib source) where
1103 ** the number "4" is hardcoded. If zlib is ever patched to
1104 ** support 64 bit file sizes, this code would need to be patched
1105 ** as well.
1106 */
1107
1108 for ( idx = 0; idx < 4; idx++ ) {
1109 *buff->zctrl.next_out = ( data & 0xff );
1110 data >>= 8;
1111 buff->zctrl.next_out++;
1112 }
1113
1114 return;
1115}
1116
1117/**
1118 *
1119 * xmlFreeZMemBuff
1120 * @buff: The memory buffer context to clear
1121 *
1122 * Release all the resources associated with the compressed memory buffer.
1123 */
1124static void
1125xmlFreeZMemBuff( xmlZMemBuffPtr buff ) {
William M. Brack78637da2003-07-31 14:47:38 +00001126
1127#ifdef DEBUG_HTTP
Daniel Veillardf012a642001-07-23 19:10:52 +00001128 int z_err;
William M. Brack78637da2003-07-31 14:47:38 +00001129#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001130
1131 if ( buff == NULL )
1132 return;
1133
1134 xmlFree( buff->zbuff );
Daniel Veillardf012a642001-07-23 19:10:52 +00001135#ifdef DEBUG_HTTP
William M. Brack78637da2003-07-31 14:47:38 +00001136 z_err = deflateEnd( &buff->zctrl );
Daniel Veillardf012a642001-07-23 19:10:52 +00001137 if ( z_err != Z_OK )
1138 xmlGenericError( xmlGenericErrorContext,
1139 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
1140 z_err );
William M. Brack78637da2003-07-31 14:47:38 +00001141#else
1142 deflateEnd( &buff->zctrl );
William M. Brack779af002003-08-01 15:55:39 +00001143#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001144
1145 xmlFree( buff );
1146 return;
1147}
1148
1149/**
1150 * xmlCreateZMemBuff
1151 *@compression: Compression value to use
1152 *
1153 * Create a memory buffer to hold the compressed XML document. The
1154 * compressed document in memory will end up being identical to what
1155 * would be created if gzopen/gzwrite/gzclose were being used to
1156 * write the document to disk. The code for the header/trailer data to
1157 * the compression is plagiarized from the zlib source files.
1158 */
1159static void *
1160xmlCreateZMemBuff( int compression ) {
1161
1162 int z_err;
1163 int hdr_lgth;
1164 xmlZMemBuffPtr buff = NULL;
1165
1166 if ( ( compression < 1 ) || ( compression > 9 ) )
1167 return ( NULL );
1168
1169 /* Create the control and data areas */
1170
1171 buff = xmlMalloc( sizeof( xmlZMemBuff ) );
1172 if ( buff == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001173 xmlIOErrMemory("creating buffer context");
Daniel Veillardf012a642001-07-23 19:10:52 +00001174 return ( NULL );
1175 }
1176
1177 (void)memset( buff, 0, sizeof( xmlZMemBuff ) );
1178 buff->size = INIT_HTTP_BUFF_SIZE;
1179 buff->zbuff = xmlMalloc( buff->size );
1180 if ( buff->zbuff == NULL ) {
1181 xmlFreeZMemBuff( buff );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001182 xmlIOErrMemory("creating buffer");
Daniel Veillardf012a642001-07-23 19:10:52 +00001183 return ( NULL );
1184 }
1185
1186 z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
1187 DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
1188 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001189 xmlChar msg[500];
Daniel Veillardf012a642001-07-23 19:10:52 +00001190 xmlFreeZMemBuff( buff );
1191 buff = NULL;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001192 xmlStrPrintf(msg, 500,
1193 (const xmlChar *) "xmlCreateZMemBuff: %s %d\n",
1194 "Error initializing compression context. ZLIB error:",
1195 z_err );
1196 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001197 return ( NULL );
1198 }
1199
1200 /* Set the header data. The CRC will be needed for the trailer */
Daniel Veillardf012a642001-07-23 19:10:52 +00001201 buff->crc = crc32( 0L, Z_NULL, 0 );
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001202 hdr_lgth = snprintf( (char *)buff->zbuff, buff->size,
1203 "%c%c%c%c%c%c%c%c%c%c",
Daniel Veillardf012a642001-07-23 19:10:52 +00001204 GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED,
1205 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE );
1206 buff->zctrl.next_out = buff->zbuff + hdr_lgth;
1207 buff->zctrl.avail_out = buff->size - hdr_lgth;
1208
1209 return ( buff );
1210}
1211
1212/**
1213 * xmlZMemBuffExtend
1214 * @buff: Buffer used to compress and consolidate data.
1215 * @ext_amt: Number of bytes to extend the buffer.
1216 *
1217 * Extend the internal buffer used to store the compressed data by the
1218 * specified amount.
1219 *
1220 * Returns 0 on success or -1 on failure to extend the buffer. On failure
1221 * the original buffer still exists at the original size.
1222 */
1223static int
1224xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) {
1225
1226 int rc = -1;
1227 size_t new_size;
1228 size_t cur_used;
1229
1230 unsigned char * tmp_ptr = NULL;
1231
1232 if ( buff == NULL )
1233 return ( -1 );
1234
1235 else if ( ext_amt == 0 )
1236 return ( 0 );
1237
1238 cur_used = buff->zctrl.next_out - buff->zbuff;
1239 new_size = buff->size + ext_amt;
1240
1241#ifdef DEBUG_HTTP
1242 if ( cur_used > new_size )
1243 xmlGenericError( xmlGenericErrorContext,
1244 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
1245 "Buffer overwrite detected during compressed memory",
1246 "buffer extension. Overflowed by",
1247 (cur_used - new_size ) );
1248#endif
1249
1250 tmp_ptr = xmlRealloc( buff->zbuff, new_size );
1251 if ( tmp_ptr != NULL ) {
1252 rc = 0;
1253 buff->size = new_size;
1254 buff->zbuff = tmp_ptr;
1255 buff->zctrl.next_out = tmp_ptr + cur_used;
1256 buff->zctrl.avail_out = new_size - cur_used;
1257 }
1258 else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001259 xmlChar msg[500];
1260 xmlStrPrintf(msg, 500,
1261 (const xmlChar *) "xmlZMemBuffExtend: %s %lu bytes.\n",
1262 "Allocation failure extending output buffer to",
1263 new_size );
1264 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001265 }
1266
1267 return ( rc );
1268}
1269
1270/**
1271 * xmlZMemBuffAppend
1272 * @buff: Buffer used to compress and consolidate data
1273 * @src: Uncompressed source content to append to buffer
1274 * @len: Length of source data to append to buffer
1275 *
1276 * Compress and append data to the internal buffer. The data buffer
1277 * will be expanded if needed to store the additional data.
1278 *
1279 * Returns the number of bytes appended to the buffer or -1 on error.
1280 */
1281static int
1282xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) {
1283
1284 int z_err;
1285 size_t min_accept;
1286
1287 if ( ( buff == NULL ) || ( src == NULL ) )
1288 return ( -1 );
1289
1290 buff->zctrl.avail_in = len;
1291 buff->zctrl.next_in = (unsigned char *)src;
1292 while ( buff->zctrl.avail_in > 0 ) {
1293 /*
1294 ** Extend the buffer prior to deflate call if a reasonable amount
1295 ** of output buffer space is not available.
1296 */
1297 min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO;
1298 if ( buff->zctrl.avail_out <= min_accept ) {
1299 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1300 return ( -1 );
1301 }
1302
1303 z_err = deflate( &buff->zctrl, Z_NO_FLUSH );
1304 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001305 xmlChar msg[500];
1306 xmlStrPrintf(msg, 500,
1307 (const xmlChar *) "xmlZMemBuffAppend: %s %d %s - %d",
Daniel Veillardf012a642001-07-23 19:10:52 +00001308 "Compression error while appending",
1309 len, "bytes to buffer. ZLIB error", z_err );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001310 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001311 return ( -1 );
1312 }
1313 }
1314
1315 buff->crc = crc32( buff->crc, (unsigned char *)src, len );
1316
1317 return ( len );
1318}
1319
1320/**
1321 * xmlZMemBuffGetContent
1322 * @buff: Compressed memory content buffer
1323 * @data_ref: Pointer reference to point to compressed content
1324 *
1325 * Flushes the compression buffers, appends gzip file trailers and
1326 * returns the compressed content and length of the compressed data.
1327 * NOTE: The gzip trailer code here is plagiarized from zlib source.
1328 *
1329 * Returns the length of the compressed data or -1 on error.
1330 */
1331static int
1332xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) {
1333
1334 int zlgth = -1;
1335 int z_err;
1336
1337 if ( ( buff == NULL ) || ( data_ref == NULL ) )
1338 return ( -1 );
1339
1340 /* Need to loop until compression output buffers are flushed */
1341
1342 do
1343 {
1344 z_err = deflate( &buff->zctrl, Z_FINISH );
1345 if ( z_err == Z_OK ) {
1346 /* In this case Z_OK means more buffer space needed */
1347
1348 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1349 return ( -1 );
1350 }
1351 }
1352 while ( z_err == Z_OK );
1353
1354 /* If the compression state is not Z_STREAM_END, some error occurred */
1355
1356 if ( z_err == Z_STREAM_END ) {
1357
1358 /* Need to append the gzip data trailer */
1359
1360 if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) {
1361 if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 )
1362 return ( -1 );
1363 }
1364
1365 /*
1366 ** For whatever reason, the CRC and length data are pushed out
1367 ** in reverse byte order. So a memcpy can't be used here.
1368 */
1369
1370 append_reverse_ulong( buff, buff->crc );
1371 append_reverse_ulong( buff, buff->zctrl.total_in );
1372
1373 zlgth = buff->zctrl.next_out - buff->zbuff;
1374 *data_ref = (char *)buff->zbuff;
1375 }
1376
Daniel Veillard05d987b2003-10-08 11:54:57 +00001377 else {
1378 xmlChar msg[500];
1379 xmlStrPrintf(msg, 500,
1380 (const xmlChar *) "xmlZMemBuffGetContent: %s - %d\n",
1381 "Error flushing zlib buffers. Error code", z_err );
1382 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1383 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001384
1385 return ( zlgth );
1386}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001387#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001388#endif /* HAVE_ZLIB_H */
1389
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001390#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001391/**
1392 * xmlFreeHTTPWriteCtxt
1393 * @ctxt: Context to cleanup
1394 *
1395 * Free allocated memory and reclaim system resources.
1396 *
1397 * No return value.
1398 */
1399static void
1400xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt )
1401{
1402 if ( ctxt->uri != NULL )
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001403 xmlFree( ctxt->uri );
Daniel Veillardf012a642001-07-23 19:10:52 +00001404
1405 if ( ctxt->doc_buff != NULL ) {
1406
1407#ifdef HAVE_ZLIB_H
1408 if ( ctxt->compression > 0 ) {
1409 xmlFreeZMemBuff( ctxt->doc_buff );
1410 }
1411 else
1412#endif
1413 {
1414 xmlOutputBufferClose( ctxt->doc_buff );
1415 }
1416 }
1417
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001418 xmlFree( ctxt );
Daniel Veillardf012a642001-07-23 19:10:52 +00001419 return;
1420}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001421#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001422
1423
Owen Taylor3473f882001-02-23 17:55:21 +00001424/**
1425 * xmlIOHTTPMatch:
1426 * @filename: the URI for matching
1427 *
1428 * check if the URI matches an HTTP one
1429 *
1430 * Returns 1 if matches, 0 otherwise
1431 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001432int
Owen Taylor3473f882001-02-23 17:55:21 +00001433xmlIOHTTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001434 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "http://", 7))
Owen Taylor3473f882001-02-23 17:55:21 +00001435 return(1);
1436 return(0);
1437}
1438
1439/**
1440 * xmlIOHTTPOpen:
1441 * @filename: the URI for matching
1442 *
1443 * open an HTTP I/O channel
1444 *
1445 * Returns an I/O context or NULL in case of error
1446 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001447void *
Owen Taylor3473f882001-02-23 17:55:21 +00001448xmlIOHTTPOpen (const char *filename) {
1449 return(xmlNanoHTTPOpen(filename, NULL));
1450}
1451
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001452#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001453/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001454 * xmlIOHTTPOpenW:
Daniel Veillardf012a642001-07-23 19:10:52 +00001455 * @post_uri: The destination URI for the document
1456 * @compression: The compression desired for the document.
1457 *
1458 * Open a temporary buffer to collect the document for a subsequent HTTP POST
1459 * request. Non-static as is called from the output buffer creation routine.
1460 *
1461 * Returns an I/O context or NULL in case of error.
1462 */
1463
1464void *
Daniel Veillard572577e2002-01-18 16:23:55 +00001465xmlIOHTTPOpenW(const char *post_uri, int compression)
1466{
Daniel Veillardf012a642001-07-23 19:10:52 +00001467
Daniel Veillard572577e2002-01-18 16:23:55 +00001468 xmlIOHTTPWriteCtxtPtr ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001469
Daniel Veillard572577e2002-01-18 16:23:55 +00001470 if (post_uri == NULL)
1471 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001472
Daniel Veillard572577e2002-01-18 16:23:55 +00001473 ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt));
1474 if (ctxt == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001475 xmlIOErrMemory("creating HTTP output context");
Daniel Veillard572577e2002-01-18 16:23:55 +00001476 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001477 }
1478
Daniel Veillard572577e2002-01-18 16:23:55 +00001479 (void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt));
Daniel Veillardf012a642001-07-23 19:10:52 +00001480
Daniel Veillard572577e2002-01-18 16:23:55 +00001481 ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri);
1482 if (ctxt->uri == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001483 xmlIOErrMemory("copying URI");
Daniel Veillard572577e2002-01-18 16:23:55 +00001484 xmlFreeHTTPWriteCtxt(ctxt);
1485 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001486 }
1487
1488 /*
Daniel Veillard572577e2002-01-18 16:23:55 +00001489 * ** Since the document length is required for an HTTP post,
1490 * ** need to put the document into a buffer. A memory buffer
1491 * ** is being used to avoid pushing the data to disk and back.
1492 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001493
1494#ifdef HAVE_ZLIB_H
Daniel Veillard572577e2002-01-18 16:23:55 +00001495 if ((compression > 0) && (compression <= 9)) {
1496
1497 ctxt->compression = compression;
1498 ctxt->doc_buff = xmlCreateZMemBuff(compression);
1499 } else
Daniel Veillardf012a642001-07-23 19:10:52 +00001500#endif
1501 {
Daniel Veillard572577e2002-01-18 16:23:55 +00001502 /* Any character conversions should have been done before this */
Daniel Veillardf012a642001-07-23 19:10:52 +00001503
Daniel Veillard572577e2002-01-18 16:23:55 +00001504 ctxt->doc_buff = xmlAllocOutputBuffer(NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001505 }
1506
Daniel Veillard572577e2002-01-18 16:23:55 +00001507 if (ctxt->doc_buff == NULL) {
1508 xmlFreeHTTPWriteCtxt(ctxt);
1509 ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001510 }
1511
Daniel Veillard572577e2002-01-18 16:23:55 +00001512 return (ctxt);
Daniel Veillardf012a642001-07-23 19:10:52 +00001513}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001514#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001515
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001516#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001517/**
1518 * xmlIOHTTPDfltOpenW
1519 * @post_uri: The destination URI for this document.
1520 *
1521 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
1522 * HTTP post command. This function should generally not be used as
1523 * the open callback is short circuited in xmlOutputBufferCreateFile.
1524 *
1525 * Returns a pointer to the new IO context.
1526 */
1527static void *
1528xmlIOHTTPDfltOpenW( const char * post_uri ) {
1529 return ( xmlIOHTTPOpenW( post_uri, 0 ) );
1530}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001531#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001532
1533/**
Owen Taylor3473f882001-02-23 17:55:21 +00001534 * xmlIOHTTPRead:
1535 * @context: the I/O context
1536 * @buffer: where to drop data
1537 * @len: number of bytes to write
1538 *
1539 * Read @len bytes to @buffer from the I/O channel.
1540 *
1541 * Returns the number of bytes written
1542 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001543int
Owen Taylor3473f882001-02-23 17:55:21 +00001544xmlIOHTTPRead(void * context, char * buffer, int len) {
1545 return(xmlNanoHTTPRead(context, &buffer[0], len));
1546}
1547
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001548#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001549/**
Daniel Veillardf012a642001-07-23 19:10:52 +00001550 * xmlIOHTTPWrite
1551 * @context: previously opened writing context
1552 * @buffer: data to output to temporary buffer
1553 * @len: bytes to output
1554 *
1555 * Collect data from memory buffer into a temporary file for later
1556 * processing.
1557 *
1558 * Returns number of bytes written.
1559 */
1560
1561static int
1562xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
1563
1564 xmlIOHTTPWriteCtxtPtr ctxt = context;
1565
1566 if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
1567 return ( -1 );
1568
1569 if ( len > 0 ) {
1570
1571 /* Use gzwrite or fwrite as previously setup in the open call */
1572
1573#ifdef HAVE_ZLIB_H
1574 if ( ctxt->compression > 0 )
1575 len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len );
1576
1577 else
1578#endif
1579 len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
1580
1581 if ( len < 0 ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001582 xmlChar msg[500];
1583 xmlStrPrintf(msg, 500,
1584 (const xmlChar *) "xmlIOHTTPWrite: %s\n%s '%s'.\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001585 "Error appending to internal buffer.",
1586 "Error sending document to URI",
1587 ctxt->uri );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001588 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001589 }
1590 }
1591
1592 return ( len );
1593}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001594#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001595
1596
1597/**
Owen Taylor3473f882001-02-23 17:55:21 +00001598 * xmlIOHTTPClose:
1599 * @context: the I/O context
1600 *
1601 * Close an HTTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001602 *
1603 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00001604 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001605int
Owen Taylor3473f882001-02-23 17:55:21 +00001606xmlIOHTTPClose (void * context) {
1607 xmlNanoHTTPClose(context);
Daniel Veillardf012a642001-07-23 19:10:52 +00001608 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001609}
Daniel Veillardf012a642001-07-23 19:10:52 +00001610
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001611#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001612/**
1613 * xmlIOHTTCloseWrite
1614 * @context: The I/O context
1615 * @http_mthd: The HTTP method to be used when sending the data
1616 *
1617 * Close the transmit HTTP I/O channel and actually send the data.
1618 */
1619static int
1620xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
1621
1622 int close_rc = -1;
1623 int http_rtn = 0;
1624 int content_lgth = 0;
1625 xmlIOHTTPWriteCtxtPtr ctxt = context;
1626
1627 char * http_content = NULL;
1628 char * content_encoding = NULL;
1629 char * content_type = (char *) "text/xml";
1630 void * http_ctxt = NULL;
1631
1632 if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
1633 return ( -1 );
1634
1635 /* Retrieve the content from the appropriate buffer */
1636
1637#ifdef HAVE_ZLIB_H
1638
1639 if ( ctxt->compression > 0 ) {
1640 content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
1641 content_encoding = (char *) "Content-Encoding: gzip";
1642 }
1643 else
1644#endif
1645 {
1646 /* Pull the data out of the memory output buffer */
1647
1648 xmlOutputBufferPtr dctxt = ctxt->doc_buff;
1649 http_content = (char *)dctxt->buffer->content;
1650 content_lgth = dctxt->buffer->use;
1651 }
1652
1653 if ( http_content == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001654 xmlChar msg[500];
1655 xmlStrPrintf(msg, 500,
1656 (const xmlChar *) "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
1657 "Error retrieving content.\nUnable to",
1658 http_mthd, "data to URI", ctxt->uri );
1659 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001660 }
1661
1662 else {
1663
1664 http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
1665 &content_type, content_encoding,
1666 content_lgth );
1667
1668 if ( http_ctxt != NULL ) {
1669#ifdef DEBUG_HTTP
1670 /* If testing/debugging - dump reply with request content */
1671
1672 FILE * tst_file = NULL;
1673 char buffer[ 4096 ];
1674 char * dump_name = NULL;
1675 int avail;
1676
1677 xmlGenericError( xmlGenericErrorContext,
1678 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
1679 http_mthd, ctxt->uri,
1680 xmlNanoHTTPReturnCode( http_ctxt ) );
1681
1682 /*
1683 ** Since either content or reply may be gzipped,
1684 ** dump them to separate files instead of the
1685 ** standard error context.
1686 */
1687
1688 dump_name = tempnam( NULL, "lxml" );
1689 if ( dump_name != NULL ) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001690 (void)snprintf( buffer, sizeof(buffer), "%s.content", dump_name );
Daniel Veillardf012a642001-07-23 19:10:52 +00001691
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00001692 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00001693 if ( tst_file != NULL ) {
1694 xmlGenericError( xmlGenericErrorContext,
1695 "Transmitted content saved in file: %s\n", buffer );
1696
1697 fwrite( http_content, sizeof( char ),
1698 content_lgth, tst_file );
1699 fclose( tst_file );
1700 }
1701
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001702 (void)snprintf( buffer, sizeof(buffer), "%s.reply", dump_name );
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00001703 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00001704 if ( tst_file != NULL ) {
1705 xmlGenericError( xmlGenericErrorContext,
1706 "Reply content saved in file: %s\n", buffer );
1707
1708
1709 while ( (avail = xmlNanoHTTPRead( http_ctxt,
1710 buffer, sizeof( buffer ) )) > 0 ) {
1711
1712 fwrite( buffer, sizeof( char ), avail, tst_file );
1713 }
1714
1715 fclose( tst_file );
1716 }
1717
1718 free( dump_name );
1719 }
1720#endif /* DEBUG_HTTP */
1721
1722 http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
1723 if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
1724 close_rc = 0;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001725 else {
1726 xmlChar msg[500];
1727 xmlStrPrintf(msg, 500,
1728 (const xmlChar *) "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001729 http_mthd, content_lgth,
1730 "bytes to URI", ctxt->uri,
1731 "failed. HTTP return code:", http_rtn );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001732 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1733 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001734
1735 xmlNanoHTTPClose( http_ctxt );
1736 xmlFree( content_type );
1737 }
1738 }
1739
1740 /* Final cleanups */
1741
1742 xmlFreeHTTPWriteCtxt( ctxt );
1743
1744 return ( close_rc );
1745}
1746
1747/**
1748 * xmlIOHTTPClosePut
1749 *
1750 * @context: The I/O context
1751 *
1752 * Close the transmit HTTP I/O channel and actually send data using a PUT
1753 * HTTP method.
1754 */
1755static int
1756xmlIOHTTPClosePut( void * ctxt ) {
1757 return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
1758}
1759
1760
1761/**
1762 * xmlIOHTTPClosePost
1763 *
1764 * @context: The I/O context
1765 *
1766 * Close the transmit HTTP I/O channel and actually send data using a POST
1767 * HTTP method.
1768 */
1769static int
1770xmlIOHTTPClosePost( void * ctxt ) {
1771 return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
1772}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001773#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001774
Owen Taylor3473f882001-02-23 17:55:21 +00001775#endif /* LIBXML_HTTP_ENABLED */
1776
1777#ifdef LIBXML_FTP_ENABLED
1778/************************************************************************
1779 * *
1780 * I/O for FTP file accesses *
1781 * *
1782 ************************************************************************/
1783/**
1784 * xmlIOFTPMatch:
1785 * @filename: the URI for matching
1786 *
1787 * check if the URI matches an FTP one
1788 *
1789 * Returns 1 if matches, 0 otherwise
1790 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001791int
Owen Taylor3473f882001-02-23 17:55:21 +00001792xmlIOFTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001793 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "ftp://", 6))
Owen Taylor3473f882001-02-23 17:55:21 +00001794 return(1);
1795 return(0);
1796}
1797
1798/**
1799 * xmlIOFTPOpen:
1800 * @filename: the URI for matching
1801 *
1802 * open an FTP I/O channel
1803 *
1804 * Returns an I/O context or NULL in case of error
1805 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001806void *
Owen Taylor3473f882001-02-23 17:55:21 +00001807xmlIOFTPOpen (const char *filename) {
1808 return(xmlNanoFTPOpen(filename));
1809}
1810
1811/**
1812 * xmlIOFTPRead:
1813 * @context: the I/O context
1814 * @buffer: where to drop data
1815 * @len: number of bytes to write
1816 *
1817 * Read @len bytes to @buffer from the I/O channel.
1818 *
1819 * Returns the number of bytes written
1820 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001821int
Owen Taylor3473f882001-02-23 17:55:21 +00001822xmlIOFTPRead(void * context, char * buffer, int len) {
1823 return(xmlNanoFTPRead(context, &buffer[0], len));
1824}
1825
1826/**
1827 * xmlIOFTPClose:
1828 * @context: the I/O context
1829 *
1830 * Close an FTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001831 *
1832 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00001833 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001834int
Owen Taylor3473f882001-02-23 17:55:21 +00001835xmlIOFTPClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001836 return ( xmlNanoFTPClose(context) );
Owen Taylor3473f882001-02-23 17:55:21 +00001837}
1838#endif /* LIBXML_FTP_ENABLED */
1839
1840
1841/**
1842 * xmlRegisterInputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001843 * @matchFunc: the xmlInputMatchCallback
1844 * @openFunc: the xmlInputOpenCallback
1845 * @readFunc: the xmlInputReadCallback
1846 * @closeFunc: the xmlInputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001847 *
1848 * Register a new set of I/O callback for handling parser input.
1849 *
1850 * Returns the registered handler number or -1 in case of error
1851 */
1852int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001853xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
1854 xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
1855 xmlInputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001856 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
1857 return(-1);
1858 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001859 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
1860 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
1861 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
1862 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00001863 xmlInputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00001864 return(xmlInputCallbackNr++);
1865}
1866
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001867#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001868/**
1869 * xmlRegisterOutputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001870 * @matchFunc: the xmlOutputMatchCallback
1871 * @openFunc: the xmlOutputOpenCallback
1872 * @writeFunc: the xmlOutputWriteCallback
1873 * @closeFunc: the xmlOutputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001874 *
1875 * Register a new set of I/O callback for handling output.
1876 *
1877 * Returns the registered handler number or -1 in case of error
1878 */
1879int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001880xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
1881 xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
1882 xmlOutputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001883 if (xmlOutputCallbackNr >= MAX_INPUT_CALLBACK) {
1884 return(-1);
1885 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001886 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
1887 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
1888 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
1889 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00001890 xmlOutputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00001891 return(xmlOutputCallbackNr++);
1892}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001893#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001894
1895/**
1896 * xmlRegisterDefaultInputCallbacks:
1897 *
1898 * Registers the default compiled-in I/O handlers.
1899 */
1900void
Owen Taylor3473f882001-02-23 17:55:21 +00001901xmlRegisterDefaultInputCallbacks
Owen Taylor3473f882001-02-23 17:55:21 +00001902(void) {
1903 if (xmlInputCallbackInitialized)
1904 return;
1905
1906 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
1907 xmlFileRead, xmlFileClose);
1908#ifdef HAVE_ZLIB_H
1909 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1910 xmlGzfileRead, xmlGzfileClose);
1911#endif /* HAVE_ZLIB_H */
1912
1913#ifdef LIBXML_HTTP_ENABLED
1914 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
1915 xmlIOHTTPRead, xmlIOHTTPClose);
1916#endif /* LIBXML_HTTP_ENABLED */
1917
1918#ifdef LIBXML_FTP_ENABLED
1919 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1920 xmlIOFTPRead, xmlIOFTPClose);
1921#endif /* LIBXML_FTP_ENABLED */
1922 xmlInputCallbackInitialized = 1;
1923}
1924
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001925#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001926/**
1927 * xmlRegisterDefaultOutputCallbacks:
1928 *
1929 * Registers the default compiled-in I/O handlers.
1930 */
1931void
Owen Taylor3473f882001-02-23 17:55:21 +00001932xmlRegisterDefaultOutputCallbacks
Owen Taylor3473f882001-02-23 17:55:21 +00001933(void) {
1934 if (xmlOutputCallbackInitialized)
1935 return;
1936
1937 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
1938 xmlFileWrite, xmlFileClose);
Daniel Veillardf012a642001-07-23 19:10:52 +00001939
1940#ifdef LIBXML_HTTP_ENABLED
1941 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
1942 xmlIOHTTPWrite, xmlIOHTTPClosePut);
1943#endif
1944
Owen Taylor3473f882001-02-23 17:55:21 +00001945/*********************************
1946 No way a-priori to distinguish between gzipped files from
1947 uncompressed ones except opening if existing then closing
1948 and saving with same compression ratio ... a pain.
1949
1950#ifdef HAVE_ZLIB_H
1951 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1952 xmlGzfileWrite, xmlGzfileClose);
1953#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001954
1955 Nor FTP PUT ....
1956#ifdef LIBXML_FTP_ENABLED
1957 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1958 xmlIOFTPWrite, xmlIOFTPClose);
1959#endif
1960 **********************************/
1961 xmlOutputCallbackInitialized = 1;
1962}
1963
Daniel Veillardf012a642001-07-23 19:10:52 +00001964#ifdef LIBXML_HTTP_ENABLED
1965/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001966 * xmlRegisterHTTPPostCallbacks:
Daniel Veillardf012a642001-07-23 19:10:52 +00001967 *
1968 * By default, libxml submits HTTP output requests using the "PUT" method.
1969 * Calling this method changes the HTTP output method to use the "POST"
1970 * method instead.
1971 *
1972 */
1973void
1974xmlRegisterHTTPPostCallbacks( void ) {
1975
1976 /* Register defaults if not done previously */
1977
1978 if ( xmlOutputCallbackInitialized == 0 )
1979 xmlRegisterDefaultOutputCallbacks( );
1980
1981 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
1982 xmlIOHTTPWrite, xmlIOHTTPClosePost);
1983 return;
1984}
1985#endif
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001986#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001987
Owen Taylor3473f882001-02-23 17:55:21 +00001988/**
1989 * xmlAllocParserInputBuffer:
1990 * @enc: the charset encoding if known
1991 *
1992 * Create a buffered parser input for progressive parsing
1993 *
1994 * Returns the new parser input or NULL
1995 */
1996xmlParserInputBufferPtr
1997xmlAllocParserInputBuffer(xmlCharEncoding enc) {
1998 xmlParserInputBufferPtr ret;
1999
2000 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2001 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002002 xmlIOErrMemory("creating input buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00002003 return(NULL);
2004 }
2005 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002006 ret->buffer = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00002007 if (ret->buffer == NULL) {
2008 xmlFree(ret);
2009 return(NULL);
2010 }
2011 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
2012 ret->encoder = xmlGetCharEncodingHandler(enc);
2013 if (ret->encoder != NULL)
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002014 ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00002015 else
2016 ret->raw = NULL;
2017 ret->readcallback = NULL;
2018 ret->closecallback = NULL;
2019 ret->context = NULL;
William M. Brackc07329e2003-09-08 01:57:30 +00002020 ret->compressed = -1;
Daniel Veillard36711902004-02-11 13:25:26 +00002021 ret->rawconsumed = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002022
2023 return(ret);
2024}
2025
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002026#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002027/**
2028 * xmlAllocOutputBuffer:
2029 * @encoder: the encoding converter or NULL
2030 *
2031 * Create a buffered parser output
2032 *
2033 * Returns the new parser output or NULL
2034 */
2035xmlOutputBufferPtr
2036xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
2037 xmlOutputBufferPtr ret;
2038
2039 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
2040 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002041 xmlIOErrMemory("creating output buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00002042 return(NULL);
2043 }
2044 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
2045 ret->buffer = xmlBufferCreate();
2046 if (ret->buffer == NULL) {
2047 xmlFree(ret);
2048 return(NULL);
2049 }
2050 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
2051 ret->encoder = encoder;
2052 if (encoder != NULL) {
2053 ret->conv = xmlBufferCreateSize(4000);
2054 /*
2055 * This call is designed to initiate the encoder state
2056 */
2057 xmlCharEncOutFunc(encoder, ret->conv, NULL);
2058 } else
2059 ret->conv = NULL;
2060 ret->writecallback = NULL;
2061 ret->closecallback = NULL;
2062 ret->context = NULL;
2063 ret->written = 0;
2064
2065 return(ret);
2066}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002067#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002068
2069/**
2070 * xmlFreeParserInputBuffer:
2071 * @in: a buffered parser input
2072 *
2073 * Free up the memory used by a buffered parser input
2074 */
2075void
2076xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
Daniel Veillard8d8bf2c2003-09-17 19:36:25 +00002077 if (in == NULL) return;
2078
Owen Taylor3473f882001-02-23 17:55:21 +00002079 if (in->raw) {
2080 xmlBufferFree(in->raw);
2081 in->raw = NULL;
2082 }
2083 if (in->encoder != NULL) {
2084 xmlCharEncCloseFunc(in->encoder);
2085 }
2086 if (in->closecallback != NULL) {
2087 in->closecallback(in->context);
2088 }
2089 if (in->buffer != NULL) {
2090 xmlBufferFree(in->buffer);
2091 in->buffer = NULL;
2092 }
2093
Owen Taylor3473f882001-02-23 17:55:21 +00002094 xmlFree(in);
2095}
2096
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002097#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002098/**
2099 * xmlOutputBufferClose:
2100 * @out: a buffered output
2101 *
2102 * flushes and close the output I/O channel
2103 * and free up all the associated resources
2104 *
2105 * Returns the number of byte written or -1 in case of error.
2106 */
2107int
Daniel Veillard828ce832003-10-08 19:19:10 +00002108xmlOutputBufferClose(xmlOutputBufferPtr out)
2109{
Owen Taylor3473f882001-02-23 17:55:21 +00002110 int written;
Daniel Veillardf012a642001-07-23 19:10:52 +00002111 int err_rc = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002112
2113 if (out == NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002114 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002115 if (out->writecallback != NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002116 xmlOutputBufferFlush(out);
Owen Taylor3473f882001-02-23 17:55:21 +00002117 if (out->closecallback != NULL) {
Daniel Veillard828ce832003-10-08 19:19:10 +00002118 err_rc = out->closecallback(out->context);
Owen Taylor3473f882001-02-23 17:55:21 +00002119 }
2120 written = out->written;
2121 if (out->conv) {
2122 xmlBufferFree(out->conv);
Daniel Veillard828ce832003-10-08 19:19:10 +00002123 out->conv = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002124 }
2125 if (out->encoder != NULL) {
2126 xmlCharEncCloseFunc(out->encoder);
2127 }
2128 if (out->buffer != NULL) {
2129 xmlBufferFree(out->buffer);
Daniel Veillard828ce832003-10-08 19:19:10 +00002130 out->buffer = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002131 }
2132
Daniel Veillard828ce832003-10-08 19:19:10 +00002133 if (out->error)
2134 err_rc = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00002135 xmlFree(out);
Daniel Veillard828ce832003-10-08 19:19:10 +00002136 return ((err_rc == 0) ? written : err_rc);
Owen Taylor3473f882001-02-23 17:55:21 +00002137}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002138#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002139
Daniel Veillard1b243b42004-06-08 10:16:42 +00002140xmlParserInputBufferPtr
Daniel Veillard0335a842004-06-02 16:18:40 +00002141__xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002142 xmlParserInputBufferPtr ret;
Daniel Veillard388236f2001-07-08 18:35:48 +00002143 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002144 void *context = NULL;
2145
2146 if (xmlInputCallbackInitialized == 0)
2147 xmlRegisterDefaultInputCallbacks();
2148
2149 if (URI == NULL) return(NULL);
2150
2151 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002152 * Try to find one of the input accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002153 * Go in reverse to give precedence to user defined handlers.
Daniel Veillard388236f2001-07-08 18:35:48 +00002154 */
2155 if (context == NULL) {
2156 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
2157 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
2158 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002159 context = xmlInputCallbackTable[i].opencallback(URI);
Daniel Veillard847332a2003-10-18 11:29:40 +00002160 if (context != NULL) {
Daniel Veillard388236f2001-07-08 18:35:48 +00002161 break;
Daniel Veillard847332a2003-10-18 11:29:40 +00002162 }
Daniel Veillard388236f2001-07-08 18:35:48 +00002163 }
Owen Taylor3473f882001-02-23 17:55:21 +00002164 }
2165 }
2166 if (context == NULL) {
2167 return(NULL);
2168 }
2169
2170 /*
2171 * Allocate the Input buffer front-end.
2172 */
2173 ret = xmlAllocParserInputBuffer(enc);
2174 if (ret != NULL) {
2175 ret->context = context;
2176 ret->readcallback = xmlInputCallbackTable[i].readcallback;
2177 ret->closecallback = xmlInputCallbackTable[i].closecallback;
William M. Brackc07329e2003-09-08 01:57:30 +00002178#ifdef HAVE_ZLIB_H
William M. Brackc5cbf992003-10-29 22:15:13 +00002179 if ((xmlInputCallbackTable[i].opencallback == xmlGzfileOpen) &&
2180 (strcmp(URI, "-") != 0)) {
William M. Brackc07329e2003-09-08 01:57:30 +00002181 if (((z_stream *)context)->avail_in > 4) {
2182 char *cptr, buff4[4];
Daniel Veillard07cb8222003-09-10 10:51:05 +00002183 cptr = (char *) ((z_stream *)context)->next_in;
William M. Brackc07329e2003-09-08 01:57:30 +00002184 if (gzread(context, buff4, 4) == 4) {
2185 if (strncmp(buff4, cptr, 4) == 0)
2186 ret->compressed = 0;
2187 else
2188 ret->compressed = 1;
2189 gzrewind(context);
2190 }
2191 }
2192 }
2193#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002194 }
William M. Brack42331a92004-07-29 07:07:16 +00002195 else
2196 xmlInputCallbackTable[i].closecallback (context);
2197
Owen Taylor3473f882001-02-23 17:55:21 +00002198 return(ret);
2199}
2200
2201/**
Daniel Veillard0335a842004-06-02 16:18:40 +00002202 * xmlParserInputBufferCreateFilename:
Owen Taylor3473f882001-02-23 17:55:21 +00002203 * @URI: a C string containing the URI or filename
Daniel Veillard0335a842004-06-02 16:18:40 +00002204 * @enc: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002205 *
Daniel Veillard0335a842004-06-02 16:18:40 +00002206 * Create a buffered parser input for the progressive parsing of a file
2207 * If filename is "-' then we use stdin as the input.
Owen Taylor3473f882001-02-23 17:55:21 +00002208 * Automatic support for ZLIB/Compress compressed document is provided
2209 * by default if found at compile-time.
Daniel Veillard0335a842004-06-02 16:18:40 +00002210 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
Owen Taylor3473f882001-02-23 17:55:21 +00002211 *
Daniel Veillard0335a842004-06-02 16:18:40 +00002212 * Returns the new parser input or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00002213 */
Daniel Veillard0335a842004-06-02 16:18:40 +00002214xmlParserInputBufferPtr
2215xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
2216 if ((xmlParserInputBufferCreateFilenameValue)) {
2217 return xmlParserInputBufferCreateFilenameValue(URI, enc);
2218 }
2219 return __xmlParserInputBufferCreateFilename(URI, enc);
2220}
2221
2222#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard1b243b42004-06-08 10:16:42 +00002223xmlOutputBufferPtr
Daniel Veillard0335a842004-06-02 16:18:40 +00002224__xmlOutputBufferCreateFilename(const char *URI,
Owen Taylor3473f882001-02-23 17:55:21 +00002225 xmlCharEncodingHandlerPtr encoder,
Daniel Veillard0335a842004-06-02 16:18:40 +00002226 int compression ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00002227 xmlOutputBufferPtr ret;
Daniel Veillard966a31e2004-05-09 02:58:44 +00002228 xmlURIPtr puri;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002229 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002230 void *context = NULL;
Daniel Veillard966a31e2004-05-09 02:58:44 +00002231 char *unescaped = NULL;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002232#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002233 int is_file_uri = 1;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002234#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00002235
Owen Taylor3473f882001-02-23 17:55:21 +00002236 if (xmlOutputCallbackInitialized == 0)
2237 xmlRegisterDefaultOutputCallbacks();
2238
2239 if (URI == NULL) return(NULL);
2240
Daniel Veillard966a31e2004-05-09 02:58:44 +00002241 puri = xmlParseURI(URI);
2242 if (puri != NULL) {
Daniel Veillard18a65092004-05-11 15:57:42 +00002243 if ((puri->scheme != NULL) &&
2244 (!xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002245#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002246 is_file_uri = 0;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002247#endif
Daniel Veillard966a31e2004-05-09 02:58:44 +00002248 /*
2249 * try to limit the damages of the URI unescaping code.
2250 */
2251 if (puri->scheme != NULL)
2252 unescaped = xmlURIUnescapeString(URI, 0, NULL);
2253 xmlFreeURI(puri);
2254 }
Owen Taylor3473f882001-02-23 17:55:21 +00002255
2256 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002257 * Try to find one of the output accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002258 * Go in reverse to give precedence to user defined handlers.
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002259 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00002260 */
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002261 if (unescaped != NULL) {
2262#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002263 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002264 context = xmlGzfileOpenW(unescaped, compression);
2265 if (context != NULL) {
2266 ret = xmlAllocOutputBuffer(encoder);
2267 if (ret != NULL) {
2268 ret->context = context;
2269 ret->writecallback = xmlGzfileWrite;
2270 ret->closecallback = xmlGzfileClose;
2271 }
2272 xmlFree(unescaped);
2273 return(ret);
2274 }
2275 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002276#endif
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002277 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2278 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
2279 (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
2280#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2281 /* Need to pass compression parameter into HTTP open calls */
2282 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2283 context = xmlIOHTTPOpenW(unescaped, compression);
2284 else
2285#endif
2286 context = xmlOutputCallbackTable[i].opencallback(unescaped);
2287 if (context != NULL)
2288 break;
2289 }
2290 }
2291 xmlFree(unescaped);
2292 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002293
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002294 /*
2295 * If this failed try with a non-escaped URI this may be a strange
2296 * filename
2297 */
2298 if (context == NULL) {
2299#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002300 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002301 context = xmlGzfileOpenW(URI, compression);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002302 if (context != NULL) {
2303 ret = xmlAllocOutputBuffer(encoder);
2304 if (ret != NULL) {
2305 ret->context = context;
2306 ret->writecallback = xmlGzfileWrite;
2307 ret->closecallback = xmlGzfileClose;
2308 }
2309 return(ret);
2310 }
2311 }
2312#endif
2313 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2314 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002315 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002316#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2317 /* Need to pass compression parameter into HTTP open calls */
2318 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2319 context = xmlIOHTTPOpenW(URI, compression);
2320 else
2321#endif
2322 context = xmlOutputCallbackTable[i].opencallback(URI);
2323 if (context != NULL)
2324 break;
2325 }
Owen Taylor3473f882001-02-23 17:55:21 +00002326 }
2327 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002328
Owen Taylor3473f882001-02-23 17:55:21 +00002329 if (context == NULL) {
2330 return(NULL);
2331 }
2332
2333 /*
2334 * Allocate the Output buffer front-end.
2335 */
2336 ret = xmlAllocOutputBuffer(encoder);
2337 if (ret != NULL) {
2338 ret->context = context;
2339 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
2340 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
2341 }
2342 return(ret);
2343}
Daniel Veillard0335a842004-06-02 16:18:40 +00002344
2345/**
2346 * xmlOutputBufferCreateFilename:
2347 * @URI: a C string containing the URI or filename
2348 * @encoder: the encoding converter or NULL
2349 * @compression: the compression ration (0 none, 9 max).
2350 *
2351 * Create a buffered output for the progressive saving of a file
2352 * If filename is "-' then we use stdout as the output.
2353 * Automatic support for ZLIB/Compress compressed document is provided
2354 * by default if found at compile-time.
2355 * TODO: currently if compression is set, the library only support
2356 * writing to a local file.
2357 *
2358 * Returns the new output or NULL
2359 */
2360xmlOutputBufferPtr
2361xmlOutputBufferCreateFilename(const char *URI,
2362 xmlCharEncodingHandlerPtr encoder,
2363 int compression ATTRIBUTE_UNUSED) {
2364 if ((xmlOutputBufferCreateFilenameValue)) {
2365 return xmlOutputBufferCreateFilenameValue(URI, encoder, compression);
2366 }
2367 return __xmlOutputBufferCreateFilename(URI, encoder, compression);
2368}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002369#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002370
2371/**
2372 * xmlParserInputBufferCreateFile:
2373 * @file: a FILE*
2374 * @enc: the charset encoding if known
2375 *
2376 * Create a buffered parser input for the progressive parsing of a FILE *
2377 * buffered C I/O
2378 *
2379 * Returns the new parser input or NULL
2380 */
2381xmlParserInputBufferPtr
2382xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
2383 xmlParserInputBufferPtr ret;
2384
2385 if (xmlInputCallbackInitialized == 0)
2386 xmlRegisterDefaultInputCallbacks();
2387
2388 if (file == NULL) return(NULL);
2389
2390 ret = xmlAllocParserInputBuffer(enc);
2391 if (ret != NULL) {
2392 ret->context = file;
2393 ret->readcallback = xmlFileRead;
2394 ret->closecallback = xmlFileFlush;
2395 }
2396
2397 return(ret);
2398}
2399
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002400#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002401/**
2402 * xmlOutputBufferCreateFile:
2403 * @file: a FILE*
2404 * @encoder: the encoding converter or NULL
2405 *
2406 * Create a buffered output for the progressive saving to a FILE *
2407 * buffered C I/O
2408 *
2409 * Returns the new parser output or NULL
2410 */
2411xmlOutputBufferPtr
2412xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
2413 xmlOutputBufferPtr ret;
2414
2415 if (xmlOutputCallbackInitialized == 0)
2416 xmlRegisterDefaultOutputCallbacks();
2417
2418 if (file == NULL) return(NULL);
2419
2420 ret = xmlAllocOutputBuffer(encoder);
2421 if (ret != NULL) {
2422 ret->context = file;
2423 ret->writecallback = xmlFileWrite;
2424 ret->closecallback = xmlFileFlush;
2425 }
2426
2427 return(ret);
2428}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002429#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002430
2431/**
2432 * xmlParserInputBufferCreateFd:
2433 * @fd: a file descriptor number
2434 * @enc: the charset encoding if known
2435 *
2436 * Create a buffered parser input for the progressive parsing for the input
2437 * from a file descriptor
2438 *
2439 * Returns the new parser input or NULL
2440 */
2441xmlParserInputBufferPtr
2442xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
2443 xmlParserInputBufferPtr ret;
2444
2445 if (fd < 0) return(NULL);
2446
2447 ret = xmlAllocParserInputBuffer(enc);
2448 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002449 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002450 ret->readcallback = xmlFdRead;
2451 ret->closecallback = xmlFdClose;
2452 }
2453
2454 return(ret);
2455}
2456
2457/**
2458 * xmlParserInputBufferCreateMem:
2459 * @mem: the memory input
2460 * @size: the length of the memory block
2461 * @enc: the charset encoding if known
2462 *
2463 * Create a buffered parser input for the progressive parsing for the input
2464 * from a memory area.
2465 *
2466 * Returns the new parser input or NULL
2467 */
2468xmlParserInputBufferPtr
2469xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
2470 xmlParserInputBufferPtr ret;
William M. Bracka3215c72004-07-31 16:24:01 +00002471 int errcode;
Owen Taylor3473f882001-02-23 17:55:21 +00002472
2473 if (size <= 0) return(NULL);
2474 if (mem == NULL) return(NULL);
2475
2476 ret = xmlAllocParserInputBuffer(enc);
2477 if (ret != NULL) {
2478 ret->context = (void *) mem;
2479 ret->readcallback = (xmlInputReadCallback) xmlNop;
2480 ret->closecallback = NULL;
William M. Bracka3215c72004-07-31 16:24:01 +00002481 errcode = xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size);
2482 if (errcode != 0) {
2483 xmlFree(ret);
2484 return(NULL);
2485 }
Owen Taylor3473f882001-02-23 17:55:21 +00002486 }
2487
2488 return(ret);
2489}
2490
2491/**
Daniel Veillard53350552003-09-18 13:35:51 +00002492 * xmlParserInputBufferCreateStatic:
2493 * @mem: the memory input
2494 * @size: the length of the memory block
2495 * @enc: the charset encoding if known
2496 *
2497 * Create a buffered parser input for the progressive parsing for the input
2498 * from an immutable memory area. This will not copy the memory area to
2499 * the buffer, but the memory is expected to be available until the end of
2500 * the parsing, this is useful for example when using mmap'ed file.
2501 *
2502 * Returns the new parser input or NULL
2503 */
2504xmlParserInputBufferPtr
2505xmlParserInputBufferCreateStatic(const char *mem, int size,
2506 xmlCharEncoding enc) {
2507 xmlParserInputBufferPtr ret;
2508
2509 if (size <= 0) return(NULL);
2510 if (mem == NULL) return(NULL);
2511
2512 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2513 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002514 xmlIOErrMemory("creating input buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00002515 return(NULL);
2516 }
2517 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillarde72c5082003-09-19 12:44:05 +00002518 ret->buffer = xmlBufferCreateStatic((void *)mem, (size_t) size);
Daniel Veillard53350552003-09-18 13:35:51 +00002519 if (ret->buffer == NULL) {
2520 xmlFree(ret);
2521 return(NULL);
2522 }
2523 ret->encoder = xmlGetCharEncodingHandler(enc);
2524 if (ret->encoder != NULL)
2525 ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
2526 else
2527 ret->raw = NULL;
2528 ret->compressed = -1;
2529 ret->context = (void *) mem;
2530 ret->readcallback = NULL;
2531 ret->closecallback = NULL;
2532
2533 return(ret);
2534}
2535
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002536#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard53350552003-09-18 13:35:51 +00002537/**
Owen Taylor3473f882001-02-23 17:55:21 +00002538 * xmlOutputBufferCreateFd:
2539 * @fd: a file descriptor number
2540 * @encoder: the encoding converter or NULL
2541 *
2542 * Create a buffered output for the progressive saving
2543 * to a file descriptor
2544 *
2545 * Returns the new parser output or NULL
2546 */
2547xmlOutputBufferPtr
2548xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
2549 xmlOutputBufferPtr ret;
2550
2551 if (fd < 0) return(NULL);
2552
2553 ret = xmlAllocOutputBuffer(encoder);
2554 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002555 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002556 ret->writecallback = xmlFdWrite;
Daniel Veillard7db38712002-02-07 16:39:11 +00002557 ret->closecallback = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002558 }
2559
2560 return(ret);
2561}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002562#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002563
2564/**
2565 * xmlParserInputBufferCreateIO:
2566 * @ioread: an I/O read function
2567 * @ioclose: an I/O close function
2568 * @ioctx: an I/O handler
2569 * @enc: the charset encoding if known
2570 *
2571 * Create a buffered parser input for the progressive parsing for the input
2572 * from an I/O handler
2573 *
2574 * Returns the new parser input or NULL
2575 */
2576xmlParserInputBufferPtr
2577xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
2578 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
2579 xmlParserInputBufferPtr ret;
2580
2581 if (ioread == NULL) return(NULL);
2582
2583 ret = xmlAllocParserInputBuffer(enc);
2584 if (ret != NULL) {
2585 ret->context = (void *) ioctx;
2586 ret->readcallback = ioread;
2587 ret->closecallback = ioclose;
2588 }
2589
2590 return(ret);
2591}
2592
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002593#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002594/**
2595 * xmlOutputBufferCreateIO:
2596 * @iowrite: an I/O write function
2597 * @ioclose: an I/O close function
2598 * @ioctx: an I/O handler
Daniel Veillard9d06d302002-01-22 18:15:52 +00002599 * @encoder: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002600 *
2601 * Create a buffered output for the progressive saving
2602 * to an I/O handler
2603 *
2604 * Returns the new parser output or NULL
2605 */
2606xmlOutputBufferPtr
2607xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
2608 xmlOutputCloseCallback ioclose, void *ioctx,
2609 xmlCharEncodingHandlerPtr encoder) {
2610 xmlOutputBufferPtr ret;
2611
2612 if (iowrite == NULL) return(NULL);
2613
2614 ret = xmlAllocOutputBuffer(encoder);
2615 if (ret != NULL) {
2616 ret->context = (void *) ioctx;
2617 ret->writecallback = iowrite;
2618 ret->closecallback = ioclose;
2619 }
2620
2621 return(ret);
2622}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002623#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002624
2625/**
Daniel Veillard1b243b42004-06-08 10:16:42 +00002626 * xmlParserInputBufferCreateFilenameDefault:
2627 * @func: function pointer to the new ParserInputBufferCreateFilenameFunc
2628 *
2629 * Registers a callback for URI input file handling
2630 *
2631 * Returns the old value of the registration function
2632 */
2633xmlParserInputBufferCreateFilenameFunc
2634xmlParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func)
2635{
2636 xmlParserInputBufferCreateFilenameFunc old = xmlParserInputBufferCreateFilenameValue;
2637 if (old == NULL) {
2638 old = __xmlParserInputBufferCreateFilename;
2639 }
2640
2641 xmlParserInputBufferCreateFilenameValue = func;
2642 return(old);
2643}
2644
2645/**
2646 * xmlOutputBufferCreateFilenameDefault:
2647 * @func: function pointer to the new OutputBufferCreateFilenameFunc
2648 *
2649 * Registers a callback for URI output file handling
2650 *
2651 * Returns the old value of the registration function
2652 */
2653xmlOutputBufferCreateFilenameFunc
2654xmlOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func)
2655{
2656 xmlOutputBufferCreateFilenameFunc old = xmlOutputBufferCreateFilenameValue;
2657#ifdef LIBXML_OUTPUT_ENABLED
2658 if (old == NULL) {
2659 old = __xmlOutputBufferCreateFilename;
2660 }
2661#endif
2662 xmlOutputBufferCreateFilenameValue = func;
2663 return(old);
2664}
2665
2666/**
Owen Taylor3473f882001-02-23 17:55:21 +00002667 * xmlParserInputBufferPush:
2668 * @in: a buffered parser input
2669 * @len: the size in bytes of the array.
2670 * @buf: an char array
2671 *
2672 * Push the content of the arry in the input buffer
2673 * This routine handle the I18N transcoding to internal UTF-8
2674 * This is used when operating the parser in progressive (push) mode.
2675 *
2676 * Returns the number of chars read and stored in the buffer, or -1
2677 * in case of error.
2678 */
2679int
2680xmlParserInputBufferPush(xmlParserInputBufferPtr in,
2681 int len, const char *buf) {
2682 int nbchars = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00002683 int ret;
Owen Taylor3473f882001-02-23 17:55:21 +00002684
2685 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002686 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002687 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00002688 unsigned int use;
2689
Owen Taylor3473f882001-02-23 17:55:21 +00002690 /*
2691 * Store the data in the incoming raw buffer
2692 */
2693 if (in->raw == NULL) {
2694 in->raw = xmlBufferCreate();
2695 }
William M. Bracka3215c72004-07-31 16:24:01 +00002696 ret = xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
2697 if (ret != 0)
2698 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002699
2700 /*
2701 * convert as much as possible to the parser reading buffer.
2702 */
Daniel Veillard36711902004-02-11 13:25:26 +00002703 use = in->raw->use;
Owen Taylor3473f882001-02-23 17:55:21 +00002704 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2705 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002706 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002707 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002708 return(-1);
2709 }
Daniel Veillard36711902004-02-11 13:25:26 +00002710 in->rawconsumed += (use - in->raw->use);
Owen Taylor3473f882001-02-23 17:55:21 +00002711 } else {
2712 nbchars = len;
William M. Bracka3215c72004-07-31 16:24:01 +00002713 ret = xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
2714 if (ret != 0)
2715 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002716 }
2717#ifdef DEBUG_INPUT
2718 xmlGenericError(xmlGenericErrorContext,
2719 "I/O: pushed %d chars, buffer %d/%d\n",
2720 nbchars, in->buffer->use, in->buffer->size);
2721#endif
2722 return(nbchars);
2723}
2724
2725/**
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002726 * endOfInput:
2727 *
2728 * When reading from an Input channel indicated end of file or error
2729 * don't reread from it again.
2730 */
2731static int
2732endOfInput (void * context ATTRIBUTE_UNUSED,
2733 char * buffer ATTRIBUTE_UNUSED,
2734 int len ATTRIBUTE_UNUSED) {
2735 return(0);
2736}
2737
2738/**
Owen Taylor3473f882001-02-23 17:55:21 +00002739 * xmlParserInputBufferGrow:
2740 * @in: a buffered parser input
2741 * @len: indicative value of the amount of chars to read
2742 *
2743 * Grow up the content of the input buffer, the old data are preserved
2744 * This routine handle the I18N transcoding to internal UTF-8
2745 * This routine is used when operating the parser in normal (pull) mode
2746 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002747 * TODO: one should be able to remove one extra copy by copying directly
Owen Taylor3473f882001-02-23 17:55:21 +00002748 * onto in->buffer or in->raw
2749 *
2750 * Returns the number of chars read and stored in the buffer, or -1
2751 * in case of error.
2752 */
2753int
2754xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
2755 char *buffer = NULL;
2756 int res = 0;
2757 int nbchars = 0;
2758 int buffree;
Daniel Veillard9e412302002-06-10 15:59:44 +00002759 unsigned int needSize;
Owen Taylor3473f882001-02-23 17:55:21 +00002760
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002761 if ((in == NULL) || (in->error)) return(-1);
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002762 if ((len <= MINLEN) && (len != 4))
Owen Taylor3473f882001-02-23 17:55:21 +00002763 len = MINLEN;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002764
Owen Taylor3473f882001-02-23 17:55:21 +00002765 buffree = in->buffer->size - in->buffer->use;
2766 if (buffree <= 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002767 xmlIOErr(XML_IO_BUFFER_FULL, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002768 in->error = XML_IO_BUFFER_FULL;
William M. Bracka3215c72004-07-31 16:24:01 +00002769 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002770 }
Owen Taylor3473f882001-02-23 17:55:21 +00002771
Daniel Veillarde5354492002-05-16 08:43:22 +00002772 needSize = in->buffer->use + len + 1;
2773 if (needSize > in->buffer->size){
2774 if (!xmlBufferResize(in->buffer, needSize)){
Daniel Veillard05d987b2003-10-08 11:54:57 +00002775 xmlIOErrMemory("growing input buffer");
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002776 in->error = XML_ERR_NO_MEMORY;
William M. Bracka3215c72004-07-31 16:24:01 +00002777 return(-1);
Daniel Veillarde5354492002-05-16 08:43:22 +00002778 }
Owen Taylor3473f882001-02-23 17:55:21 +00002779 }
Daniel Veillarde5354492002-05-16 08:43:22 +00002780 buffer = (char *)&in->buffer->content[in->buffer->use];
Owen Taylor3473f882001-02-23 17:55:21 +00002781
2782 /*
2783 * Call the read method for this I/O type.
2784 */
2785 if (in->readcallback != NULL) {
2786 res = in->readcallback(in->context, &buffer[0], len);
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002787 if (res <= 0)
2788 in->readcallback = endOfInput;
Owen Taylor3473f882001-02-23 17:55:21 +00002789 } else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002790 xmlIOErr(XML_IO_NO_INPUT, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002791 in->error = XML_IO_NO_INPUT;
Owen Taylor3473f882001-02-23 17:55:21 +00002792 return(-1);
2793 }
2794 if (res < 0) {
Owen Taylor3473f882001-02-23 17:55:21 +00002795 return(-1);
2796 }
2797 len = res;
2798 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00002799 unsigned int use;
2800
Owen Taylor3473f882001-02-23 17:55:21 +00002801 /*
2802 * Store the data in the incoming raw buffer
2803 */
2804 if (in->raw == NULL) {
2805 in->raw = xmlBufferCreate();
2806 }
William M. Bracka3215c72004-07-31 16:24:01 +00002807 res = xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
2808 if (res != 0)
2809 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002810
2811 /*
2812 * convert as much as possible to the parser reading buffer.
2813 */
Daniel Veillard36711902004-02-11 13:25:26 +00002814 use = in->raw->use;
Owen Taylor3473f882001-02-23 17:55:21 +00002815 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2816 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002817 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002818 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002819 return(-1);
2820 }
Daniel Veillard36711902004-02-11 13:25:26 +00002821 in->rawconsumed += (use - in->raw->use);
Owen Taylor3473f882001-02-23 17:55:21 +00002822 } else {
2823 nbchars = len;
Daniel Veillarde5354492002-05-16 08:43:22 +00002824 in->buffer->use += nbchars;
2825 buffer[nbchars] = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002826 }
2827#ifdef DEBUG_INPUT
2828 xmlGenericError(xmlGenericErrorContext,
2829 "I/O: read %d chars, buffer %d/%d\n",
2830 nbchars, in->buffer->use, in->buffer->size);
2831#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002832 return(nbchars);
2833}
2834
2835/**
2836 * xmlParserInputBufferRead:
2837 * @in: a buffered parser input
2838 * @len: indicative value of the amount of chars to read
2839 *
2840 * Refresh the content of the input buffer, the old data are considered
2841 * consumed
2842 * This routine handle the I18N transcoding to internal UTF-8
2843 *
2844 * Returns the number of chars read and stored in the buffer, or -1
2845 * in case of error.
2846 */
2847int
2848xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002849 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002850 if (in->readcallback != NULL)
2851 return(xmlParserInputBufferGrow(in, len));
Daniel Veillard53350552003-09-18 13:35:51 +00002852 else if ((in->buffer != NULL) &&
2853 (in->buffer->alloc == XML_BUFFER_ALLOC_IMMUTABLE))
2854 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002855 else
2856 return(-1);
2857}
2858
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002859#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002860/**
2861 * xmlOutputBufferWrite:
2862 * @out: a buffered parser output
2863 * @len: the size in bytes of the array.
2864 * @buf: an char array
2865 *
2866 * Write the content of the array in the output I/O buffer
2867 * This routine handle the I18N transcoding from internal UTF-8
2868 * The buffer is lossless, i.e. will store in case of partial
2869 * or delayed writes.
2870 *
2871 * Returns the number of chars immediately written, or -1
2872 * in case of error.
2873 */
2874int
2875xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
2876 int nbchars = 0; /* number of chars to output to I/O */
2877 int ret; /* return from function call */
2878 int written = 0; /* number of char written to I/O so far */
2879 int chunk; /* number of byte curreent processed from buf */
2880
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002881 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002882 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002883 if (out->error) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002884
2885 do {
2886 chunk = len;
2887 if (chunk > 4 * MINLEN)
2888 chunk = 4 * MINLEN;
2889
2890 /*
2891 * first handle encoding stuff.
2892 */
2893 if (out->encoder != NULL) {
2894 /*
2895 * Store the data in the incoming raw buffer
2896 */
2897 if (out->conv == NULL) {
2898 out->conv = xmlBufferCreate();
2899 }
William M. Bracka3215c72004-07-31 16:24:01 +00002900 ret = xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2901 if (ret != 0)
2902 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002903
2904 if ((out->buffer->use < MINLEN) && (chunk == len))
2905 goto done;
2906
2907 /*
2908 * convert as much as possible to the parser reading buffer.
2909 */
2910 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
Daniel Veillard809faa52003-02-10 15:43:53 +00002911 if ((ret < 0) && (ret != -3)) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002912 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002913 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002914 return(-1);
2915 }
2916 nbchars = out->conv->use;
2917 } else {
William M. Bracka3215c72004-07-31 16:24:01 +00002918 ret = xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2919 if (ret != 0)
2920 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002921 nbchars = out->buffer->use;
2922 }
2923 buf += chunk;
2924 len -= chunk;
2925
2926 if ((nbchars < MINLEN) && (len <= 0))
2927 goto done;
2928
2929 if (out->writecallback) {
2930 /*
2931 * second write the stuff to the I/O channel
2932 */
2933 if (out->encoder != NULL) {
2934 ret = out->writecallback(out->context,
2935 (const char *)out->conv->content, nbchars);
2936 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002937 xmlBufferShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002938 } else {
2939 ret = out->writecallback(out->context,
2940 (const char *)out->buffer->content, nbchars);
2941 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002942 xmlBufferShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002943 }
2944 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002945 xmlIOErr(XML_IO_WRITE, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002946 out->error = XML_IO_WRITE;
Owen Taylor3473f882001-02-23 17:55:21 +00002947 return(ret);
2948 }
2949 out->written += ret;
2950 }
2951 written += nbchars;
2952 } while (len > 0);
2953
2954done:
2955#ifdef DEBUG_INPUT
2956 xmlGenericError(xmlGenericErrorContext,
2957 "I/O: wrote %d chars\n", written);
2958#endif
2959 return(written);
2960}
2961
2962/**
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00002963 * xmlEscapeContent:
2964 * @out: a pointer to an array of bytes to store the result
2965 * @outlen: the length of @out
2966 * @in: a pointer to an array of unescaped UTF-8 bytes
2967 * @inlen: the length of @in
2968 *
2969 * Take a block of UTF-8 chars in and escape them.
2970 * Returns 0 if success, or -1 otherwise
2971 * The value of @inlen after return is the number of octets consumed
2972 * if the return value is positive, else unpredictable.
2973 * The value of @outlen after return is the number of octets consumed.
2974 */
2975static int
2976xmlEscapeContent(unsigned char* out, int *outlen,
2977 const xmlChar* in, int *inlen) {
2978 unsigned char* outstart = out;
2979 const unsigned char* base = in;
2980 unsigned char* outend = out + *outlen;
2981 const unsigned char* inend;
2982
2983 inend = in + (*inlen);
2984
2985 while ((in < inend) && (out < outend)) {
2986 if (*in == '<') {
2987 if (outend - out < 4) break;
2988 *out++ = '&';
2989 *out++ = 'l';
2990 *out++ = 't';
2991 *out++ = ';';
2992 } else if (*in == '>') {
2993 if (outend - out < 4) break;
2994 *out++ = '&';
2995 *out++ = 'g';
2996 *out++ = 't';
2997 *out++ = ';';
2998 } else if (*in == '&') {
2999 if (outend - out < 5) break;
3000 *out++ = '&';
3001 *out++ = 'a';
3002 *out++ = 'm';
3003 *out++ = 'p';
3004 *out++ = ';';
3005 } else if (*in == '\r') {
3006 if (outend - out < 5) break;
3007 *out++ = '&';
3008 *out++ = '#';
3009 *out++ = '1';
3010 *out++ = '3';
3011 *out++ = ';';
3012 } else {
3013 *out++ = (unsigned char) *in;
3014 }
3015 ++in;
3016 }
3017 *outlen = out - outstart;
3018 *inlen = in - base;
3019 return(0);
3020}
3021
3022/**
3023 * xmlOutputBufferWriteEscape:
3024 * @out: a buffered parser output
3025 * @str: a zero terminated UTF-8 string
Daniel Veillardee8960b2004-05-14 03:25:14 +00003026 * @escaping: an optional escaping function (or NULL)
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003027 *
3028 * Write the content of the string in the output I/O buffer
3029 * This routine escapes the caracters and then handle the I18N
3030 * transcoding from internal UTF-8
3031 * The buffer is lossless, i.e. will store in case of partial
3032 * or delayed writes.
3033 *
3034 * Returns the number of chars immediately written, or -1
3035 * in case of error.
3036 */
3037int
Daniel Veillardee8960b2004-05-14 03:25:14 +00003038xmlOutputBufferWriteEscape(xmlOutputBufferPtr out, const xmlChar *str,
3039 xmlCharEncodingOutputFunc escaping) {
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003040 int nbchars = 0; /* number of chars to output to I/O */
3041 int ret; /* return from function call */
3042 int written = 0; /* number of char written to I/O so far */
Daniel Veillard71b95632004-08-31 12:15:36 +00003043 int oldwritten=0;/* loop guard */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003044 int chunk; /* number of byte currently processed from str */
3045 int len; /* number of bytes in str */
3046 int cons; /* byte from str consumed */
3047
3048 if ((out == NULL) || (out->error) || (str == NULL)) return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003049 len = strlen((const char *)str);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003050 if (len < 0) return(0);
3051 if (out->error) return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003052 if (escaping == NULL) escaping = xmlEscapeContent;
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003053
3054 do {
Daniel Veillard71b95632004-08-31 12:15:36 +00003055 oldwritten = written;
3056
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003057 /*
3058 * how many bytes to consume and how many bytes to store.
3059 */
3060 cons = len;
3061 chunk = (out->buffer->size - out->buffer->use) - 1;
3062
3063 /*
3064 * first handle encoding stuff.
3065 */
3066 if (out->encoder != NULL) {
3067 /*
3068 * Store the data in the incoming raw buffer
3069 */
3070 if (out->conv == NULL) {
3071 out->conv = xmlBufferCreate();
3072 }
Daniel Veillardee8960b2004-05-14 03:25:14 +00003073 ret = escaping(out->buffer->content + out->buffer->use ,
3074 &chunk, str, &cons);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003075 if (ret < 0)
3076 return(-1);
3077 out->buffer->use += chunk;
3078 out->buffer->content[out->buffer->use] = 0;
3079
3080 if ((out->buffer->use < MINLEN) && (cons == len))
3081 goto done;
3082
3083 /*
3084 * convert as much as possible to the output buffer.
3085 */
3086 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
3087 if ((ret < 0) && (ret != -3)) {
3088 xmlIOErr(XML_IO_ENCODER, NULL);
3089 out->error = XML_IO_ENCODER;
3090 return(-1);
3091 }
3092 nbchars = out->conv->use;
3093 } else {
Daniel Veillardee8960b2004-05-14 03:25:14 +00003094 ret = escaping(out->buffer->content + out->buffer->use ,
3095 &chunk, str, &cons);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003096 if (ret < 0)
3097 return(-1);
3098 out->buffer->use += chunk;
3099 out->buffer->content[out->buffer->use] = 0;
3100 nbchars = out->buffer->use;
3101 }
3102 str += cons;
3103 len -= cons;
3104
3105 if ((nbchars < MINLEN) && (len <= 0))
3106 goto done;
3107
3108 if (out->writecallback) {
3109 /*
3110 * second write the stuff to the I/O channel
3111 */
3112 if (out->encoder != NULL) {
3113 ret = out->writecallback(out->context,
3114 (const char *)out->conv->content, nbchars);
3115 if (ret >= 0)
3116 xmlBufferShrink(out->conv, ret);
3117 } else {
3118 ret = out->writecallback(out->context,
3119 (const char *)out->buffer->content, nbchars);
3120 if (ret >= 0)
3121 xmlBufferShrink(out->buffer, ret);
3122 }
3123 if (ret < 0) {
3124 xmlIOErr(XML_IO_WRITE, NULL);
3125 out->error = XML_IO_WRITE;
3126 return(ret);
3127 }
3128 out->written += ret;
Daniel Veillard83a75e02004-05-14 21:50:42 +00003129 } else if (out->buffer->size - out->buffer->use < MINLEN) {
3130 xmlBufferResize(out->buffer, out->buffer->size + MINLEN);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003131 }
3132 written += nbchars;
Daniel Veillard71b95632004-08-31 12:15:36 +00003133 } while ((len > 0) && (oldwritten != written));
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003134
3135done:
3136#ifdef DEBUG_INPUT
3137 xmlGenericError(xmlGenericErrorContext,
3138 "I/O: wrote %d chars\n", written);
3139#endif
3140 return(written);
3141}
3142
3143/**
Owen Taylor3473f882001-02-23 17:55:21 +00003144 * xmlOutputBufferWriteString:
3145 * @out: a buffered parser output
3146 * @str: a zero terminated C string
3147 *
3148 * Write the content of the string in the output I/O buffer
3149 * This routine handle the I18N transcoding from internal UTF-8
3150 * The buffer is lossless, i.e. will store in case of partial
3151 * or delayed writes.
3152 *
3153 * Returns the number of chars immediately written, or -1
3154 * in case of error.
3155 */
3156int
3157xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
3158 int len;
3159
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003160 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003161 if (str == NULL)
3162 return(-1);
3163 len = strlen(str);
3164
3165 if (len > 0)
3166 return(xmlOutputBufferWrite(out, len, str));
3167 return(len);
3168}
3169
3170/**
3171 * xmlOutputBufferFlush:
3172 * @out: a buffered output
3173 *
3174 * flushes the output I/O channel
3175 *
3176 * Returns the number of byte written or -1 in case of error.
3177 */
3178int
3179xmlOutputBufferFlush(xmlOutputBufferPtr out) {
3180 int nbchars = 0, ret = 0;
3181
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003182 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003183 /*
3184 * first handle encoding stuff.
3185 */
3186 if ((out->conv != NULL) && (out->encoder != NULL)) {
3187 /*
3188 * convert as much as possible to the parser reading buffer.
3189 */
3190 nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
3191 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003192 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003193 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003194 return(-1);
3195 }
3196 }
3197
3198 /*
3199 * second flush the stuff to the I/O channel
3200 */
3201 if ((out->conv != NULL) && (out->encoder != NULL) &&
3202 (out->writecallback != NULL)) {
3203 ret = out->writecallback(out->context,
3204 (const char *)out->conv->content, out->conv->use);
3205 if (ret >= 0)
3206 xmlBufferShrink(out->conv, ret);
3207 } else if (out->writecallback != NULL) {
3208 ret = out->writecallback(out->context,
3209 (const char *)out->buffer->content, out->buffer->use);
3210 if (ret >= 0)
3211 xmlBufferShrink(out->buffer, ret);
3212 }
3213 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003214 xmlIOErr(XML_IO_FLUSH, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003215 out->error = XML_IO_FLUSH;
Owen Taylor3473f882001-02-23 17:55:21 +00003216 return(ret);
3217 }
3218 out->written += ret;
3219
3220#ifdef DEBUG_INPUT
3221 xmlGenericError(xmlGenericErrorContext,
3222 "I/O: flushed %d chars\n", ret);
3223#endif
3224 return(ret);
3225}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003226#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003227
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003228/**
Owen Taylor3473f882001-02-23 17:55:21 +00003229 * xmlParserGetDirectory:
3230 * @filename: the path to a file
3231 *
3232 * lookup the directory for that file
3233 *
3234 * Returns a new allocated string containing the directory, or NULL.
3235 */
3236char *
3237xmlParserGetDirectory(const char *filename) {
3238 char *ret = NULL;
3239 char dir[1024];
3240 char *cur;
3241 char sep = '/';
3242
Igor Zlatkovic9181cc02002-09-29 17:51:06 +00003243#ifdef _WIN32_WCE /* easy way by now ... wince does not have dirs! */
3244 return NULL;
3245#endif
3246
Owen Taylor3473f882001-02-23 17:55:21 +00003247 if (xmlInputCallbackInitialized == 0)
3248 xmlRegisterDefaultInputCallbacks();
3249
3250 if (filename == NULL) return(NULL);
Daniel Veillard3c5ed912002-01-08 10:36:16 +00003251#if defined(WIN32) && !defined(__CYGWIN__)
Owen Taylor3473f882001-02-23 17:55:21 +00003252 sep = '\\';
3253#endif
3254
3255 strncpy(dir, filename, 1023);
3256 dir[1023] = 0;
3257 cur = &dir[strlen(dir)];
3258 while (cur > dir) {
3259 if (*cur == sep) break;
3260 cur --;
3261 }
3262 if (*cur == sep) {
3263 if (cur == dir) dir[1] = 0;
3264 else *cur = 0;
3265 ret = xmlMemStrdup(dir);
3266 } else {
3267 if (getcwd(dir, 1024) != NULL) {
3268 dir[1023] = 0;
3269 ret = xmlMemStrdup(dir);
3270 }
3271 }
3272 return(ret);
3273}
3274
3275/****************************************************************
3276 * *
3277 * External entities loading *
3278 * *
3279 ****************************************************************/
3280
Daniel Veillarda840b692003-10-19 13:35:37 +00003281/**
3282 * xmlCheckHTTPInput:
3283 * @ctxt: an XML parser context
3284 * @ret: an XML parser input
3285 *
3286 * Check an input in case it was created from an HTTP stream, in that
3287 * case it will handle encoding and update of the base URL in case of
3288 * redirection. It also checks for HTTP errors in which case the input
3289 * is cleanly freed up and an appropriate error is raised in context
3290 *
3291 * Returns the input or NULL in case of HTTP error.
3292 */
3293xmlParserInputPtr
3294xmlCheckHTTPInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr ret) {
3295#ifdef LIBXML_HTTP_ENABLED
3296 if ((ret != NULL) && (ret->buf != NULL) &&
3297 (ret->buf->readcallback == xmlIOHTTPRead) &&
3298 (ret->buf->context != NULL)) {
3299 const char *encoding;
3300 const char *redir;
3301 const char *mime;
3302 int code;
3303
3304 code = xmlNanoHTTPReturnCode(ret->buf->context);
3305 if (code >= 400) {
3306 /* fatal error */
3307 if (ret->filename != NULL)
Daniel Veillarde8039df2003-10-27 11:25:13 +00003308 __xmlLoaderErr(ctxt, "failed to load HTTP resource \"%s\"\n",
Daniel Veillarda840b692003-10-19 13:35:37 +00003309 (const char *) ret->filename);
3310 else
Daniel Veillarde8039df2003-10-27 11:25:13 +00003311 __xmlLoaderErr(ctxt, "failed to load HTTP resource\n", NULL);
Daniel Veillarda840b692003-10-19 13:35:37 +00003312 xmlFreeInputStream(ret);
3313 ret = NULL;
3314 } else {
3315
3316 mime = xmlNanoHTTPMimeType(ret->buf->context);
3317 if ((xmlStrstr(BAD_CAST mime, BAD_CAST "/xml")) ||
3318 (xmlStrstr(BAD_CAST mime, BAD_CAST "+xml"))) {
3319 encoding = xmlNanoHTTPEncoding(ret->buf->context);
3320 if (encoding != NULL) {
3321 xmlCharEncodingHandlerPtr handler;
3322
3323 handler = xmlFindCharEncodingHandler(encoding);
3324 if (handler != NULL) {
3325 xmlSwitchInputEncoding(ctxt, ret, handler);
3326 } else {
3327 __xmlErrEncoding(ctxt, XML_ERR_UNKNOWN_ENCODING,
3328 "Unknown encoding %s",
3329 BAD_CAST encoding, NULL);
3330 }
3331 if (ret->encoding == NULL)
3332 ret->encoding = xmlStrdup(BAD_CAST encoding);
3333 }
3334#if 0
3335 } else if (xmlStrstr(BAD_CAST mime, BAD_CAST "html")) {
3336#endif
3337 }
3338 redir = xmlNanoHTTPRedir(ret->buf->context);
3339 if (redir != NULL) {
3340 if (ret->filename != NULL)
3341 xmlFree((xmlChar *) ret->filename);
3342 if (ret->directory != NULL) {
3343 xmlFree((xmlChar *) ret->directory);
3344 ret->directory = NULL;
3345 }
3346 ret->filename =
3347 (char *) xmlStrdup((const xmlChar *) redir);
3348 }
3349 }
3350 }
3351#endif
3352 return(ret);
3353}
3354
Daniel Veillard561b7f82002-03-20 21:55:57 +00003355static int xmlSysIDExists(const char *URL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003356#ifdef HAVE_STAT
3357 int ret;
3358 struct stat info;
3359 const char *path;
3360
3361 if (URL == NULL)
3362 return(0);
3363
Daniel Veillardf4862f02002-09-10 11:13:43 +00003364 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003365#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00003366 path = &URL[17];
3367#else
Daniel Veillard6990bf32001-08-23 21:17:48 +00003368 path = &URL[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00003369#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003370 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003371#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard6990bf32001-08-23 21:17:48 +00003372 path = &URL[8];
3373#else
3374 path = &URL[7];
3375#endif
3376 } else
3377 path = URL;
3378 ret = stat(path, &info);
Daniel Veillard561b7f82002-03-20 21:55:57 +00003379 if (ret == 0)
3380 return(1);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003381#endif
Daniel Veillard561b7f82002-03-20 21:55:57 +00003382 return(0);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003383}
Daniel Veillard6990bf32001-08-23 21:17:48 +00003384
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003385/**
Owen Taylor3473f882001-02-23 17:55:21 +00003386 * xmlDefaultExternalEntityLoader:
3387 * @URL: the URL for the entity to load
3388 * @ID: the System ID for the entity to load
3389 * @ctxt: the context in which the entity is called or NULL
3390 *
3391 * By default we don't load external entitites, yet.
3392 *
3393 * Returns a new allocated xmlParserInputPtr, or NULL.
3394 */
Daniel Veillarda840b692003-10-19 13:35:37 +00003395static xmlParserInputPtr
Owen Taylor3473f882001-02-23 17:55:21 +00003396xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
Daniel Veillarda840b692003-10-19 13:35:37 +00003397 xmlParserCtxtPtr ctxt)
3398{
Owen Taylor3473f882001-02-23 17:55:21 +00003399 xmlParserInputPtr ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003400 xmlChar *resource = NULL;
Daniel Veillarda840b692003-10-19 13:35:37 +00003401
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003402#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003403 xmlCatalogAllow pref;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003404#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003405
3406#ifdef DEBUG_EXTERNAL_ENTITIES
3407 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda840b692003-10-19 13:35:37 +00003408 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00003409#endif
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003410#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillard61b93382003-11-03 14:28:31 +00003411 if ((ctxt != NULL) && (ctxt->options & XML_PARSE_NONET)) {
3412 int options = ctxt->options;
3413
3414 ctxt->options -= XML_PARSE_NONET;
3415 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
3416 ctxt->options = options;
3417 return(ret);
3418 }
3419
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003420 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003421 * If the resource doesn't exists as a file,
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003422 * try to load it from the resource pointed in the catalogs
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003423 */
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003424 pref = xmlCatalogGetDefaults();
3425
Daniel Veillard561b7f82002-03-20 21:55:57 +00003426 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlSysIDExists(URL))) {
Daniel Veillarda840b692003-10-19 13:35:37 +00003427 /*
3428 * Do a local lookup
3429 */
3430 if ((ctxt->catalogs != NULL) &&
3431 ((pref == XML_CATA_ALLOW_ALL) ||
3432 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3433 resource = xmlCatalogLocalResolve(ctxt->catalogs,
3434 (const xmlChar *) ID,
3435 (const xmlChar *) URL);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003436 }
Daniel Veillarda840b692003-10-19 13:35:37 +00003437 /*
3438 * Try a global lookup
3439 */
3440 if ((resource == NULL) &&
3441 ((pref == XML_CATA_ALLOW_ALL) ||
3442 (pref == XML_CATA_ALLOW_GLOBAL))) {
3443 resource = xmlCatalogResolve((const xmlChar *) ID,
3444 (const xmlChar *) URL);
3445 }
3446 if ((resource == NULL) && (URL != NULL))
3447 resource = xmlStrdup((const xmlChar *) URL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003448
Daniel Veillarda840b692003-10-19 13:35:37 +00003449 /*
3450 * TODO: do an URI lookup on the reference
3451 */
3452 if ((resource != NULL)
3453 && (!xmlSysIDExists((const char *) resource))) {
3454 xmlChar *tmp = NULL;
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003455
Daniel Veillarda840b692003-10-19 13:35:37 +00003456 if ((ctxt->catalogs != NULL) &&
3457 ((pref == XML_CATA_ALLOW_ALL) ||
3458 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3459 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
3460 }
3461 if ((tmp == NULL) &&
3462 ((pref == XML_CATA_ALLOW_ALL) ||
3463 (pref == XML_CATA_ALLOW_GLOBAL))) {
3464 tmp = xmlCatalogResolveURI(resource);
3465 }
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003466
Daniel Veillarda840b692003-10-19 13:35:37 +00003467 if (tmp != NULL) {
3468 xmlFree(resource);
3469 resource = tmp;
3470 }
3471 }
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003472 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003473#endif
3474
3475 if (resource == NULL)
Daniel Veillarda840b692003-10-19 13:35:37 +00003476 resource = (xmlChar *) URL;
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003477
3478 if (resource == NULL) {
Daniel Veillarda840b692003-10-19 13:35:37 +00003479 if (ID == NULL)
3480 ID = "NULL";
Daniel Veillarde8039df2003-10-27 11:25:13 +00003481 __xmlLoaderErr(ctxt, "failed to load external entity \"%s\"\n", ID);
Daniel Veillarda840b692003-10-19 13:35:37 +00003482 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003483 }
Daniel Veillarda840b692003-10-19 13:35:37 +00003484 ret = xmlNewInputFromFile(ctxt, (const char *) resource);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003485 if ((resource != NULL) && (resource != (xmlChar *) URL))
Daniel Veillarda840b692003-10-19 13:35:37 +00003486 xmlFree(resource);
3487 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003488}
3489
3490static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
3491 xmlDefaultExternalEntityLoader;
3492
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003493/**
Owen Taylor3473f882001-02-23 17:55:21 +00003494 * xmlSetExternalEntityLoader:
3495 * @f: the new entity resolver function
3496 *
3497 * Changes the defaultexternal entity resolver function for the application
3498 */
3499void
3500xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
3501 xmlCurrentExternalEntityLoader = f;
3502}
3503
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003504/**
Owen Taylor3473f882001-02-23 17:55:21 +00003505 * xmlGetExternalEntityLoader:
3506 *
3507 * Get the default external entity resolver function for the application
3508 *
3509 * Returns the xmlExternalEntityLoader function pointer
3510 */
3511xmlExternalEntityLoader
3512xmlGetExternalEntityLoader(void) {
3513 return(xmlCurrentExternalEntityLoader);
3514}
3515
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003516/**
Owen Taylor3473f882001-02-23 17:55:21 +00003517 * xmlLoadExternalEntity:
3518 * @URL: the URL for the entity to load
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00003519 * @ID: the Public ID for the entity to load
Owen Taylor3473f882001-02-23 17:55:21 +00003520 * @ctxt: the context in which the entity is called or NULL
3521 *
3522 * Load an external entity, note that the use of this function for
3523 * unparsed entities may generate problems
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003524 * TODO: a more generic External entity API must be designed
Owen Taylor3473f882001-02-23 17:55:21 +00003525 *
3526 * Returns the xmlParserInputPtr or NULL
3527 */
3528xmlParserInputPtr
3529xmlLoadExternalEntity(const char *URL, const char *ID,
3530 xmlParserCtxtPtr ctxt) {
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00003531 if ((URL != NULL) && (xmlSysIDExists(URL) == 0)) {
3532 char *canonicFilename;
3533 xmlParserInputPtr ret;
3534
3535 canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL);
3536 if (canonicFilename == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003537 xmlIOErrMemory("building canonical path\n");
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00003538 return(NULL);
3539 }
3540
3541 ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt);
3542 xmlFree(canonicFilename);
3543 return(ret);
3544 }
Owen Taylor3473f882001-02-23 17:55:21 +00003545 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
3546}
3547
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003548/************************************************************************
3549 * *
3550 * Disabling Network access *
3551 * *
3552 ************************************************************************/
3553
3554#ifdef LIBXML_CATALOG_ENABLED
3555static int
3556xmlNoNetExists(const char *URL)
3557{
3558#ifdef HAVE_STAT
3559 int ret;
3560 struct stat info;
3561 const char *path;
3562
3563 if (URL == NULL)
3564 return (0);
3565
Daniel Veillardf4862f02002-09-10 11:13:43 +00003566 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003567#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00003568 path = &URL[17];
3569#else
3570 path = &URL[16];
3571#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003572 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003573#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003574 path = &URL[8];
3575#else
3576 path = &URL[7];
3577#endif
3578 } else
3579 path = URL;
3580 ret = stat(path, &info);
3581 if (ret == 0)
3582 return (1);
3583#endif
3584 return (0);
3585}
3586#endif
3587
3588/**
3589 * xmlNoNetExternalEntityLoader:
3590 * @URL: the URL for the entity to load
3591 * @ID: the System ID for the entity to load
3592 * @ctxt: the context in which the entity is called or NULL
3593 *
3594 * A specific entity loader disabling network accesses, though still
3595 * allowing local catalog accesses for resolution.
3596 *
3597 * Returns a new allocated xmlParserInputPtr, or NULL.
3598 */
3599xmlParserInputPtr
3600xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
3601 xmlParserCtxtPtr ctxt) {
3602 xmlParserInputPtr input = NULL;
3603 xmlChar *resource = NULL;
3604
3605#ifdef LIBXML_CATALOG_ENABLED
3606 xmlCatalogAllow pref;
3607
3608 /*
3609 * If the resource doesn't exists as a file,
3610 * try to load it from the resource pointed in the catalogs
3611 */
3612 pref = xmlCatalogGetDefaults();
3613
3614 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
3615 /*
3616 * Do a local lookup
3617 */
3618 if ((ctxt->catalogs != NULL) &&
3619 ((pref == XML_CATA_ALLOW_ALL) ||
3620 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3621 resource = xmlCatalogLocalResolve(ctxt->catalogs,
3622 (const xmlChar *)ID,
3623 (const xmlChar *)URL);
3624 }
3625 /*
3626 * Try a global lookup
3627 */
3628 if ((resource == NULL) &&
3629 ((pref == XML_CATA_ALLOW_ALL) ||
3630 (pref == XML_CATA_ALLOW_GLOBAL))) {
3631 resource = xmlCatalogResolve((const xmlChar *)ID,
3632 (const xmlChar *)URL);
3633 }
3634 if ((resource == NULL) && (URL != NULL))
3635 resource = xmlStrdup((const xmlChar *) URL);
3636
3637 /*
3638 * TODO: do an URI lookup on the reference
3639 */
3640 if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
3641 xmlChar *tmp = NULL;
3642
3643 if ((ctxt->catalogs != NULL) &&
3644 ((pref == XML_CATA_ALLOW_ALL) ||
3645 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3646 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
3647 }
3648 if ((tmp == NULL) &&
3649 ((pref == XML_CATA_ALLOW_ALL) ||
3650 (pref == XML_CATA_ALLOW_GLOBAL))) {
3651 tmp = xmlCatalogResolveURI(resource);
3652 }
3653
3654 if (tmp != NULL) {
3655 xmlFree(resource);
3656 resource = tmp;
3657 }
3658 }
3659 }
3660#endif
3661 if (resource == NULL)
3662 resource = (xmlChar *) URL;
3663
3664 if (resource != NULL) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003665 if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
3666 (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003667 xmlIOErr(XML_IO_NETWORK_ATTEMPT, (const char *) resource);
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003668 if (resource != (xmlChar *) URL)
3669 xmlFree(resource);
3670 return(NULL);
3671 }
3672 }
3673 input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
3674 if (resource != (xmlChar *) URL)
3675 xmlFree(resource);
3676 return(input);
3677}
3678