blob: 13a57e7e4e17c95848fb368894db9ed21cd9fe82 [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
557 if (stat(path, &stat_buffer) == -1)
558 return 0;
559
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000560#ifdef S_ISDIR
Owen Taylor3473f882001-02-23 17:55:21 +0000561 if (S_ISDIR(stat_buffer.st_mode)) {
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000562 return 2;
Owen Taylor3473f882001-02-23 17:55:21 +0000563 }
Owen Taylor3473f882001-02-23 17:55:21 +0000564#endif
565#endif
566 return 1;
567}
568
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000569static int
Owen Taylor3473f882001-02-23 17:55:21 +0000570xmlNop(void) {
571 return(0);
572}
573
574/**
Owen Taylor3473f882001-02-23 17:55:21 +0000575 * xmlFdRead:
576 * @context: the I/O context
577 * @buffer: where to drop data
578 * @len: number of bytes to read
579 *
580 * Read @len bytes to @buffer from the I/O channel.
581 *
582 * Returns the number of bytes written
583 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000584static int
Owen Taylor3473f882001-02-23 17:55:21 +0000585xmlFdRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000586 int ret;
587
588 ret = read((int) (long) context, &buffer[0], len);
589 if (ret < 0) xmlIOErr(0, "read()");
590 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000591}
592
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000593#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000594/**
595 * xmlFdWrite:
596 * @context: the I/O context
597 * @buffer: where to get data
598 * @len: number of bytes to write
599 *
600 * Write @len bytes from @buffer to the I/O channel.
601 *
602 * Returns the number of bytes written
603 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000604static int
Owen Taylor3473f882001-02-23 17:55:21 +0000605xmlFdWrite (void * context, const char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000606 int ret;
607
608 ret = write((int) (long) context, &buffer[0], len);
609 if (ret < 0) xmlIOErr(0, "write()");
610 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000611}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000612#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000613
614/**
615 * xmlFdClose:
616 * @context: the I/O context
617 *
618 * Close an I/O channel
Daniel Veillardf012a642001-07-23 19:10:52 +0000619 *
620 * Returns 0 in case of success and error code otherwise
Owen Taylor3473f882001-02-23 17:55:21 +0000621 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000622static int
Owen Taylor3473f882001-02-23 17:55:21 +0000623xmlFdClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000624 int ret;
625 ret = close((int) (long) context);
626 if (ret < 0) xmlIOErr(0, "close()");
627 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000628}
629
630/**
631 * xmlFileMatch:
632 * @filename: the URI for matching
633 *
634 * input from FILE *
635 *
636 * Returns 1 if matches, 0 otherwise
637 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000638int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000639xmlFileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000640 return(1);
641}
642
643/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000644 * xmlFileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +0000645 * @filename: the URI for matching
646 *
647 * input from FILE *, supports compressed input
648 * if @filename is " " then the standard input is used
649 *
650 * Returns an I/O context or NULL in case of error
651 */
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000652static void *
653xmlFileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +0000654 const char *path = NULL;
655 FILE *fd;
656
657 if (!strcmp(filename, "-")) {
658 fd = stdin;
659 return((void *) fd);
660 }
661
Daniel Veillardf4862f02002-09-10 11:13:43 +0000662 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000663#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000664 path = &filename[17];
665#else
Owen Taylor3473f882001-02-23 17:55:21 +0000666 path = &filename[16];
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000667#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000668 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000669#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000670 path = &filename[8];
671#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000672 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000673#endif
674 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000675 path = filename;
676
677 if (path == NULL)
678 return(NULL);
679 if (!xmlCheckFilename(path))
680 return(NULL);
681
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000682#if defined(WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
Owen Taylor3473f882001-02-23 17:55:21 +0000683 fd = fopen(path, "rb");
684#else
685 fd = fopen(path, "r");
686#endif /* WIN32 */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000687 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +0000688 return((void *) fd);
689}
690
691/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000692 * xmlFileOpen:
693 * @filename: the URI for matching
694 *
695 * Wrapper around xmlFileOpen_real that try it with an unescaped
696 * version of @filename, if this fails fallback to @filename
Daniel Veillard71531f32003-02-05 13:19:53 +0000697 *
698 * Returns a handler or NULL in case or failure
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000699 */
700void *
701xmlFileOpen (const char *filename) {
702 char *unescaped;
703 void *retval;
704 unescaped = xmlURIUnescapeString(filename, 0, NULL);
705 if (unescaped != NULL) {
706 retval = xmlFileOpen_real(unescaped);
707 } else {
708 retval = xmlFileOpen_real(filename);
709 }
710 xmlFree(unescaped);
711 return retval;
712}
713
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000714#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000715/**
Owen Taylor3473f882001-02-23 17:55:21 +0000716 * xmlFileOpenW:
717 * @filename: the URI for matching
718 *
719 * output to from FILE *,
720 * if @filename is "-" then the standard output is used
721 *
722 * Returns an I/O context or NULL in case of error
723 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000724static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000725xmlFileOpenW (const char *filename) {
726 const char *path = NULL;
727 FILE *fd;
728
729 if (!strcmp(filename, "-")) {
730 fd = stdout;
731 return((void *) fd);
732 }
733
Daniel Veillardf4862f02002-09-10 11:13:43 +0000734 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000735#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000736 path = &filename[17];
737#else
Owen Taylor3473f882001-02-23 17:55:21 +0000738 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000739#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000740 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000741#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000742 path = &filename[8];
743#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000744 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000745#endif
746 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000747 path = filename;
748
749 if (path == NULL)
750 return(NULL);
751
Daniel Veillardcbbd78d2003-07-20 15:21:30 +0000752 fd = fopen(path, "wb");
Daniel Veillard05d987b2003-10-08 11:54:57 +0000753 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +0000754 return((void *) fd);
755}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000756#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000757
758/**
759 * xmlFileRead:
760 * @context: the I/O context
761 * @buffer: where to drop data
762 * @len: number of bytes to write
763 *
764 * Read @len bytes to @buffer from the I/O channel.
765 *
766 * Returns the number of bytes written
767 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000768int
Owen Taylor3473f882001-02-23 17:55:21 +0000769xmlFileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000770 int ret;
771 ret = fread(&buffer[0], 1, len, (FILE *) context);
772 if (ret < 0) xmlIOErr(0, "fread()");
773 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000774}
775
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000776#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000777/**
778 * xmlFileWrite:
779 * @context: the I/O context
780 * @buffer: where to drop data
781 * @len: number of bytes to write
782 *
783 * Write @len bytes from @buffer to the I/O channel.
784 *
785 * Returns the number of bytes written
786 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000787static int
Owen Taylor3473f882001-02-23 17:55:21 +0000788xmlFileWrite (void * context, const char * buffer, int len) {
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000789 int items;
790
791 items = fwrite(&buffer[0], len, 1, (FILE *) context);
Daniel Veillard97bf4d02003-10-08 18:58:28 +0000792 if ((items == 0) && (ferror((FILE *) context))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000793 xmlIOErr(0, "fwrite()");
Daniel Veillard97bf4d02003-10-08 18:58:28 +0000794 return(-1);
795 }
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000796 return(items * len);
Owen Taylor3473f882001-02-23 17:55:21 +0000797}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000798#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000799
800/**
801 * xmlFileClose:
802 * @context: the I/O context
803 *
804 * Close an I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000805 *
806 * Returns 0 or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +0000807 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000808int
Owen Taylor3473f882001-02-23 17:55:21 +0000809xmlFileClose (void * context) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000810 FILE *fil;
Daniel Veillard05d987b2003-10-08 11:54:57 +0000811 int ret;
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000812
813 fil = (FILE *) context;
Daniel Veillard500a1de2004-03-22 15:22:58 +0000814 if ((fil == stdout) || (fil == stderr)) {
815 ret = fflush(fil);
816 if (ret < 0)
817 xmlIOErr(0, "fflush()");
818 return(0);
819 }
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000820 if (fil == stdin)
821 return(0);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000822 ret = ( fclose((FILE *) context) == EOF ) ? -1 : 0;
823 if (ret < 0)
824 xmlIOErr(0, "fclose()");
825 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000826}
827
828/**
829 * xmlFileFlush:
830 * @context: the I/O context
831 *
832 * Flush an I/O channel
833 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000834static int
Owen Taylor3473f882001-02-23 17:55:21 +0000835xmlFileFlush (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000836 int ret;
837 ret = ( fflush((FILE *) context) == EOF ) ? -1 : 0;
838 if (ret < 0)
839 xmlIOErr(0, "fflush()");
840 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000841}
842
843#ifdef HAVE_ZLIB_H
844/************************************************************************
845 * *
846 * I/O for compressed file accesses *
847 * *
848 ************************************************************************/
849/**
850 * xmlGzfileMatch:
851 * @filename: the URI for matching
852 *
853 * input from compressed file test
854 *
855 * Returns 1 if matches, 0 otherwise
856 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000857static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000858xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000859 return(1);
860}
861
862/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000863 * xmlGzfileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +0000864 * @filename: the URI for matching
865 *
866 * input from compressed file open
867 * if @filename is " " then the standard input is used
868 *
869 * Returns an I/O context or NULL in case of error
870 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000871static void *
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000872xmlGzfileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +0000873 const char *path = NULL;
874 gzFile fd;
875
876 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000877 fd = gzdopen(dup(0), "rb");
Owen Taylor3473f882001-02-23 17:55:21 +0000878 return((void *) fd);
879 }
880
Daniel Veillardf4862f02002-09-10 11:13:43 +0000881 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000882#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000883 path = &filename[17];
884#else
Owen Taylor3473f882001-02-23 17:55:21 +0000885 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000886#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000887 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000888#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000889 path = &filename[8];
890#else
Owen Taylor3473f882001-02-23 17:55:21 +0000891 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000892#endif
893 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000894 path = filename;
895
896 if (path == NULL)
897 return(NULL);
898 if (!xmlCheckFilename(path))
899 return(NULL);
900
901 fd = gzopen(path, "rb");
902 return((void *) fd);
903}
904
905/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000906 * xmlGzfileOpen:
907 * @filename: the URI for matching
908 *
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +0000909 * Wrapper around xmlGzfileOpen if the open fais, it will
910 * try to unescape @filename
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000911 */
912static void *
913xmlGzfileOpen (const char *filename) {
914 char *unescaped;
915 void *retval;
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +0000916
917 retval = xmlGzfileOpen_real(filename);
918 if (retval == NULL) {
919 unescaped = xmlURIUnescapeString(filename, 0, NULL);
920 if (unescaped != NULL) {
921 retval = xmlGzfileOpen_real(unescaped);
922 }
923 xmlFree(unescaped);
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000924 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000925 return retval;
926}
927
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000928#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000929/**
Owen Taylor3473f882001-02-23 17:55:21 +0000930 * xmlGzfileOpenW:
931 * @filename: the URI for matching
932 * @compression: the compression factor (0 - 9 included)
933 *
934 * input from compressed file open
935 * if @filename is " " then the standard input is used
936 *
937 * Returns an I/O context or NULL in case of error
938 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000939static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000940xmlGzfileOpenW (const char *filename, int compression) {
941 const char *path = NULL;
942 char mode[15];
943 gzFile fd;
944
Aleksey Sanin49cc9752002-06-14 17:07:10 +0000945 snprintf(mode, sizeof(mode), "wb%d", compression);
Owen Taylor3473f882001-02-23 17:55:21 +0000946 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000947 fd = gzdopen(dup(1), mode);
Owen Taylor3473f882001-02-23 17:55:21 +0000948 return((void *) fd);
949 }
950
Daniel Veillardf4862f02002-09-10 11:13:43 +0000951 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000952#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000953 path = &filename[17];
954#else
Owen Taylor3473f882001-02-23 17:55:21 +0000955 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000956#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000957 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000958#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000959 path = &filename[8];
960#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000961 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000962#endif
963 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000964 path = filename;
965
966 if (path == NULL)
967 return(NULL);
968
969 fd = gzopen(path, mode);
970 return((void *) fd);
971}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000972#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000973
974/**
975 * xmlGzfileRead:
976 * @context: the I/O context
977 * @buffer: where to drop data
978 * @len: number of bytes to write
979 *
980 * Read @len bytes to @buffer from the compressed I/O channel.
981 *
982 * Returns the number of bytes written
983 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000984static int
Owen Taylor3473f882001-02-23 17:55:21 +0000985xmlGzfileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000986 int ret;
987
988 ret = gzread((gzFile) context, &buffer[0], len);
989 if (ret < 0) xmlIOErr(0, "gzread()");
990 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000991}
992
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000993#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000994/**
995 * xmlGzfileWrite:
996 * @context: the I/O context
997 * @buffer: where to drop data
998 * @len: number of bytes to write
999 *
1000 * Write @len bytes from @buffer to the compressed I/O channel.
1001 *
1002 * Returns the number of bytes written
1003 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001004static int
Owen Taylor3473f882001-02-23 17:55:21 +00001005xmlGzfileWrite (void * context, const char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001006 int ret;
1007
1008 ret = gzwrite((gzFile) context, (char *) &buffer[0], len);
1009 if (ret < 0) xmlIOErr(0, "gzwrite()");
1010 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001011}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001012#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001013
1014/**
1015 * xmlGzfileClose:
1016 * @context: the I/O context
1017 *
1018 * Close a compressed I/O channel
1019 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001020static int
Owen Taylor3473f882001-02-23 17:55:21 +00001021xmlGzfileClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001022 int ret;
1023
1024 ret = (gzclose((gzFile) context) == Z_OK ) ? 0 : -1;
1025 if (ret < 0) xmlIOErr(0, "gzclose()");
1026 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001027}
1028#endif /* HAVE_ZLIB_H */
1029
1030#ifdef LIBXML_HTTP_ENABLED
1031/************************************************************************
1032 * *
1033 * I/O for HTTP file accesses *
1034 * *
1035 ************************************************************************/
Daniel Veillardf012a642001-07-23 19:10:52 +00001036
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001037#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001038typedef struct xmlIOHTTPWriteCtxt_
1039{
1040 int compression;
1041
1042 char * uri;
1043
1044 void * doc_buff;
1045
1046} xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr;
1047
1048#ifdef HAVE_ZLIB_H
1049
1050#define DFLT_WBITS ( -15 )
1051#define DFLT_MEM_LVL ( 8 )
1052#define GZ_MAGIC1 ( 0x1f )
1053#define GZ_MAGIC2 ( 0x8b )
1054#define LXML_ZLIB_OS_CODE ( 0x03 )
1055#define INIT_HTTP_BUFF_SIZE ( 32768 )
1056#define DFLT_ZLIB_RATIO ( 5 )
1057
1058/*
1059** Data structure and functions to work with sending compressed data
1060** via HTTP.
1061*/
1062
1063typedef struct xmlZMemBuff_
1064{
1065 unsigned long size;
1066 unsigned long crc;
1067
1068 unsigned char * zbuff;
1069 z_stream zctrl;
1070
1071} xmlZMemBuff, *xmlZMemBuffPtr;
1072
1073/**
1074 * append_reverse_ulong
1075 * @buff: Compressed memory buffer
1076 * @data: Unsigned long to append
1077 *
1078 * Append a unsigned long in reverse byte order to the end of the
1079 * memory buffer.
1080 */
1081static void
1082append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) {
1083
1084 int idx;
1085
1086 if ( buff == NULL )
1087 return;
1088
1089 /*
1090 ** This is plagiarized from putLong in gzio.c (zlib source) where
1091 ** the number "4" is hardcoded. If zlib is ever patched to
1092 ** support 64 bit file sizes, this code would need to be patched
1093 ** as well.
1094 */
1095
1096 for ( idx = 0; idx < 4; idx++ ) {
1097 *buff->zctrl.next_out = ( data & 0xff );
1098 data >>= 8;
1099 buff->zctrl.next_out++;
1100 }
1101
1102 return;
1103}
1104
1105/**
1106 *
1107 * xmlFreeZMemBuff
1108 * @buff: The memory buffer context to clear
1109 *
1110 * Release all the resources associated with the compressed memory buffer.
1111 */
1112static void
1113xmlFreeZMemBuff( xmlZMemBuffPtr buff ) {
William M. Brack78637da2003-07-31 14:47:38 +00001114
1115#ifdef DEBUG_HTTP
Daniel Veillardf012a642001-07-23 19:10:52 +00001116 int z_err;
William M. Brack78637da2003-07-31 14:47:38 +00001117#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001118
1119 if ( buff == NULL )
1120 return;
1121
1122 xmlFree( buff->zbuff );
Daniel Veillardf012a642001-07-23 19:10:52 +00001123#ifdef DEBUG_HTTP
William M. Brack78637da2003-07-31 14:47:38 +00001124 z_err = deflateEnd( &buff->zctrl );
Daniel Veillardf012a642001-07-23 19:10:52 +00001125 if ( z_err != Z_OK )
1126 xmlGenericError( xmlGenericErrorContext,
1127 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
1128 z_err );
William M. Brack78637da2003-07-31 14:47:38 +00001129#else
1130 deflateEnd( &buff->zctrl );
William M. Brack779af002003-08-01 15:55:39 +00001131#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001132
1133 xmlFree( buff );
1134 return;
1135}
1136
1137/**
1138 * xmlCreateZMemBuff
1139 *@compression: Compression value to use
1140 *
1141 * Create a memory buffer to hold the compressed XML document. The
1142 * compressed document in memory will end up being identical to what
1143 * would be created if gzopen/gzwrite/gzclose were being used to
1144 * write the document to disk. The code for the header/trailer data to
1145 * the compression is plagiarized from the zlib source files.
1146 */
1147static void *
1148xmlCreateZMemBuff( int compression ) {
1149
1150 int z_err;
1151 int hdr_lgth;
1152 xmlZMemBuffPtr buff = NULL;
1153
1154 if ( ( compression < 1 ) || ( compression > 9 ) )
1155 return ( NULL );
1156
1157 /* Create the control and data areas */
1158
1159 buff = xmlMalloc( sizeof( xmlZMemBuff ) );
1160 if ( buff == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001161 xmlIOErrMemory("creating buffer context");
Daniel Veillardf012a642001-07-23 19:10:52 +00001162 return ( NULL );
1163 }
1164
1165 (void)memset( buff, 0, sizeof( xmlZMemBuff ) );
1166 buff->size = INIT_HTTP_BUFF_SIZE;
1167 buff->zbuff = xmlMalloc( buff->size );
1168 if ( buff->zbuff == NULL ) {
1169 xmlFreeZMemBuff( buff );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001170 xmlIOErrMemory("creating buffer");
Daniel Veillardf012a642001-07-23 19:10:52 +00001171 return ( NULL );
1172 }
1173
1174 z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
1175 DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
1176 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001177 xmlChar msg[500];
Daniel Veillardf012a642001-07-23 19:10:52 +00001178 xmlFreeZMemBuff( buff );
1179 buff = NULL;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001180 xmlStrPrintf(msg, 500,
1181 (const xmlChar *) "xmlCreateZMemBuff: %s %d\n",
1182 "Error initializing compression context. ZLIB error:",
1183 z_err );
1184 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001185 return ( NULL );
1186 }
1187
1188 /* Set the header data. The CRC will be needed for the trailer */
Daniel Veillardf012a642001-07-23 19:10:52 +00001189 buff->crc = crc32( 0L, Z_NULL, 0 );
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001190 hdr_lgth = snprintf( (char *)buff->zbuff, buff->size,
1191 "%c%c%c%c%c%c%c%c%c%c",
Daniel Veillardf012a642001-07-23 19:10:52 +00001192 GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED,
1193 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE );
1194 buff->zctrl.next_out = buff->zbuff + hdr_lgth;
1195 buff->zctrl.avail_out = buff->size - hdr_lgth;
1196
1197 return ( buff );
1198}
1199
1200/**
1201 * xmlZMemBuffExtend
1202 * @buff: Buffer used to compress and consolidate data.
1203 * @ext_amt: Number of bytes to extend the buffer.
1204 *
1205 * Extend the internal buffer used to store the compressed data by the
1206 * specified amount.
1207 *
1208 * Returns 0 on success or -1 on failure to extend the buffer. On failure
1209 * the original buffer still exists at the original size.
1210 */
1211static int
1212xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) {
1213
1214 int rc = -1;
1215 size_t new_size;
1216 size_t cur_used;
1217
1218 unsigned char * tmp_ptr = NULL;
1219
1220 if ( buff == NULL )
1221 return ( -1 );
1222
1223 else if ( ext_amt == 0 )
1224 return ( 0 );
1225
1226 cur_used = buff->zctrl.next_out - buff->zbuff;
1227 new_size = buff->size + ext_amt;
1228
1229#ifdef DEBUG_HTTP
1230 if ( cur_used > new_size )
1231 xmlGenericError( xmlGenericErrorContext,
1232 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
1233 "Buffer overwrite detected during compressed memory",
1234 "buffer extension. Overflowed by",
1235 (cur_used - new_size ) );
1236#endif
1237
1238 tmp_ptr = xmlRealloc( buff->zbuff, new_size );
1239 if ( tmp_ptr != NULL ) {
1240 rc = 0;
1241 buff->size = new_size;
1242 buff->zbuff = tmp_ptr;
1243 buff->zctrl.next_out = tmp_ptr + cur_used;
1244 buff->zctrl.avail_out = new_size - cur_used;
1245 }
1246 else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001247 xmlChar msg[500];
1248 xmlStrPrintf(msg, 500,
1249 (const xmlChar *) "xmlZMemBuffExtend: %s %lu bytes.\n",
1250 "Allocation failure extending output buffer to",
1251 new_size );
1252 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001253 }
1254
1255 return ( rc );
1256}
1257
1258/**
1259 * xmlZMemBuffAppend
1260 * @buff: Buffer used to compress and consolidate data
1261 * @src: Uncompressed source content to append to buffer
1262 * @len: Length of source data to append to buffer
1263 *
1264 * Compress and append data to the internal buffer. The data buffer
1265 * will be expanded if needed to store the additional data.
1266 *
1267 * Returns the number of bytes appended to the buffer or -1 on error.
1268 */
1269static int
1270xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) {
1271
1272 int z_err;
1273 size_t min_accept;
1274
1275 if ( ( buff == NULL ) || ( src == NULL ) )
1276 return ( -1 );
1277
1278 buff->zctrl.avail_in = len;
1279 buff->zctrl.next_in = (unsigned char *)src;
1280 while ( buff->zctrl.avail_in > 0 ) {
1281 /*
1282 ** Extend the buffer prior to deflate call if a reasonable amount
1283 ** of output buffer space is not available.
1284 */
1285 min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO;
1286 if ( buff->zctrl.avail_out <= min_accept ) {
1287 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1288 return ( -1 );
1289 }
1290
1291 z_err = deflate( &buff->zctrl, Z_NO_FLUSH );
1292 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001293 xmlChar msg[500];
1294 xmlStrPrintf(msg, 500,
1295 (const xmlChar *) "xmlZMemBuffAppend: %s %d %s - %d",
Daniel Veillardf012a642001-07-23 19:10:52 +00001296 "Compression error while appending",
1297 len, "bytes to buffer. ZLIB error", z_err );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001298 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001299 return ( -1 );
1300 }
1301 }
1302
1303 buff->crc = crc32( buff->crc, (unsigned char *)src, len );
1304
1305 return ( len );
1306}
1307
1308/**
1309 * xmlZMemBuffGetContent
1310 * @buff: Compressed memory content buffer
1311 * @data_ref: Pointer reference to point to compressed content
1312 *
1313 * Flushes the compression buffers, appends gzip file trailers and
1314 * returns the compressed content and length of the compressed data.
1315 * NOTE: The gzip trailer code here is plagiarized from zlib source.
1316 *
1317 * Returns the length of the compressed data or -1 on error.
1318 */
1319static int
1320xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) {
1321
1322 int zlgth = -1;
1323 int z_err;
1324
1325 if ( ( buff == NULL ) || ( data_ref == NULL ) )
1326 return ( -1 );
1327
1328 /* Need to loop until compression output buffers are flushed */
1329
1330 do
1331 {
1332 z_err = deflate( &buff->zctrl, Z_FINISH );
1333 if ( z_err == Z_OK ) {
1334 /* In this case Z_OK means more buffer space needed */
1335
1336 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1337 return ( -1 );
1338 }
1339 }
1340 while ( z_err == Z_OK );
1341
1342 /* If the compression state is not Z_STREAM_END, some error occurred */
1343
1344 if ( z_err == Z_STREAM_END ) {
1345
1346 /* Need to append the gzip data trailer */
1347
1348 if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) {
1349 if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 )
1350 return ( -1 );
1351 }
1352
1353 /*
1354 ** For whatever reason, the CRC and length data are pushed out
1355 ** in reverse byte order. So a memcpy can't be used here.
1356 */
1357
1358 append_reverse_ulong( buff, buff->crc );
1359 append_reverse_ulong( buff, buff->zctrl.total_in );
1360
1361 zlgth = buff->zctrl.next_out - buff->zbuff;
1362 *data_ref = (char *)buff->zbuff;
1363 }
1364
Daniel Veillard05d987b2003-10-08 11:54:57 +00001365 else {
1366 xmlChar msg[500];
1367 xmlStrPrintf(msg, 500,
1368 (const xmlChar *) "xmlZMemBuffGetContent: %s - %d\n",
1369 "Error flushing zlib buffers. Error code", z_err );
1370 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1371 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001372
1373 return ( zlgth );
1374}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001375#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001376#endif /* HAVE_ZLIB_H */
1377
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001378#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001379/**
1380 * xmlFreeHTTPWriteCtxt
1381 * @ctxt: Context to cleanup
1382 *
1383 * Free allocated memory and reclaim system resources.
1384 *
1385 * No return value.
1386 */
1387static void
1388xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt )
1389{
1390 if ( ctxt->uri != NULL )
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001391 xmlFree( ctxt->uri );
Daniel Veillardf012a642001-07-23 19:10:52 +00001392
1393 if ( ctxt->doc_buff != NULL ) {
1394
1395#ifdef HAVE_ZLIB_H
1396 if ( ctxt->compression > 0 ) {
1397 xmlFreeZMemBuff( ctxt->doc_buff );
1398 }
1399 else
1400#endif
1401 {
1402 xmlOutputBufferClose( ctxt->doc_buff );
1403 }
1404 }
1405
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001406 xmlFree( ctxt );
Daniel Veillardf012a642001-07-23 19:10:52 +00001407 return;
1408}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001409#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001410
1411
Owen Taylor3473f882001-02-23 17:55:21 +00001412/**
1413 * xmlIOHTTPMatch:
1414 * @filename: the URI for matching
1415 *
1416 * check if the URI matches an HTTP one
1417 *
1418 * Returns 1 if matches, 0 otherwise
1419 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001420int
Owen Taylor3473f882001-02-23 17:55:21 +00001421xmlIOHTTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001422 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "http://", 7))
Owen Taylor3473f882001-02-23 17:55:21 +00001423 return(1);
1424 return(0);
1425}
1426
1427/**
1428 * xmlIOHTTPOpen:
1429 * @filename: the URI for matching
1430 *
1431 * open an HTTP I/O channel
1432 *
1433 * Returns an I/O context or NULL in case of error
1434 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001435void *
Owen Taylor3473f882001-02-23 17:55:21 +00001436xmlIOHTTPOpen (const char *filename) {
1437 return(xmlNanoHTTPOpen(filename, NULL));
1438}
1439
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001440#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001441/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001442 * xmlIOHTTPOpenW:
Daniel Veillardf012a642001-07-23 19:10:52 +00001443 * @post_uri: The destination URI for the document
1444 * @compression: The compression desired for the document.
1445 *
1446 * Open a temporary buffer to collect the document for a subsequent HTTP POST
1447 * request. Non-static as is called from the output buffer creation routine.
1448 *
1449 * Returns an I/O context or NULL in case of error.
1450 */
1451
1452void *
Daniel Veillard572577e2002-01-18 16:23:55 +00001453xmlIOHTTPOpenW(const char *post_uri, int compression)
1454{
Daniel Veillardf012a642001-07-23 19:10:52 +00001455
Daniel Veillard572577e2002-01-18 16:23:55 +00001456 xmlIOHTTPWriteCtxtPtr ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001457
Daniel Veillard572577e2002-01-18 16:23:55 +00001458 if (post_uri == NULL)
1459 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001460
Daniel Veillard572577e2002-01-18 16:23:55 +00001461 ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt));
1462 if (ctxt == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001463 xmlIOErrMemory("creating HTTP output context");
Daniel Veillard572577e2002-01-18 16:23:55 +00001464 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001465 }
1466
Daniel Veillard572577e2002-01-18 16:23:55 +00001467 (void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt));
Daniel Veillardf012a642001-07-23 19:10:52 +00001468
Daniel Veillard572577e2002-01-18 16:23:55 +00001469 ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri);
1470 if (ctxt->uri == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001471 xmlIOErrMemory("copying URI");
Daniel Veillard572577e2002-01-18 16:23:55 +00001472 xmlFreeHTTPWriteCtxt(ctxt);
1473 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001474 }
1475
1476 /*
Daniel Veillard572577e2002-01-18 16:23:55 +00001477 * ** Since the document length is required for an HTTP post,
1478 * ** need to put the document into a buffer. A memory buffer
1479 * ** is being used to avoid pushing the data to disk and back.
1480 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001481
1482#ifdef HAVE_ZLIB_H
Daniel Veillard572577e2002-01-18 16:23:55 +00001483 if ((compression > 0) && (compression <= 9)) {
1484
1485 ctxt->compression = compression;
1486 ctxt->doc_buff = xmlCreateZMemBuff(compression);
1487 } else
Daniel Veillardf012a642001-07-23 19:10:52 +00001488#endif
1489 {
Daniel Veillard572577e2002-01-18 16:23:55 +00001490 /* Any character conversions should have been done before this */
Daniel Veillardf012a642001-07-23 19:10:52 +00001491
Daniel Veillard572577e2002-01-18 16:23:55 +00001492 ctxt->doc_buff = xmlAllocOutputBuffer(NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001493 }
1494
Daniel Veillard572577e2002-01-18 16:23:55 +00001495 if (ctxt->doc_buff == NULL) {
1496 xmlFreeHTTPWriteCtxt(ctxt);
1497 ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001498 }
1499
Daniel Veillard572577e2002-01-18 16:23:55 +00001500 return (ctxt);
Daniel Veillardf012a642001-07-23 19:10:52 +00001501}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001502#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001503
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001504#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001505/**
1506 * xmlIOHTTPDfltOpenW
1507 * @post_uri: The destination URI for this document.
1508 *
1509 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
1510 * HTTP post command. This function should generally not be used as
1511 * the open callback is short circuited in xmlOutputBufferCreateFile.
1512 *
1513 * Returns a pointer to the new IO context.
1514 */
1515static void *
1516xmlIOHTTPDfltOpenW( const char * post_uri ) {
1517 return ( xmlIOHTTPOpenW( post_uri, 0 ) );
1518}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001519#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001520
1521/**
Owen Taylor3473f882001-02-23 17:55:21 +00001522 * xmlIOHTTPRead:
1523 * @context: the I/O context
1524 * @buffer: where to drop data
1525 * @len: number of bytes to write
1526 *
1527 * Read @len bytes to @buffer from the I/O channel.
1528 *
1529 * Returns the number of bytes written
1530 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001531int
Owen Taylor3473f882001-02-23 17:55:21 +00001532xmlIOHTTPRead(void * context, char * buffer, int len) {
1533 return(xmlNanoHTTPRead(context, &buffer[0], len));
1534}
1535
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001536#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001537/**
Daniel Veillardf012a642001-07-23 19:10:52 +00001538 * xmlIOHTTPWrite
1539 * @context: previously opened writing context
1540 * @buffer: data to output to temporary buffer
1541 * @len: bytes to output
1542 *
1543 * Collect data from memory buffer into a temporary file for later
1544 * processing.
1545 *
1546 * Returns number of bytes written.
1547 */
1548
1549static int
1550xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
1551
1552 xmlIOHTTPWriteCtxtPtr ctxt = context;
1553
1554 if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
1555 return ( -1 );
1556
1557 if ( len > 0 ) {
1558
1559 /* Use gzwrite or fwrite as previously setup in the open call */
1560
1561#ifdef HAVE_ZLIB_H
1562 if ( ctxt->compression > 0 )
1563 len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len );
1564
1565 else
1566#endif
1567 len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
1568
1569 if ( len < 0 ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001570 xmlChar msg[500];
1571 xmlStrPrintf(msg, 500,
1572 (const xmlChar *) "xmlIOHTTPWrite: %s\n%s '%s'.\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001573 "Error appending to internal buffer.",
1574 "Error sending document to URI",
1575 ctxt->uri );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001576 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001577 }
1578 }
1579
1580 return ( len );
1581}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001582#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001583
1584
1585/**
Owen Taylor3473f882001-02-23 17:55:21 +00001586 * xmlIOHTTPClose:
1587 * @context: the I/O context
1588 *
1589 * Close an HTTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001590 *
1591 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00001592 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001593int
Owen Taylor3473f882001-02-23 17:55:21 +00001594xmlIOHTTPClose (void * context) {
1595 xmlNanoHTTPClose(context);
Daniel Veillardf012a642001-07-23 19:10:52 +00001596 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001597}
Daniel Veillardf012a642001-07-23 19:10:52 +00001598
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001599#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001600/**
1601 * xmlIOHTTCloseWrite
1602 * @context: The I/O context
1603 * @http_mthd: The HTTP method to be used when sending the data
1604 *
1605 * Close the transmit HTTP I/O channel and actually send the data.
1606 */
1607static int
1608xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
1609
1610 int close_rc = -1;
1611 int http_rtn = 0;
1612 int content_lgth = 0;
1613 xmlIOHTTPWriteCtxtPtr ctxt = context;
1614
1615 char * http_content = NULL;
1616 char * content_encoding = NULL;
1617 char * content_type = (char *) "text/xml";
1618 void * http_ctxt = NULL;
1619
1620 if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
1621 return ( -1 );
1622
1623 /* Retrieve the content from the appropriate buffer */
1624
1625#ifdef HAVE_ZLIB_H
1626
1627 if ( ctxt->compression > 0 ) {
1628 content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
1629 content_encoding = (char *) "Content-Encoding: gzip";
1630 }
1631 else
1632#endif
1633 {
1634 /* Pull the data out of the memory output buffer */
1635
1636 xmlOutputBufferPtr dctxt = ctxt->doc_buff;
1637 http_content = (char *)dctxt->buffer->content;
1638 content_lgth = dctxt->buffer->use;
1639 }
1640
1641 if ( http_content == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001642 xmlChar msg[500];
1643 xmlStrPrintf(msg, 500,
1644 (const xmlChar *) "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
1645 "Error retrieving content.\nUnable to",
1646 http_mthd, "data to URI", ctxt->uri );
1647 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001648 }
1649
1650 else {
1651
1652 http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
1653 &content_type, content_encoding,
1654 content_lgth );
1655
1656 if ( http_ctxt != NULL ) {
1657#ifdef DEBUG_HTTP
1658 /* If testing/debugging - dump reply with request content */
1659
1660 FILE * tst_file = NULL;
1661 char buffer[ 4096 ];
1662 char * dump_name = NULL;
1663 int avail;
1664
1665 xmlGenericError( xmlGenericErrorContext,
1666 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
1667 http_mthd, ctxt->uri,
1668 xmlNanoHTTPReturnCode( http_ctxt ) );
1669
1670 /*
1671 ** Since either content or reply may be gzipped,
1672 ** dump them to separate files instead of the
1673 ** standard error context.
1674 */
1675
1676 dump_name = tempnam( NULL, "lxml" );
1677 if ( dump_name != NULL ) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001678 (void)snprintf( buffer, sizeof(buffer), "%s.content", dump_name );
Daniel Veillardf012a642001-07-23 19:10:52 +00001679
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00001680 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00001681 if ( tst_file != NULL ) {
1682 xmlGenericError( xmlGenericErrorContext,
1683 "Transmitted content saved in file: %s\n", buffer );
1684
1685 fwrite( http_content, sizeof( char ),
1686 content_lgth, tst_file );
1687 fclose( tst_file );
1688 }
1689
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001690 (void)snprintf( buffer, sizeof(buffer), "%s.reply", dump_name );
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00001691 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00001692 if ( tst_file != NULL ) {
1693 xmlGenericError( xmlGenericErrorContext,
1694 "Reply content saved in file: %s\n", buffer );
1695
1696
1697 while ( (avail = xmlNanoHTTPRead( http_ctxt,
1698 buffer, sizeof( buffer ) )) > 0 ) {
1699
1700 fwrite( buffer, sizeof( char ), avail, tst_file );
1701 }
1702
1703 fclose( tst_file );
1704 }
1705
1706 free( dump_name );
1707 }
1708#endif /* DEBUG_HTTP */
1709
1710 http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
1711 if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
1712 close_rc = 0;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001713 else {
1714 xmlChar msg[500];
1715 xmlStrPrintf(msg, 500,
1716 (const xmlChar *) "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001717 http_mthd, content_lgth,
1718 "bytes to URI", ctxt->uri,
1719 "failed. HTTP return code:", http_rtn );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001720 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1721 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001722
1723 xmlNanoHTTPClose( http_ctxt );
1724 xmlFree( content_type );
1725 }
1726 }
1727
1728 /* Final cleanups */
1729
1730 xmlFreeHTTPWriteCtxt( ctxt );
1731
1732 return ( close_rc );
1733}
1734
1735/**
1736 * xmlIOHTTPClosePut
1737 *
1738 * @context: The I/O context
1739 *
1740 * Close the transmit HTTP I/O channel and actually send data using a PUT
1741 * HTTP method.
1742 */
1743static int
1744xmlIOHTTPClosePut( void * ctxt ) {
1745 return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
1746}
1747
1748
1749/**
1750 * xmlIOHTTPClosePost
1751 *
1752 * @context: The I/O context
1753 *
1754 * Close the transmit HTTP I/O channel and actually send data using a POST
1755 * HTTP method.
1756 */
1757static int
1758xmlIOHTTPClosePost( void * ctxt ) {
1759 return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
1760}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001761#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001762
Owen Taylor3473f882001-02-23 17:55:21 +00001763#endif /* LIBXML_HTTP_ENABLED */
1764
1765#ifdef LIBXML_FTP_ENABLED
1766/************************************************************************
1767 * *
1768 * I/O for FTP file accesses *
1769 * *
1770 ************************************************************************/
1771/**
1772 * xmlIOFTPMatch:
1773 * @filename: the URI for matching
1774 *
1775 * check if the URI matches an FTP one
1776 *
1777 * Returns 1 if matches, 0 otherwise
1778 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001779int
Owen Taylor3473f882001-02-23 17:55:21 +00001780xmlIOFTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001781 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "ftp://", 6))
Owen Taylor3473f882001-02-23 17:55:21 +00001782 return(1);
1783 return(0);
1784}
1785
1786/**
1787 * xmlIOFTPOpen:
1788 * @filename: the URI for matching
1789 *
1790 * open an FTP I/O channel
1791 *
1792 * Returns an I/O context or NULL in case of error
1793 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001794void *
Owen Taylor3473f882001-02-23 17:55:21 +00001795xmlIOFTPOpen (const char *filename) {
1796 return(xmlNanoFTPOpen(filename));
1797}
1798
1799/**
1800 * xmlIOFTPRead:
1801 * @context: the I/O context
1802 * @buffer: where to drop data
1803 * @len: number of bytes to write
1804 *
1805 * Read @len bytes to @buffer from the I/O channel.
1806 *
1807 * Returns the number of bytes written
1808 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001809int
Owen Taylor3473f882001-02-23 17:55:21 +00001810xmlIOFTPRead(void * context, char * buffer, int len) {
1811 return(xmlNanoFTPRead(context, &buffer[0], len));
1812}
1813
1814/**
1815 * xmlIOFTPClose:
1816 * @context: the I/O context
1817 *
1818 * Close an FTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001819 *
1820 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00001821 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001822int
Owen Taylor3473f882001-02-23 17:55:21 +00001823xmlIOFTPClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001824 return ( xmlNanoFTPClose(context) );
Owen Taylor3473f882001-02-23 17:55:21 +00001825}
1826#endif /* LIBXML_FTP_ENABLED */
1827
1828
1829/**
1830 * xmlRegisterInputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001831 * @matchFunc: the xmlInputMatchCallback
1832 * @openFunc: the xmlInputOpenCallback
1833 * @readFunc: the xmlInputReadCallback
1834 * @closeFunc: the xmlInputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001835 *
1836 * Register a new set of I/O callback for handling parser input.
1837 *
1838 * Returns the registered handler number or -1 in case of error
1839 */
1840int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001841xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
1842 xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
1843 xmlInputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001844 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
1845 return(-1);
1846 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001847 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
1848 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
1849 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
1850 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00001851 xmlInputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00001852 return(xmlInputCallbackNr++);
1853}
1854
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001855#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001856/**
1857 * xmlRegisterOutputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001858 * @matchFunc: the xmlOutputMatchCallback
1859 * @openFunc: the xmlOutputOpenCallback
1860 * @writeFunc: the xmlOutputWriteCallback
1861 * @closeFunc: the xmlOutputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001862 *
1863 * Register a new set of I/O callback for handling output.
1864 *
1865 * Returns the registered handler number or -1 in case of error
1866 */
1867int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001868xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
1869 xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
1870 xmlOutputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001871 if (xmlOutputCallbackNr >= MAX_INPUT_CALLBACK) {
1872 return(-1);
1873 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001874 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
1875 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
1876 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
1877 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00001878 xmlOutputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00001879 return(xmlOutputCallbackNr++);
1880}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001881#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001882
1883/**
1884 * xmlRegisterDefaultInputCallbacks:
1885 *
1886 * Registers the default compiled-in I/O handlers.
1887 */
1888void
Owen Taylor3473f882001-02-23 17:55:21 +00001889xmlRegisterDefaultInputCallbacks
Owen Taylor3473f882001-02-23 17:55:21 +00001890(void) {
1891 if (xmlInputCallbackInitialized)
1892 return;
1893
1894 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
1895 xmlFileRead, xmlFileClose);
1896#ifdef HAVE_ZLIB_H
1897 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1898 xmlGzfileRead, xmlGzfileClose);
1899#endif /* HAVE_ZLIB_H */
1900
1901#ifdef LIBXML_HTTP_ENABLED
1902 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
1903 xmlIOHTTPRead, xmlIOHTTPClose);
1904#endif /* LIBXML_HTTP_ENABLED */
1905
1906#ifdef LIBXML_FTP_ENABLED
1907 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1908 xmlIOFTPRead, xmlIOFTPClose);
1909#endif /* LIBXML_FTP_ENABLED */
1910 xmlInputCallbackInitialized = 1;
1911}
1912
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001913#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001914/**
1915 * xmlRegisterDefaultOutputCallbacks:
1916 *
1917 * Registers the default compiled-in I/O handlers.
1918 */
1919void
Owen Taylor3473f882001-02-23 17:55:21 +00001920xmlRegisterDefaultOutputCallbacks
Owen Taylor3473f882001-02-23 17:55:21 +00001921(void) {
1922 if (xmlOutputCallbackInitialized)
1923 return;
1924
1925 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
1926 xmlFileWrite, xmlFileClose);
Daniel Veillardf012a642001-07-23 19:10:52 +00001927
1928#ifdef LIBXML_HTTP_ENABLED
1929 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
1930 xmlIOHTTPWrite, xmlIOHTTPClosePut);
1931#endif
1932
Owen Taylor3473f882001-02-23 17:55:21 +00001933/*********************************
1934 No way a-priori to distinguish between gzipped files from
1935 uncompressed ones except opening if existing then closing
1936 and saving with same compression ratio ... a pain.
1937
1938#ifdef HAVE_ZLIB_H
1939 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1940 xmlGzfileWrite, xmlGzfileClose);
1941#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001942
1943 Nor FTP PUT ....
1944#ifdef LIBXML_FTP_ENABLED
1945 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1946 xmlIOFTPWrite, xmlIOFTPClose);
1947#endif
1948 **********************************/
1949 xmlOutputCallbackInitialized = 1;
1950}
1951
Daniel Veillardf012a642001-07-23 19:10:52 +00001952#ifdef LIBXML_HTTP_ENABLED
1953/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001954 * xmlRegisterHTTPPostCallbacks:
Daniel Veillardf012a642001-07-23 19:10:52 +00001955 *
1956 * By default, libxml submits HTTP output requests using the "PUT" method.
1957 * Calling this method changes the HTTP output method to use the "POST"
1958 * method instead.
1959 *
1960 */
1961void
1962xmlRegisterHTTPPostCallbacks( void ) {
1963
1964 /* Register defaults if not done previously */
1965
1966 if ( xmlOutputCallbackInitialized == 0 )
1967 xmlRegisterDefaultOutputCallbacks( );
1968
1969 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
1970 xmlIOHTTPWrite, xmlIOHTTPClosePost);
1971 return;
1972}
1973#endif
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001974#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001975
Owen Taylor3473f882001-02-23 17:55:21 +00001976/**
1977 * xmlAllocParserInputBuffer:
1978 * @enc: the charset encoding if known
1979 *
1980 * Create a buffered parser input for progressive parsing
1981 *
1982 * Returns the new parser input or NULL
1983 */
1984xmlParserInputBufferPtr
1985xmlAllocParserInputBuffer(xmlCharEncoding enc) {
1986 xmlParserInputBufferPtr ret;
1987
1988 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
1989 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001990 xmlIOErrMemory("creating input buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00001991 return(NULL);
1992 }
1993 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00001994 ret->buffer = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00001995 if (ret->buffer == NULL) {
1996 xmlFree(ret);
1997 return(NULL);
1998 }
1999 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
2000 ret->encoder = xmlGetCharEncodingHandler(enc);
2001 if (ret->encoder != NULL)
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002002 ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00002003 else
2004 ret->raw = NULL;
2005 ret->readcallback = NULL;
2006 ret->closecallback = NULL;
2007 ret->context = NULL;
William M. Brackc07329e2003-09-08 01:57:30 +00002008 ret->compressed = -1;
Daniel Veillard36711902004-02-11 13:25:26 +00002009 ret->rawconsumed = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002010
2011 return(ret);
2012}
2013
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002014#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002015/**
2016 * xmlAllocOutputBuffer:
2017 * @encoder: the encoding converter or NULL
2018 *
2019 * Create a buffered parser output
2020 *
2021 * Returns the new parser output or NULL
2022 */
2023xmlOutputBufferPtr
2024xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
2025 xmlOutputBufferPtr ret;
2026
2027 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
2028 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002029 xmlIOErrMemory("creating output buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00002030 return(NULL);
2031 }
2032 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
2033 ret->buffer = xmlBufferCreate();
2034 if (ret->buffer == NULL) {
2035 xmlFree(ret);
2036 return(NULL);
2037 }
2038 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
2039 ret->encoder = encoder;
2040 if (encoder != NULL) {
2041 ret->conv = xmlBufferCreateSize(4000);
2042 /*
2043 * This call is designed to initiate the encoder state
2044 */
2045 xmlCharEncOutFunc(encoder, ret->conv, NULL);
2046 } else
2047 ret->conv = NULL;
2048 ret->writecallback = NULL;
2049 ret->closecallback = NULL;
2050 ret->context = NULL;
2051 ret->written = 0;
2052
2053 return(ret);
2054}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002055#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002056
2057/**
2058 * xmlFreeParserInputBuffer:
2059 * @in: a buffered parser input
2060 *
2061 * Free up the memory used by a buffered parser input
2062 */
2063void
2064xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
Daniel Veillard8d8bf2c2003-09-17 19:36:25 +00002065 if (in == NULL) return;
2066
Owen Taylor3473f882001-02-23 17:55:21 +00002067 if (in->raw) {
2068 xmlBufferFree(in->raw);
2069 in->raw = NULL;
2070 }
2071 if (in->encoder != NULL) {
2072 xmlCharEncCloseFunc(in->encoder);
2073 }
2074 if (in->closecallback != NULL) {
2075 in->closecallback(in->context);
2076 }
2077 if (in->buffer != NULL) {
2078 xmlBufferFree(in->buffer);
2079 in->buffer = NULL;
2080 }
2081
Owen Taylor3473f882001-02-23 17:55:21 +00002082 xmlFree(in);
2083}
2084
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002085#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002086/**
2087 * xmlOutputBufferClose:
2088 * @out: a buffered output
2089 *
2090 * flushes and close the output I/O channel
2091 * and free up all the associated resources
2092 *
2093 * Returns the number of byte written or -1 in case of error.
2094 */
2095int
Daniel Veillard828ce832003-10-08 19:19:10 +00002096xmlOutputBufferClose(xmlOutputBufferPtr out)
2097{
Owen Taylor3473f882001-02-23 17:55:21 +00002098 int written;
Daniel Veillardf012a642001-07-23 19:10:52 +00002099 int err_rc = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002100
2101 if (out == NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002102 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002103 if (out->writecallback != NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002104 xmlOutputBufferFlush(out);
Owen Taylor3473f882001-02-23 17:55:21 +00002105 if (out->closecallback != NULL) {
Daniel Veillard828ce832003-10-08 19:19:10 +00002106 err_rc = out->closecallback(out->context);
Owen Taylor3473f882001-02-23 17:55:21 +00002107 }
2108 written = out->written;
2109 if (out->conv) {
2110 xmlBufferFree(out->conv);
Daniel Veillard828ce832003-10-08 19:19:10 +00002111 out->conv = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002112 }
2113 if (out->encoder != NULL) {
2114 xmlCharEncCloseFunc(out->encoder);
2115 }
2116 if (out->buffer != NULL) {
2117 xmlBufferFree(out->buffer);
Daniel Veillard828ce832003-10-08 19:19:10 +00002118 out->buffer = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002119 }
2120
Daniel Veillard828ce832003-10-08 19:19:10 +00002121 if (out->error)
2122 err_rc = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00002123 xmlFree(out);
Daniel Veillard828ce832003-10-08 19:19:10 +00002124 return ((err_rc == 0) ? written : err_rc);
Owen Taylor3473f882001-02-23 17:55:21 +00002125}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002126#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002127
Daniel Veillard1b243b42004-06-08 10:16:42 +00002128xmlParserInputBufferPtr
Daniel Veillard0335a842004-06-02 16:18:40 +00002129__xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002130 xmlParserInputBufferPtr ret;
Daniel Veillard388236f2001-07-08 18:35:48 +00002131 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002132 void *context = NULL;
2133
2134 if (xmlInputCallbackInitialized == 0)
2135 xmlRegisterDefaultInputCallbacks();
2136
2137 if (URI == NULL) return(NULL);
2138
2139 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002140 * Try to find one of the input accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002141 * Go in reverse to give precedence to user defined handlers.
Daniel Veillard388236f2001-07-08 18:35:48 +00002142 */
2143 if (context == NULL) {
2144 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
2145 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
2146 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002147 context = xmlInputCallbackTable[i].opencallback(URI);
Daniel Veillard847332a2003-10-18 11:29:40 +00002148 if (context != NULL) {
Daniel Veillard388236f2001-07-08 18:35:48 +00002149 break;
Daniel Veillard847332a2003-10-18 11:29:40 +00002150 }
Daniel Veillard388236f2001-07-08 18:35:48 +00002151 }
Owen Taylor3473f882001-02-23 17:55:21 +00002152 }
2153 }
2154 if (context == NULL) {
2155 return(NULL);
2156 }
2157
2158 /*
2159 * Allocate the Input buffer front-end.
2160 */
2161 ret = xmlAllocParserInputBuffer(enc);
2162 if (ret != NULL) {
2163 ret->context = context;
2164 ret->readcallback = xmlInputCallbackTable[i].readcallback;
2165 ret->closecallback = xmlInputCallbackTable[i].closecallback;
William M. Brackc07329e2003-09-08 01:57:30 +00002166#ifdef HAVE_ZLIB_H
William M. Brackc5cbf992003-10-29 22:15:13 +00002167 if ((xmlInputCallbackTable[i].opencallback == xmlGzfileOpen) &&
2168 (strcmp(URI, "-") != 0)) {
William M. Brackc07329e2003-09-08 01:57:30 +00002169 if (((z_stream *)context)->avail_in > 4) {
2170 char *cptr, buff4[4];
Daniel Veillard07cb8222003-09-10 10:51:05 +00002171 cptr = (char *) ((z_stream *)context)->next_in;
William M. Brackc07329e2003-09-08 01:57:30 +00002172 if (gzread(context, buff4, 4) == 4) {
2173 if (strncmp(buff4, cptr, 4) == 0)
2174 ret->compressed = 0;
2175 else
2176 ret->compressed = 1;
2177 gzrewind(context);
2178 }
2179 }
2180 }
2181#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002182 }
William M. Brack42331a92004-07-29 07:07:16 +00002183 else
2184 xmlInputCallbackTable[i].closecallback (context);
2185
Owen Taylor3473f882001-02-23 17:55:21 +00002186 return(ret);
2187}
2188
2189/**
Daniel Veillard0335a842004-06-02 16:18:40 +00002190 * xmlParserInputBufferCreateFilename:
Owen Taylor3473f882001-02-23 17:55:21 +00002191 * @URI: a C string containing the URI or filename
Daniel Veillard0335a842004-06-02 16:18:40 +00002192 * @enc: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002193 *
Daniel Veillard0335a842004-06-02 16:18:40 +00002194 * Create a buffered parser input for the progressive parsing of a file
2195 * If filename is "-' then we use stdin as the input.
Owen Taylor3473f882001-02-23 17:55:21 +00002196 * Automatic support for ZLIB/Compress compressed document is provided
2197 * by default if found at compile-time.
Daniel Veillard0335a842004-06-02 16:18:40 +00002198 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
Owen Taylor3473f882001-02-23 17:55:21 +00002199 *
Daniel Veillard0335a842004-06-02 16:18:40 +00002200 * Returns the new parser input or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00002201 */
Daniel Veillard0335a842004-06-02 16:18:40 +00002202xmlParserInputBufferPtr
2203xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
2204 if ((xmlParserInputBufferCreateFilenameValue)) {
2205 return xmlParserInputBufferCreateFilenameValue(URI, enc);
2206 }
2207 return __xmlParserInputBufferCreateFilename(URI, enc);
2208}
2209
2210#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard1b243b42004-06-08 10:16:42 +00002211xmlOutputBufferPtr
Daniel Veillard0335a842004-06-02 16:18:40 +00002212__xmlOutputBufferCreateFilename(const char *URI,
Owen Taylor3473f882001-02-23 17:55:21 +00002213 xmlCharEncodingHandlerPtr encoder,
Daniel Veillard0335a842004-06-02 16:18:40 +00002214 int compression ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00002215 xmlOutputBufferPtr ret;
Daniel Veillard966a31e2004-05-09 02:58:44 +00002216 xmlURIPtr puri;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002217 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002218 void *context = NULL;
Daniel Veillard966a31e2004-05-09 02:58:44 +00002219 char *unescaped = NULL;
2220 int is_file_uri = 1;
Daniel Veillardf012a642001-07-23 19:10:52 +00002221
Owen Taylor3473f882001-02-23 17:55:21 +00002222 if (xmlOutputCallbackInitialized == 0)
2223 xmlRegisterDefaultOutputCallbacks();
2224
2225 if (URI == NULL) return(NULL);
2226
Daniel Veillard966a31e2004-05-09 02:58:44 +00002227 puri = xmlParseURI(URI);
2228 if (puri != NULL) {
Daniel Veillard18a65092004-05-11 15:57:42 +00002229 if ((puri->scheme != NULL) &&
2230 (!xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
Daniel Veillard966a31e2004-05-09 02:58:44 +00002231 is_file_uri = 0;
2232 /*
2233 * try to limit the damages of the URI unescaping code.
2234 */
2235 if (puri->scheme != NULL)
2236 unescaped = xmlURIUnescapeString(URI, 0, NULL);
2237 xmlFreeURI(puri);
2238 }
Owen Taylor3473f882001-02-23 17:55:21 +00002239
2240 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002241 * Try to find one of the output accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002242 * Go in reverse to give precedence to user defined handlers.
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002243 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00002244 */
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002245 if (unescaped != NULL) {
2246#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002247 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002248 context = xmlGzfileOpenW(unescaped, compression);
2249 if (context != NULL) {
2250 ret = xmlAllocOutputBuffer(encoder);
2251 if (ret != NULL) {
2252 ret->context = context;
2253 ret->writecallback = xmlGzfileWrite;
2254 ret->closecallback = xmlGzfileClose;
2255 }
2256 xmlFree(unescaped);
2257 return(ret);
2258 }
2259 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002260#endif
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002261 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2262 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
2263 (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
2264#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2265 /* Need to pass compression parameter into HTTP open calls */
2266 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2267 context = xmlIOHTTPOpenW(unescaped, compression);
2268 else
2269#endif
2270 context = xmlOutputCallbackTable[i].opencallback(unescaped);
2271 if (context != NULL)
2272 break;
2273 }
2274 }
2275 xmlFree(unescaped);
2276 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002277
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002278 /*
2279 * If this failed try with a non-escaped URI this may be a strange
2280 * filename
2281 */
2282 if (context == NULL) {
2283#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002284 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002285 context = xmlGzfileOpenW(URI, compression);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002286 if (context != NULL) {
2287 ret = xmlAllocOutputBuffer(encoder);
2288 if (ret != NULL) {
2289 ret->context = context;
2290 ret->writecallback = xmlGzfileWrite;
2291 ret->closecallback = xmlGzfileClose;
2292 }
2293 return(ret);
2294 }
2295 }
2296#endif
2297 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2298 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002299 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002300#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2301 /* Need to pass compression parameter into HTTP open calls */
2302 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2303 context = xmlIOHTTPOpenW(URI, compression);
2304 else
2305#endif
2306 context = xmlOutputCallbackTable[i].opencallback(URI);
2307 if (context != NULL)
2308 break;
2309 }
Owen Taylor3473f882001-02-23 17:55:21 +00002310 }
2311 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002312
Owen Taylor3473f882001-02-23 17:55:21 +00002313 if (context == NULL) {
2314 return(NULL);
2315 }
2316
2317 /*
2318 * Allocate the Output buffer front-end.
2319 */
2320 ret = xmlAllocOutputBuffer(encoder);
2321 if (ret != NULL) {
2322 ret->context = context;
2323 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
2324 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
2325 }
2326 return(ret);
2327}
Daniel Veillard0335a842004-06-02 16:18:40 +00002328
2329/**
2330 * xmlOutputBufferCreateFilename:
2331 * @URI: a C string containing the URI or filename
2332 * @encoder: the encoding converter or NULL
2333 * @compression: the compression ration (0 none, 9 max).
2334 *
2335 * Create a buffered output for the progressive saving of a file
2336 * If filename is "-' then we use stdout as the output.
2337 * Automatic support for ZLIB/Compress compressed document is provided
2338 * by default if found at compile-time.
2339 * TODO: currently if compression is set, the library only support
2340 * writing to a local file.
2341 *
2342 * Returns the new output or NULL
2343 */
2344xmlOutputBufferPtr
2345xmlOutputBufferCreateFilename(const char *URI,
2346 xmlCharEncodingHandlerPtr encoder,
2347 int compression ATTRIBUTE_UNUSED) {
2348 if ((xmlOutputBufferCreateFilenameValue)) {
2349 return xmlOutputBufferCreateFilenameValue(URI, encoder, compression);
2350 }
2351 return __xmlOutputBufferCreateFilename(URI, encoder, compression);
2352}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002353#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002354
2355/**
2356 * xmlParserInputBufferCreateFile:
2357 * @file: a FILE*
2358 * @enc: the charset encoding if known
2359 *
2360 * Create a buffered parser input for the progressive parsing of a FILE *
2361 * buffered C I/O
2362 *
2363 * Returns the new parser input or NULL
2364 */
2365xmlParserInputBufferPtr
2366xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
2367 xmlParserInputBufferPtr ret;
2368
2369 if (xmlInputCallbackInitialized == 0)
2370 xmlRegisterDefaultInputCallbacks();
2371
2372 if (file == NULL) return(NULL);
2373
2374 ret = xmlAllocParserInputBuffer(enc);
2375 if (ret != NULL) {
2376 ret->context = file;
2377 ret->readcallback = xmlFileRead;
2378 ret->closecallback = xmlFileFlush;
2379 }
2380
2381 return(ret);
2382}
2383
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002384#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002385/**
2386 * xmlOutputBufferCreateFile:
2387 * @file: a FILE*
2388 * @encoder: the encoding converter or NULL
2389 *
2390 * Create a buffered output for the progressive saving to a FILE *
2391 * buffered C I/O
2392 *
2393 * Returns the new parser output or NULL
2394 */
2395xmlOutputBufferPtr
2396xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
2397 xmlOutputBufferPtr ret;
2398
2399 if (xmlOutputCallbackInitialized == 0)
2400 xmlRegisterDefaultOutputCallbacks();
2401
2402 if (file == NULL) return(NULL);
2403
2404 ret = xmlAllocOutputBuffer(encoder);
2405 if (ret != NULL) {
2406 ret->context = file;
2407 ret->writecallback = xmlFileWrite;
2408 ret->closecallback = xmlFileFlush;
2409 }
2410
2411 return(ret);
2412}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002413#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002414
2415/**
2416 * xmlParserInputBufferCreateFd:
2417 * @fd: a file descriptor number
2418 * @enc: the charset encoding if known
2419 *
2420 * Create a buffered parser input for the progressive parsing for the input
2421 * from a file descriptor
2422 *
2423 * Returns the new parser input or NULL
2424 */
2425xmlParserInputBufferPtr
2426xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
2427 xmlParserInputBufferPtr ret;
2428
2429 if (fd < 0) return(NULL);
2430
2431 ret = xmlAllocParserInputBuffer(enc);
2432 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002433 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002434 ret->readcallback = xmlFdRead;
2435 ret->closecallback = xmlFdClose;
2436 }
2437
2438 return(ret);
2439}
2440
2441/**
2442 * xmlParserInputBufferCreateMem:
2443 * @mem: the memory input
2444 * @size: the length of the memory block
2445 * @enc: the charset encoding if known
2446 *
2447 * Create a buffered parser input for the progressive parsing for the input
2448 * from a memory area.
2449 *
2450 * Returns the new parser input or NULL
2451 */
2452xmlParserInputBufferPtr
2453xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
2454 xmlParserInputBufferPtr ret;
William M. Bracka3215c72004-07-31 16:24:01 +00002455 int errcode;
Owen Taylor3473f882001-02-23 17:55:21 +00002456
2457 if (size <= 0) return(NULL);
2458 if (mem == NULL) return(NULL);
2459
2460 ret = xmlAllocParserInputBuffer(enc);
2461 if (ret != NULL) {
2462 ret->context = (void *) mem;
2463 ret->readcallback = (xmlInputReadCallback) xmlNop;
2464 ret->closecallback = NULL;
William M. Bracka3215c72004-07-31 16:24:01 +00002465 errcode = xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size);
2466 if (errcode != 0) {
2467 xmlFree(ret);
2468 return(NULL);
2469 }
Owen Taylor3473f882001-02-23 17:55:21 +00002470 }
2471
2472 return(ret);
2473}
2474
2475/**
Daniel Veillard53350552003-09-18 13:35:51 +00002476 * xmlParserInputBufferCreateStatic:
2477 * @mem: the memory input
2478 * @size: the length of the memory block
2479 * @enc: the charset encoding if known
2480 *
2481 * Create a buffered parser input for the progressive parsing for the input
2482 * from an immutable memory area. This will not copy the memory area to
2483 * the buffer, but the memory is expected to be available until the end of
2484 * the parsing, this is useful for example when using mmap'ed file.
2485 *
2486 * Returns the new parser input or NULL
2487 */
2488xmlParserInputBufferPtr
2489xmlParserInputBufferCreateStatic(const char *mem, int size,
2490 xmlCharEncoding enc) {
2491 xmlParserInputBufferPtr ret;
2492
2493 if (size <= 0) return(NULL);
2494 if (mem == NULL) return(NULL);
2495
2496 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2497 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002498 xmlIOErrMemory("creating input buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00002499 return(NULL);
2500 }
2501 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillarde72c5082003-09-19 12:44:05 +00002502 ret->buffer = xmlBufferCreateStatic((void *)mem, (size_t) size);
Daniel Veillard53350552003-09-18 13:35:51 +00002503 if (ret->buffer == NULL) {
2504 xmlFree(ret);
2505 return(NULL);
2506 }
2507 ret->encoder = xmlGetCharEncodingHandler(enc);
2508 if (ret->encoder != NULL)
2509 ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
2510 else
2511 ret->raw = NULL;
2512 ret->compressed = -1;
2513 ret->context = (void *) mem;
2514 ret->readcallback = NULL;
2515 ret->closecallback = NULL;
2516
2517 return(ret);
2518}
2519
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002520#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard53350552003-09-18 13:35:51 +00002521/**
Owen Taylor3473f882001-02-23 17:55:21 +00002522 * xmlOutputBufferCreateFd:
2523 * @fd: a file descriptor number
2524 * @encoder: the encoding converter or NULL
2525 *
2526 * Create a buffered output for the progressive saving
2527 * to a file descriptor
2528 *
2529 * Returns the new parser output or NULL
2530 */
2531xmlOutputBufferPtr
2532xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
2533 xmlOutputBufferPtr ret;
2534
2535 if (fd < 0) return(NULL);
2536
2537 ret = xmlAllocOutputBuffer(encoder);
2538 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002539 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002540 ret->writecallback = xmlFdWrite;
Daniel Veillard7db38712002-02-07 16:39:11 +00002541 ret->closecallback = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002542 }
2543
2544 return(ret);
2545}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002546#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002547
2548/**
2549 * xmlParserInputBufferCreateIO:
2550 * @ioread: an I/O read function
2551 * @ioclose: an I/O close function
2552 * @ioctx: an I/O handler
2553 * @enc: the charset encoding if known
2554 *
2555 * Create a buffered parser input for the progressive parsing for the input
2556 * from an I/O handler
2557 *
2558 * Returns the new parser input or NULL
2559 */
2560xmlParserInputBufferPtr
2561xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
2562 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
2563 xmlParserInputBufferPtr ret;
2564
2565 if (ioread == NULL) return(NULL);
2566
2567 ret = xmlAllocParserInputBuffer(enc);
2568 if (ret != NULL) {
2569 ret->context = (void *) ioctx;
2570 ret->readcallback = ioread;
2571 ret->closecallback = ioclose;
2572 }
2573
2574 return(ret);
2575}
2576
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002577#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002578/**
2579 * xmlOutputBufferCreateIO:
2580 * @iowrite: an I/O write function
2581 * @ioclose: an I/O close function
2582 * @ioctx: an I/O handler
Daniel Veillard9d06d302002-01-22 18:15:52 +00002583 * @encoder: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002584 *
2585 * Create a buffered output for the progressive saving
2586 * to an I/O handler
2587 *
2588 * Returns the new parser output or NULL
2589 */
2590xmlOutputBufferPtr
2591xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
2592 xmlOutputCloseCallback ioclose, void *ioctx,
2593 xmlCharEncodingHandlerPtr encoder) {
2594 xmlOutputBufferPtr ret;
2595
2596 if (iowrite == NULL) return(NULL);
2597
2598 ret = xmlAllocOutputBuffer(encoder);
2599 if (ret != NULL) {
2600 ret->context = (void *) ioctx;
2601 ret->writecallback = iowrite;
2602 ret->closecallback = ioclose;
2603 }
2604
2605 return(ret);
2606}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002607#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002608
2609/**
Daniel Veillard1b243b42004-06-08 10:16:42 +00002610 * xmlParserInputBufferCreateFilenameDefault:
2611 * @func: function pointer to the new ParserInputBufferCreateFilenameFunc
2612 *
2613 * Registers a callback for URI input file handling
2614 *
2615 * Returns the old value of the registration function
2616 */
2617xmlParserInputBufferCreateFilenameFunc
2618xmlParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func)
2619{
2620 xmlParserInputBufferCreateFilenameFunc old = xmlParserInputBufferCreateFilenameValue;
2621 if (old == NULL) {
2622 old = __xmlParserInputBufferCreateFilename;
2623 }
2624
2625 xmlParserInputBufferCreateFilenameValue = func;
2626 return(old);
2627}
2628
2629/**
2630 * xmlOutputBufferCreateFilenameDefault:
2631 * @func: function pointer to the new OutputBufferCreateFilenameFunc
2632 *
2633 * Registers a callback for URI output file handling
2634 *
2635 * Returns the old value of the registration function
2636 */
2637xmlOutputBufferCreateFilenameFunc
2638xmlOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func)
2639{
2640 xmlOutputBufferCreateFilenameFunc old = xmlOutputBufferCreateFilenameValue;
2641#ifdef LIBXML_OUTPUT_ENABLED
2642 if (old == NULL) {
2643 old = __xmlOutputBufferCreateFilename;
2644 }
2645#endif
2646 xmlOutputBufferCreateFilenameValue = func;
2647 return(old);
2648}
2649
2650/**
Owen Taylor3473f882001-02-23 17:55:21 +00002651 * xmlParserInputBufferPush:
2652 * @in: a buffered parser input
2653 * @len: the size in bytes of the array.
2654 * @buf: an char array
2655 *
2656 * Push the content of the arry in the input buffer
2657 * This routine handle the I18N transcoding to internal UTF-8
2658 * This is used when operating the parser in progressive (push) mode.
2659 *
2660 * Returns the number of chars read and stored in the buffer, or -1
2661 * in case of error.
2662 */
2663int
2664xmlParserInputBufferPush(xmlParserInputBufferPtr in,
2665 int len, const char *buf) {
2666 int nbchars = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00002667 int ret;
Owen Taylor3473f882001-02-23 17:55:21 +00002668
2669 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002670 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002671 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00002672 unsigned int use;
2673
Owen Taylor3473f882001-02-23 17:55:21 +00002674 /*
2675 * Store the data in the incoming raw buffer
2676 */
2677 if (in->raw == NULL) {
2678 in->raw = xmlBufferCreate();
2679 }
William M. Bracka3215c72004-07-31 16:24:01 +00002680 ret = xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
2681 if (ret != 0)
2682 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002683
2684 /*
2685 * convert as much as possible to the parser reading buffer.
2686 */
Daniel Veillard36711902004-02-11 13:25:26 +00002687 use = in->raw->use;
Owen Taylor3473f882001-02-23 17:55:21 +00002688 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2689 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002690 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002691 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002692 return(-1);
2693 }
Daniel Veillard36711902004-02-11 13:25:26 +00002694 in->rawconsumed += (use - in->raw->use);
Owen Taylor3473f882001-02-23 17:55:21 +00002695 } else {
2696 nbchars = len;
William M. Bracka3215c72004-07-31 16:24:01 +00002697 ret = xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
2698 if (ret != 0)
2699 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002700 }
2701#ifdef DEBUG_INPUT
2702 xmlGenericError(xmlGenericErrorContext,
2703 "I/O: pushed %d chars, buffer %d/%d\n",
2704 nbchars, in->buffer->use, in->buffer->size);
2705#endif
2706 return(nbchars);
2707}
2708
2709/**
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002710 * endOfInput:
2711 *
2712 * When reading from an Input channel indicated end of file or error
2713 * don't reread from it again.
2714 */
2715static int
2716endOfInput (void * context ATTRIBUTE_UNUSED,
2717 char * buffer ATTRIBUTE_UNUSED,
2718 int len ATTRIBUTE_UNUSED) {
2719 return(0);
2720}
2721
2722/**
Owen Taylor3473f882001-02-23 17:55:21 +00002723 * xmlParserInputBufferGrow:
2724 * @in: a buffered parser input
2725 * @len: indicative value of the amount of chars to read
2726 *
2727 * Grow up the content of the input buffer, the old data are preserved
2728 * This routine handle the I18N transcoding to internal UTF-8
2729 * This routine is used when operating the parser in normal (pull) mode
2730 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002731 * TODO: one should be able to remove one extra copy by copying directly
Owen Taylor3473f882001-02-23 17:55:21 +00002732 * onto in->buffer or in->raw
2733 *
2734 * Returns the number of chars read and stored in the buffer, or -1
2735 * in case of error.
2736 */
2737int
2738xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
2739 char *buffer = NULL;
2740 int res = 0;
2741 int nbchars = 0;
2742 int buffree;
Daniel Veillard9e412302002-06-10 15:59:44 +00002743 unsigned int needSize;
Owen Taylor3473f882001-02-23 17:55:21 +00002744
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002745 if ((in == NULL) || (in->error)) return(-1);
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002746 if ((len <= MINLEN) && (len != 4))
Owen Taylor3473f882001-02-23 17:55:21 +00002747 len = MINLEN;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002748
Owen Taylor3473f882001-02-23 17:55:21 +00002749 buffree = in->buffer->size - in->buffer->use;
2750 if (buffree <= 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002751 xmlIOErr(XML_IO_BUFFER_FULL, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002752 in->error = XML_IO_BUFFER_FULL;
William M. Bracka3215c72004-07-31 16:24:01 +00002753 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002754 }
Owen Taylor3473f882001-02-23 17:55:21 +00002755
Daniel Veillarde5354492002-05-16 08:43:22 +00002756 needSize = in->buffer->use + len + 1;
2757 if (needSize > in->buffer->size){
2758 if (!xmlBufferResize(in->buffer, needSize)){
Daniel Veillard05d987b2003-10-08 11:54:57 +00002759 xmlIOErrMemory("growing input buffer");
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002760 in->error = XML_ERR_NO_MEMORY;
William M. Bracka3215c72004-07-31 16:24:01 +00002761 return(-1);
Daniel Veillarde5354492002-05-16 08:43:22 +00002762 }
Owen Taylor3473f882001-02-23 17:55:21 +00002763 }
Daniel Veillarde5354492002-05-16 08:43:22 +00002764 buffer = (char *)&in->buffer->content[in->buffer->use];
Owen Taylor3473f882001-02-23 17:55:21 +00002765
2766 /*
2767 * Call the read method for this I/O type.
2768 */
2769 if (in->readcallback != NULL) {
2770 res = in->readcallback(in->context, &buffer[0], len);
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002771 if (res <= 0)
2772 in->readcallback = endOfInput;
Owen Taylor3473f882001-02-23 17:55:21 +00002773 } else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002774 xmlIOErr(XML_IO_NO_INPUT, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002775 in->error = XML_IO_NO_INPUT;
Owen Taylor3473f882001-02-23 17:55:21 +00002776 return(-1);
2777 }
2778 if (res < 0) {
Owen Taylor3473f882001-02-23 17:55:21 +00002779 return(-1);
2780 }
2781 len = res;
2782 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00002783 unsigned int use;
2784
Owen Taylor3473f882001-02-23 17:55:21 +00002785 /*
2786 * Store the data in the incoming raw buffer
2787 */
2788 if (in->raw == NULL) {
2789 in->raw = xmlBufferCreate();
2790 }
William M. Bracka3215c72004-07-31 16:24:01 +00002791 res = xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
2792 if (res != 0)
2793 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002794
2795 /*
2796 * convert as much as possible to the parser reading buffer.
2797 */
Daniel Veillard36711902004-02-11 13:25:26 +00002798 use = in->raw->use;
Owen Taylor3473f882001-02-23 17:55:21 +00002799 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2800 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002801 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002802 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002803 return(-1);
2804 }
Daniel Veillard36711902004-02-11 13:25:26 +00002805 in->rawconsumed += (use - in->raw->use);
Owen Taylor3473f882001-02-23 17:55:21 +00002806 } else {
2807 nbchars = len;
Daniel Veillarde5354492002-05-16 08:43:22 +00002808 in->buffer->use += nbchars;
2809 buffer[nbchars] = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002810 }
2811#ifdef DEBUG_INPUT
2812 xmlGenericError(xmlGenericErrorContext,
2813 "I/O: read %d chars, buffer %d/%d\n",
2814 nbchars, in->buffer->use, in->buffer->size);
2815#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002816 return(nbchars);
2817}
2818
2819/**
2820 * xmlParserInputBufferRead:
2821 * @in: a buffered parser input
2822 * @len: indicative value of the amount of chars to read
2823 *
2824 * Refresh the content of the input buffer, the old data are considered
2825 * consumed
2826 * This routine handle the I18N transcoding to internal UTF-8
2827 *
2828 * Returns the number of chars read and stored in the buffer, or -1
2829 * in case of error.
2830 */
2831int
2832xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002833 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002834 if (in->readcallback != NULL)
2835 return(xmlParserInputBufferGrow(in, len));
Daniel Veillard53350552003-09-18 13:35:51 +00002836 else if ((in->buffer != NULL) &&
2837 (in->buffer->alloc == XML_BUFFER_ALLOC_IMMUTABLE))
2838 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002839 else
2840 return(-1);
2841}
2842
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002843#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002844/**
2845 * xmlOutputBufferWrite:
2846 * @out: a buffered parser output
2847 * @len: the size in bytes of the array.
2848 * @buf: an char array
2849 *
2850 * Write the content of the array in the output I/O buffer
2851 * This routine handle the I18N transcoding from internal UTF-8
2852 * The buffer is lossless, i.e. will store in case of partial
2853 * or delayed writes.
2854 *
2855 * Returns the number of chars immediately written, or -1
2856 * in case of error.
2857 */
2858int
2859xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
2860 int nbchars = 0; /* number of chars to output to I/O */
2861 int ret; /* return from function call */
2862 int written = 0; /* number of char written to I/O so far */
2863 int chunk; /* number of byte curreent processed from buf */
2864
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002865 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002866 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002867 if (out->error) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002868
2869 do {
2870 chunk = len;
2871 if (chunk > 4 * MINLEN)
2872 chunk = 4 * MINLEN;
2873
2874 /*
2875 * first handle encoding stuff.
2876 */
2877 if (out->encoder != NULL) {
2878 /*
2879 * Store the data in the incoming raw buffer
2880 */
2881 if (out->conv == NULL) {
2882 out->conv = xmlBufferCreate();
2883 }
William M. Bracka3215c72004-07-31 16:24:01 +00002884 ret = xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2885 if (ret != 0)
2886 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002887
2888 if ((out->buffer->use < MINLEN) && (chunk == len))
2889 goto done;
2890
2891 /*
2892 * convert as much as possible to the parser reading buffer.
2893 */
2894 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
Daniel Veillard809faa52003-02-10 15:43:53 +00002895 if ((ret < 0) && (ret != -3)) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002896 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002897 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002898 return(-1);
2899 }
2900 nbchars = out->conv->use;
2901 } else {
William M. Bracka3215c72004-07-31 16:24:01 +00002902 ret = xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2903 if (ret != 0)
2904 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002905 nbchars = out->buffer->use;
2906 }
2907 buf += chunk;
2908 len -= chunk;
2909
2910 if ((nbchars < MINLEN) && (len <= 0))
2911 goto done;
2912
2913 if (out->writecallback) {
2914 /*
2915 * second write the stuff to the I/O channel
2916 */
2917 if (out->encoder != NULL) {
2918 ret = out->writecallback(out->context,
2919 (const char *)out->conv->content, nbchars);
2920 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002921 xmlBufferShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002922 } else {
2923 ret = out->writecallback(out->context,
2924 (const char *)out->buffer->content, nbchars);
2925 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002926 xmlBufferShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002927 }
2928 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002929 xmlIOErr(XML_IO_WRITE, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002930 out->error = XML_IO_WRITE;
Owen Taylor3473f882001-02-23 17:55:21 +00002931 return(ret);
2932 }
2933 out->written += ret;
2934 }
2935 written += nbchars;
2936 } while (len > 0);
2937
2938done:
2939#ifdef DEBUG_INPUT
2940 xmlGenericError(xmlGenericErrorContext,
2941 "I/O: wrote %d chars\n", written);
2942#endif
2943 return(written);
2944}
2945
2946/**
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00002947 * xmlEscapeContent:
2948 * @out: a pointer to an array of bytes to store the result
2949 * @outlen: the length of @out
2950 * @in: a pointer to an array of unescaped UTF-8 bytes
2951 * @inlen: the length of @in
2952 *
2953 * Take a block of UTF-8 chars in and escape them.
2954 * Returns 0 if success, or -1 otherwise
2955 * The value of @inlen after return is the number of octets consumed
2956 * if the return value is positive, else unpredictable.
2957 * The value of @outlen after return is the number of octets consumed.
2958 */
2959static int
2960xmlEscapeContent(unsigned char* out, int *outlen,
2961 const xmlChar* in, int *inlen) {
2962 unsigned char* outstart = out;
2963 const unsigned char* base = in;
2964 unsigned char* outend = out + *outlen;
2965 const unsigned char* inend;
2966
2967 inend = in + (*inlen);
2968
2969 while ((in < inend) && (out < outend)) {
2970 if (*in == '<') {
2971 if (outend - out < 4) break;
2972 *out++ = '&';
2973 *out++ = 'l';
2974 *out++ = 't';
2975 *out++ = ';';
2976 } else if (*in == '>') {
2977 if (outend - out < 4) break;
2978 *out++ = '&';
2979 *out++ = 'g';
2980 *out++ = 't';
2981 *out++ = ';';
2982 } else if (*in == '&') {
2983 if (outend - out < 5) break;
2984 *out++ = '&';
2985 *out++ = 'a';
2986 *out++ = 'm';
2987 *out++ = 'p';
2988 *out++ = ';';
2989 } else if (*in == '\r') {
2990 if (outend - out < 5) break;
2991 *out++ = '&';
2992 *out++ = '#';
2993 *out++ = '1';
2994 *out++ = '3';
2995 *out++ = ';';
2996 } else {
2997 *out++ = (unsigned char) *in;
2998 }
2999 ++in;
3000 }
3001 *outlen = out - outstart;
3002 *inlen = in - base;
3003 return(0);
3004}
3005
3006/**
3007 * xmlOutputBufferWriteEscape:
3008 * @out: a buffered parser output
3009 * @str: a zero terminated UTF-8 string
Daniel Veillardee8960b2004-05-14 03:25:14 +00003010 * @escaping: an optional escaping function (or NULL)
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003011 *
3012 * Write the content of the string in the output I/O buffer
3013 * This routine escapes the caracters and then handle the I18N
3014 * transcoding from internal UTF-8
3015 * The buffer is lossless, i.e. will store in case of partial
3016 * or delayed writes.
3017 *
3018 * Returns the number of chars immediately written, or -1
3019 * in case of error.
3020 */
3021int
Daniel Veillardee8960b2004-05-14 03:25:14 +00003022xmlOutputBufferWriteEscape(xmlOutputBufferPtr out, const xmlChar *str,
3023 xmlCharEncodingOutputFunc escaping) {
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003024 int nbchars = 0; /* number of chars to output to I/O */
3025 int ret; /* return from function call */
3026 int written = 0; /* number of char written to I/O so far */
Daniel Veillard71b95632004-08-31 12:15:36 +00003027 int oldwritten=0;/* loop guard */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003028 int chunk; /* number of byte currently processed from str */
3029 int len; /* number of bytes in str */
3030 int cons; /* byte from str consumed */
3031
3032 if ((out == NULL) || (out->error) || (str == NULL)) return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003033 len = strlen((const char *)str);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003034 if (len < 0) return(0);
3035 if (out->error) return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003036 if (escaping == NULL) escaping = xmlEscapeContent;
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003037
3038 do {
Daniel Veillard71b95632004-08-31 12:15:36 +00003039 oldwritten = written;
3040
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003041 /*
3042 * how many bytes to consume and how many bytes to store.
3043 */
3044 cons = len;
3045 chunk = (out->buffer->size - out->buffer->use) - 1;
3046
3047 /*
3048 * first handle encoding stuff.
3049 */
3050 if (out->encoder != NULL) {
3051 /*
3052 * Store the data in the incoming raw buffer
3053 */
3054 if (out->conv == NULL) {
3055 out->conv = xmlBufferCreate();
3056 }
Daniel Veillardee8960b2004-05-14 03:25:14 +00003057 ret = escaping(out->buffer->content + out->buffer->use ,
3058 &chunk, str, &cons);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003059 if (ret < 0)
3060 return(-1);
3061 out->buffer->use += chunk;
3062 out->buffer->content[out->buffer->use] = 0;
3063
3064 if ((out->buffer->use < MINLEN) && (cons == len))
3065 goto done;
3066
3067 /*
3068 * convert as much as possible to the output buffer.
3069 */
3070 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
3071 if ((ret < 0) && (ret != -3)) {
3072 xmlIOErr(XML_IO_ENCODER, NULL);
3073 out->error = XML_IO_ENCODER;
3074 return(-1);
3075 }
3076 nbchars = out->conv->use;
3077 } else {
Daniel Veillardee8960b2004-05-14 03:25:14 +00003078 ret = escaping(out->buffer->content + out->buffer->use ,
3079 &chunk, str, &cons);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003080 if (ret < 0)
3081 return(-1);
3082 out->buffer->use += chunk;
3083 out->buffer->content[out->buffer->use] = 0;
3084 nbchars = out->buffer->use;
3085 }
3086 str += cons;
3087 len -= cons;
3088
3089 if ((nbchars < MINLEN) && (len <= 0))
3090 goto done;
3091
3092 if (out->writecallback) {
3093 /*
3094 * second write the stuff to the I/O channel
3095 */
3096 if (out->encoder != NULL) {
3097 ret = out->writecallback(out->context,
3098 (const char *)out->conv->content, nbchars);
3099 if (ret >= 0)
3100 xmlBufferShrink(out->conv, ret);
3101 } else {
3102 ret = out->writecallback(out->context,
3103 (const char *)out->buffer->content, nbchars);
3104 if (ret >= 0)
3105 xmlBufferShrink(out->buffer, ret);
3106 }
3107 if (ret < 0) {
3108 xmlIOErr(XML_IO_WRITE, NULL);
3109 out->error = XML_IO_WRITE;
3110 return(ret);
3111 }
3112 out->written += ret;
Daniel Veillard83a75e02004-05-14 21:50:42 +00003113 } else if (out->buffer->size - out->buffer->use < MINLEN) {
3114 xmlBufferResize(out->buffer, out->buffer->size + MINLEN);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003115 }
3116 written += nbchars;
Daniel Veillard71b95632004-08-31 12:15:36 +00003117 } while ((len > 0) && (oldwritten != written));
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003118
3119done:
3120#ifdef DEBUG_INPUT
3121 xmlGenericError(xmlGenericErrorContext,
3122 "I/O: wrote %d chars\n", written);
3123#endif
3124 return(written);
3125}
3126
3127/**
Owen Taylor3473f882001-02-23 17:55:21 +00003128 * xmlOutputBufferWriteString:
3129 * @out: a buffered parser output
3130 * @str: a zero terminated C string
3131 *
3132 * Write the content of the string in the output I/O buffer
3133 * This routine handle the I18N transcoding from internal UTF-8
3134 * The buffer is lossless, i.e. will store in case of partial
3135 * or delayed writes.
3136 *
3137 * Returns the number of chars immediately written, or -1
3138 * in case of error.
3139 */
3140int
3141xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
3142 int len;
3143
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003144 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003145 if (str == NULL)
3146 return(-1);
3147 len = strlen(str);
3148
3149 if (len > 0)
3150 return(xmlOutputBufferWrite(out, len, str));
3151 return(len);
3152}
3153
3154/**
3155 * xmlOutputBufferFlush:
3156 * @out: a buffered output
3157 *
3158 * flushes the output I/O channel
3159 *
3160 * Returns the number of byte written or -1 in case of error.
3161 */
3162int
3163xmlOutputBufferFlush(xmlOutputBufferPtr out) {
3164 int nbchars = 0, ret = 0;
3165
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003166 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003167 /*
3168 * first handle encoding stuff.
3169 */
3170 if ((out->conv != NULL) && (out->encoder != NULL)) {
3171 /*
3172 * convert as much as possible to the parser reading buffer.
3173 */
3174 nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
3175 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003176 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003177 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003178 return(-1);
3179 }
3180 }
3181
3182 /*
3183 * second flush the stuff to the I/O channel
3184 */
3185 if ((out->conv != NULL) && (out->encoder != NULL) &&
3186 (out->writecallback != NULL)) {
3187 ret = out->writecallback(out->context,
3188 (const char *)out->conv->content, out->conv->use);
3189 if (ret >= 0)
3190 xmlBufferShrink(out->conv, ret);
3191 } else if (out->writecallback != NULL) {
3192 ret = out->writecallback(out->context,
3193 (const char *)out->buffer->content, out->buffer->use);
3194 if (ret >= 0)
3195 xmlBufferShrink(out->buffer, ret);
3196 }
3197 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003198 xmlIOErr(XML_IO_FLUSH, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003199 out->error = XML_IO_FLUSH;
Owen Taylor3473f882001-02-23 17:55:21 +00003200 return(ret);
3201 }
3202 out->written += ret;
3203
3204#ifdef DEBUG_INPUT
3205 xmlGenericError(xmlGenericErrorContext,
3206 "I/O: flushed %d chars\n", ret);
3207#endif
3208 return(ret);
3209}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003210#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003211
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003212/**
Owen Taylor3473f882001-02-23 17:55:21 +00003213 * xmlParserGetDirectory:
3214 * @filename: the path to a file
3215 *
3216 * lookup the directory for that file
3217 *
3218 * Returns a new allocated string containing the directory, or NULL.
3219 */
3220char *
3221xmlParserGetDirectory(const char *filename) {
3222 char *ret = NULL;
3223 char dir[1024];
3224 char *cur;
3225 char sep = '/';
3226
Igor Zlatkovic9181cc02002-09-29 17:51:06 +00003227#ifdef _WIN32_WCE /* easy way by now ... wince does not have dirs! */
3228 return NULL;
3229#endif
3230
Owen Taylor3473f882001-02-23 17:55:21 +00003231 if (xmlInputCallbackInitialized == 0)
3232 xmlRegisterDefaultInputCallbacks();
3233
3234 if (filename == NULL) return(NULL);
Daniel Veillard3c5ed912002-01-08 10:36:16 +00003235#if defined(WIN32) && !defined(__CYGWIN__)
Owen Taylor3473f882001-02-23 17:55:21 +00003236 sep = '\\';
3237#endif
3238
3239 strncpy(dir, filename, 1023);
3240 dir[1023] = 0;
3241 cur = &dir[strlen(dir)];
3242 while (cur > dir) {
3243 if (*cur == sep) break;
3244 cur --;
3245 }
3246 if (*cur == sep) {
3247 if (cur == dir) dir[1] = 0;
3248 else *cur = 0;
3249 ret = xmlMemStrdup(dir);
3250 } else {
3251 if (getcwd(dir, 1024) != NULL) {
3252 dir[1023] = 0;
3253 ret = xmlMemStrdup(dir);
3254 }
3255 }
3256 return(ret);
3257}
3258
3259/****************************************************************
3260 * *
3261 * External entities loading *
3262 * *
3263 ****************************************************************/
3264
Daniel Veillarda840b692003-10-19 13:35:37 +00003265/**
3266 * xmlCheckHTTPInput:
3267 * @ctxt: an XML parser context
3268 * @ret: an XML parser input
3269 *
3270 * Check an input in case it was created from an HTTP stream, in that
3271 * case it will handle encoding and update of the base URL in case of
3272 * redirection. It also checks for HTTP errors in which case the input
3273 * is cleanly freed up and an appropriate error is raised in context
3274 *
3275 * Returns the input or NULL in case of HTTP error.
3276 */
3277xmlParserInputPtr
3278xmlCheckHTTPInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr ret) {
3279#ifdef LIBXML_HTTP_ENABLED
3280 if ((ret != NULL) && (ret->buf != NULL) &&
3281 (ret->buf->readcallback == xmlIOHTTPRead) &&
3282 (ret->buf->context != NULL)) {
3283 const char *encoding;
3284 const char *redir;
3285 const char *mime;
3286 int code;
3287
3288 code = xmlNanoHTTPReturnCode(ret->buf->context);
3289 if (code >= 400) {
3290 /* fatal error */
3291 if (ret->filename != NULL)
Daniel Veillarde8039df2003-10-27 11:25:13 +00003292 __xmlLoaderErr(ctxt, "failed to load HTTP resource \"%s\"\n",
Daniel Veillarda840b692003-10-19 13:35:37 +00003293 (const char *) ret->filename);
3294 else
Daniel Veillarde8039df2003-10-27 11:25:13 +00003295 __xmlLoaderErr(ctxt, "failed to load HTTP resource\n", NULL);
Daniel Veillarda840b692003-10-19 13:35:37 +00003296 xmlFreeInputStream(ret);
3297 ret = NULL;
3298 } else {
3299
3300 mime = xmlNanoHTTPMimeType(ret->buf->context);
3301 if ((xmlStrstr(BAD_CAST mime, BAD_CAST "/xml")) ||
3302 (xmlStrstr(BAD_CAST mime, BAD_CAST "+xml"))) {
3303 encoding = xmlNanoHTTPEncoding(ret->buf->context);
3304 if (encoding != NULL) {
3305 xmlCharEncodingHandlerPtr handler;
3306
3307 handler = xmlFindCharEncodingHandler(encoding);
3308 if (handler != NULL) {
3309 xmlSwitchInputEncoding(ctxt, ret, handler);
3310 } else {
3311 __xmlErrEncoding(ctxt, XML_ERR_UNKNOWN_ENCODING,
3312 "Unknown encoding %s",
3313 BAD_CAST encoding, NULL);
3314 }
3315 if (ret->encoding == NULL)
3316 ret->encoding = xmlStrdup(BAD_CAST encoding);
3317 }
3318#if 0
3319 } else if (xmlStrstr(BAD_CAST mime, BAD_CAST "html")) {
3320#endif
3321 }
3322 redir = xmlNanoHTTPRedir(ret->buf->context);
3323 if (redir != NULL) {
3324 if (ret->filename != NULL)
3325 xmlFree((xmlChar *) ret->filename);
3326 if (ret->directory != NULL) {
3327 xmlFree((xmlChar *) ret->directory);
3328 ret->directory = NULL;
3329 }
3330 ret->filename =
3331 (char *) xmlStrdup((const xmlChar *) redir);
3332 }
3333 }
3334 }
3335#endif
3336 return(ret);
3337}
3338
Daniel Veillard561b7f82002-03-20 21:55:57 +00003339static int xmlSysIDExists(const char *URL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003340#ifdef HAVE_STAT
3341 int ret;
3342 struct stat info;
3343 const char *path;
3344
3345 if (URL == NULL)
3346 return(0);
3347
Daniel Veillardf4862f02002-09-10 11:13:43 +00003348 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003349#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00003350 path = &URL[17];
3351#else
Daniel Veillard6990bf32001-08-23 21:17:48 +00003352 path = &URL[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00003353#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003354 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003355#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard6990bf32001-08-23 21:17:48 +00003356 path = &URL[8];
3357#else
3358 path = &URL[7];
3359#endif
3360 } else
3361 path = URL;
3362 ret = stat(path, &info);
Daniel Veillard561b7f82002-03-20 21:55:57 +00003363 if (ret == 0)
3364 return(1);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003365#endif
Daniel Veillard561b7f82002-03-20 21:55:57 +00003366 return(0);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003367}
Daniel Veillard6990bf32001-08-23 21:17:48 +00003368
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003369/**
Owen Taylor3473f882001-02-23 17:55:21 +00003370 * xmlDefaultExternalEntityLoader:
3371 * @URL: the URL for the entity to load
3372 * @ID: the System ID for the entity to load
3373 * @ctxt: the context in which the entity is called or NULL
3374 *
3375 * By default we don't load external entitites, yet.
3376 *
3377 * Returns a new allocated xmlParserInputPtr, or NULL.
3378 */
Daniel Veillarda840b692003-10-19 13:35:37 +00003379static xmlParserInputPtr
Owen Taylor3473f882001-02-23 17:55:21 +00003380xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
Daniel Veillarda840b692003-10-19 13:35:37 +00003381 xmlParserCtxtPtr ctxt)
3382{
Owen Taylor3473f882001-02-23 17:55:21 +00003383 xmlParserInputPtr ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003384 xmlChar *resource = NULL;
Daniel Veillarda840b692003-10-19 13:35:37 +00003385
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003386#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003387 xmlCatalogAllow pref;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003388#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003389
3390#ifdef DEBUG_EXTERNAL_ENTITIES
3391 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda840b692003-10-19 13:35:37 +00003392 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00003393#endif
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003394#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillard61b93382003-11-03 14:28:31 +00003395 if ((ctxt != NULL) && (ctxt->options & XML_PARSE_NONET)) {
3396 int options = ctxt->options;
3397
3398 ctxt->options -= XML_PARSE_NONET;
3399 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
3400 ctxt->options = options;
3401 return(ret);
3402 }
3403
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003404 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003405 * If the resource doesn't exists as a file,
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003406 * try to load it from the resource pointed in the catalogs
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003407 */
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003408 pref = xmlCatalogGetDefaults();
3409
Daniel Veillard561b7f82002-03-20 21:55:57 +00003410 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlSysIDExists(URL))) {
Daniel Veillarda840b692003-10-19 13:35:37 +00003411 /*
3412 * Do a local lookup
3413 */
3414 if ((ctxt->catalogs != NULL) &&
3415 ((pref == XML_CATA_ALLOW_ALL) ||
3416 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3417 resource = xmlCatalogLocalResolve(ctxt->catalogs,
3418 (const xmlChar *) ID,
3419 (const xmlChar *) URL);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003420 }
Daniel Veillarda840b692003-10-19 13:35:37 +00003421 /*
3422 * Try a global lookup
3423 */
3424 if ((resource == NULL) &&
3425 ((pref == XML_CATA_ALLOW_ALL) ||
3426 (pref == XML_CATA_ALLOW_GLOBAL))) {
3427 resource = xmlCatalogResolve((const xmlChar *) ID,
3428 (const xmlChar *) URL);
3429 }
3430 if ((resource == NULL) && (URL != NULL))
3431 resource = xmlStrdup((const xmlChar *) URL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003432
Daniel Veillarda840b692003-10-19 13:35:37 +00003433 /*
3434 * TODO: do an URI lookup on the reference
3435 */
3436 if ((resource != NULL)
3437 && (!xmlSysIDExists((const char *) resource))) {
3438 xmlChar *tmp = NULL;
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003439
Daniel Veillarda840b692003-10-19 13:35:37 +00003440 if ((ctxt->catalogs != NULL) &&
3441 ((pref == XML_CATA_ALLOW_ALL) ||
3442 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3443 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
3444 }
3445 if ((tmp == NULL) &&
3446 ((pref == XML_CATA_ALLOW_ALL) ||
3447 (pref == XML_CATA_ALLOW_GLOBAL))) {
3448 tmp = xmlCatalogResolveURI(resource);
3449 }
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003450
Daniel Veillarda840b692003-10-19 13:35:37 +00003451 if (tmp != NULL) {
3452 xmlFree(resource);
3453 resource = tmp;
3454 }
3455 }
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003456 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003457#endif
3458
3459 if (resource == NULL)
Daniel Veillarda840b692003-10-19 13:35:37 +00003460 resource = (xmlChar *) URL;
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003461
3462 if (resource == NULL) {
Daniel Veillarda840b692003-10-19 13:35:37 +00003463 if (ID == NULL)
3464 ID = "NULL";
Daniel Veillarde8039df2003-10-27 11:25:13 +00003465 __xmlLoaderErr(ctxt, "failed to load external entity \"%s\"\n", ID);
Daniel Veillarda840b692003-10-19 13:35:37 +00003466 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003467 }
Daniel Veillarda840b692003-10-19 13:35:37 +00003468 ret = xmlNewInputFromFile(ctxt, (const char *) resource);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003469 if ((resource != NULL) && (resource != (xmlChar *) URL))
Daniel Veillarda840b692003-10-19 13:35:37 +00003470 xmlFree(resource);
3471 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003472}
3473
3474static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
3475 xmlDefaultExternalEntityLoader;
3476
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003477/**
Owen Taylor3473f882001-02-23 17:55:21 +00003478 * xmlSetExternalEntityLoader:
3479 * @f: the new entity resolver function
3480 *
3481 * Changes the defaultexternal entity resolver function for the application
3482 */
3483void
3484xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
3485 xmlCurrentExternalEntityLoader = f;
3486}
3487
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003488/**
Owen Taylor3473f882001-02-23 17:55:21 +00003489 * xmlGetExternalEntityLoader:
3490 *
3491 * Get the default external entity resolver function for the application
3492 *
3493 * Returns the xmlExternalEntityLoader function pointer
3494 */
3495xmlExternalEntityLoader
3496xmlGetExternalEntityLoader(void) {
3497 return(xmlCurrentExternalEntityLoader);
3498}
3499
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003500/**
Owen Taylor3473f882001-02-23 17:55:21 +00003501 * xmlLoadExternalEntity:
3502 * @URL: the URL for the entity to load
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00003503 * @ID: the Public ID for the entity to load
Owen Taylor3473f882001-02-23 17:55:21 +00003504 * @ctxt: the context in which the entity is called or NULL
3505 *
3506 * Load an external entity, note that the use of this function for
3507 * unparsed entities may generate problems
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003508 * TODO: a more generic External entity API must be designed
Owen Taylor3473f882001-02-23 17:55:21 +00003509 *
3510 * Returns the xmlParserInputPtr or NULL
3511 */
3512xmlParserInputPtr
3513xmlLoadExternalEntity(const char *URL, const char *ID,
3514 xmlParserCtxtPtr ctxt) {
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00003515 if ((URL != NULL) && (xmlSysIDExists(URL) == 0)) {
3516 char *canonicFilename;
3517 xmlParserInputPtr ret;
3518
3519 canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL);
3520 if (canonicFilename == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003521 xmlIOErrMemory("building canonical path\n");
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00003522 return(NULL);
3523 }
3524
3525 ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt);
3526 xmlFree(canonicFilename);
3527 return(ret);
3528 }
Owen Taylor3473f882001-02-23 17:55:21 +00003529 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
3530}
3531
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003532/************************************************************************
3533 * *
3534 * Disabling Network access *
3535 * *
3536 ************************************************************************/
3537
3538#ifdef LIBXML_CATALOG_ENABLED
3539static int
3540xmlNoNetExists(const char *URL)
3541{
3542#ifdef HAVE_STAT
3543 int ret;
3544 struct stat info;
3545 const char *path;
3546
3547 if (URL == NULL)
3548 return (0);
3549
Daniel Veillardf4862f02002-09-10 11:13:43 +00003550 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003551#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00003552 path = &URL[17];
3553#else
3554 path = &URL[16];
3555#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003556 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003557#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003558 path = &URL[8];
3559#else
3560 path = &URL[7];
3561#endif
3562 } else
3563 path = URL;
3564 ret = stat(path, &info);
3565 if (ret == 0)
3566 return (1);
3567#endif
3568 return (0);
3569}
3570#endif
3571
3572/**
3573 * xmlNoNetExternalEntityLoader:
3574 * @URL: the URL for the entity to load
3575 * @ID: the System ID for the entity to load
3576 * @ctxt: the context in which the entity is called or NULL
3577 *
3578 * A specific entity loader disabling network accesses, though still
3579 * allowing local catalog accesses for resolution.
3580 *
3581 * Returns a new allocated xmlParserInputPtr, or NULL.
3582 */
3583xmlParserInputPtr
3584xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
3585 xmlParserCtxtPtr ctxt) {
3586 xmlParserInputPtr input = NULL;
3587 xmlChar *resource = NULL;
3588
3589#ifdef LIBXML_CATALOG_ENABLED
3590 xmlCatalogAllow pref;
3591
3592 /*
3593 * If the resource doesn't exists as a file,
3594 * try to load it from the resource pointed in the catalogs
3595 */
3596 pref = xmlCatalogGetDefaults();
3597
3598 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
3599 /*
3600 * Do a local lookup
3601 */
3602 if ((ctxt->catalogs != NULL) &&
3603 ((pref == XML_CATA_ALLOW_ALL) ||
3604 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3605 resource = xmlCatalogLocalResolve(ctxt->catalogs,
3606 (const xmlChar *)ID,
3607 (const xmlChar *)URL);
3608 }
3609 /*
3610 * Try a global lookup
3611 */
3612 if ((resource == NULL) &&
3613 ((pref == XML_CATA_ALLOW_ALL) ||
3614 (pref == XML_CATA_ALLOW_GLOBAL))) {
3615 resource = xmlCatalogResolve((const xmlChar *)ID,
3616 (const xmlChar *)URL);
3617 }
3618 if ((resource == NULL) && (URL != NULL))
3619 resource = xmlStrdup((const xmlChar *) URL);
3620
3621 /*
3622 * TODO: do an URI lookup on the reference
3623 */
3624 if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
3625 xmlChar *tmp = NULL;
3626
3627 if ((ctxt->catalogs != NULL) &&
3628 ((pref == XML_CATA_ALLOW_ALL) ||
3629 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3630 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
3631 }
3632 if ((tmp == NULL) &&
3633 ((pref == XML_CATA_ALLOW_ALL) ||
3634 (pref == XML_CATA_ALLOW_GLOBAL))) {
3635 tmp = xmlCatalogResolveURI(resource);
3636 }
3637
3638 if (tmp != NULL) {
3639 xmlFree(resource);
3640 resource = tmp;
3641 }
3642 }
3643 }
3644#endif
3645 if (resource == NULL)
3646 resource = (xmlChar *) URL;
3647
3648 if (resource != NULL) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003649 if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
3650 (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003651 xmlIOErr(XML_IO_NETWORK_ATTEMPT, (const char *) resource);
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003652 if (resource != (xmlChar *) URL)
3653 xmlFree(resource);
3654 return(NULL);
3655 }
3656 }
3657 input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
3658 if (resource != (xmlChar *) URL)
3659 xmlFree(resource);
3660 return(input);
3661}
3662