blob: 2c73f6125ace67faf38b14ccc0b290fe91336600 [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
2 * xmlIO.c : implementation of the I/O interfaces used by the parser
3 *
4 * See Copyright for the status of this software.
5 *
Daniel Veillard344cee72001-08-20 00:08:40 +00006 * daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +00007 *
8 * 14 Nov 2000 ht - for VMS, truncated name of long functions to under 32 char
9 */
10
Daniel Veillard34ce8be2002-03-18 19:37:11 +000011#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000012#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000013
Owen Taylor3473f882001-02-23 17:55:21 +000014#include <string.h>
Daniel Veillard92727042002-09-17 17:59:20 +000015#ifdef HAVE_ERRNO_H
Owen Taylor3473f882001-02-23 17:55:21 +000016#include <errno.h>
Daniel Veillard92727042002-09-17 17:59:20 +000017#endif
18
Owen Taylor3473f882001-02-23 17:55:21 +000019
20#ifdef HAVE_SYS_TYPES_H
21#include <sys/types.h>
22#endif
23#ifdef HAVE_SYS_STAT_H
24#include <sys/stat.h>
25#endif
26#ifdef HAVE_FCNTL_H
27#include <fcntl.h>
28#endif
29#ifdef HAVE_UNISTD_H
30#include <unistd.h>
31#endif
32#ifdef HAVE_STDLIB_H
33#include <stdlib.h>
34#endif
35#ifdef HAVE_ZLIB_H
36#include <zlib.h>
37#endif
38
39/* Figure a portable way to know if a file is a directory. */
40#ifndef HAVE_STAT
41# ifdef HAVE__STAT
Daniel Veillard50f34372001-08-03 12:06:36 +000042 /* MS C library seems to define stat and _stat. The definition
43 is identical. Still, mapping them to each other causes a warning. */
44# ifndef _MSC_VER
45# define stat(x,y) _stat(x,y)
46# endif
Owen Taylor3473f882001-02-23 17:55:21 +000047# define HAVE_STAT
48# endif
49#endif
50#ifdef HAVE_STAT
51# ifndef S_ISDIR
52# ifdef _S_ISDIR
53# define S_ISDIR(x) _S_ISDIR(x)
54# else
55# ifdef S_IFDIR
56# ifndef S_IFMT
57# ifdef _S_IFMT
58# define S_IFMT _S_IFMT
59# endif
60# endif
61# ifdef S_IFMT
62# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
63# endif
64# endif
65# endif
66# endif
67#endif
68
69#include <libxml/xmlmemory.h>
70#include <libxml/parser.h>
71#include <libxml/parserInternals.h>
72#include <libxml/xmlIO.h>
Daniel Veillard388236f2001-07-08 18:35:48 +000073#include <libxml/uri.h>
Owen Taylor3473f882001-02-23 17:55:21 +000074#include <libxml/nanohttp.h>
75#include <libxml/nanoftp.h>
76#include <libxml/xmlerror.h>
Daniel Veillard7d6fd212001-05-10 15:34:11 +000077#ifdef LIBXML_CATALOG_ENABLED
78#include <libxml/catalog.h>
79#endif
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000080#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000081
Daniel Veillardf012a642001-07-23 19:10:52 +000082/* #define VERBOSE_FAILURE */
Daniel Veillard1fd36d22001-07-04 22:54:28 +000083/* #define DEBUG_EXTERNAL_ENTITIES */
Owen Taylor3473f882001-02-23 17:55:21 +000084/* #define DEBUG_INPUT */
85
86#ifdef DEBUG_INPUT
87#define MINLEN 40
88#else
89#define MINLEN 4000
90#endif
91
92/*
93 * Input I/O callback sets
94 */
95typedef struct _xmlInputCallback {
96 xmlInputMatchCallback matchcallback;
97 xmlInputOpenCallback opencallback;
98 xmlInputReadCallback readcallback;
99 xmlInputCloseCallback closecallback;
100} xmlInputCallback;
101
102#define MAX_INPUT_CALLBACK 15
103
Daniel Veillard22090732001-07-16 00:06:07 +0000104static xmlInputCallback xmlInputCallbackTable[MAX_INPUT_CALLBACK];
105static int xmlInputCallbackNr = 0;
106static int xmlInputCallbackInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000107
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000108#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000109/*
110 * Output I/O callback sets
111 */
112typedef struct _xmlOutputCallback {
113 xmlOutputMatchCallback matchcallback;
114 xmlOutputOpenCallback opencallback;
115 xmlOutputWriteCallback writecallback;
116 xmlOutputCloseCallback closecallback;
117} xmlOutputCallback;
118
119#define MAX_OUTPUT_CALLBACK 15
120
Daniel Veillard22090732001-07-16 00:06:07 +0000121static xmlOutputCallback xmlOutputCallbackTable[MAX_OUTPUT_CALLBACK];
122static int xmlOutputCallbackNr = 0;
123static int xmlOutputCallbackInitialized = 0;
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000124#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000125
Daniel Veillard05d987b2003-10-08 11:54:57 +0000126/************************************************************************
127 * *
128 * Tree memory error handler *
129 * *
130 ************************************************************************/
Daniel Veillardf4862f02002-09-10 11:13:43 +0000131
Daniel Veillard05d987b2003-10-08 11:54:57 +0000132static const char *IOerr[] = {
Daniel Veillarda8856222003-10-08 19:26:03 +0000133 "Unknown IO error", /* UNKNOWN */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000134 "Permission denied", /* EACCES */
135 "Resource temporarily unavailable",/* EAGAIN */
136 "Bad file descriptor", /* EBADF */
137 "Bad message", /* EBADMSG */
138 "Resource busy", /* EBUSY */
139 "Operation canceled", /* ECANCELED */
140 "No child processes", /* ECHILD */
141 "Resource deadlock avoided",/* EDEADLK */
142 "Domain error", /* EDOM */
143 "File exists", /* EEXIST */
144 "Bad address", /* EFAULT */
145 "File too large", /* EFBIG */
146 "Operation in progress", /* EINPROGRESS */
147 "Interrupted function call",/* EINTR */
148 "Invalid argument", /* EINVAL */
149 "Input/output error", /* EIO */
150 "Is a directory", /* EISDIR */
151 "Too many open files", /* EMFILE */
152 "Too many links", /* EMLINK */
153 "Inappropriate message buffer length",/* EMSGSIZE */
154 "Filename too long", /* ENAMETOOLONG */
155 "Too many open files in system",/* ENFILE */
156 "No such device", /* ENODEV */
157 "No such file or directory",/* ENOENT */
158 "Exec format error", /* ENOEXEC */
159 "No locks available", /* ENOLCK */
160 "Not enough space", /* ENOMEM */
161 "No space left on device", /* ENOSPC */
162 "Function not implemented", /* ENOSYS */
163 "Not a directory", /* ENOTDIR */
164 "Directory not empty", /* ENOTEMPTY */
165 "Not supported", /* ENOTSUP */
166 "Inappropriate I/O control operation",/* ENOTTY */
167 "No such device or address",/* ENXIO */
168 "Operation not permitted", /* EPERM */
169 "Broken pipe", /* EPIPE */
170 "Result too large", /* ERANGE */
171 "Read-only file system", /* EROFS */
172 "Invalid seek", /* ESPIPE */
173 "No such process", /* ESRCH */
174 "Operation timed out", /* ETIMEDOUT */
175 "Improper link", /* EXDEV */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000176 "Attempt to load network entity %s", /* XML_IO_NETWORK_ATTEMPT */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000177 "encoder error", /* XML_IO_ENCODER */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000178 "flush error",
179 "write error",
180 "no input",
181 "buffer full",
182 "loading error",
183 "not a socket", /* ENOTSOCK */
184 "already connected", /* EISCONN */
Daniel Veillard29b17482004-08-16 00:39:03 +0000185 "connection refused", /* ECONNREFUSED */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000186 "unreachable network", /* ENETUNREACH */
187 "adddress in use", /* EADDRINUSE */
188 "already in use", /* EALREADY */
189 "unknown address familly", /* EAFNOSUPPORT */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000190};
191
192/**
193 * xmlIOErrMemory:
194 * @extra: extra informations
195 *
196 * Handle an out of memory condition
197 */
198static void
199xmlIOErrMemory(const char *extra)
200{
201 __xmlSimpleError(XML_FROM_IO, XML_ERR_NO_MEMORY, NULL, NULL, extra);
202}
203
204/**
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000205 * __xmlIOErr:
Daniel Veillard05d987b2003-10-08 11:54:57 +0000206 * @code: the error number
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000207 * @
Daniel Veillard05d987b2003-10-08 11:54:57 +0000208 * @extra: extra informations
209 *
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000210 * Handle an I/O error
Daniel Veillard05d987b2003-10-08 11:54:57 +0000211 */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000212void
213__xmlIOErr(int domain, int code, const char *extra)
Daniel Veillard05d987b2003-10-08 11:54:57 +0000214{
215 unsigned int idx;
216
217 if (code == 0) {
218#ifdef HAVE_ERRNO_H
219 if (errno == 0) code = 0;
220#ifdef EACCES
221 else if (errno == EACCES) code = XML_IO_EACCES;
222#endif
223#ifdef EAGAIN
224 else if (errno == EAGAIN) code = XML_IO_EAGAIN;
225#endif
226#ifdef EBADF
227 else if (errno == EBADF) code = XML_IO_EBADF;
228#endif
229#ifdef EBADMSG
230 else if (errno == EBADMSG) code = XML_IO_EBADMSG;
231#endif
232#ifdef EBUSY
233 else if (errno == EBUSY) code = XML_IO_EBUSY;
234#endif
235#ifdef ECANCELED
236 else if (errno == ECANCELED) code = XML_IO_ECANCELED;
237#endif
238#ifdef ECHILD
239 else if (errno == ECHILD) code = XML_IO_ECHILD;
240#endif
241#ifdef EDEADLK
242 else if (errno == EDEADLK) code = XML_IO_EDEADLK;
243#endif
244#ifdef EDOM
245 else if (errno == EDOM) code = XML_IO_EDOM;
246#endif
247#ifdef EEXIST
248 else if (errno == EEXIST) code = XML_IO_EEXIST;
249#endif
250#ifdef EFAULT
251 else if (errno == EFAULT) code = XML_IO_EFAULT;
252#endif
253#ifdef EFBIG
254 else if (errno == EFBIG) code = XML_IO_EFBIG;
255#endif
256#ifdef EINPROGRESS
257 else if (errno == EINPROGRESS) code = XML_IO_EINPROGRESS;
258#endif
259#ifdef EINTR
260 else if (errno == EINTR) code = XML_IO_EINTR;
261#endif
262#ifdef EINVAL
263 else if (errno == EINVAL) code = XML_IO_EINVAL;
264#endif
265#ifdef EIO
266 else if (errno == EIO) code = XML_IO_EIO;
267#endif
268#ifdef EISDIR
269 else if (errno == EISDIR) code = XML_IO_EISDIR;
270#endif
271#ifdef EMFILE
272 else if (errno == EMFILE) code = XML_IO_EMFILE;
273#endif
274#ifdef EMLINK
275 else if (errno == EMLINK) code = XML_IO_EMLINK;
276#endif
277#ifdef EMSGSIZE
278 else if (errno == EMSGSIZE) code = XML_IO_EMSGSIZE;
279#endif
280#ifdef ENAMETOOLONG
281 else if (errno == ENAMETOOLONG) code = XML_IO_ENAMETOOLONG;
282#endif
283#ifdef ENFILE
284 else if (errno == ENFILE) code = XML_IO_ENFILE;
285#endif
286#ifdef ENODEV
287 else if (errno == ENODEV) code = XML_IO_ENODEV;
288#endif
289#ifdef ENOENT
290 else if (errno == ENOENT) code = XML_IO_ENOENT;
291#endif
292#ifdef ENOEXEC
293 else if (errno == ENOEXEC) code = XML_IO_ENOEXEC;
294#endif
295#ifdef ENOLCK
296 else if (errno == ENOLCK) code = XML_IO_ENOLCK;
297#endif
298#ifdef ENOMEM
299 else if (errno == ENOMEM) code = XML_IO_ENOMEM;
300#endif
301#ifdef ENOSPC
302 else if (errno == ENOSPC) code = XML_IO_ENOSPC;
303#endif
304#ifdef ENOSYS
305 else if (errno == ENOSYS) code = XML_IO_ENOSYS;
306#endif
307#ifdef ENOTDIR
308 else if (errno == ENOTDIR) code = XML_IO_ENOTDIR;
309#endif
310#ifdef ENOTEMPTY
311 else if (errno == ENOTEMPTY) code = XML_IO_ENOTEMPTY;
312#endif
313#ifdef ENOTSUP
314 else if (errno == ENOTSUP) code = XML_IO_ENOTSUP;
315#endif
316#ifdef ENOTTY
317 else if (errno == ENOTTY) code = XML_IO_ENOTTY;
318#endif
319#ifdef ENXIO
320 else if (errno == ENXIO) code = XML_IO_ENXIO;
321#endif
322#ifdef EPERM
323 else if (errno == EPERM) code = XML_IO_EPERM;
324#endif
325#ifdef EPIPE
326 else if (errno == EPIPE) code = XML_IO_EPIPE;
327#endif
328#ifdef ERANGE
329 else if (errno == ERANGE) code = XML_IO_ERANGE;
330#endif
331#ifdef EROFS
332 else if (errno == EROFS) code = XML_IO_EROFS;
333#endif
334#ifdef ESPIPE
335 else if (errno == ESPIPE) code = XML_IO_ESPIPE;
336#endif
337#ifdef ESRCH
338 else if (errno == ESRCH) code = XML_IO_ESRCH;
339#endif
340#ifdef ETIMEDOUT
341 else if (errno == ETIMEDOUT) code = XML_IO_ETIMEDOUT;
342#endif
343#ifdef EXDEV
344 else if (errno == EXDEV) code = XML_IO_EXDEV;
345#endif
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000346#ifdef ENOTSOCK
347 else if (errno == ENOTSOCK) code = XML_IO_ENOTSOCK;
348#endif
349#ifdef EISCONN
350 else if (errno == EISCONN) code = XML_IO_EISCONN;
351#endif
352#ifdef ECONNREFUSED
353 else if (errno == ECONNREFUSED) code = XML_IO_ECONNREFUSED;
354#endif
355#ifdef ETIMEDOUT
356 else if (errno == ETIMEDOUT) code = XML_IO_ETIMEDOUT;
357#endif
358#ifdef ENETUNREACH
359 else if (errno == ENETUNREACH) code = XML_IO_ENETUNREACH;
360#endif
361#ifdef EADDRINUSE
362 else if (errno == EADDRINUSE) code = XML_IO_EADDRINUSE;
363#endif
364#ifdef EINPROGRESS
365 else if (errno == EINPROGRESS) code = XML_IO_EINPROGRESS;
366#endif
367#ifdef EALREADY
368 else if (errno == EALREADY) code = XML_IO_EALREADY;
369#endif
370#ifdef EAFNOSUPPORT
371 else if (errno == EAFNOSUPPORT) code = XML_IO_EAFNOSUPPORT;
372#endif
Daniel Veillard05d987b2003-10-08 11:54:57 +0000373 else code = XML_IO_UNKNOWN;
374#endif /* HAVE_ERRNO_H */
375 }
376 idx = 0;
377 if (code >= XML_IO_UNKNOWN) idx = code - XML_IO_UNKNOWN;
378 if (idx >= (sizeof(IOerr) / sizeof(IOerr[0]))) idx = 0;
379
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000380 __xmlSimpleError(domain, code, NULL, IOerr[idx], extra);
381}
382
383/**
384 * xmlIOErr:
385 * @code: the error number
386 * @extra: extra informations
387 *
388 * Handle an I/O error
389 */
390static void
391xmlIOErr(int code, const char *extra)
392{
393 __xmlIOErr(XML_FROM_IO, code, extra);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000394}
395
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000396/**
Daniel Veillarde8039df2003-10-27 11:25:13 +0000397 * __xmlLoaderErr:
398 * @ctx: the parser context
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000399 * @extra: extra informations
400 *
401 * Handle a resource access error
402 */
Daniel Veillarde8039df2003-10-27 11:25:13 +0000403void
404__xmlLoaderErr(void *ctx, const char *msg, const char *filename)
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000405{
Daniel Veillarde8039df2003-10-27 11:25:13 +0000406 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000407 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000408 xmlGenericErrorFunc channel = NULL;
409 void *data = NULL;
410 xmlErrorLevel level = XML_ERR_ERROR;
411
Daniel Veillard157fee02003-10-31 10:36:03 +0000412 if ((ctxt != NULL) && (ctxt->disableSAX != 0) &&
413 (ctxt->instate == XML_PARSER_EOF))
414 return;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000415 if ((ctxt != NULL) && (ctxt->sax != NULL)) {
416 if (ctxt->validate) {
417 channel = ctxt->sax->error;
418 level = XML_ERR_ERROR;
419 } else {
420 channel = ctxt->sax->warning;
421 level = XML_ERR_WARNING;
422 }
Daniel Veillard659e71e2003-10-10 14:10:40 +0000423 schannel = ctxt->sax->serror;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000424 data = ctxt->userData;
425 }
Daniel Veillard659e71e2003-10-10 14:10:40 +0000426 __xmlRaiseError(schannel, channel, data, ctxt, NULL, XML_FROM_IO,
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000427 XML_IO_LOAD_ERROR, level, NULL, 0,
428 filename, NULL, NULL, 0, 0,
429 msg, filename);
430
431}
432
Daniel Veillard05d987b2003-10-08 11:54:57 +0000433/************************************************************************
434 * *
435 * Tree memory error handler *
436 * *
437 ************************************************************************/
Daniel Veillardf4862f02002-09-10 11:13:43 +0000438/**
Daniel Veillard01c13b52002-12-10 15:19:08 +0000439 * xmlNormalizeWindowsPath:
Daniel Veillard33300b42003-04-17 09:09:19 +0000440 * @path: the input file path
Daniel Veillardf4862f02002-09-10 11:13:43 +0000441 *
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +0000442 * This function is obsolete. Please see xmlURIFromPath in uri.c for
443 * a better solution.
Daniel Veillard33300b42003-04-17 09:09:19 +0000444 *
445 * Returns a canonicalized version of the path
Daniel Veillardf4862f02002-09-10 11:13:43 +0000446 */
447xmlChar *
448xmlNormalizeWindowsPath(const xmlChar *path)
449{
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +0000450 return xmlCanonicPath(path);
Daniel Veillardf4862f02002-09-10 11:13:43 +0000451}
452
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000453/**
454 * xmlCleanupInputCallbacks:
455 *
456 * clears the entire input callback table. this includes the
457 * compiled-in I/O.
458 */
459void
460xmlCleanupInputCallbacks(void)
461{
462 int i;
463
464 if (!xmlInputCallbackInitialized)
465 return;
466
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000467 for (i = xmlInputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000468 xmlInputCallbackTable[i].matchcallback = NULL;
469 xmlInputCallbackTable[i].opencallback = NULL;
470 xmlInputCallbackTable[i].readcallback = NULL;
471 xmlInputCallbackTable[i].closecallback = NULL;
472 }
473
474 xmlInputCallbackNr = 0;
Aleksey Sanin9c45ba82002-06-06 21:46:13 +0000475 xmlInputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000476}
477
Daniel Veillardaecc0dc2004-05-08 02:32:07 +0000478/**
William M. Brack4e3a9fa2004-08-03 22:41:11 +0000479 * xmlPopInputCallbacks:
Daniel Veillardaecc0dc2004-05-08 02:32:07 +0000480 *
481 * Clear the top input callback from the input stack. this includes the
482 * compiled-in I/O.
483 *
484 * Returns the number of input callback registered or -1 in case of error.
485 */
486int
487xmlPopInputCallbacks(void)
488{
489 if (!xmlInputCallbackInitialized)
490 return(-1);
491
492 if (xmlInputCallbackNr <= 0)
493 return(-1);
494
495 xmlInputCallbackNr--;
496 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = NULL;
497 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = NULL;
498 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = NULL;
499 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = NULL;
500
501 return(xmlInputCallbackNr);
502}
503
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000504#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000505/**
506 * xmlCleanupOutputCallbacks:
507 *
508 * clears the entire output callback table. this includes the
509 * compiled-in I/O callbacks.
510 */
511void
512xmlCleanupOutputCallbacks(void)
513{
514 int i;
515
516 if (!xmlOutputCallbackInitialized)
517 return;
518
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000519 for (i = xmlOutputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000520 xmlOutputCallbackTable[i].matchcallback = NULL;
521 xmlOutputCallbackTable[i].opencallback = NULL;
522 xmlOutputCallbackTable[i].writecallback = NULL;
523 xmlOutputCallbackTable[i].closecallback = NULL;
524 }
525
526 xmlOutputCallbackNr = 0;
Aleksey Sanin9c45ba82002-06-06 21:46:13 +0000527 xmlOutputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000528}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000529#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000530
Owen Taylor3473f882001-02-23 17:55:21 +0000531/************************************************************************
532 * *
533 * Standard I/O for file accesses *
534 * *
535 ************************************************************************/
536
537/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000538 * xmlCheckFilename:
Owen Taylor3473f882001-02-23 17:55:21 +0000539 * @path: the path to check
540 *
541 * function checks to see if @path is a valid source
542 * (file, socket...) for XML.
543 *
544 * if stat is not available on the target machine,
545 * returns 1. if stat fails, returns 0 (if calling
546 * stat on the filename fails, it can't be right).
547 * if stat succeeds and the file is a directory,
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000548 * returns 2. otherwise returns 1.
Owen Taylor3473f882001-02-23 17:55:21 +0000549 */
550
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000551int
Owen Taylor3473f882001-02-23 17:55:21 +0000552xmlCheckFilename (const char *path)
553{
554#ifdef HAVE_STAT
Owen Taylor3473f882001-02-23 17:55:21 +0000555 struct stat stat_buffer;
556
Daniel Veillard34099b42004-11-04 17:34:35 +0000557 if (path == NULL)
558 return(0);
559
Owen Taylor3473f882001-02-23 17:55:21 +0000560 if (stat(path, &stat_buffer) == -1)
561 return 0;
562
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000563#ifdef S_ISDIR
Owen Taylor3473f882001-02-23 17:55:21 +0000564 if (S_ISDIR(stat_buffer.st_mode)) {
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000565 return 2;
Owen Taylor3473f882001-02-23 17:55:21 +0000566 }
Owen Taylor3473f882001-02-23 17:55:21 +0000567#endif
568#endif
Daniel Veillard34099b42004-11-04 17:34:35 +0000569 if (path == NULL)
570 return(0);
571
Owen Taylor3473f882001-02-23 17:55:21 +0000572 return 1;
573}
574
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000575static int
Owen Taylor3473f882001-02-23 17:55:21 +0000576xmlNop(void) {
577 return(0);
578}
579
580/**
Owen Taylor3473f882001-02-23 17:55:21 +0000581 * xmlFdRead:
582 * @context: the I/O context
583 * @buffer: where to drop data
584 * @len: number of bytes to read
585 *
586 * Read @len bytes to @buffer from the I/O channel.
587 *
588 * Returns the number of bytes written
589 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000590static int
Owen Taylor3473f882001-02-23 17:55:21 +0000591xmlFdRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000592 int ret;
593
594 ret = read((int) (long) context, &buffer[0], len);
595 if (ret < 0) xmlIOErr(0, "read()");
596 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000597}
598
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000599#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000600/**
601 * xmlFdWrite:
602 * @context: the I/O context
603 * @buffer: where to get data
604 * @len: number of bytes to write
605 *
606 * Write @len bytes from @buffer to the I/O channel.
607 *
608 * Returns the number of bytes written
609 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000610static int
Owen Taylor3473f882001-02-23 17:55:21 +0000611xmlFdWrite (void * context, const char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000612 int ret;
613
614 ret = write((int) (long) context, &buffer[0], len);
615 if (ret < 0) xmlIOErr(0, "write()");
616 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000617}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000618#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000619
620/**
621 * xmlFdClose:
622 * @context: the I/O context
623 *
624 * Close an I/O channel
Daniel Veillardf012a642001-07-23 19:10:52 +0000625 *
626 * Returns 0 in case of success and error code otherwise
Owen Taylor3473f882001-02-23 17:55:21 +0000627 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000628static int
Owen Taylor3473f882001-02-23 17:55:21 +0000629xmlFdClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000630 int ret;
631 ret = close((int) (long) context);
632 if (ret < 0) xmlIOErr(0, "close()");
633 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000634}
635
636/**
637 * xmlFileMatch:
638 * @filename: the URI for matching
639 *
640 * input from FILE *
641 *
642 * Returns 1 if matches, 0 otherwise
643 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000644int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000645xmlFileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000646 return(1);
647}
648
649/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000650 * xmlFileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +0000651 * @filename: the URI for matching
652 *
653 * input from FILE *, supports compressed input
654 * if @filename is " " then the standard input is used
655 *
656 * Returns an I/O context or NULL in case of error
657 */
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000658static void *
659xmlFileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +0000660 const char *path = NULL;
661 FILE *fd;
662
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000663 if (filename == NULL)
664 return(NULL);
665
Owen Taylor3473f882001-02-23 17:55:21 +0000666 if (!strcmp(filename, "-")) {
667 fd = stdin;
668 return((void *) fd);
669 }
670
Daniel Veillardf4862f02002-09-10 11:13:43 +0000671 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000672#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000673 path = &filename[17];
674#else
Owen Taylor3473f882001-02-23 17:55:21 +0000675 path = &filename[16];
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000676#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000677 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000678#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000679 path = &filename[8];
680#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000681 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000682#endif
683 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000684 path = filename;
685
686 if (path == NULL)
687 return(NULL);
688 if (!xmlCheckFilename(path))
689 return(NULL);
690
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000691#if defined(WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
Owen Taylor3473f882001-02-23 17:55:21 +0000692 fd = fopen(path, "rb");
693#else
694 fd = fopen(path, "r");
695#endif /* WIN32 */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000696 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +0000697 return((void *) fd);
698}
699
700/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000701 * xmlFileOpen:
702 * @filename: the URI for matching
703 *
704 * Wrapper around xmlFileOpen_real that try it with an unescaped
705 * version of @filename, if this fails fallback to @filename
Daniel Veillard71531f32003-02-05 13:19:53 +0000706 *
707 * Returns a handler or NULL in case or failure
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000708 */
709void *
710xmlFileOpen (const char *filename) {
711 char *unescaped;
712 void *retval;
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000713
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000714 unescaped = xmlURIUnescapeString(filename, 0, NULL);
715 if (unescaped != NULL) {
716 retval = xmlFileOpen_real(unescaped);
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000717 xmlFree(unescaped);
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000718 } else {
719 retval = xmlFileOpen_real(filename);
720 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000721 return retval;
722}
723
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000724#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000725/**
Owen Taylor3473f882001-02-23 17:55:21 +0000726 * xmlFileOpenW:
727 * @filename: the URI for matching
728 *
729 * output to from FILE *,
730 * if @filename is "-" then the standard output is used
731 *
732 * Returns an I/O context or NULL in case of error
733 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000734static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000735xmlFileOpenW (const char *filename) {
736 const char *path = NULL;
737 FILE *fd;
738
739 if (!strcmp(filename, "-")) {
740 fd = stdout;
741 return((void *) fd);
742 }
743
Daniel Veillardf4862f02002-09-10 11:13:43 +0000744 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000745#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000746 path = &filename[17];
747#else
Owen Taylor3473f882001-02-23 17:55:21 +0000748 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000749#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000750 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000751#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000752 path = &filename[8];
753#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000754 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000755#endif
756 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000757 path = filename;
758
759 if (path == NULL)
760 return(NULL);
761
Daniel Veillardcbbd78d2003-07-20 15:21:30 +0000762 fd = fopen(path, "wb");
Daniel Veillard05d987b2003-10-08 11:54:57 +0000763 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +0000764 return((void *) fd);
765}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000766#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000767
768/**
769 * xmlFileRead:
770 * @context: the I/O context
771 * @buffer: where to drop data
772 * @len: number of bytes to write
773 *
774 * Read @len bytes to @buffer from the I/O channel.
775 *
776 * Returns the number of bytes written
777 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000778int
Owen Taylor3473f882001-02-23 17:55:21 +0000779xmlFileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000780 int ret;
781 ret = fread(&buffer[0], 1, len, (FILE *) context);
782 if (ret < 0) xmlIOErr(0, "fread()");
783 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000784}
785
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000786#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000787/**
788 * xmlFileWrite:
789 * @context: the I/O context
790 * @buffer: where to drop data
791 * @len: number of bytes to write
792 *
793 * Write @len bytes from @buffer to the I/O channel.
794 *
795 * Returns the number of bytes written
796 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000797static int
Owen Taylor3473f882001-02-23 17:55:21 +0000798xmlFileWrite (void * context, const char * buffer, int len) {
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000799 int items;
800
801 items = fwrite(&buffer[0], len, 1, (FILE *) context);
Daniel Veillard97bf4d02003-10-08 18:58:28 +0000802 if ((items == 0) && (ferror((FILE *) context))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000803 xmlIOErr(0, "fwrite()");
Daniel Veillard97bf4d02003-10-08 18:58:28 +0000804 return(-1);
805 }
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000806 return(items * len);
Owen Taylor3473f882001-02-23 17:55:21 +0000807}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000808#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000809
810/**
811 * xmlFileClose:
812 * @context: the I/O context
813 *
814 * Close an I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000815 *
816 * Returns 0 or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +0000817 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000818int
Owen Taylor3473f882001-02-23 17:55:21 +0000819xmlFileClose (void * context) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000820 FILE *fil;
Daniel Veillard05d987b2003-10-08 11:54:57 +0000821 int ret;
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000822
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000823 if (context == NULL)
824 return(-1);
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000825 fil = (FILE *) context;
Daniel Veillard500a1de2004-03-22 15:22:58 +0000826 if ((fil == stdout) || (fil == stderr)) {
827 ret = fflush(fil);
828 if (ret < 0)
829 xmlIOErr(0, "fflush()");
830 return(0);
831 }
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000832 if (fil == stdin)
833 return(0);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000834 ret = ( fclose((FILE *) context) == EOF ) ? -1 : 0;
835 if (ret < 0)
836 xmlIOErr(0, "fclose()");
837 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000838}
839
840/**
841 * xmlFileFlush:
842 * @context: the I/O context
843 *
844 * Flush an I/O channel
845 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000846static int
Owen Taylor3473f882001-02-23 17:55:21 +0000847xmlFileFlush (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000848 int ret;
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000849
850 if (context == NULL)
851 return(-1);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000852 ret = ( fflush((FILE *) context) == EOF ) ? -1 : 0;
853 if (ret < 0)
854 xmlIOErr(0, "fflush()");
855 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000856}
857
858#ifdef HAVE_ZLIB_H
859/************************************************************************
860 * *
861 * I/O for compressed file accesses *
862 * *
863 ************************************************************************/
864/**
865 * xmlGzfileMatch:
866 * @filename: the URI for matching
867 *
868 * input from compressed file test
869 *
870 * Returns 1 if matches, 0 otherwise
871 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000872static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000873xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000874 return(1);
875}
876
877/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000878 * xmlGzfileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +0000879 * @filename: the URI for matching
880 *
881 * input from compressed file open
882 * if @filename is " " then the standard input is used
883 *
884 * Returns an I/O context or NULL in case of error
885 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000886static void *
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000887xmlGzfileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +0000888 const char *path = NULL;
889 gzFile fd;
890
891 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000892 fd = gzdopen(dup(0), "rb");
Owen Taylor3473f882001-02-23 17:55:21 +0000893 return((void *) fd);
894 }
895
Daniel Veillardf4862f02002-09-10 11:13:43 +0000896 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000897#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000898 path = &filename[17];
899#else
Owen Taylor3473f882001-02-23 17:55:21 +0000900 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000901#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000902 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000903#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000904 path = &filename[8];
905#else
Owen Taylor3473f882001-02-23 17:55:21 +0000906 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000907#endif
908 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000909 path = filename;
910
911 if (path == NULL)
912 return(NULL);
913 if (!xmlCheckFilename(path))
914 return(NULL);
915
916 fd = gzopen(path, "rb");
917 return((void *) fd);
918}
919
920/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000921 * xmlGzfileOpen:
922 * @filename: the URI for matching
923 *
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +0000924 * Wrapper around xmlGzfileOpen if the open fais, it will
925 * try to unescape @filename
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000926 */
927static void *
928xmlGzfileOpen (const char *filename) {
929 char *unescaped;
930 void *retval;
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +0000931
932 retval = xmlGzfileOpen_real(filename);
933 if (retval == NULL) {
934 unescaped = xmlURIUnescapeString(filename, 0, NULL);
935 if (unescaped != NULL) {
936 retval = xmlGzfileOpen_real(unescaped);
937 }
938 xmlFree(unescaped);
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000939 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000940 return retval;
941}
942
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000943#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000944/**
Owen Taylor3473f882001-02-23 17:55:21 +0000945 * xmlGzfileOpenW:
946 * @filename: the URI for matching
947 * @compression: the compression factor (0 - 9 included)
948 *
949 * input from compressed file open
950 * if @filename is " " then the standard input is used
951 *
952 * Returns an I/O context or NULL in case of error
953 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000954static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000955xmlGzfileOpenW (const char *filename, int compression) {
956 const char *path = NULL;
957 char mode[15];
958 gzFile fd;
959
Aleksey Sanin49cc9752002-06-14 17:07:10 +0000960 snprintf(mode, sizeof(mode), "wb%d", compression);
Owen Taylor3473f882001-02-23 17:55:21 +0000961 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000962 fd = gzdopen(dup(1), mode);
Owen Taylor3473f882001-02-23 17:55:21 +0000963 return((void *) fd);
964 }
965
Daniel Veillardf4862f02002-09-10 11:13:43 +0000966 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000967#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000968 path = &filename[17];
969#else
Owen Taylor3473f882001-02-23 17:55:21 +0000970 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000971#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000972 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000973#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000974 path = &filename[8];
975#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000976 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000977#endif
978 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000979 path = filename;
980
981 if (path == NULL)
982 return(NULL);
983
984 fd = gzopen(path, mode);
985 return((void *) fd);
986}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000987#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000988
989/**
990 * xmlGzfileRead:
991 * @context: the I/O context
992 * @buffer: where to drop data
993 * @len: number of bytes to write
994 *
995 * Read @len bytes to @buffer from the compressed I/O channel.
996 *
997 * Returns the number of bytes written
998 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000999static int
Owen Taylor3473f882001-02-23 17:55:21 +00001000xmlGzfileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001001 int ret;
1002
1003 ret = gzread((gzFile) context, &buffer[0], len);
1004 if (ret < 0) xmlIOErr(0, "gzread()");
1005 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001006}
1007
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001008#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001009/**
1010 * xmlGzfileWrite:
1011 * @context: the I/O context
1012 * @buffer: where to drop data
1013 * @len: number of bytes to write
1014 *
1015 * Write @len bytes from @buffer to the compressed I/O channel.
1016 *
1017 * Returns the number of bytes written
1018 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001019static int
Owen Taylor3473f882001-02-23 17:55:21 +00001020xmlGzfileWrite (void * context, const char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001021 int ret;
1022
1023 ret = gzwrite((gzFile) context, (char *) &buffer[0], len);
1024 if (ret < 0) xmlIOErr(0, "gzwrite()");
1025 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001026}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001027#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001028
1029/**
1030 * xmlGzfileClose:
1031 * @context: the I/O context
1032 *
1033 * Close a compressed I/O channel
1034 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001035static int
Owen Taylor3473f882001-02-23 17:55:21 +00001036xmlGzfileClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001037 int ret;
1038
1039 ret = (gzclose((gzFile) context) == Z_OK ) ? 0 : -1;
1040 if (ret < 0) xmlIOErr(0, "gzclose()");
1041 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001042}
1043#endif /* HAVE_ZLIB_H */
1044
1045#ifdef LIBXML_HTTP_ENABLED
1046/************************************************************************
1047 * *
1048 * I/O for HTTP file accesses *
1049 * *
1050 ************************************************************************/
Daniel Veillardf012a642001-07-23 19:10:52 +00001051
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001052#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001053typedef struct xmlIOHTTPWriteCtxt_
1054{
1055 int compression;
1056
1057 char * uri;
1058
1059 void * doc_buff;
1060
1061} xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr;
1062
1063#ifdef HAVE_ZLIB_H
1064
1065#define DFLT_WBITS ( -15 )
1066#define DFLT_MEM_LVL ( 8 )
1067#define GZ_MAGIC1 ( 0x1f )
1068#define GZ_MAGIC2 ( 0x8b )
1069#define LXML_ZLIB_OS_CODE ( 0x03 )
1070#define INIT_HTTP_BUFF_SIZE ( 32768 )
1071#define DFLT_ZLIB_RATIO ( 5 )
1072
1073/*
1074** Data structure and functions to work with sending compressed data
1075** via HTTP.
1076*/
1077
1078typedef struct xmlZMemBuff_
1079{
1080 unsigned long size;
1081 unsigned long crc;
1082
1083 unsigned char * zbuff;
1084 z_stream zctrl;
1085
1086} xmlZMemBuff, *xmlZMemBuffPtr;
1087
1088/**
1089 * append_reverse_ulong
1090 * @buff: Compressed memory buffer
1091 * @data: Unsigned long to append
1092 *
1093 * Append a unsigned long in reverse byte order to the end of the
1094 * memory buffer.
1095 */
1096static void
1097append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) {
1098
1099 int idx;
1100
1101 if ( buff == NULL )
1102 return;
1103
1104 /*
1105 ** This is plagiarized from putLong in gzio.c (zlib source) where
1106 ** the number "4" is hardcoded. If zlib is ever patched to
1107 ** support 64 bit file sizes, this code would need to be patched
1108 ** as well.
1109 */
1110
1111 for ( idx = 0; idx < 4; idx++ ) {
1112 *buff->zctrl.next_out = ( data & 0xff );
1113 data >>= 8;
1114 buff->zctrl.next_out++;
1115 }
1116
1117 return;
1118}
1119
1120/**
1121 *
1122 * xmlFreeZMemBuff
1123 * @buff: The memory buffer context to clear
1124 *
1125 * Release all the resources associated with the compressed memory buffer.
1126 */
1127static void
1128xmlFreeZMemBuff( xmlZMemBuffPtr buff ) {
William M. Brack78637da2003-07-31 14:47:38 +00001129
1130#ifdef DEBUG_HTTP
Daniel Veillardf012a642001-07-23 19:10:52 +00001131 int z_err;
William M. Brack78637da2003-07-31 14:47:38 +00001132#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001133
1134 if ( buff == NULL )
1135 return;
1136
1137 xmlFree( buff->zbuff );
Daniel Veillardf012a642001-07-23 19:10:52 +00001138#ifdef DEBUG_HTTP
William M. Brack78637da2003-07-31 14:47:38 +00001139 z_err = deflateEnd( &buff->zctrl );
Daniel Veillardf012a642001-07-23 19:10:52 +00001140 if ( z_err != Z_OK )
1141 xmlGenericError( xmlGenericErrorContext,
1142 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
1143 z_err );
William M. Brack78637da2003-07-31 14:47:38 +00001144#else
1145 deflateEnd( &buff->zctrl );
William M. Brack779af002003-08-01 15:55:39 +00001146#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001147
1148 xmlFree( buff );
1149 return;
1150}
1151
1152/**
1153 * xmlCreateZMemBuff
1154 *@compression: Compression value to use
1155 *
1156 * Create a memory buffer to hold the compressed XML document. The
1157 * compressed document in memory will end up being identical to what
1158 * would be created if gzopen/gzwrite/gzclose were being used to
1159 * write the document to disk. The code for the header/trailer data to
1160 * the compression is plagiarized from the zlib source files.
1161 */
1162static void *
1163xmlCreateZMemBuff( int compression ) {
1164
1165 int z_err;
1166 int hdr_lgth;
1167 xmlZMemBuffPtr buff = NULL;
1168
1169 if ( ( compression < 1 ) || ( compression > 9 ) )
1170 return ( NULL );
1171
1172 /* Create the control and data areas */
1173
1174 buff = xmlMalloc( sizeof( xmlZMemBuff ) );
1175 if ( buff == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001176 xmlIOErrMemory("creating buffer context");
Daniel Veillardf012a642001-07-23 19:10:52 +00001177 return ( NULL );
1178 }
1179
1180 (void)memset( buff, 0, sizeof( xmlZMemBuff ) );
1181 buff->size = INIT_HTTP_BUFF_SIZE;
1182 buff->zbuff = xmlMalloc( buff->size );
1183 if ( buff->zbuff == NULL ) {
1184 xmlFreeZMemBuff( buff );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001185 xmlIOErrMemory("creating buffer");
Daniel Veillardf012a642001-07-23 19:10:52 +00001186 return ( NULL );
1187 }
1188
1189 z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
1190 DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
1191 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001192 xmlChar msg[500];
Daniel Veillardf012a642001-07-23 19:10:52 +00001193 xmlFreeZMemBuff( buff );
1194 buff = NULL;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001195 xmlStrPrintf(msg, 500,
1196 (const xmlChar *) "xmlCreateZMemBuff: %s %d\n",
1197 "Error initializing compression context. ZLIB error:",
1198 z_err );
1199 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001200 return ( NULL );
1201 }
1202
1203 /* Set the header data. The CRC will be needed for the trailer */
Daniel Veillardf012a642001-07-23 19:10:52 +00001204 buff->crc = crc32( 0L, Z_NULL, 0 );
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001205 hdr_lgth = snprintf( (char *)buff->zbuff, buff->size,
1206 "%c%c%c%c%c%c%c%c%c%c",
Daniel Veillardf012a642001-07-23 19:10:52 +00001207 GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED,
1208 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE );
1209 buff->zctrl.next_out = buff->zbuff + hdr_lgth;
1210 buff->zctrl.avail_out = buff->size - hdr_lgth;
1211
1212 return ( buff );
1213}
1214
1215/**
1216 * xmlZMemBuffExtend
1217 * @buff: Buffer used to compress and consolidate data.
1218 * @ext_amt: Number of bytes to extend the buffer.
1219 *
1220 * Extend the internal buffer used to store the compressed data by the
1221 * specified amount.
1222 *
1223 * Returns 0 on success or -1 on failure to extend the buffer. On failure
1224 * the original buffer still exists at the original size.
1225 */
1226static int
1227xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) {
1228
1229 int rc = -1;
1230 size_t new_size;
1231 size_t cur_used;
1232
1233 unsigned char * tmp_ptr = NULL;
1234
1235 if ( buff == NULL )
1236 return ( -1 );
1237
1238 else if ( ext_amt == 0 )
1239 return ( 0 );
1240
1241 cur_used = buff->zctrl.next_out - buff->zbuff;
1242 new_size = buff->size + ext_amt;
1243
1244#ifdef DEBUG_HTTP
1245 if ( cur_used > new_size )
1246 xmlGenericError( xmlGenericErrorContext,
1247 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
1248 "Buffer overwrite detected during compressed memory",
1249 "buffer extension. Overflowed by",
1250 (cur_used - new_size ) );
1251#endif
1252
1253 tmp_ptr = xmlRealloc( buff->zbuff, new_size );
1254 if ( tmp_ptr != NULL ) {
1255 rc = 0;
1256 buff->size = new_size;
1257 buff->zbuff = tmp_ptr;
1258 buff->zctrl.next_out = tmp_ptr + cur_used;
1259 buff->zctrl.avail_out = new_size - cur_used;
1260 }
1261 else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001262 xmlChar msg[500];
1263 xmlStrPrintf(msg, 500,
1264 (const xmlChar *) "xmlZMemBuffExtend: %s %lu bytes.\n",
1265 "Allocation failure extending output buffer to",
1266 new_size );
1267 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001268 }
1269
1270 return ( rc );
1271}
1272
1273/**
1274 * xmlZMemBuffAppend
1275 * @buff: Buffer used to compress and consolidate data
1276 * @src: Uncompressed source content to append to buffer
1277 * @len: Length of source data to append to buffer
1278 *
1279 * Compress and append data to the internal buffer. The data buffer
1280 * will be expanded if needed to store the additional data.
1281 *
1282 * Returns the number of bytes appended to the buffer or -1 on error.
1283 */
1284static int
1285xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) {
1286
1287 int z_err;
1288 size_t min_accept;
1289
1290 if ( ( buff == NULL ) || ( src == NULL ) )
1291 return ( -1 );
1292
1293 buff->zctrl.avail_in = len;
1294 buff->zctrl.next_in = (unsigned char *)src;
1295 while ( buff->zctrl.avail_in > 0 ) {
1296 /*
1297 ** Extend the buffer prior to deflate call if a reasonable amount
1298 ** of output buffer space is not available.
1299 */
1300 min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO;
1301 if ( buff->zctrl.avail_out <= min_accept ) {
1302 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1303 return ( -1 );
1304 }
1305
1306 z_err = deflate( &buff->zctrl, Z_NO_FLUSH );
1307 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001308 xmlChar msg[500];
1309 xmlStrPrintf(msg, 500,
1310 (const xmlChar *) "xmlZMemBuffAppend: %s %d %s - %d",
Daniel Veillardf012a642001-07-23 19:10:52 +00001311 "Compression error while appending",
1312 len, "bytes to buffer. ZLIB error", z_err );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001313 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001314 return ( -1 );
1315 }
1316 }
1317
1318 buff->crc = crc32( buff->crc, (unsigned char *)src, len );
1319
1320 return ( len );
1321}
1322
1323/**
1324 * xmlZMemBuffGetContent
1325 * @buff: Compressed memory content buffer
1326 * @data_ref: Pointer reference to point to compressed content
1327 *
1328 * Flushes the compression buffers, appends gzip file trailers and
1329 * returns the compressed content and length of the compressed data.
1330 * NOTE: The gzip trailer code here is plagiarized from zlib source.
1331 *
1332 * Returns the length of the compressed data or -1 on error.
1333 */
1334static int
1335xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) {
1336
1337 int zlgth = -1;
1338 int z_err;
1339
1340 if ( ( buff == NULL ) || ( data_ref == NULL ) )
1341 return ( -1 );
1342
1343 /* Need to loop until compression output buffers are flushed */
1344
1345 do
1346 {
1347 z_err = deflate( &buff->zctrl, Z_FINISH );
1348 if ( z_err == Z_OK ) {
1349 /* In this case Z_OK means more buffer space needed */
1350
1351 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1352 return ( -1 );
1353 }
1354 }
1355 while ( z_err == Z_OK );
1356
1357 /* If the compression state is not Z_STREAM_END, some error occurred */
1358
1359 if ( z_err == Z_STREAM_END ) {
1360
1361 /* Need to append the gzip data trailer */
1362
1363 if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) {
1364 if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 )
1365 return ( -1 );
1366 }
1367
1368 /*
1369 ** For whatever reason, the CRC and length data are pushed out
1370 ** in reverse byte order. So a memcpy can't be used here.
1371 */
1372
1373 append_reverse_ulong( buff, buff->crc );
1374 append_reverse_ulong( buff, buff->zctrl.total_in );
1375
1376 zlgth = buff->zctrl.next_out - buff->zbuff;
1377 *data_ref = (char *)buff->zbuff;
1378 }
1379
Daniel Veillard05d987b2003-10-08 11:54:57 +00001380 else {
1381 xmlChar msg[500];
1382 xmlStrPrintf(msg, 500,
1383 (const xmlChar *) "xmlZMemBuffGetContent: %s - %d\n",
1384 "Error flushing zlib buffers. Error code", z_err );
1385 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1386 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001387
1388 return ( zlgth );
1389}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001390#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001391#endif /* HAVE_ZLIB_H */
1392
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001393#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001394/**
1395 * xmlFreeHTTPWriteCtxt
1396 * @ctxt: Context to cleanup
1397 *
1398 * Free allocated memory and reclaim system resources.
1399 *
1400 * No return value.
1401 */
1402static void
1403xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt )
1404{
1405 if ( ctxt->uri != NULL )
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001406 xmlFree( ctxt->uri );
Daniel Veillardf012a642001-07-23 19:10:52 +00001407
1408 if ( ctxt->doc_buff != NULL ) {
1409
1410#ifdef HAVE_ZLIB_H
1411 if ( ctxt->compression > 0 ) {
1412 xmlFreeZMemBuff( ctxt->doc_buff );
1413 }
1414 else
1415#endif
1416 {
1417 xmlOutputBufferClose( ctxt->doc_buff );
1418 }
1419 }
1420
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001421 xmlFree( ctxt );
Daniel Veillardf012a642001-07-23 19:10:52 +00001422 return;
1423}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001424#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001425
1426
Owen Taylor3473f882001-02-23 17:55:21 +00001427/**
1428 * xmlIOHTTPMatch:
1429 * @filename: the URI for matching
1430 *
1431 * check if the URI matches an HTTP one
1432 *
1433 * Returns 1 if matches, 0 otherwise
1434 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001435int
Owen Taylor3473f882001-02-23 17:55:21 +00001436xmlIOHTTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001437 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "http://", 7))
Owen Taylor3473f882001-02-23 17:55:21 +00001438 return(1);
1439 return(0);
1440}
1441
1442/**
1443 * xmlIOHTTPOpen:
1444 * @filename: the URI for matching
1445 *
1446 * open an HTTP I/O channel
1447 *
1448 * Returns an I/O context or NULL in case of error
1449 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001450void *
Owen Taylor3473f882001-02-23 17:55:21 +00001451xmlIOHTTPOpen (const char *filename) {
1452 return(xmlNanoHTTPOpen(filename, NULL));
1453}
1454
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001455#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001456/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001457 * xmlIOHTTPOpenW:
Daniel Veillardf012a642001-07-23 19:10:52 +00001458 * @post_uri: The destination URI for the document
1459 * @compression: The compression desired for the document.
1460 *
1461 * Open a temporary buffer to collect the document for a subsequent HTTP POST
1462 * request. Non-static as is called from the output buffer creation routine.
1463 *
1464 * Returns an I/O context or NULL in case of error.
1465 */
1466
1467void *
Daniel Veillard572577e2002-01-18 16:23:55 +00001468xmlIOHTTPOpenW(const char *post_uri, int compression)
1469{
Daniel Veillardf012a642001-07-23 19:10:52 +00001470
Daniel Veillard572577e2002-01-18 16:23:55 +00001471 xmlIOHTTPWriteCtxtPtr ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001472
Daniel Veillard572577e2002-01-18 16:23:55 +00001473 if (post_uri == NULL)
1474 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001475
Daniel Veillard572577e2002-01-18 16:23:55 +00001476 ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt));
1477 if (ctxt == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001478 xmlIOErrMemory("creating HTTP output context");
Daniel Veillard572577e2002-01-18 16:23:55 +00001479 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001480 }
1481
Daniel Veillard572577e2002-01-18 16:23:55 +00001482 (void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt));
Daniel Veillardf012a642001-07-23 19:10:52 +00001483
Daniel Veillard572577e2002-01-18 16:23:55 +00001484 ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri);
1485 if (ctxt->uri == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001486 xmlIOErrMemory("copying URI");
Daniel Veillard572577e2002-01-18 16:23:55 +00001487 xmlFreeHTTPWriteCtxt(ctxt);
1488 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001489 }
1490
1491 /*
Daniel Veillard572577e2002-01-18 16:23:55 +00001492 * ** Since the document length is required for an HTTP post,
1493 * ** need to put the document into a buffer. A memory buffer
1494 * ** is being used to avoid pushing the data to disk and back.
1495 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001496
1497#ifdef HAVE_ZLIB_H
Daniel Veillard572577e2002-01-18 16:23:55 +00001498 if ((compression > 0) && (compression <= 9)) {
1499
1500 ctxt->compression = compression;
1501 ctxt->doc_buff = xmlCreateZMemBuff(compression);
1502 } else
Daniel Veillardf012a642001-07-23 19:10:52 +00001503#endif
1504 {
Daniel Veillard572577e2002-01-18 16:23:55 +00001505 /* Any character conversions should have been done before this */
Daniel Veillardf012a642001-07-23 19:10:52 +00001506
Daniel Veillard572577e2002-01-18 16:23:55 +00001507 ctxt->doc_buff = xmlAllocOutputBuffer(NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001508 }
1509
Daniel Veillard572577e2002-01-18 16:23:55 +00001510 if (ctxt->doc_buff == NULL) {
1511 xmlFreeHTTPWriteCtxt(ctxt);
1512 ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001513 }
1514
Daniel Veillard572577e2002-01-18 16:23:55 +00001515 return (ctxt);
Daniel Veillardf012a642001-07-23 19:10:52 +00001516}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001517#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001518
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001519#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001520/**
1521 * xmlIOHTTPDfltOpenW
1522 * @post_uri: The destination URI for this document.
1523 *
1524 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
1525 * HTTP post command. This function should generally not be used as
1526 * the open callback is short circuited in xmlOutputBufferCreateFile.
1527 *
1528 * Returns a pointer to the new IO context.
1529 */
1530static void *
1531xmlIOHTTPDfltOpenW( const char * post_uri ) {
1532 return ( xmlIOHTTPOpenW( post_uri, 0 ) );
1533}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001534#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001535
1536/**
Owen Taylor3473f882001-02-23 17:55:21 +00001537 * xmlIOHTTPRead:
1538 * @context: the I/O context
1539 * @buffer: where to drop data
1540 * @len: number of bytes to write
1541 *
1542 * Read @len bytes to @buffer from the I/O channel.
1543 *
1544 * Returns the number of bytes written
1545 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001546int
Owen Taylor3473f882001-02-23 17:55:21 +00001547xmlIOHTTPRead(void * context, char * buffer, int len) {
1548 return(xmlNanoHTTPRead(context, &buffer[0], len));
1549}
1550
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001551#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001552/**
Daniel Veillardf012a642001-07-23 19:10:52 +00001553 * xmlIOHTTPWrite
1554 * @context: previously opened writing context
1555 * @buffer: data to output to temporary buffer
1556 * @len: bytes to output
1557 *
1558 * Collect data from memory buffer into a temporary file for later
1559 * processing.
1560 *
1561 * Returns number of bytes written.
1562 */
1563
1564static int
1565xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
1566
1567 xmlIOHTTPWriteCtxtPtr ctxt = context;
1568
1569 if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
1570 return ( -1 );
1571
1572 if ( len > 0 ) {
1573
1574 /* Use gzwrite or fwrite as previously setup in the open call */
1575
1576#ifdef HAVE_ZLIB_H
1577 if ( ctxt->compression > 0 )
1578 len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len );
1579
1580 else
1581#endif
1582 len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
1583
1584 if ( len < 0 ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001585 xmlChar msg[500];
1586 xmlStrPrintf(msg, 500,
1587 (const xmlChar *) "xmlIOHTTPWrite: %s\n%s '%s'.\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001588 "Error appending to internal buffer.",
1589 "Error sending document to URI",
1590 ctxt->uri );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001591 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001592 }
1593 }
1594
1595 return ( len );
1596}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001597#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001598
1599
1600/**
Owen Taylor3473f882001-02-23 17:55:21 +00001601 * xmlIOHTTPClose:
1602 * @context: the I/O context
1603 *
1604 * Close an HTTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001605 *
1606 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00001607 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001608int
Owen Taylor3473f882001-02-23 17:55:21 +00001609xmlIOHTTPClose (void * context) {
1610 xmlNanoHTTPClose(context);
Daniel Veillardf012a642001-07-23 19:10:52 +00001611 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001612}
Daniel Veillardf012a642001-07-23 19:10:52 +00001613
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001614#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001615/**
1616 * xmlIOHTTCloseWrite
1617 * @context: The I/O context
1618 * @http_mthd: The HTTP method to be used when sending the data
1619 *
1620 * Close the transmit HTTP I/O channel and actually send the data.
1621 */
1622static int
1623xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
1624
1625 int close_rc = -1;
1626 int http_rtn = 0;
1627 int content_lgth = 0;
1628 xmlIOHTTPWriteCtxtPtr ctxt = context;
1629
1630 char * http_content = NULL;
1631 char * content_encoding = NULL;
1632 char * content_type = (char *) "text/xml";
1633 void * http_ctxt = NULL;
1634
1635 if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
1636 return ( -1 );
1637
1638 /* Retrieve the content from the appropriate buffer */
1639
1640#ifdef HAVE_ZLIB_H
1641
1642 if ( ctxt->compression > 0 ) {
1643 content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
1644 content_encoding = (char *) "Content-Encoding: gzip";
1645 }
1646 else
1647#endif
1648 {
1649 /* Pull the data out of the memory output buffer */
1650
1651 xmlOutputBufferPtr dctxt = ctxt->doc_buff;
1652 http_content = (char *)dctxt->buffer->content;
1653 content_lgth = dctxt->buffer->use;
1654 }
1655
1656 if ( http_content == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001657 xmlChar msg[500];
1658 xmlStrPrintf(msg, 500,
1659 (const xmlChar *) "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
1660 "Error retrieving content.\nUnable to",
1661 http_mthd, "data to URI", ctxt->uri );
1662 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001663 }
1664
1665 else {
1666
1667 http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
1668 &content_type, content_encoding,
1669 content_lgth );
1670
1671 if ( http_ctxt != NULL ) {
1672#ifdef DEBUG_HTTP
1673 /* If testing/debugging - dump reply with request content */
1674
1675 FILE * tst_file = NULL;
1676 char buffer[ 4096 ];
1677 char * dump_name = NULL;
1678 int avail;
1679
1680 xmlGenericError( xmlGenericErrorContext,
1681 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
1682 http_mthd, ctxt->uri,
1683 xmlNanoHTTPReturnCode( http_ctxt ) );
1684
1685 /*
1686 ** Since either content or reply may be gzipped,
1687 ** dump them to separate files instead of the
1688 ** standard error context.
1689 */
1690
1691 dump_name = tempnam( NULL, "lxml" );
1692 if ( dump_name != NULL ) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001693 (void)snprintf( buffer, sizeof(buffer), "%s.content", dump_name );
Daniel Veillardf012a642001-07-23 19:10:52 +00001694
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00001695 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00001696 if ( tst_file != NULL ) {
1697 xmlGenericError( xmlGenericErrorContext,
1698 "Transmitted content saved in file: %s\n", buffer );
1699
1700 fwrite( http_content, sizeof( char ),
1701 content_lgth, tst_file );
1702 fclose( tst_file );
1703 }
1704
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001705 (void)snprintf( buffer, sizeof(buffer), "%s.reply", dump_name );
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00001706 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00001707 if ( tst_file != NULL ) {
1708 xmlGenericError( xmlGenericErrorContext,
1709 "Reply content saved in file: %s\n", buffer );
1710
1711
1712 while ( (avail = xmlNanoHTTPRead( http_ctxt,
1713 buffer, sizeof( buffer ) )) > 0 ) {
1714
1715 fwrite( buffer, sizeof( char ), avail, tst_file );
1716 }
1717
1718 fclose( tst_file );
1719 }
1720
1721 free( dump_name );
1722 }
1723#endif /* DEBUG_HTTP */
1724
1725 http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
1726 if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
1727 close_rc = 0;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001728 else {
1729 xmlChar msg[500];
1730 xmlStrPrintf(msg, 500,
1731 (const xmlChar *) "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001732 http_mthd, content_lgth,
1733 "bytes to URI", ctxt->uri,
1734 "failed. HTTP return code:", http_rtn );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001735 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1736 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001737
1738 xmlNanoHTTPClose( http_ctxt );
1739 xmlFree( content_type );
1740 }
1741 }
1742
1743 /* Final cleanups */
1744
1745 xmlFreeHTTPWriteCtxt( ctxt );
1746
1747 return ( close_rc );
1748}
1749
1750/**
1751 * xmlIOHTTPClosePut
1752 *
1753 * @context: The I/O context
1754 *
1755 * Close the transmit HTTP I/O channel and actually send data using a PUT
1756 * HTTP method.
1757 */
1758static int
1759xmlIOHTTPClosePut( void * ctxt ) {
1760 return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
1761}
1762
1763
1764/**
1765 * xmlIOHTTPClosePost
1766 *
1767 * @context: The I/O context
1768 *
1769 * Close the transmit HTTP I/O channel and actually send data using a POST
1770 * HTTP method.
1771 */
1772static int
1773xmlIOHTTPClosePost( void * ctxt ) {
1774 return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
1775}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001776#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001777
Owen Taylor3473f882001-02-23 17:55:21 +00001778#endif /* LIBXML_HTTP_ENABLED */
1779
1780#ifdef LIBXML_FTP_ENABLED
1781/************************************************************************
1782 * *
1783 * I/O for FTP file accesses *
1784 * *
1785 ************************************************************************/
1786/**
1787 * xmlIOFTPMatch:
1788 * @filename: the URI for matching
1789 *
1790 * check if the URI matches an FTP one
1791 *
1792 * Returns 1 if matches, 0 otherwise
1793 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001794int
Owen Taylor3473f882001-02-23 17:55:21 +00001795xmlIOFTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001796 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "ftp://", 6))
Owen Taylor3473f882001-02-23 17:55:21 +00001797 return(1);
1798 return(0);
1799}
1800
1801/**
1802 * xmlIOFTPOpen:
1803 * @filename: the URI for matching
1804 *
1805 * open an FTP I/O channel
1806 *
1807 * Returns an I/O context or NULL in case of error
1808 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001809void *
Owen Taylor3473f882001-02-23 17:55:21 +00001810xmlIOFTPOpen (const char *filename) {
1811 return(xmlNanoFTPOpen(filename));
1812}
1813
1814/**
1815 * xmlIOFTPRead:
1816 * @context: the I/O context
1817 * @buffer: where to drop data
1818 * @len: number of bytes to write
1819 *
1820 * Read @len bytes to @buffer from the I/O channel.
1821 *
1822 * Returns the number of bytes written
1823 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001824int
Owen Taylor3473f882001-02-23 17:55:21 +00001825xmlIOFTPRead(void * context, char * buffer, int len) {
1826 return(xmlNanoFTPRead(context, &buffer[0], len));
1827}
1828
1829/**
1830 * xmlIOFTPClose:
1831 * @context: the I/O context
1832 *
1833 * Close an FTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001834 *
1835 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00001836 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001837int
Owen Taylor3473f882001-02-23 17:55:21 +00001838xmlIOFTPClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001839 return ( xmlNanoFTPClose(context) );
Owen Taylor3473f882001-02-23 17:55:21 +00001840}
1841#endif /* LIBXML_FTP_ENABLED */
1842
1843
1844/**
1845 * xmlRegisterInputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001846 * @matchFunc: the xmlInputMatchCallback
1847 * @openFunc: the xmlInputOpenCallback
1848 * @readFunc: the xmlInputReadCallback
1849 * @closeFunc: the xmlInputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001850 *
1851 * Register a new set of I/O callback for handling parser input.
1852 *
1853 * Returns the registered handler number or -1 in case of error
1854 */
1855int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001856xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
1857 xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
1858 xmlInputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001859 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
1860 return(-1);
1861 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001862 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
1863 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
1864 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
1865 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00001866 xmlInputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00001867 return(xmlInputCallbackNr++);
1868}
1869
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001870#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001871/**
1872 * xmlRegisterOutputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001873 * @matchFunc: the xmlOutputMatchCallback
1874 * @openFunc: the xmlOutputOpenCallback
1875 * @writeFunc: the xmlOutputWriteCallback
1876 * @closeFunc: the xmlOutputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001877 *
1878 * Register a new set of I/O callback for handling output.
1879 *
1880 * Returns the registered handler number or -1 in case of error
1881 */
1882int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001883xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
1884 xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
1885 xmlOutputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001886 if (xmlOutputCallbackNr >= MAX_INPUT_CALLBACK) {
1887 return(-1);
1888 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001889 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
1890 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
1891 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
1892 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00001893 xmlOutputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00001894 return(xmlOutputCallbackNr++);
1895}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001896#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001897
1898/**
1899 * xmlRegisterDefaultInputCallbacks:
1900 *
1901 * Registers the default compiled-in I/O handlers.
1902 */
1903void
Owen Taylor3473f882001-02-23 17:55:21 +00001904xmlRegisterDefaultInputCallbacks
Owen Taylor3473f882001-02-23 17:55:21 +00001905(void) {
1906 if (xmlInputCallbackInitialized)
1907 return;
1908
1909 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
1910 xmlFileRead, xmlFileClose);
1911#ifdef HAVE_ZLIB_H
1912 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1913 xmlGzfileRead, xmlGzfileClose);
1914#endif /* HAVE_ZLIB_H */
1915
1916#ifdef LIBXML_HTTP_ENABLED
1917 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
1918 xmlIOHTTPRead, xmlIOHTTPClose);
1919#endif /* LIBXML_HTTP_ENABLED */
1920
1921#ifdef LIBXML_FTP_ENABLED
1922 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1923 xmlIOFTPRead, xmlIOFTPClose);
1924#endif /* LIBXML_FTP_ENABLED */
1925 xmlInputCallbackInitialized = 1;
1926}
1927
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001928#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001929/**
1930 * xmlRegisterDefaultOutputCallbacks:
1931 *
1932 * Registers the default compiled-in I/O handlers.
1933 */
1934void
Owen Taylor3473f882001-02-23 17:55:21 +00001935xmlRegisterDefaultOutputCallbacks
Owen Taylor3473f882001-02-23 17:55:21 +00001936(void) {
1937 if (xmlOutputCallbackInitialized)
1938 return;
1939
1940 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
1941 xmlFileWrite, xmlFileClose);
Daniel Veillardf012a642001-07-23 19:10:52 +00001942
1943#ifdef LIBXML_HTTP_ENABLED
1944 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
1945 xmlIOHTTPWrite, xmlIOHTTPClosePut);
1946#endif
1947
Owen Taylor3473f882001-02-23 17:55:21 +00001948/*********************************
1949 No way a-priori to distinguish between gzipped files from
1950 uncompressed ones except opening if existing then closing
1951 and saving with same compression ratio ... a pain.
1952
1953#ifdef HAVE_ZLIB_H
1954 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1955 xmlGzfileWrite, xmlGzfileClose);
1956#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001957
1958 Nor FTP PUT ....
1959#ifdef LIBXML_FTP_ENABLED
1960 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1961 xmlIOFTPWrite, xmlIOFTPClose);
1962#endif
1963 **********************************/
1964 xmlOutputCallbackInitialized = 1;
1965}
1966
Daniel Veillardf012a642001-07-23 19:10:52 +00001967#ifdef LIBXML_HTTP_ENABLED
1968/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001969 * xmlRegisterHTTPPostCallbacks:
Daniel Veillardf012a642001-07-23 19:10:52 +00001970 *
1971 * By default, libxml submits HTTP output requests using the "PUT" method.
1972 * Calling this method changes the HTTP output method to use the "POST"
1973 * method instead.
1974 *
1975 */
1976void
1977xmlRegisterHTTPPostCallbacks( void ) {
1978
1979 /* Register defaults if not done previously */
1980
1981 if ( xmlOutputCallbackInitialized == 0 )
1982 xmlRegisterDefaultOutputCallbacks( );
1983
1984 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
1985 xmlIOHTTPWrite, xmlIOHTTPClosePost);
1986 return;
1987}
1988#endif
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001989#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001990
Owen Taylor3473f882001-02-23 17:55:21 +00001991/**
1992 * xmlAllocParserInputBuffer:
1993 * @enc: the charset encoding if known
1994 *
1995 * Create a buffered parser input for progressive parsing
1996 *
1997 * Returns the new parser input or NULL
1998 */
1999xmlParserInputBufferPtr
2000xmlAllocParserInputBuffer(xmlCharEncoding enc) {
2001 xmlParserInputBufferPtr ret;
2002
2003 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2004 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002005 xmlIOErrMemory("creating input buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00002006 return(NULL);
2007 }
2008 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002009 ret->buffer = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00002010 if (ret->buffer == NULL) {
2011 xmlFree(ret);
2012 return(NULL);
2013 }
2014 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
2015 ret->encoder = xmlGetCharEncodingHandler(enc);
2016 if (ret->encoder != NULL)
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002017 ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00002018 else
2019 ret->raw = NULL;
2020 ret->readcallback = NULL;
2021 ret->closecallback = NULL;
2022 ret->context = NULL;
William M. Brackc07329e2003-09-08 01:57:30 +00002023 ret->compressed = -1;
Daniel Veillard36711902004-02-11 13:25:26 +00002024 ret->rawconsumed = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002025
2026 return(ret);
2027}
2028
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002029#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002030/**
2031 * xmlAllocOutputBuffer:
2032 * @encoder: the encoding converter or NULL
2033 *
2034 * Create a buffered parser output
2035 *
2036 * Returns the new parser output or NULL
2037 */
2038xmlOutputBufferPtr
2039xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
2040 xmlOutputBufferPtr ret;
2041
2042 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
2043 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002044 xmlIOErrMemory("creating output buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00002045 return(NULL);
2046 }
2047 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
2048 ret->buffer = xmlBufferCreate();
2049 if (ret->buffer == NULL) {
2050 xmlFree(ret);
2051 return(NULL);
2052 }
2053 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
2054 ret->encoder = encoder;
2055 if (encoder != NULL) {
2056 ret->conv = xmlBufferCreateSize(4000);
2057 /*
2058 * This call is designed to initiate the encoder state
2059 */
2060 xmlCharEncOutFunc(encoder, ret->conv, NULL);
2061 } else
2062 ret->conv = NULL;
2063 ret->writecallback = NULL;
2064 ret->closecallback = NULL;
2065 ret->context = NULL;
2066 ret->written = 0;
2067
2068 return(ret);
2069}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002070#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002071
2072/**
2073 * xmlFreeParserInputBuffer:
2074 * @in: a buffered parser input
2075 *
2076 * Free up the memory used by a buffered parser input
2077 */
2078void
2079xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
Daniel Veillard8d8bf2c2003-09-17 19:36:25 +00002080 if (in == NULL) return;
2081
Owen Taylor3473f882001-02-23 17:55:21 +00002082 if (in->raw) {
2083 xmlBufferFree(in->raw);
2084 in->raw = NULL;
2085 }
2086 if (in->encoder != NULL) {
2087 xmlCharEncCloseFunc(in->encoder);
2088 }
2089 if (in->closecallback != NULL) {
2090 in->closecallback(in->context);
2091 }
2092 if (in->buffer != NULL) {
2093 xmlBufferFree(in->buffer);
2094 in->buffer = NULL;
2095 }
2096
Owen Taylor3473f882001-02-23 17:55:21 +00002097 xmlFree(in);
2098}
2099
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002100#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002101/**
2102 * xmlOutputBufferClose:
2103 * @out: a buffered output
2104 *
2105 * flushes and close the output I/O channel
2106 * and free up all the associated resources
2107 *
2108 * Returns the number of byte written or -1 in case of error.
2109 */
2110int
Daniel Veillard828ce832003-10-08 19:19:10 +00002111xmlOutputBufferClose(xmlOutputBufferPtr out)
2112{
Owen Taylor3473f882001-02-23 17:55:21 +00002113 int written;
Daniel Veillardf012a642001-07-23 19:10:52 +00002114 int err_rc = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002115
2116 if (out == NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002117 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002118 if (out->writecallback != NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002119 xmlOutputBufferFlush(out);
Owen Taylor3473f882001-02-23 17:55:21 +00002120 if (out->closecallback != NULL) {
Daniel Veillard828ce832003-10-08 19:19:10 +00002121 err_rc = out->closecallback(out->context);
Owen Taylor3473f882001-02-23 17:55:21 +00002122 }
2123 written = out->written;
2124 if (out->conv) {
2125 xmlBufferFree(out->conv);
Daniel Veillard828ce832003-10-08 19:19:10 +00002126 out->conv = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002127 }
2128 if (out->encoder != NULL) {
2129 xmlCharEncCloseFunc(out->encoder);
2130 }
2131 if (out->buffer != NULL) {
2132 xmlBufferFree(out->buffer);
Daniel Veillard828ce832003-10-08 19:19:10 +00002133 out->buffer = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002134 }
2135
Daniel Veillard828ce832003-10-08 19:19:10 +00002136 if (out->error)
2137 err_rc = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00002138 xmlFree(out);
Daniel Veillard828ce832003-10-08 19:19:10 +00002139 return ((err_rc == 0) ? written : err_rc);
Owen Taylor3473f882001-02-23 17:55:21 +00002140}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002141#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002142
Daniel Veillard1b243b42004-06-08 10:16:42 +00002143xmlParserInputBufferPtr
Daniel Veillard0335a842004-06-02 16:18:40 +00002144__xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002145 xmlParserInputBufferPtr ret;
Daniel Veillard388236f2001-07-08 18:35:48 +00002146 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002147 void *context = NULL;
2148
2149 if (xmlInputCallbackInitialized == 0)
2150 xmlRegisterDefaultInputCallbacks();
2151
2152 if (URI == NULL) return(NULL);
2153
2154 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002155 * Try to find one of the input accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002156 * Go in reverse to give precedence to user defined handlers.
Daniel Veillard388236f2001-07-08 18:35:48 +00002157 */
2158 if (context == NULL) {
2159 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
2160 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
2161 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002162 context = xmlInputCallbackTable[i].opencallback(URI);
Daniel Veillard847332a2003-10-18 11:29:40 +00002163 if (context != NULL) {
Daniel Veillard388236f2001-07-08 18:35:48 +00002164 break;
Daniel Veillard847332a2003-10-18 11:29:40 +00002165 }
Daniel Veillard388236f2001-07-08 18:35:48 +00002166 }
Owen Taylor3473f882001-02-23 17:55:21 +00002167 }
2168 }
2169 if (context == NULL) {
2170 return(NULL);
2171 }
2172
2173 /*
2174 * Allocate the Input buffer front-end.
2175 */
2176 ret = xmlAllocParserInputBuffer(enc);
2177 if (ret != NULL) {
2178 ret->context = context;
2179 ret->readcallback = xmlInputCallbackTable[i].readcallback;
2180 ret->closecallback = xmlInputCallbackTable[i].closecallback;
William M. Brackc07329e2003-09-08 01:57:30 +00002181#ifdef HAVE_ZLIB_H
William M. Brackc5cbf992003-10-29 22:15:13 +00002182 if ((xmlInputCallbackTable[i].opencallback == xmlGzfileOpen) &&
2183 (strcmp(URI, "-") != 0)) {
William M. Brackc07329e2003-09-08 01:57:30 +00002184 if (((z_stream *)context)->avail_in > 4) {
2185 char *cptr, buff4[4];
Daniel Veillard07cb8222003-09-10 10:51:05 +00002186 cptr = (char *) ((z_stream *)context)->next_in;
William M. Brackc07329e2003-09-08 01:57:30 +00002187 if (gzread(context, buff4, 4) == 4) {
2188 if (strncmp(buff4, cptr, 4) == 0)
2189 ret->compressed = 0;
2190 else
2191 ret->compressed = 1;
2192 gzrewind(context);
2193 }
2194 }
2195 }
2196#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002197 }
William M. Brack42331a92004-07-29 07:07:16 +00002198 else
2199 xmlInputCallbackTable[i].closecallback (context);
2200
Owen Taylor3473f882001-02-23 17:55:21 +00002201 return(ret);
2202}
2203
2204/**
Daniel Veillard0335a842004-06-02 16:18:40 +00002205 * xmlParserInputBufferCreateFilename:
Owen Taylor3473f882001-02-23 17:55:21 +00002206 * @URI: a C string containing the URI or filename
Daniel Veillard0335a842004-06-02 16:18:40 +00002207 * @enc: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002208 *
Daniel Veillard0335a842004-06-02 16:18:40 +00002209 * Create a buffered parser input for the progressive parsing of a file
2210 * If filename is "-' then we use stdin as the input.
Owen Taylor3473f882001-02-23 17:55:21 +00002211 * Automatic support for ZLIB/Compress compressed document is provided
2212 * by default if found at compile-time.
Daniel Veillard0335a842004-06-02 16:18:40 +00002213 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
Owen Taylor3473f882001-02-23 17:55:21 +00002214 *
Daniel Veillard0335a842004-06-02 16:18:40 +00002215 * Returns the new parser input or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00002216 */
Daniel Veillard0335a842004-06-02 16:18:40 +00002217xmlParserInputBufferPtr
2218xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
2219 if ((xmlParserInputBufferCreateFilenameValue)) {
2220 return xmlParserInputBufferCreateFilenameValue(URI, enc);
2221 }
2222 return __xmlParserInputBufferCreateFilename(URI, enc);
2223}
2224
2225#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard1b243b42004-06-08 10:16:42 +00002226xmlOutputBufferPtr
Daniel Veillard0335a842004-06-02 16:18:40 +00002227__xmlOutputBufferCreateFilename(const char *URI,
Owen Taylor3473f882001-02-23 17:55:21 +00002228 xmlCharEncodingHandlerPtr encoder,
Daniel Veillard0335a842004-06-02 16:18:40 +00002229 int compression ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00002230 xmlOutputBufferPtr ret;
Daniel Veillard966a31e2004-05-09 02:58:44 +00002231 xmlURIPtr puri;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002232 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002233 void *context = NULL;
Daniel Veillard966a31e2004-05-09 02:58:44 +00002234 char *unescaped = NULL;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002235#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002236 int is_file_uri = 1;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002237#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00002238
Owen Taylor3473f882001-02-23 17:55:21 +00002239 if (xmlOutputCallbackInitialized == 0)
2240 xmlRegisterDefaultOutputCallbacks();
2241
2242 if (URI == NULL) return(NULL);
2243
Daniel Veillard966a31e2004-05-09 02:58:44 +00002244 puri = xmlParseURI(URI);
2245 if (puri != NULL) {
Daniel Veillard18a65092004-05-11 15:57:42 +00002246 if ((puri->scheme != NULL) &&
2247 (!xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002248#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002249 is_file_uri = 0;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002250#endif
Daniel Veillard966a31e2004-05-09 02:58:44 +00002251 /*
2252 * try to limit the damages of the URI unescaping code.
2253 */
2254 if (puri->scheme != NULL)
2255 unescaped = xmlURIUnescapeString(URI, 0, NULL);
2256 xmlFreeURI(puri);
2257 }
Owen Taylor3473f882001-02-23 17:55:21 +00002258
2259 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002260 * Try to find one of the output accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002261 * Go in reverse to give precedence to user defined handlers.
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002262 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00002263 */
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002264 if (unescaped != NULL) {
2265#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002266 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002267 context = xmlGzfileOpenW(unescaped, compression);
2268 if (context != NULL) {
2269 ret = xmlAllocOutputBuffer(encoder);
2270 if (ret != NULL) {
2271 ret->context = context;
2272 ret->writecallback = xmlGzfileWrite;
2273 ret->closecallback = xmlGzfileClose;
2274 }
2275 xmlFree(unescaped);
2276 return(ret);
2277 }
2278 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002279#endif
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002280 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2281 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
2282 (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
2283#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2284 /* Need to pass compression parameter into HTTP open calls */
2285 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2286 context = xmlIOHTTPOpenW(unescaped, compression);
2287 else
2288#endif
2289 context = xmlOutputCallbackTable[i].opencallback(unescaped);
2290 if (context != NULL)
2291 break;
2292 }
2293 }
2294 xmlFree(unescaped);
2295 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002296
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002297 /*
2298 * If this failed try with a non-escaped URI this may be a strange
2299 * filename
2300 */
2301 if (context == NULL) {
2302#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002303 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002304 context = xmlGzfileOpenW(URI, compression);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002305 if (context != NULL) {
2306 ret = xmlAllocOutputBuffer(encoder);
2307 if (ret != NULL) {
2308 ret->context = context;
2309 ret->writecallback = xmlGzfileWrite;
2310 ret->closecallback = xmlGzfileClose;
2311 }
2312 return(ret);
2313 }
2314 }
2315#endif
2316 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2317 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002318 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002319#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2320 /* Need to pass compression parameter into HTTP open calls */
2321 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2322 context = xmlIOHTTPOpenW(URI, compression);
2323 else
2324#endif
2325 context = xmlOutputCallbackTable[i].opencallback(URI);
2326 if (context != NULL)
2327 break;
2328 }
Owen Taylor3473f882001-02-23 17:55:21 +00002329 }
2330 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002331
Owen Taylor3473f882001-02-23 17:55:21 +00002332 if (context == NULL) {
2333 return(NULL);
2334 }
2335
2336 /*
2337 * Allocate the Output buffer front-end.
2338 */
2339 ret = xmlAllocOutputBuffer(encoder);
2340 if (ret != NULL) {
2341 ret->context = context;
2342 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
2343 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
2344 }
2345 return(ret);
2346}
Daniel Veillard0335a842004-06-02 16:18:40 +00002347
2348/**
2349 * xmlOutputBufferCreateFilename:
2350 * @URI: a C string containing the URI or filename
2351 * @encoder: the encoding converter or NULL
2352 * @compression: the compression ration (0 none, 9 max).
2353 *
2354 * Create a buffered output for the progressive saving of a file
2355 * If filename is "-' then we use stdout as the output.
2356 * Automatic support for ZLIB/Compress compressed document is provided
2357 * by default if found at compile-time.
2358 * TODO: currently if compression is set, the library only support
2359 * writing to a local file.
2360 *
2361 * Returns the new output or NULL
2362 */
2363xmlOutputBufferPtr
2364xmlOutputBufferCreateFilename(const char *URI,
2365 xmlCharEncodingHandlerPtr encoder,
2366 int compression ATTRIBUTE_UNUSED) {
2367 if ((xmlOutputBufferCreateFilenameValue)) {
2368 return xmlOutputBufferCreateFilenameValue(URI, encoder, compression);
2369 }
2370 return __xmlOutputBufferCreateFilename(URI, encoder, compression);
2371}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002372#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002373
2374/**
2375 * xmlParserInputBufferCreateFile:
2376 * @file: a FILE*
2377 * @enc: the charset encoding if known
2378 *
2379 * Create a buffered parser input for the progressive parsing of a FILE *
2380 * buffered C I/O
2381 *
2382 * Returns the new parser input or NULL
2383 */
2384xmlParserInputBufferPtr
2385xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
2386 xmlParserInputBufferPtr ret;
2387
2388 if (xmlInputCallbackInitialized == 0)
2389 xmlRegisterDefaultInputCallbacks();
2390
2391 if (file == NULL) return(NULL);
2392
2393 ret = xmlAllocParserInputBuffer(enc);
2394 if (ret != NULL) {
2395 ret->context = file;
2396 ret->readcallback = xmlFileRead;
2397 ret->closecallback = xmlFileFlush;
2398 }
2399
2400 return(ret);
2401}
2402
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002403#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002404/**
2405 * xmlOutputBufferCreateFile:
2406 * @file: a FILE*
2407 * @encoder: the encoding converter or NULL
2408 *
2409 * Create a buffered output for the progressive saving to a FILE *
2410 * buffered C I/O
2411 *
2412 * Returns the new parser output or NULL
2413 */
2414xmlOutputBufferPtr
2415xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
2416 xmlOutputBufferPtr ret;
2417
2418 if (xmlOutputCallbackInitialized == 0)
2419 xmlRegisterDefaultOutputCallbacks();
2420
2421 if (file == NULL) return(NULL);
2422
2423 ret = xmlAllocOutputBuffer(encoder);
2424 if (ret != NULL) {
2425 ret->context = file;
2426 ret->writecallback = xmlFileWrite;
2427 ret->closecallback = xmlFileFlush;
2428 }
2429
2430 return(ret);
2431}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002432#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002433
2434/**
2435 * xmlParserInputBufferCreateFd:
2436 * @fd: a file descriptor number
2437 * @enc: the charset encoding if known
2438 *
2439 * Create a buffered parser input for the progressive parsing for the input
2440 * from a file descriptor
2441 *
2442 * Returns the new parser input or NULL
2443 */
2444xmlParserInputBufferPtr
2445xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
2446 xmlParserInputBufferPtr ret;
2447
2448 if (fd < 0) return(NULL);
2449
2450 ret = xmlAllocParserInputBuffer(enc);
2451 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002452 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002453 ret->readcallback = xmlFdRead;
2454 ret->closecallback = xmlFdClose;
2455 }
2456
2457 return(ret);
2458}
2459
2460/**
2461 * xmlParserInputBufferCreateMem:
2462 * @mem: the memory input
2463 * @size: the length of the memory block
2464 * @enc: the charset encoding if known
2465 *
2466 * Create a buffered parser input for the progressive parsing for the input
2467 * from a memory area.
2468 *
2469 * Returns the new parser input or NULL
2470 */
2471xmlParserInputBufferPtr
2472xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
2473 xmlParserInputBufferPtr ret;
William M. Bracka3215c72004-07-31 16:24:01 +00002474 int errcode;
Owen Taylor3473f882001-02-23 17:55:21 +00002475
2476 if (size <= 0) return(NULL);
2477 if (mem == NULL) return(NULL);
2478
2479 ret = xmlAllocParserInputBuffer(enc);
2480 if (ret != NULL) {
2481 ret->context = (void *) mem;
2482 ret->readcallback = (xmlInputReadCallback) xmlNop;
2483 ret->closecallback = NULL;
William M. Bracka3215c72004-07-31 16:24:01 +00002484 errcode = xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size);
2485 if (errcode != 0) {
2486 xmlFree(ret);
2487 return(NULL);
2488 }
Owen Taylor3473f882001-02-23 17:55:21 +00002489 }
2490
2491 return(ret);
2492}
2493
2494/**
Daniel Veillard53350552003-09-18 13:35:51 +00002495 * xmlParserInputBufferCreateStatic:
2496 * @mem: the memory input
2497 * @size: the length of the memory block
2498 * @enc: the charset encoding if known
2499 *
2500 * Create a buffered parser input for the progressive parsing for the input
2501 * from an immutable memory area. This will not copy the memory area to
2502 * the buffer, but the memory is expected to be available until the end of
2503 * the parsing, this is useful for example when using mmap'ed file.
2504 *
2505 * Returns the new parser input or NULL
2506 */
2507xmlParserInputBufferPtr
2508xmlParserInputBufferCreateStatic(const char *mem, int size,
2509 xmlCharEncoding enc) {
2510 xmlParserInputBufferPtr ret;
2511
2512 if (size <= 0) return(NULL);
2513 if (mem == NULL) return(NULL);
2514
2515 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2516 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002517 xmlIOErrMemory("creating input buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00002518 return(NULL);
2519 }
2520 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillarde72c5082003-09-19 12:44:05 +00002521 ret->buffer = xmlBufferCreateStatic((void *)mem, (size_t) size);
Daniel Veillard53350552003-09-18 13:35:51 +00002522 if (ret->buffer == NULL) {
2523 xmlFree(ret);
2524 return(NULL);
2525 }
2526 ret->encoder = xmlGetCharEncodingHandler(enc);
2527 if (ret->encoder != NULL)
2528 ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
2529 else
2530 ret->raw = NULL;
2531 ret->compressed = -1;
2532 ret->context = (void *) mem;
2533 ret->readcallback = NULL;
2534 ret->closecallback = NULL;
2535
2536 return(ret);
2537}
2538
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002539#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard53350552003-09-18 13:35:51 +00002540/**
Owen Taylor3473f882001-02-23 17:55:21 +00002541 * xmlOutputBufferCreateFd:
2542 * @fd: a file descriptor number
2543 * @encoder: the encoding converter or NULL
2544 *
2545 * Create a buffered output for the progressive saving
2546 * to a file descriptor
2547 *
2548 * Returns the new parser output or NULL
2549 */
2550xmlOutputBufferPtr
2551xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
2552 xmlOutputBufferPtr ret;
2553
2554 if (fd < 0) return(NULL);
2555
2556 ret = xmlAllocOutputBuffer(encoder);
2557 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002558 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002559 ret->writecallback = xmlFdWrite;
Daniel Veillard7db38712002-02-07 16:39:11 +00002560 ret->closecallback = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002561 }
2562
2563 return(ret);
2564}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002565#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002566
2567/**
2568 * xmlParserInputBufferCreateIO:
2569 * @ioread: an I/O read function
2570 * @ioclose: an I/O close function
2571 * @ioctx: an I/O handler
2572 * @enc: the charset encoding if known
2573 *
2574 * Create a buffered parser input for the progressive parsing for the input
2575 * from an I/O handler
2576 *
2577 * Returns the new parser input or NULL
2578 */
2579xmlParserInputBufferPtr
2580xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
2581 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
2582 xmlParserInputBufferPtr ret;
2583
2584 if (ioread == NULL) return(NULL);
2585
2586 ret = xmlAllocParserInputBuffer(enc);
2587 if (ret != NULL) {
2588 ret->context = (void *) ioctx;
2589 ret->readcallback = ioread;
2590 ret->closecallback = ioclose;
2591 }
2592
2593 return(ret);
2594}
2595
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002596#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002597/**
2598 * xmlOutputBufferCreateIO:
2599 * @iowrite: an I/O write function
2600 * @ioclose: an I/O close function
2601 * @ioctx: an I/O handler
Daniel Veillard9d06d302002-01-22 18:15:52 +00002602 * @encoder: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002603 *
2604 * Create a buffered output for the progressive saving
2605 * to an I/O handler
2606 *
2607 * Returns the new parser output or NULL
2608 */
2609xmlOutputBufferPtr
2610xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
2611 xmlOutputCloseCallback ioclose, void *ioctx,
2612 xmlCharEncodingHandlerPtr encoder) {
2613 xmlOutputBufferPtr ret;
2614
2615 if (iowrite == NULL) return(NULL);
2616
2617 ret = xmlAllocOutputBuffer(encoder);
2618 if (ret != NULL) {
2619 ret->context = (void *) ioctx;
2620 ret->writecallback = iowrite;
2621 ret->closecallback = ioclose;
2622 }
2623
2624 return(ret);
2625}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002626#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002627
2628/**
Daniel Veillard1b243b42004-06-08 10:16:42 +00002629 * xmlParserInputBufferCreateFilenameDefault:
2630 * @func: function pointer to the new ParserInputBufferCreateFilenameFunc
2631 *
2632 * Registers a callback for URI input file handling
2633 *
2634 * Returns the old value of the registration function
2635 */
2636xmlParserInputBufferCreateFilenameFunc
2637xmlParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func)
2638{
2639 xmlParserInputBufferCreateFilenameFunc old = xmlParserInputBufferCreateFilenameValue;
2640 if (old == NULL) {
2641 old = __xmlParserInputBufferCreateFilename;
2642 }
2643
2644 xmlParserInputBufferCreateFilenameValue = func;
2645 return(old);
2646}
2647
2648/**
2649 * xmlOutputBufferCreateFilenameDefault:
2650 * @func: function pointer to the new OutputBufferCreateFilenameFunc
2651 *
2652 * Registers a callback for URI output file handling
2653 *
2654 * Returns the old value of the registration function
2655 */
2656xmlOutputBufferCreateFilenameFunc
2657xmlOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func)
2658{
2659 xmlOutputBufferCreateFilenameFunc old = xmlOutputBufferCreateFilenameValue;
2660#ifdef LIBXML_OUTPUT_ENABLED
2661 if (old == NULL) {
2662 old = __xmlOutputBufferCreateFilename;
2663 }
2664#endif
2665 xmlOutputBufferCreateFilenameValue = func;
2666 return(old);
2667}
2668
2669/**
Owen Taylor3473f882001-02-23 17:55:21 +00002670 * xmlParserInputBufferPush:
2671 * @in: a buffered parser input
2672 * @len: the size in bytes of the array.
2673 * @buf: an char array
2674 *
2675 * Push the content of the arry in the input buffer
2676 * This routine handle the I18N transcoding to internal UTF-8
2677 * This is used when operating the parser in progressive (push) mode.
2678 *
2679 * Returns the number of chars read and stored in the buffer, or -1
2680 * in case of error.
2681 */
2682int
2683xmlParserInputBufferPush(xmlParserInputBufferPtr in,
2684 int len, const char *buf) {
2685 int nbchars = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00002686 int ret;
Owen Taylor3473f882001-02-23 17:55:21 +00002687
2688 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002689 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002690 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00002691 unsigned int use;
2692
Owen Taylor3473f882001-02-23 17:55:21 +00002693 /*
2694 * Store the data in the incoming raw buffer
2695 */
2696 if (in->raw == NULL) {
2697 in->raw = xmlBufferCreate();
2698 }
William M. Bracka3215c72004-07-31 16:24:01 +00002699 ret = xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
2700 if (ret != 0)
2701 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002702
2703 /*
2704 * convert as much as possible to the parser reading buffer.
2705 */
Daniel Veillard36711902004-02-11 13:25:26 +00002706 use = in->raw->use;
Owen Taylor3473f882001-02-23 17:55:21 +00002707 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2708 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002709 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002710 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002711 return(-1);
2712 }
Daniel Veillard36711902004-02-11 13:25:26 +00002713 in->rawconsumed += (use - in->raw->use);
Owen Taylor3473f882001-02-23 17:55:21 +00002714 } else {
2715 nbchars = len;
William M. Bracka3215c72004-07-31 16:24:01 +00002716 ret = xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
2717 if (ret != 0)
2718 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002719 }
2720#ifdef DEBUG_INPUT
2721 xmlGenericError(xmlGenericErrorContext,
2722 "I/O: pushed %d chars, buffer %d/%d\n",
2723 nbchars, in->buffer->use, in->buffer->size);
2724#endif
2725 return(nbchars);
2726}
2727
2728/**
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002729 * endOfInput:
2730 *
2731 * When reading from an Input channel indicated end of file or error
2732 * don't reread from it again.
2733 */
2734static int
2735endOfInput (void * context ATTRIBUTE_UNUSED,
2736 char * buffer ATTRIBUTE_UNUSED,
2737 int len ATTRIBUTE_UNUSED) {
2738 return(0);
2739}
2740
2741/**
Owen Taylor3473f882001-02-23 17:55:21 +00002742 * xmlParserInputBufferGrow:
2743 * @in: a buffered parser input
2744 * @len: indicative value of the amount of chars to read
2745 *
2746 * Grow up the content of the input buffer, the old data are preserved
2747 * This routine handle the I18N transcoding to internal UTF-8
2748 * This routine is used when operating the parser in normal (pull) mode
2749 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002750 * TODO: one should be able to remove one extra copy by copying directly
Owen Taylor3473f882001-02-23 17:55:21 +00002751 * onto in->buffer or in->raw
2752 *
2753 * Returns the number of chars read and stored in the buffer, or -1
2754 * in case of error.
2755 */
2756int
2757xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
2758 char *buffer = NULL;
2759 int res = 0;
2760 int nbchars = 0;
2761 int buffree;
Daniel Veillard9e412302002-06-10 15:59:44 +00002762 unsigned int needSize;
Owen Taylor3473f882001-02-23 17:55:21 +00002763
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002764 if ((in == NULL) || (in->error)) return(-1);
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002765 if ((len <= MINLEN) && (len != 4))
Owen Taylor3473f882001-02-23 17:55:21 +00002766 len = MINLEN;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002767
Owen Taylor3473f882001-02-23 17:55:21 +00002768 buffree = in->buffer->size - in->buffer->use;
2769 if (buffree <= 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002770 xmlIOErr(XML_IO_BUFFER_FULL, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002771 in->error = XML_IO_BUFFER_FULL;
William M. Bracka3215c72004-07-31 16:24:01 +00002772 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002773 }
Owen Taylor3473f882001-02-23 17:55:21 +00002774
Daniel Veillarde5354492002-05-16 08:43:22 +00002775 needSize = in->buffer->use + len + 1;
2776 if (needSize > in->buffer->size){
2777 if (!xmlBufferResize(in->buffer, needSize)){
Daniel Veillard05d987b2003-10-08 11:54:57 +00002778 xmlIOErrMemory("growing input buffer");
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002779 in->error = XML_ERR_NO_MEMORY;
William M. Bracka3215c72004-07-31 16:24:01 +00002780 return(-1);
Daniel Veillarde5354492002-05-16 08:43:22 +00002781 }
Owen Taylor3473f882001-02-23 17:55:21 +00002782 }
Daniel Veillarde5354492002-05-16 08:43:22 +00002783 buffer = (char *)&in->buffer->content[in->buffer->use];
Owen Taylor3473f882001-02-23 17:55:21 +00002784
2785 /*
2786 * Call the read method for this I/O type.
2787 */
2788 if (in->readcallback != NULL) {
2789 res = in->readcallback(in->context, &buffer[0], len);
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002790 if (res <= 0)
2791 in->readcallback = endOfInput;
Owen Taylor3473f882001-02-23 17:55:21 +00002792 } else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002793 xmlIOErr(XML_IO_NO_INPUT, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002794 in->error = XML_IO_NO_INPUT;
Owen Taylor3473f882001-02-23 17:55:21 +00002795 return(-1);
2796 }
2797 if (res < 0) {
Owen Taylor3473f882001-02-23 17:55:21 +00002798 return(-1);
2799 }
2800 len = res;
2801 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00002802 unsigned int use;
2803
Owen Taylor3473f882001-02-23 17:55:21 +00002804 /*
2805 * Store the data in the incoming raw buffer
2806 */
2807 if (in->raw == NULL) {
2808 in->raw = xmlBufferCreate();
2809 }
William M. Bracka3215c72004-07-31 16:24:01 +00002810 res = xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
2811 if (res != 0)
2812 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002813
2814 /*
2815 * convert as much as possible to the parser reading buffer.
2816 */
Daniel Veillard36711902004-02-11 13:25:26 +00002817 use = in->raw->use;
Owen Taylor3473f882001-02-23 17:55:21 +00002818 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2819 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002820 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002821 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002822 return(-1);
2823 }
Daniel Veillard36711902004-02-11 13:25:26 +00002824 in->rawconsumed += (use - in->raw->use);
Owen Taylor3473f882001-02-23 17:55:21 +00002825 } else {
2826 nbchars = len;
Daniel Veillarde5354492002-05-16 08:43:22 +00002827 in->buffer->use += nbchars;
2828 buffer[nbchars] = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002829 }
2830#ifdef DEBUG_INPUT
2831 xmlGenericError(xmlGenericErrorContext,
2832 "I/O: read %d chars, buffer %d/%d\n",
2833 nbchars, in->buffer->use, in->buffer->size);
2834#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002835 return(nbchars);
2836}
2837
2838/**
2839 * xmlParserInputBufferRead:
2840 * @in: a buffered parser input
2841 * @len: indicative value of the amount of chars to read
2842 *
2843 * Refresh the content of the input buffer, the old data are considered
2844 * consumed
2845 * This routine handle the I18N transcoding to internal UTF-8
2846 *
2847 * Returns the number of chars read and stored in the buffer, or -1
2848 * in case of error.
2849 */
2850int
2851xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002852 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002853 if (in->readcallback != NULL)
2854 return(xmlParserInputBufferGrow(in, len));
Daniel Veillard53350552003-09-18 13:35:51 +00002855 else if ((in->buffer != NULL) &&
2856 (in->buffer->alloc == XML_BUFFER_ALLOC_IMMUTABLE))
2857 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002858 else
2859 return(-1);
2860}
2861
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002862#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002863/**
2864 * xmlOutputBufferWrite:
2865 * @out: a buffered parser output
2866 * @len: the size in bytes of the array.
2867 * @buf: an char array
2868 *
2869 * Write the content of the array in the output I/O buffer
2870 * This routine handle the I18N transcoding from internal UTF-8
2871 * The buffer is lossless, i.e. will store in case of partial
2872 * or delayed writes.
2873 *
2874 * Returns the number of chars immediately written, or -1
2875 * in case of error.
2876 */
2877int
2878xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
2879 int nbchars = 0; /* number of chars to output to I/O */
2880 int ret; /* return from function call */
2881 int written = 0; /* number of char written to I/O so far */
2882 int chunk; /* number of byte curreent processed from buf */
2883
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002884 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002885 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002886 if (out->error) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002887
2888 do {
2889 chunk = len;
2890 if (chunk > 4 * MINLEN)
2891 chunk = 4 * MINLEN;
2892
2893 /*
2894 * first handle encoding stuff.
2895 */
2896 if (out->encoder != NULL) {
2897 /*
2898 * Store the data in the incoming raw buffer
2899 */
2900 if (out->conv == NULL) {
2901 out->conv = xmlBufferCreate();
2902 }
William M. Bracka3215c72004-07-31 16:24:01 +00002903 ret = xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2904 if (ret != 0)
2905 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002906
2907 if ((out->buffer->use < MINLEN) && (chunk == len))
2908 goto done;
2909
2910 /*
2911 * convert as much as possible to the parser reading buffer.
2912 */
2913 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
Daniel Veillard809faa52003-02-10 15:43:53 +00002914 if ((ret < 0) && (ret != -3)) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002915 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002916 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002917 return(-1);
2918 }
2919 nbchars = out->conv->use;
2920 } else {
William M. Bracka3215c72004-07-31 16:24:01 +00002921 ret = xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2922 if (ret != 0)
2923 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002924 nbchars = out->buffer->use;
2925 }
2926 buf += chunk;
2927 len -= chunk;
2928
2929 if ((nbchars < MINLEN) && (len <= 0))
2930 goto done;
2931
2932 if (out->writecallback) {
2933 /*
2934 * second write the stuff to the I/O channel
2935 */
2936 if (out->encoder != NULL) {
2937 ret = out->writecallback(out->context,
2938 (const char *)out->conv->content, nbchars);
2939 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002940 xmlBufferShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002941 } else {
2942 ret = out->writecallback(out->context,
2943 (const char *)out->buffer->content, nbchars);
2944 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002945 xmlBufferShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002946 }
2947 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002948 xmlIOErr(XML_IO_WRITE, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002949 out->error = XML_IO_WRITE;
Owen Taylor3473f882001-02-23 17:55:21 +00002950 return(ret);
2951 }
2952 out->written += ret;
2953 }
2954 written += nbchars;
2955 } while (len > 0);
2956
2957done:
2958#ifdef DEBUG_INPUT
2959 xmlGenericError(xmlGenericErrorContext,
2960 "I/O: wrote %d chars\n", written);
2961#endif
2962 return(written);
2963}
2964
2965/**
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00002966 * xmlEscapeContent:
2967 * @out: a pointer to an array of bytes to store the result
2968 * @outlen: the length of @out
2969 * @in: a pointer to an array of unescaped UTF-8 bytes
2970 * @inlen: the length of @in
2971 *
2972 * Take a block of UTF-8 chars in and escape them.
2973 * Returns 0 if success, or -1 otherwise
2974 * The value of @inlen after return is the number of octets consumed
2975 * if the return value is positive, else unpredictable.
2976 * The value of @outlen after return is the number of octets consumed.
2977 */
2978static int
2979xmlEscapeContent(unsigned char* out, int *outlen,
2980 const xmlChar* in, int *inlen) {
2981 unsigned char* outstart = out;
2982 const unsigned char* base = in;
2983 unsigned char* outend = out + *outlen;
2984 const unsigned char* inend;
2985
2986 inend = in + (*inlen);
2987
2988 while ((in < inend) && (out < outend)) {
2989 if (*in == '<') {
2990 if (outend - out < 4) break;
2991 *out++ = '&';
2992 *out++ = 'l';
2993 *out++ = 't';
2994 *out++ = ';';
2995 } else if (*in == '>') {
2996 if (outend - out < 4) break;
2997 *out++ = '&';
2998 *out++ = 'g';
2999 *out++ = 't';
3000 *out++ = ';';
3001 } else if (*in == '&') {
3002 if (outend - out < 5) break;
3003 *out++ = '&';
3004 *out++ = 'a';
3005 *out++ = 'm';
3006 *out++ = 'p';
3007 *out++ = ';';
3008 } else if (*in == '\r') {
3009 if (outend - out < 5) break;
3010 *out++ = '&';
3011 *out++ = '#';
3012 *out++ = '1';
3013 *out++ = '3';
3014 *out++ = ';';
3015 } else {
3016 *out++ = (unsigned char) *in;
3017 }
3018 ++in;
3019 }
3020 *outlen = out - outstart;
3021 *inlen = in - base;
3022 return(0);
3023}
3024
3025/**
3026 * xmlOutputBufferWriteEscape:
3027 * @out: a buffered parser output
3028 * @str: a zero terminated UTF-8 string
Daniel Veillardee8960b2004-05-14 03:25:14 +00003029 * @escaping: an optional escaping function (or NULL)
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003030 *
3031 * Write the content of the string in the output I/O buffer
3032 * This routine escapes the caracters and then handle the I18N
3033 * transcoding from internal UTF-8
3034 * The buffer is lossless, i.e. will store in case of partial
3035 * or delayed writes.
3036 *
3037 * Returns the number of chars immediately written, or -1
3038 * in case of error.
3039 */
3040int
Daniel Veillardee8960b2004-05-14 03:25:14 +00003041xmlOutputBufferWriteEscape(xmlOutputBufferPtr out, const xmlChar *str,
3042 xmlCharEncodingOutputFunc escaping) {
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003043 int nbchars = 0; /* number of chars to output to I/O */
3044 int ret; /* return from function call */
3045 int written = 0; /* number of char written to I/O so far */
Daniel Veillard71b95632004-08-31 12:15:36 +00003046 int oldwritten=0;/* loop guard */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003047 int chunk; /* number of byte currently processed from str */
3048 int len; /* number of bytes in str */
3049 int cons; /* byte from str consumed */
3050
3051 if ((out == NULL) || (out->error) || (str == NULL)) return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003052 len = strlen((const char *)str);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003053 if (len < 0) return(0);
3054 if (out->error) return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003055 if (escaping == NULL) escaping = xmlEscapeContent;
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003056
3057 do {
Daniel Veillard71b95632004-08-31 12:15:36 +00003058 oldwritten = written;
3059
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003060 /*
3061 * how many bytes to consume and how many bytes to store.
3062 */
3063 cons = len;
3064 chunk = (out->buffer->size - out->buffer->use) - 1;
3065
3066 /*
3067 * first handle encoding stuff.
3068 */
3069 if (out->encoder != NULL) {
3070 /*
3071 * Store the data in the incoming raw buffer
3072 */
3073 if (out->conv == NULL) {
3074 out->conv = xmlBufferCreate();
3075 }
Daniel Veillardee8960b2004-05-14 03:25:14 +00003076 ret = escaping(out->buffer->content + out->buffer->use ,
3077 &chunk, str, &cons);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003078 if (ret < 0)
3079 return(-1);
3080 out->buffer->use += chunk;
3081 out->buffer->content[out->buffer->use] = 0;
3082
3083 if ((out->buffer->use < MINLEN) && (cons == len))
3084 goto done;
3085
3086 /*
3087 * convert as much as possible to the output buffer.
3088 */
3089 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
3090 if ((ret < 0) && (ret != -3)) {
3091 xmlIOErr(XML_IO_ENCODER, NULL);
3092 out->error = XML_IO_ENCODER;
3093 return(-1);
3094 }
3095 nbchars = out->conv->use;
3096 } else {
Daniel Veillardee8960b2004-05-14 03:25:14 +00003097 ret = escaping(out->buffer->content + out->buffer->use ,
3098 &chunk, str, &cons);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003099 if (ret < 0)
3100 return(-1);
3101 out->buffer->use += chunk;
3102 out->buffer->content[out->buffer->use] = 0;
3103 nbchars = out->buffer->use;
3104 }
3105 str += cons;
3106 len -= cons;
3107
3108 if ((nbchars < MINLEN) && (len <= 0))
3109 goto done;
3110
3111 if (out->writecallback) {
3112 /*
3113 * second write the stuff to the I/O channel
3114 */
3115 if (out->encoder != NULL) {
3116 ret = out->writecallback(out->context,
3117 (const char *)out->conv->content, nbchars);
3118 if (ret >= 0)
3119 xmlBufferShrink(out->conv, ret);
3120 } else {
3121 ret = out->writecallback(out->context,
3122 (const char *)out->buffer->content, nbchars);
3123 if (ret >= 0)
3124 xmlBufferShrink(out->buffer, ret);
3125 }
3126 if (ret < 0) {
3127 xmlIOErr(XML_IO_WRITE, NULL);
3128 out->error = XML_IO_WRITE;
3129 return(ret);
3130 }
3131 out->written += ret;
Daniel Veillard83a75e02004-05-14 21:50:42 +00003132 } else if (out->buffer->size - out->buffer->use < MINLEN) {
3133 xmlBufferResize(out->buffer, out->buffer->size + MINLEN);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003134 }
3135 written += nbchars;
Daniel Veillard71b95632004-08-31 12:15:36 +00003136 } while ((len > 0) && (oldwritten != written));
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003137
3138done:
3139#ifdef DEBUG_INPUT
3140 xmlGenericError(xmlGenericErrorContext,
3141 "I/O: wrote %d chars\n", written);
3142#endif
3143 return(written);
3144}
3145
3146/**
Owen Taylor3473f882001-02-23 17:55:21 +00003147 * xmlOutputBufferWriteString:
3148 * @out: a buffered parser output
3149 * @str: a zero terminated C string
3150 *
3151 * Write the content of the string in the output I/O buffer
3152 * This routine handle the I18N transcoding from internal UTF-8
3153 * The buffer is lossless, i.e. will store in case of partial
3154 * or delayed writes.
3155 *
3156 * Returns the number of chars immediately written, or -1
3157 * in case of error.
3158 */
3159int
3160xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
3161 int len;
3162
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003163 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003164 if (str == NULL)
3165 return(-1);
3166 len = strlen(str);
3167
3168 if (len > 0)
3169 return(xmlOutputBufferWrite(out, len, str));
3170 return(len);
3171}
3172
3173/**
3174 * xmlOutputBufferFlush:
3175 * @out: a buffered output
3176 *
3177 * flushes the output I/O channel
3178 *
3179 * Returns the number of byte written or -1 in case of error.
3180 */
3181int
3182xmlOutputBufferFlush(xmlOutputBufferPtr out) {
3183 int nbchars = 0, ret = 0;
3184
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003185 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003186 /*
3187 * first handle encoding stuff.
3188 */
3189 if ((out->conv != NULL) && (out->encoder != NULL)) {
3190 /*
3191 * convert as much as possible to the parser reading buffer.
3192 */
3193 nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
3194 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003195 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003196 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003197 return(-1);
3198 }
3199 }
3200
3201 /*
3202 * second flush the stuff to the I/O channel
3203 */
3204 if ((out->conv != NULL) && (out->encoder != NULL) &&
3205 (out->writecallback != NULL)) {
3206 ret = out->writecallback(out->context,
3207 (const char *)out->conv->content, out->conv->use);
3208 if (ret >= 0)
3209 xmlBufferShrink(out->conv, ret);
3210 } else if (out->writecallback != NULL) {
3211 ret = out->writecallback(out->context,
3212 (const char *)out->buffer->content, out->buffer->use);
3213 if (ret >= 0)
3214 xmlBufferShrink(out->buffer, ret);
3215 }
3216 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003217 xmlIOErr(XML_IO_FLUSH, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003218 out->error = XML_IO_FLUSH;
Owen Taylor3473f882001-02-23 17:55:21 +00003219 return(ret);
3220 }
3221 out->written += ret;
3222
3223#ifdef DEBUG_INPUT
3224 xmlGenericError(xmlGenericErrorContext,
3225 "I/O: flushed %d chars\n", ret);
3226#endif
3227 return(ret);
3228}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003229#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003230
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003231/**
Owen Taylor3473f882001-02-23 17:55:21 +00003232 * xmlParserGetDirectory:
3233 * @filename: the path to a file
3234 *
3235 * lookup the directory for that file
3236 *
3237 * Returns a new allocated string containing the directory, or NULL.
3238 */
3239char *
3240xmlParserGetDirectory(const char *filename) {
3241 char *ret = NULL;
3242 char dir[1024];
3243 char *cur;
3244 char sep = '/';
3245
Igor Zlatkovic9181cc02002-09-29 17:51:06 +00003246#ifdef _WIN32_WCE /* easy way by now ... wince does not have dirs! */
3247 return NULL;
3248#endif
3249
Owen Taylor3473f882001-02-23 17:55:21 +00003250 if (xmlInputCallbackInitialized == 0)
3251 xmlRegisterDefaultInputCallbacks();
3252
3253 if (filename == NULL) return(NULL);
Daniel Veillard3c5ed912002-01-08 10:36:16 +00003254#if defined(WIN32) && !defined(__CYGWIN__)
Owen Taylor3473f882001-02-23 17:55:21 +00003255 sep = '\\';
3256#endif
3257
3258 strncpy(dir, filename, 1023);
3259 dir[1023] = 0;
3260 cur = &dir[strlen(dir)];
3261 while (cur > dir) {
3262 if (*cur == sep) break;
3263 cur --;
3264 }
3265 if (*cur == sep) {
3266 if (cur == dir) dir[1] = 0;
3267 else *cur = 0;
3268 ret = xmlMemStrdup(dir);
3269 } else {
3270 if (getcwd(dir, 1024) != NULL) {
3271 dir[1023] = 0;
3272 ret = xmlMemStrdup(dir);
3273 }
3274 }
3275 return(ret);
3276}
3277
3278/****************************************************************
3279 * *
3280 * External entities loading *
3281 * *
3282 ****************************************************************/
3283
Daniel Veillarda840b692003-10-19 13:35:37 +00003284/**
3285 * xmlCheckHTTPInput:
3286 * @ctxt: an XML parser context
3287 * @ret: an XML parser input
3288 *
3289 * Check an input in case it was created from an HTTP stream, in that
3290 * case it will handle encoding and update of the base URL in case of
3291 * redirection. It also checks for HTTP errors in which case the input
3292 * is cleanly freed up and an appropriate error is raised in context
3293 *
3294 * Returns the input or NULL in case of HTTP error.
3295 */
3296xmlParserInputPtr
3297xmlCheckHTTPInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr ret) {
3298#ifdef LIBXML_HTTP_ENABLED
3299 if ((ret != NULL) && (ret->buf != NULL) &&
3300 (ret->buf->readcallback == xmlIOHTTPRead) &&
3301 (ret->buf->context != NULL)) {
3302 const char *encoding;
3303 const char *redir;
3304 const char *mime;
3305 int code;
3306
3307 code = xmlNanoHTTPReturnCode(ret->buf->context);
3308 if (code >= 400) {
3309 /* fatal error */
3310 if (ret->filename != NULL)
Daniel Veillarde8039df2003-10-27 11:25:13 +00003311 __xmlLoaderErr(ctxt, "failed to load HTTP resource \"%s\"\n",
Daniel Veillarda840b692003-10-19 13:35:37 +00003312 (const char *) ret->filename);
3313 else
Daniel Veillarde8039df2003-10-27 11:25:13 +00003314 __xmlLoaderErr(ctxt, "failed to load HTTP resource\n", NULL);
Daniel Veillarda840b692003-10-19 13:35:37 +00003315 xmlFreeInputStream(ret);
3316 ret = NULL;
3317 } else {
3318
3319 mime = xmlNanoHTTPMimeType(ret->buf->context);
3320 if ((xmlStrstr(BAD_CAST mime, BAD_CAST "/xml")) ||
3321 (xmlStrstr(BAD_CAST mime, BAD_CAST "+xml"))) {
3322 encoding = xmlNanoHTTPEncoding(ret->buf->context);
3323 if (encoding != NULL) {
3324 xmlCharEncodingHandlerPtr handler;
3325
3326 handler = xmlFindCharEncodingHandler(encoding);
3327 if (handler != NULL) {
3328 xmlSwitchInputEncoding(ctxt, ret, handler);
3329 } else {
3330 __xmlErrEncoding(ctxt, XML_ERR_UNKNOWN_ENCODING,
3331 "Unknown encoding %s",
3332 BAD_CAST encoding, NULL);
3333 }
3334 if (ret->encoding == NULL)
3335 ret->encoding = xmlStrdup(BAD_CAST encoding);
3336 }
3337#if 0
3338 } else if (xmlStrstr(BAD_CAST mime, BAD_CAST "html")) {
3339#endif
3340 }
3341 redir = xmlNanoHTTPRedir(ret->buf->context);
3342 if (redir != NULL) {
3343 if (ret->filename != NULL)
3344 xmlFree((xmlChar *) ret->filename);
3345 if (ret->directory != NULL) {
3346 xmlFree((xmlChar *) ret->directory);
3347 ret->directory = NULL;
3348 }
3349 ret->filename =
3350 (char *) xmlStrdup((const xmlChar *) redir);
3351 }
3352 }
3353 }
3354#endif
3355 return(ret);
3356}
3357
Daniel Veillard561b7f82002-03-20 21:55:57 +00003358static int xmlSysIDExists(const char *URL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003359#ifdef HAVE_STAT
3360 int ret;
3361 struct stat info;
3362 const char *path;
3363
3364 if (URL == NULL)
3365 return(0);
3366
Daniel Veillardf4862f02002-09-10 11:13:43 +00003367 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003368#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00003369 path = &URL[17];
3370#else
Daniel Veillard6990bf32001-08-23 21:17:48 +00003371 path = &URL[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00003372#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003373 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003374#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard6990bf32001-08-23 21:17:48 +00003375 path = &URL[8];
3376#else
3377 path = &URL[7];
3378#endif
3379 } else
3380 path = URL;
3381 ret = stat(path, &info);
Daniel Veillard561b7f82002-03-20 21:55:57 +00003382 if (ret == 0)
3383 return(1);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003384#endif
Daniel Veillard561b7f82002-03-20 21:55:57 +00003385 return(0);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003386}
Daniel Veillard6990bf32001-08-23 21:17:48 +00003387
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003388/**
Owen Taylor3473f882001-02-23 17:55:21 +00003389 * xmlDefaultExternalEntityLoader:
3390 * @URL: the URL for the entity to load
3391 * @ID: the System ID for the entity to load
3392 * @ctxt: the context in which the entity is called or NULL
3393 *
3394 * By default we don't load external entitites, yet.
3395 *
3396 * Returns a new allocated xmlParserInputPtr, or NULL.
3397 */
Daniel Veillarda840b692003-10-19 13:35:37 +00003398static xmlParserInputPtr
Owen Taylor3473f882001-02-23 17:55:21 +00003399xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
Daniel Veillarda840b692003-10-19 13:35:37 +00003400 xmlParserCtxtPtr ctxt)
3401{
Owen Taylor3473f882001-02-23 17:55:21 +00003402 xmlParserInputPtr ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003403 xmlChar *resource = NULL;
Daniel Veillarda840b692003-10-19 13:35:37 +00003404
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003405#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003406 xmlCatalogAllow pref;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003407#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003408
3409#ifdef DEBUG_EXTERNAL_ENTITIES
3410 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda840b692003-10-19 13:35:37 +00003411 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00003412#endif
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003413#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillard61b93382003-11-03 14:28:31 +00003414 if ((ctxt != NULL) && (ctxt->options & XML_PARSE_NONET)) {
3415 int options = ctxt->options;
3416
3417 ctxt->options -= XML_PARSE_NONET;
3418 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
3419 ctxt->options = options;
3420 return(ret);
3421 }
3422
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003423 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003424 * If the resource doesn't exists as a file,
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003425 * try to load it from the resource pointed in the catalogs
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003426 */
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003427 pref = xmlCatalogGetDefaults();
3428
Daniel Veillard561b7f82002-03-20 21:55:57 +00003429 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlSysIDExists(URL))) {
Daniel Veillarda840b692003-10-19 13:35:37 +00003430 /*
3431 * Do a local lookup
3432 */
3433 if ((ctxt->catalogs != NULL) &&
3434 ((pref == XML_CATA_ALLOW_ALL) ||
3435 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3436 resource = xmlCatalogLocalResolve(ctxt->catalogs,
3437 (const xmlChar *) ID,
3438 (const xmlChar *) URL);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003439 }
Daniel Veillarda840b692003-10-19 13:35:37 +00003440 /*
3441 * Try a global lookup
3442 */
3443 if ((resource == NULL) &&
3444 ((pref == XML_CATA_ALLOW_ALL) ||
3445 (pref == XML_CATA_ALLOW_GLOBAL))) {
3446 resource = xmlCatalogResolve((const xmlChar *) ID,
3447 (const xmlChar *) URL);
3448 }
3449 if ((resource == NULL) && (URL != NULL))
3450 resource = xmlStrdup((const xmlChar *) URL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003451
Daniel Veillarda840b692003-10-19 13:35:37 +00003452 /*
3453 * TODO: do an URI lookup on the reference
3454 */
3455 if ((resource != NULL)
3456 && (!xmlSysIDExists((const char *) resource))) {
3457 xmlChar *tmp = NULL;
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003458
Daniel Veillarda840b692003-10-19 13:35:37 +00003459 if ((ctxt->catalogs != NULL) &&
3460 ((pref == XML_CATA_ALLOW_ALL) ||
3461 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3462 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
3463 }
3464 if ((tmp == NULL) &&
3465 ((pref == XML_CATA_ALLOW_ALL) ||
3466 (pref == XML_CATA_ALLOW_GLOBAL))) {
3467 tmp = xmlCatalogResolveURI(resource);
3468 }
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003469
Daniel Veillarda840b692003-10-19 13:35:37 +00003470 if (tmp != NULL) {
3471 xmlFree(resource);
3472 resource = tmp;
3473 }
3474 }
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003475 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003476#endif
3477
3478 if (resource == NULL)
Daniel Veillarda840b692003-10-19 13:35:37 +00003479 resource = (xmlChar *) URL;
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003480
3481 if (resource == NULL) {
Daniel Veillarda840b692003-10-19 13:35:37 +00003482 if (ID == NULL)
3483 ID = "NULL";
Daniel Veillarde8039df2003-10-27 11:25:13 +00003484 __xmlLoaderErr(ctxt, "failed to load external entity \"%s\"\n", ID);
Daniel Veillarda840b692003-10-19 13:35:37 +00003485 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003486 }
Daniel Veillarda840b692003-10-19 13:35:37 +00003487 ret = xmlNewInputFromFile(ctxt, (const char *) resource);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003488 if ((resource != NULL) && (resource != (xmlChar *) URL))
Daniel Veillarda840b692003-10-19 13:35:37 +00003489 xmlFree(resource);
3490 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003491}
3492
3493static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
3494 xmlDefaultExternalEntityLoader;
3495
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003496/**
Owen Taylor3473f882001-02-23 17:55:21 +00003497 * xmlSetExternalEntityLoader:
3498 * @f: the new entity resolver function
3499 *
3500 * Changes the defaultexternal entity resolver function for the application
3501 */
3502void
3503xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
3504 xmlCurrentExternalEntityLoader = f;
3505}
3506
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003507/**
Owen Taylor3473f882001-02-23 17:55:21 +00003508 * xmlGetExternalEntityLoader:
3509 *
3510 * Get the default external entity resolver function for the application
3511 *
3512 * Returns the xmlExternalEntityLoader function pointer
3513 */
3514xmlExternalEntityLoader
3515xmlGetExternalEntityLoader(void) {
3516 return(xmlCurrentExternalEntityLoader);
3517}
3518
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003519/**
Owen Taylor3473f882001-02-23 17:55:21 +00003520 * xmlLoadExternalEntity:
3521 * @URL: the URL for the entity to load
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00003522 * @ID: the Public ID for the entity to load
Owen Taylor3473f882001-02-23 17:55:21 +00003523 * @ctxt: the context in which the entity is called or NULL
3524 *
3525 * Load an external entity, note that the use of this function for
3526 * unparsed entities may generate problems
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003527 * TODO: a more generic External entity API must be designed
Owen Taylor3473f882001-02-23 17:55:21 +00003528 *
3529 * Returns the xmlParserInputPtr or NULL
3530 */
3531xmlParserInputPtr
3532xmlLoadExternalEntity(const char *URL, const char *ID,
3533 xmlParserCtxtPtr ctxt) {
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00003534 if ((URL != NULL) && (xmlSysIDExists(URL) == 0)) {
3535 char *canonicFilename;
3536 xmlParserInputPtr ret;
3537
3538 canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL);
3539 if (canonicFilename == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003540 xmlIOErrMemory("building canonical path\n");
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00003541 return(NULL);
3542 }
3543
3544 ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt);
3545 xmlFree(canonicFilename);
3546 return(ret);
3547 }
Owen Taylor3473f882001-02-23 17:55:21 +00003548 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
3549}
3550
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003551/************************************************************************
3552 * *
3553 * Disabling Network access *
3554 * *
3555 ************************************************************************/
3556
3557#ifdef LIBXML_CATALOG_ENABLED
3558static int
3559xmlNoNetExists(const char *URL)
3560{
3561#ifdef HAVE_STAT
3562 int ret;
3563 struct stat info;
3564 const char *path;
3565
3566 if (URL == NULL)
3567 return (0);
3568
Daniel Veillardf4862f02002-09-10 11:13:43 +00003569 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003570#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00003571 path = &URL[17];
3572#else
3573 path = &URL[16];
3574#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003575 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003576#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003577 path = &URL[8];
3578#else
3579 path = &URL[7];
3580#endif
3581 } else
3582 path = URL;
3583 ret = stat(path, &info);
3584 if (ret == 0)
3585 return (1);
3586#endif
3587 return (0);
3588}
3589#endif
3590
3591/**
3592 * xmlNoNetExternalEntityLoader:
3593 * @URL: the URL for the entity to load
3594 * @ID: the System ID for the entity to load
3595 * @ctxt: the context in which the entity is called or NULL
3596 *
3597 * A specific entity loader disabling network accesses, though still
3598 * allowing local catalog accesses for resolution.
3599 *
3600 * Returns a new allocated xmlParserInputPtr, or NULL.
3601 */
3602xmlParserInputPtr
3603xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
3604 xmlParserCtxtPtr ctxt) {
3605 xmlParserInputPtr input = NULL;
3606 xmlChar *resource = NULL;
3607
3608#ifdef LIBXML_CATALOG_ENABLED
3609 xmlCatalogAllow pref;
3610
3611 /*
3612 * If the resource doesn't exists as a file,
3613 * try to load it from the resource pointed in the catalogs
3614 */
3615 pref = xmlCatalogGetDefaults();
3616
3617 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
3618 /*
3619 * Do a local lookup
3620 */
3621 if ((ctxt->catalogs != NULL) &&
3622 ((pref == XML_CATA_ALLOW_ALL) ||
3623 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3624 resource = xmlCatalogLocalResolve(ctxt->catalogs,
3625 (const xmlChar *)ID,
3626 (const xmlChar *)URL);
3627 }
3628 /*
3629 * Try a global lookup
3630 */
3631 if ((resource == NULL) &&
3632 ((pref == XML_CATA_ALLOW_ALL) ||
3633 (pref == XML_CATA_ALLOW_GLOBAL))) {
3634 resource = xmlCatalogResolve((const xmlChar *)ID,
3635 (const xmlChar *)URL);
3636 }
3637 if ((resource == NULL) && (URL != NULL))
3638 resource = xmlStrdup((const xmlChar *) URL);
3639
3640 /*
3641 * TODO: do an URI lookup on the reference
3642 */
3643 if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
3644 xmlChar *tmp = NULL;
3645
3646 if ((ctxt->catalogs != NULL) &&
3647 ((pref == XML_CATA_ALLOW_ALL) ||
3648 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3649 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
3650 }
3651 if ((tmp == NULL) &&
3652 ((pref == XML_CATA_ALLOW_ALL) ||
3653 (pref == XML_CATA_ALLOW_GLOBAL))) {
3654 tmp = xmlCatalogResolveURI(resource);
3655 }
3656
3657 if (tmp != NULL) {
3658 xmlFree(resource);
3659 resource = tmp;
3660 }
3661 }
3662 }
3663#endif
3664 if (resource == NULL)
3665 resource = (xmlChar *) URL;
3666
3667 if (resource != NULL) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003668 if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
3669 (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003670 xmlIOErr(XML_IO_NETWORK_ATTEMPT, (const char *) resource);
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003671 if (resource != (xmlChar *) URL)
3672 xmlFree(resource);
3673 return(NULL);
3674 }
3675 }
3676 input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
3677 if (resource != (xmlChar *) URL)
3678 xmlFree(resource);
3679 return(input);
3680}
3681