blob: 2610e252fdbdba94a95249d4c34aa1ec97c81dd3 [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
2 * xmlIO.c : implementation of the I/O interfaces used by the parser
3 *
4 * See Copyright for the status of this software.
5 *
Daniel Veillard344cee72001-08-20 00:08:40 +00006 * daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +00007 *
8 * 14 Nov 2000 ht - for VMS, truncated name of long functions to under 32 char
9 */
10
Daniel Veillard34ce8be2002-03-18 19:37:11 +000011#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000012#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000013
Owen Taylor3473f882001-02-23 17:55:21 +000014#include <string.h>
Daniel Veillard92727042002-09-17 17:59:20 +000015#ifdef HAVE_ERRNO_H
Owen Taylor3473f882001-02-23 17:55:21 +000016#include <errno.h>
Daniel Veillard92727042002-09-17 17:59:20 +000017#endif
18
Owen Taylor3473f882001-02-23 17:55:21 +000019
20#ifdef HAVE_SYS_TYPES_H
21#include <sys/types.h>
22#endif
23#ifdef HAVE_SYS_STAT_H
24#include <sys/stat.h>
25#endif
26#ifdef HAVE_FCNTL_H
27#include <fcntl.h>
28#endif
29#ifdef HAVE_UNISTD_H
30#include <unistd.h>
31#endif
32#ifdef HAVE_STDLIB_H
33#include <stdlib.h>
34#endif
35#ifdef HAVE_ZLIB_H
36#include <zlib.h>
37#endif
38
39/* Figure a portable way to know if a file is a directory. */
40#ifndef HAVE_STAT
41# ifdef HAVE__STAT
Daniel Veillard50f34372001-08-03 12:06:36 +000042 /* MS C library seems to define stat and _stat. The definition
43 is identical. Still, mapping them to each other causes a warning. */
44# ifndef _MSC_VER
45# define stat(x,y) _stat(x,y)
46# endif
Owen Taylor3473f882001-02-23 17:55:21 +000047# define HAVE_STAT
48# endif
49#endif
50#ifdef HAVE_STAT
51# ifndef S_ISDIR
52# ifdef _S_ISDIR
53# define S_ISDIR(x) _S_ISDIR(x)
54# else
55# ifdef S_IFDIR
56# ifndef S_IFMT
57# ifdef _S_IFMT
58# define S_IFMT _S_IFMT
59# endif
60# endif
61# ifdef S_IFMT
62# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
63# endif
64# endif
65# endif
66# endif
67#endif
68
69#include <libxml/xmlmemory.h>
70#include <libxml/parser.h>
71#include <libxml/parserInternals.h>
72#include <libxml/xmlIO.h>
Daniel Veillard388236f2001-07-08 18:35:48 +000073#include <libxml/uri.h>
Owen Taylor3473f882001-02-23 17:55:21 +000074#include <libxml/nanohttp.h>
75#include <libxml/nanoftp.h>
76#include <libxml/xmlerror.h>
Daniel Veillard7d6fd212001-05-10 15:34:11 +000077#ifdef LIBXML_CATALOG_ENABLED
78#include <libxml/catalog.h>
79#endif
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000080#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000081
Daniel Veillardf012a642001-07-23 19:10:52 +000082/* #define VERBOSE_FAILURE */
Daniel Veillard1fd36d22001-07-04 22:54:28 +000083/* #define DEBUG_EXTERNAL_ENTITIES */
Owen Taylor3473f882001-02-23 17:55:21 +000084/* #define DEBUG_INPUT */
85
86#ifdef DEBUG_INPUT
87#define MINLEN 40
88#else
89#define MINLEN 4000
90#endif
91
92/*
93 * Input I/O callback sets
94 */
95typedef struct _xmlInputCallback {
96 xmlInputMatchCallback matchcallback;
97 xmlInputOpenCallback opencallback;
98 xmlInputReadCallback readcallback;
99 xmlInputCloseCallback closecallback;
100} xmlInputCallback;
101
102#define MAX_INPUT_CALLBACK 15
103
Daniel Veillard22090732001-07-16 00:06:07 +0000104static xmlInputCallback xmlInputCallbackTable[MAX_INPUT_CALLBACK];
105static int xmlInputCallbackNr = 0;
106static int xmlInputCallbackInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000107
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000108#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000109/*
110 * Output I/O callback sets
111 */
112typedef struct _xmlOutputCallback {
113 xmlOutputMatchCallback matchcallback;
114 xmlOutputOpenCallback opencallback;
115 xmlOutputWriteCallback writecallback;
116 xmlOutputCloseCallback closecallback;
117} xmlOutputCallback;
118
119#define MAX_OUTPUT_CALLBACK 15
120
Daniel Veillard22090732001-07-16 00:06:07 +0000121static xmlOutputCallback xmlOutputCallbackTable[MAX_OUTPUT_CALLBACK];
122static int xmlOutputCallbackNr = 0;
123static int xmlOutputCallbackInitialized = 0;
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000124#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000125
Daniel Veillard05d987b2003-10-08 11:54:57 +0000126/************************************************************************
127 * *
128 * Tree memory error handler *
129 * *
130 ************************************************************************/
Daniel Veillardf4862f02002-09-10 11:13:43 +0000131
Daniel Veillard05d987b2003-10-08 11:54:57 +0000132static const char *IOerr[] = {
Daniel Veillarda8856222003-10-08 19:26:03 +0000133 "Unknown IO error", /* UNKNOWN */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000134 "Permission denied", /* EACCES */
135 "Resource temporarily unavailable",/* EAGAIN */
136 "Bad file descriptor", /* EBADF */
137 "Bad message", /* EBADMSG */
138 "Resource busy", /* EBUSY */
139 "Operation canceled", /* ECANCELED */
140 "No child processes", /* ECHILD */
141 "Resource deadlock avoided",/* EDEADLK */
142 "Domain error", /* EDOM */
143 "File exists", /* EEXIST */
144 "Bad address", /* EFAULT */
145 "File too large", /* EFBIG */
146 "Operation in progress", /* EINPROGRESS */
147 "Interrupted function call",/* EINTR */
148 "Invalid argument", /* EINVAL */
149 "Input/output error", /* EIO */
150 "Is a directory", /* EISDIR */
151 "Too many open files", /* EMFILE */
152 "Too many links", /* EMLINK */
153 "Inappropriate message buffer length",/* EMSGSIZE */
154 "Filename too long", /* ENAMETOOLONG */
155 "Too many open files in system",/* ENFILE */
156 "No such device", /* ENODEV */
157 "No such file or directory",/* ENOENT */
158 "Exec format error", /* ENOEXEC */
159 "No locks available", /* ENOLCK */
160 "Not enough space", /* ENOMEM */
161 "No space left on device", /* ENOSPC */
162 "Function not implemented", /* ENOSYS */
163 "Not a directory", /* ENOTDIR */
164 "Directory not empty", /* ENOTEMPTY */
165 "Not supported", /* ENOTSUP */
166 "Inappropriate I/O control operation",/* ENOTTY */
167 "No such device or address",/* ENXIO */
168 "Operation not permitted", /* EPERM */
169 "Broken pipe", /* EPIPE */
170 "Result too large", /* ERANGE */
171 "Read-only file system", /* EROFS */
172 "Invalid seek", /* ESPIPE */
173 "No such process", /* ESRCH */
174 "Operation timed out", /* ETIMEDOUT */
175 "Improper link", /* EXDEV */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000176 "Attempt to load network entity %s", /* XML_IO_NETWORK_ATTEMPT */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000177 "encoder error", /* XML_IO_ENCODER */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000178 "flush error",
179 "write error",
180 "no input",
181 "buffer full",
182 "loading error",
183 "not a socket", /* ENOTSOCK */
184 "already connected", /* EISCONN */
Daniel Veillard29b17482004-08-16 00:39:03 +0000185 "connection refused", /* ECONNREFUSED */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000186 "unreachable network", /* ENETUNREACH */
187 "adddress in use", /* EADDRINUSE */
188 "already in use", /* EALREADY */
189 "unknown address familly", /* EAFNOSUPPORT */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000190};
191
192/**
193 * xmlIOErrMemory:
194 * @extra: extra informations
195 *
196 * Handle an out of memory condition
197 */
198static void
199xmlIOErrMemory(const char *extra)
200{
201 __xmlSimpleError(XML_FROM_IO, XML_ERR_NO_MEMORY, NULL, NULL, extra);
202}
203
204/**
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000205 * __xmlIOErr:
Daniel Veillard05d987b2003-10-08 11:54:57 +0000206 * @code: the error number
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000207 * @
Daniel Veillard05d987b2003-10-08 11:54:57 +0000208 * @extra: extra informations
209 *
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000210 * Handle an I/O error
Daniel Veillard05d987b2003-10-08 11:54:57 +0000211 */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000212void
213__xmlIOErr(int domain, int code, const char *extra)
Daniel Veillard05d987b2003-10-08 11:54:57 +0000214{
215 unsigned int idx;
216
217 if (code == 0) {
218#ifdef HAVE_ERRNO_H
219 if (errno == 0) code = 0;
220#ifdef EACCES
221 else if (errno == EACCES) code = XML_IO_EACCES;
222#endif
223#ifdef EAGAIN
224 else if (errno == EAGAIN) code = XML_IO_EAGAIN;
225#endif
226#ifdef EBADF
227 else if (errno == EBADF) code = XML_IO_EBADF;
228#endif
229#ifdef EBADMSG
230 else if (errno == EBADMSG) code = XML_IO_EBADMSG;
231#endif
232#ifdef EBUSY
233 else if (errno == EBUSY) code = XML_IO_EBUSY;
234#endif
235#ifdef ECANCELED
236 else if (errno == ECANCELED) code = XML_IO_ECANCELED;
237#endif
238#ifdef ECHILD
239 else if (errno == ECHILD) code = XML_IO_ECHILD;
240#endif
241#ifdef EDEADLK
242 else if (errno == EDEADLK) code = XML_IO_EDEADLK;
243#endif
244#ifdef EDOM
245 else if (errno == EDOM) code = XML_IO_EDOM;
246#endif
247#ifdef EEXIST
248 else if (errno == EEXIST) code = XML_IO_EEXIST;
249#endif
250#ifdef EFAULT
251 else if (errno == EFAULT) code = XML_IO_EFAULT;
252#endif
253#ifdef EFBIG
254 else if (errno == EFBIG) code = XML_IO_EFBIG;
255#endif
256#ifdef EINPROGRESS
257 else if (errno == EINPROGRESS) code = XML_IO_EINPROGRESS;
258#endif
259#ifdef EINTR
260 else if (errno == EINTR) code = XML_IO_EINTR;
261#endif
262#ifdef EINVAL
263 else if (errno == EINVAL) code = XML_IO_EINVAL;
264#endif
265#ifdef EIO
266 else if (errno == EIO) code = XML_IO_EIO;
267#endif
268#ifdef EISDIR
269 else if (errno == EISDIR) code = XML_IO_EISDIR;
270#endif
271#ifdef EMFILE
272 else if (errno == EMFILE) code = XML_IO_EMFILE;
273#endif
274#ifdef EMLINK
275 else if (errno == EMLINK) code = XML_IO_EMLINK;
276#endif
277#ifdef EMSGSIZE
278 else if (errno == EMSGSIZE) code = XML_IO_EMSGSIZE;
279#endif
280#ifdef ENAMETOOLONG
281 else if (errno == ENAMETOOLONG) code = XML_IO_ENAMETOOLONG;
282#endif
283#ifdef ENFILE
284 else if (errno == ENFILE) code = XML_IO_ENFILE;
285#endif
286#ifdef ENODEV
287 else if (errno == ENODEV) code = XML_IO_ENODEV;
288#endif
289#ifdef ENOENT
290 else if (errno == ENOENT) code = XML_IO_ENOENT;
291#endif
292#ifdef ENOEXEC
293 else if (errno == ENOEXEC) code = XML_IO_ENOEXEC;
294#endif
295#ifdef ENOLCK
296 else if (errno == ENOLCK) code = XML_IO_ENOLCK;
297#endif
298#ifdef ENOMEM
299 else if (errno == ENOMEM) code = XML_IO_ENOMEM;
300#endif
301#ifdef ENOSPC
302 else if (errno == ENOSPC) code = XML_IO_ENOSPC;
303#endif
304#ifdef ENOSYS
305 else if (errno == ENOSYS) code = XML_IO_ENOSYS;
306#endif
307#ifdef ENOTDIR
308 else if (errno == ENOTDIR) code = XML_IO_ENOTDIR;
309#endif
310#ifdef ENOTEMPTY
311 else if (errno == ENOTEMPTY) code = XML_IO_ENOTEMPTY;
312#endif
313#ifdef ENOTSUP
314 else if (errno == ENOTSUP) code = XML_IO_ENOTSUP;
315#endif
316#ifdef ENOTTY
317 else if (errno == ENOTTY) code = XML_IO_ENOTTY;
318#endif
319#ifdef ENXIO
320 else if (errno == ENXIO) code = XML_IO_ENXIO;
321#endif
322#ifdef EPERM
323 else if (errno == EPERM) code = XML_IO_EPERM;
324#endif
325#ifdef EPIPE
326 else if (errno == EPIPE) code = XML_IO_EPIPE;
327#endif
328#ifdef ERANGE
329 else if (errno == ERANGE) code = XML_IO_ERANGE;
330#endif
331#ifdef EROFS
332 else if (errno == EROFS) code = XML_IO_EROFS;
333#endif
334#ifdef ESPIPE
335 else if (errno == ESPIPE) code = XML_IO_ESPIPE;
336#endif
337#ifdef ESRCH
338 else if (errno == ESRCH) code = XML_IO_ESRCH;
339#endif
340#ifdef ETIMEDOUT
341 else if (errno == ETIMEDOUT) code = XML_IO_ETIMEDOUT;
342#endif
343#ifdef EXDEV
344 else if (errno == EXDEV) code = XML_IO_EXDEV;
345#endif
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000346#ifdef ENOTSOCK
347 else if (errno == ENOTSOCK) code = XML_IO_ENOTSOCK;
348#endif
349#ifdef EISCONN
350 else if (errno == EISCONN) code = XML_IO_EISCONN;
351#endif
352#ifdef ECONNREFUSED
353 else if (errno == ECONNREFUSED) code = XML_IO_ECONNREFUSED;
354#endif
355#ifdef ETIMEDOUT
356 else if (errno == ETIMEDOUT) code = XML_IO_ETIMEDOUT;
357#endif
358#ifdef ENETUNREACH
359 else if (errno == ENETUNREACH) code = XML_IO_ENETUNREACH;
360#endif
361#ifdef EADDRINUSE
362 else if (errno == EADDRINUSE) code = XML_IO_EADDRINUSE;
363#endif
364#ifdef EINPROGRESS
365 else if (errno == EINPROGRESS) code = XML_IO_EINPROGRESS;
366#endif
367#ifdef EALREADY
368 else if (errno == EALREADY) code = XML_IO_EALREADY;
369#endif
370#ifdef EAFNOSUPPORT
371 else if (errno == EAFNOSUPPORT) code = XML_IO_EAFNOSUPPORT;
372#endif
Daniel Veillard05d987b2003-10-08 11:54:57 +0000373 else code = XML_IO_UNKNOWN;
374#endif /* HAVE_ERRNO_H */
375 }
376 idx = 0;
377 if (code >= XML_IO_UNKNOWN) idx = code - XML_IO_UNKNOWN;
378 if (idx >= (sizeof(IOerr) / sizeof(IOerr[0]))) idx = 0;
379
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000380 __xmlSimpleError(domain, code, NULL, IOerr[idx], extra);
381}
382
383/**
384 * xmlIOErr:
385 * @code: the error number
386 * @extra: extra informations
387 *
388 * Handle an I/O error
389 */
390static void
391xmlIOErr(int code, const char *extra)
392{
393 __xmlIOErr(XML_FROM_IO, code, extra);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000394}
395
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000396/**
Daniel Veillarde8039df2003-10-27 11:25:13 +0000397 * __xmlLoaderErr:
398 * @ctx: the parser context
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000399 * @extra: extra informations
400 *
401 * Handle a resource access error
402 */
Daniel Veillarde8039df2003-10-27 11:25:13 +0000403void
404__xmlLoaderErr(void *ctx, const char *msg, const char *filename)
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000405{
Daniel Veillarde8039df2003-10-27 11:25:13 +0000406 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000407 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000408 xmlGenericErrorFunc channel = NULL;
409 void *data = NULL;
410 xmlErrorLevel level = XML_ERR_ERROR;
411
Daniel Veillard157fee02003-10-31 10:36:03 +0000412 if ((ctxt != NULL) && (ctxt->disableSAX != 0) &&
413 (ctxt->instate == XML_PARSER_EOF))
414 return;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000415 if ((ctxt != NULL) && (ctxt->sax != NULL)) {
416 if (ctxt->validate) {
417 channel = ctxt->sax->error;
418 level = XML_ERR_ERROR;
419 } else {
420 channel = ctxt->sax->warning;
421 level = XML_ERR_WARNING;
422 }
Daniel Veillard5ea30d72004-11-08 11:54:28 +0000423 if (ctxt->sax->initialized == XML_SAX2_MAGIC)
424 schannel = ctxt->sax->serror;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000425 data = ctxt->userData;
426 }
Daniel Veillard659e71e2003-10-10 14:10:40 +0000427 __xmlRaiseError(schannel, channel, data, ctxt, NULL, XML_FROM_IO,
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000428 XML_IO_LOAD_ERROR, level, NULL, 0,
429 filename, NULL, NULL, 0, 0,
430 msg, filename);
431
432}
433
Daniel Veillard05d987b2003-10-08 11:54:57 +0000434/************************************************************************
435 * *
436 * Tree memory error handler *
437 * *
438 ************************************************************************/
Daniel Veillardf4862f02002-09-10 11:13:43 +0000439/**
Daniel Veillard01c13b52002-12-10 15:19:08 +0000440 * xmlNormalizeWindowsPath:
Daniel Veillard33300b42003-04-17 09:09:19 +0000441 * @path: the input file path
Daniel Veillardf4862f02002-09-10 11:13:43 +0000442 *
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +0000443 * This function is obsolete. Please see xmlURIFromPath in uri.c for
444 * a better solution.
Daniel Veillard33300b42003-04-17 09:09:19 +0000445 *
446 * Returns a canonicalized version of the path
Daniel Veillardf4862f02002-09-10 11:13:43 +0000447 */
448xmlChar *
449xmlNormalizeWindowsPath(const xmlChar *path)
450{
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +0000451 return xmlCanonicPath(path);
Daniel Veillardf4862f02002-09-10 11:13:43 +0000452}
453
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000454/**
455 * xmlCleanupInputCallbacks:
456 *
457 * clears the entire input callback table. this includes the
458 * compiled-in I/O.
459 */
460void
461xmlCleanupInputCallbacks(void)
462{
463 int i;
464
465 if (!xmlInputCallbackInitialized)
466 return;
467
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000468 for (i = xmlInputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000469 xmlInputCallbackTable[i].matchcallback = NULL;
470 xmlInputCallbackTable[i].opencallback = NULL;
471 xmlInputCallbackTable[i].readcallback = NULL;
472 xmlInputCallbackTable[i].closecallback = NULL;
473 }
474
475 xmlInputCallbackNr = 0;
Aleksey Sanin9c45ba82002-06-06 21:46:13 +0000476 xmlInputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000477}
478
Daniel Veillardaecc0dc2004-05-08 02:32:07 +0000479/**
William M. Brack4e3a9fa2004-08-03 22:41:11 +0000480 * xmlPopInputCallbacks:
Daniel Veillardaecc0dc2004-05-08 02:32:07 +0000481 *
482 * Clear the top input callback from the input stack. this includes the
483 * compiled-in I/O.
484 *
485 * Returns the number of input callback registered or -1 in case of error.
486 */
487int
488xmlPopInputCallbacks(void)
489{
490 if (!xmlInputCallbackInitialized)
491 return(-1);
492
493 if (xmlInputCallbackNr <= 0)
494 return(-1);
495
496 xmlInputCallbackNr--;
497 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = NULL;
498 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = NULL;
499 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = NULL;
500 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = NULL;
501
502 return(xmlInputCallbackNr);
503}
504
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000505#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000506/**
507 * xmlCleanupOutputCallbacks:
508 *
509 * clears the entire output callback table. this includes the
510 * compiled-in I/O callbacks.
511 */
512void
513xmlCleanupOutputCallbacks(void)
514{
515 int i;
516
517 if (!xmlOutputCallbackInitialized)
518 return;
519
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000520 for (i = xmlOutputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000521 xmlOutputCallbackTable[i].matchcallback = NULL;
522 xmlOutputCallbackTable[i].opencallback = NULL;
523 xmlOutputCallbackTable[i].writecallback = NULL;
524 xmlOutputCallbackTable[i].closecallback = NULL;
525 }
526
527 xmlOutputCallbackNr = 0;
Aleksey Sanin9c45ba82002-06-06 21:46:13 +0000528 xmlOutputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000529}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000530#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000531
Owen Taylor3473f882001-02-23 17:55:21 +0000532/************************************************************************
533 * *
534 * Standard I/O for file accesses *
535 * *
536 ************************************************************************/
537
538/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000539 * xmlCheckFilename:
Owen Taylor3473f882001-02-23 17:55:21 +0000540 * @path: the path to check
541 *
542 * function checks to see if @path is a valid source
543 * (file, socket...) for XML.
544 *
545 * if stat is not available on the target machine,
546 * returns 1. if stat fails, returns 0 (if calling
547 * stat on the filename fails, it can't be right).
548 * if stat succeeds and the file is a directory,
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000549 * returns 2. otherwise returns 1.
Owen Taylor3473f882001-02-23 17:55:21 +0000550 */
551
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000552int
Owen Taylor3473f882001-02-23 17:55:21 +0000553xmlCheckFilename (const char *path)
554{
555#ifdef HAVE_STAT
Owen Taylor3473f882001-02-23 17:55:21 +0000556 struct stat stat_buffer;
557
Daniel Veillard34099b42004-11-04 17:34:35 +0000558 if (path == NULL)
559 return(0);
560
Owen Taylor3473f882001-02-23 17:55:21 +0000561 if (stat(path, &stat_buffer) == -1)
562 return 0;
563
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000564#ifdef S_ISDIR
Owen Taylor3473f882001-02-23 17:55:21 +0000565 if (S_ISDIR(stat_buffer.st_mode)) {
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000566 return 2;
Owen Taylor3473f882001-02-23 17:55:21 +0000567 }
Owen Taylor3473f882001-02-23 17:55:21 +0000568#endif
569#endif
Daniel Veillard34099b42004-11-04 17:34:35 +0000570 if (path == NULL)
571 return(0);
572
Owen Taylor3473f882001-02-23 17:55:21 +0000573 return 1;
574}
575
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000576static int
Owen Taylor3473f882001-02-23 17:55:21 +0000577xmlNop(void) {
578 return(0);
579}
580
581/**
Owen Taylor3473f882001-02-23 17:55:21 +0000582 * xmlFdRead:
583 * @context: the I/O context
584 * @buffer: where to drop data
585 * @len: number of bytes to read
586 *
587 * Read @len bytes to @buffer from the I/O channel.
588 *
589 * Returns the number of bytes written
590 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000591static int
Owen Taylor3473f882001-02-23 17:55:21 +0000592xmlFdRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000593 int ret;
594
595 ret = read((int) (long) context, &buffer[0], len);
596 if (ret < 0) xmlIOErr(0, "read()");
597 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000598}
599
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000600#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000601/**
602 * xmlFdWrite:
603 * @context: the I/O context
604 * @buffer: where to get data
605 * @len: number of bytes to write
606 *
607 * Write @len bytes from @buffer to the I/O channel.
608 *
609 * Returns the number of bytes written
610 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000611static int
Owen Taylor3473f882001-02-23 17:55:21 +0000612xmlFdWrite (void * context, const char * buffer, int len) {
Daniel Veillard9b693b42005-10-28 14:54:17 +0000613 int ret = 0;
Daniel Veillard05d987b2003-10-08 11:54:57 +0000614
Daniel Veillard9b693b42005-10-28 14:54:17 +0000615 if (len > 0) {
616 ret = write((int) (long) context, &buffer[0], len);
617 if (ret < 0) xmlIOErr(0, "write()");
618 }
Daniel Veillard05d987b2003-10-08 11:54:57 +0000619 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000620}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000621#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000622
623/**
624 * xmlFdClose:
625 * @context: the I/O context
626 *
627 * Close an I/O channel
Daniel Veillardf012a642001-07-23 19:10:52 +0000628 *
629 * Returns 0 in case of success and error code otherwise
Owen Taylor3473f882001-02-23 17:55:21 +0000630 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000631static int
Owen Taylor3473f882001-02-23 17:55:21 +0000632xmlFdClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000633 int ret;
634 ret = close((int) (long) context);
635 if (ret < 0) xmlIOErr(0, "close()");
636 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000637}
638
639/**
640 * xmlFileMatch:
641 * @filename: the URI for matching
642 *
643 * input from FILE *
644 *
645 * Returns 1 if matches, 0 otherwise
646 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000647int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000648xmlFileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000649 return(1);
650}
651
652/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000653 * xmlFileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +0000654 * @filename: the URI for matching
655 *
656 * input from FILE *, supports compressed input
657 * if @filename is " " then the standard input is used
658 *
659 * Returns an I/O context or NULL in case of error
660 */
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000661static void *
662xmlFileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +0000663 const char *path = NULL;
664 FILE *fd;
665
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000666 if (filename == NULL)
667 return(NULL);
668
Owen Taylor3473f882001-02-23 17:55:21 +0000669 if (!strcmp(filename, "-")) {
670 fd = stdin;
671 return((void *) fd);
672 }
673
Daniel Veillardf4862f02002-09-10 11:13:43 +0000674 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000675#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000676 path = &filename[17];
677#else
Owen Taylor3473f882001-02-23 17:55:21 +0000678 path = &filename[16];
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000679#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000680 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000681#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000682 path = &filename[8];
683#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000684 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000685#endif
686 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000687 path = filename;
688
689 if (path == NULL)
690 return(NULL);
691 if (!xmlCheckFilename(path))
692 return(NULL);
693
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000694#if defined(WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
Owen Taylor3473f882001-02-23 17:55:21 +0000695 fd = fopen(path, "rb");
696#else
697 fd = fopen(path, "r");
698#endif /* WIN32 */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000699 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +0000700 return((void *) fd);
701}
702
703/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000704 * xmlFileOpen:
705 * @filename: the URI for matching
706 *
707 * Wrapper around xmlFileOpen_real that try it with an unescaped
708 * version of @filename, if this fails fallback to @filename
Daniel Veillard71531f32003-02-05 13:19:53 +0000709 *
710 * Returns a handler or NULL in case or failure
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000711 */
712void *
713xmlFileOpen (const char *filename) {
714 char *unescaped;
715 void *retval;
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000716
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000717 unescaped = xmlURIUnescapeString(filename, 0, NULL);
718 if (unescaped != NULL) {
719 retval = xmlFileOpen_real(unescaped);
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000720 xmlFree(unescaped);
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000721 } else {
722 retval = xmlFileOpen_real(filename);
723 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000724 return retval;
725}
726
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000727#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000728/**
Owen Taylor3473f882001-02-23 17:55:21 +0000729 * xmlFileOpenW:
730 * @filename: the URI for matching
731 *
732 * output to from FILE *,
733 * if @filename is "-" then the standard output is used
734 *
735 * Returns an I/O context or NULL in case of error
736 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000737static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000738xmlFileOpenW (const char *filename) {
739 const char *path = NULL;
740 FILE *fd;
741
742 if (!strcmp(filename, "-")) {
743 fd = stdout;
744 return((void *) fd);
745 }
746
Daniel Veillardf4862f02002-09-10 11:13:43 +0000747 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000748#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000749 path = &filename[17];
750#else
Owen Taylor3473f882001-02-23 17:55:21 +0000751 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000752#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000753 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000754#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000755 path = &filename[8];
756#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000757 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000758#endif
759 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000760 path = filename;
761
762 if (path == NULL)
763 return(NULL);
764
Daniel Veillardcbbd78d2003-07-20 15:21:30 +0000765 fd = fopen(path, "wb");
Daniel Veillard05d987b2003-10-08 11:54:57 +0000766 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +0000767 return((void *) fd);
768}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000769#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000770
771/**
772 * xmlFileRead:
773 * @context: the I/O context
774 * @buffer: where to drop data
775 * @len: number of bytes to write
776 *
777 * Read @len bytes to @buffer from the I/O channel.
778 *
Daniel Veillardce682bc2004-11-05 17:22:25 +0000779 * Returns the number of bytes written or < 0 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +0000780 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000781int
Owen Taylor3473f882001-02-23 17:55:21 +0000782xmlFileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000783 int ret;
Daniel Veillardce682bc2004-11-05 17:22:25 +0000784 if ((context == NULL) || (buffer == NULL))
785 return(-1);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000786 ret = fread(&buffer[0], 1, len, (FILE *) context);
787 if (ret < 0) xmlIOErr(0, "fread()");
788 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000789}
790
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000791#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000792/**
793 * xmlFileWrite:
794 * @context: the I/O context
795 * @buffer: where to drop data
796 * @len: number of bytes to write
797 *
798 * Write @len bytes from @buffer to the I/O channel.
799 *
800 * Returns the number of bytes written
801 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000802static int
Owen Taylor3473f882001-02-23 17:55:21 +0000803xmlFileWrite (void * context, const char * buffer, int len) {
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000804 int items;
805
Daniel Veillardce682bc2004-11-05 17:22:25 +0000806 if ((context == NULL) || (buffer == NULL))
807 return(-1);
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000808 items = fwrite(&buffer[0], len, 1, (FILE *) context);
Daniel Veillard97bf4d02003-10-08 18:58:28 +0000809 if ((items == 0) && (ferror((FILE *) context))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000810 xmlIOErr(0, "fwrite()");
Daniel Veillard97bf4d02003-10-08 18:58:28 +0000811 return(-1);
812 }
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000813 return(items * len);
Owen Taylor3473f882001-02-23 17:55:21 +0000814}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000815#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000816
817/**
818 * xmlFileClose:
819 * @context: the I/O context
820 *
821 * Close an I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000822 *
823 * Returns 0 or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +0000824 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000825int
Owen Taylor3473f882001-02-23 17:55:21 +0000826xmlFileClose (void * context) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000827 FILE *fil;
Daniel Veillard05d987b2003-10-08 11:54:57 +0000828 int ret;
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000829
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000830 if (context == NULL)
831 return(-1);
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000832 fil = (FILE *) context;
Daniel Veillard500a1de2004-03-22 15:22:58 +0000833 if ((fil == stdout) || (fil == stderr)) {
834 ret = fflush(fil);
835 if (ret < 0)
836 xmlIOErr(0, "fflush()");
837 return(0);
838 }
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000839 if (fil == stdin)
840 return(0);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000841 ret = ( fclose((FILE *) context) == EOF ) ? -1 : 0;
842 if (ret < 0)
843 xmlIOErr(0, "fclose()");
844 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000845}
846
847/**
848 * xmlFileFlush:
849 * @context: the I/O context
850 *
851 * Flush an I/O channel
852 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000853static int
Owen Taylor3473f882001-02-23 17:55:21 +0000854xmlFileFlush (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000855 int ret;
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000856
857 if (context == NULL)
858 return(-1);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000859 ret = ( fflush((FILE *) context) == EOF ) ? -1 : 0;
860 if (ret < 0)
861 xmlIOErr(0, "fflush()");
862 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000863}
864
Daniel Veillard9a00fd22005-11-09 08:56:26 +0000865#ifdef LIBXML_OUTPUT_ENABLED
866/**
867 * xmlBufferWrite:
868 * @context: the xmlBuffer
869 * @buffer: the data to write
870 * @len: number of bytes to write
871 *
872 * Write @len bytes from @buffer to the xml buffer
873 *
874 * Returns the number of bytes written
875 */
876static int
877xmlBufferWrite (void * context, const char * buffer, int len) {
878 int ret;
879
880 ret = xmlBufferAdd((xmlBufferPtr) context, (const xmlChar *) buffer, len);
881 if (ret != 0)
882 return(-1);
883 return(len);
884}
Daniel Veillard9a00fd22005-11-09 08:56:26 +0000885#endif
886
Owen Taylor3473f882001-02-23 17:55:21 +0000887#ifdef HAVE_ZLIB_H
888/************************************************************************
889 * *
890 * I/O for compressed file accesses *
891 * *
892 ************************************************************************/
893/**
894 * xmlGzfileMatch:
895 * @filename: the URI for matching
896 *
897 * input from compressed file test
898 *
899 * Returns 1 if matches, 0 otherwise
900 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000901static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000902xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000903 return(1);
904}
905
906/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000907 * xmlGzfileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +0000908 * @filename: the URI for matching
909 *
910 * input from compressed file open
911 * if @filename is " " then the standard input is used
912 *
913 * Returns an I/O context or NULL in case of error
914 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000915static void *
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000916xmlGzfileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +0000917 const char *path = NULL;
918 gzFile fd;
919
920 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000921 fd = gzdopen(dup(0), "rb");
Owen Taylor3473f882001-02-23 17:55:21 +0000922 return((void *) fd);
923 }
924
Daniel Veillardf4862f02002-09-10 11:13:43 +0000925 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000926#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000927 path = &filename[17];
928#else
Owen Taylor3473f882001-02-23 17:55:21 +0000929 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000930#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000931 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000932#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000933 path = &filename[8];
934#else
Owen Taylor3473f882001-02-23 17:55:21 +0000935 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000936#endif
937 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000938 path = filename;
939
940 if (path == NULL)
941 return(NULL);
942 if (!xmlCheckFilename(path))
943 return(NULL);
944
945 fd = gzopen(path, "rb");
946 return((void *) fd);
947}
948
949/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000950 * xmlGzfileOpen:
951 * @filename: the URI for matching
952 *
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +0000953 * Wrapper around xmlGzfileOpen if the open fais, it will
954 * try to unescape @filename
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000955 */
956static void *
957xmlGzfileOpen (const char *filename) {
958 char *unescaped;
959 void *retval;
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +0000960
961 retval = xmlGzfileOpen_real(filename);
962 if (retval == NULL) {
963 unescaped = xmlURIUnescapeString(filename, 0, NULL);
964 if (unescaped != NULL) {
965 retval = xmlGzfileOpen_real(unescaped);
966 }
967 xmlFree(unescaped);
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000968 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000969 return retval;
970}
971
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000972#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000973/**
Owen Taylor3473f882001-02-23 17:55:21 +0000974 * xmlGzfileOpenW:
975 * @filename: the URI for matching
976 * @compression: the compression factor (0 - 9 included)
977 *
978 * input from compressed file open
979 * if @filename is " " then the standard input is used
980 *
981 * Returns an I/O context or NULL in case of error
982 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000983static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000984xmlGzfileOpenW (const char *filename, int compression) {
985 const char *path = NULL;
986 char mode[15];
987 gzFile fd;
988
Aleksey Sanin49cc9752002-06-14 17:07:10 +0000989 snprintf(mode, sizeof(mode), "wb%d", compression);
Owen Taylor3473f882001-02-23 17:55:21 +0000990 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +0000991 fd = gzdopen(dup(1), mode);
Owen Taylor3473f882001-02-23 17:55:21 +0000992 return((void *) fd);
993 }
994
Daniel Veillardf4862f02002-09-10 11:13:43 +0000995 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000996#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000997 path = &filename[17];
998#else
Owen Taylor3473f882001-02-23 17:55:21 +0000999 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00001000#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001001 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001002#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +00001003 path = &filename[8];
1004#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +00001005 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +00001006#endif
1007 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001008 path = filename;
1009
1010 if (path == NULL)
1011 return(NULL);
1012
1013 fd = gzopen(path, mode);
1014 return((void *) fd);
1015}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001016#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001017
1018/**
1019 * xmlGzfileRead:
1020 * @context: the I/O context
1021 * @buffer: where to drop data
1022 * @len: number of bytes to write
1023 *
1024 * Read @len bytes to @buffer from the compressed I/O channel.
1025 *
1026 * Returns the number of bytes written
1027 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001028static int
Owen Taylor3473f882001-02-23 17:55:21 +00001029xmlGzfileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001030 int ret;
1031
1032 ret = gzread((gzFile) context, &buffer[0], len);
1033 if (ret < 0) xmlIOErr(0, "gzread()");
1034 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001035}
1036
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001037#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001038/**
1039 * xmlGzfileWrite:
1040 * @context: the I/O context
1041 * @buffer: where to drop data
1042 * @len: number of bytes to write
1043 *
1044 * Write @len bytes from @buffer to the compressed I/O channel.
1045 *
1046 * Returns the number of bytes written
1047 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001048static int
Owen Taylor3473f882001-02-23 17:55:21 +00001049xmlGzfileWrite (void * context, const char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001050 int ret;
1051
1052 ret = gzwrite((gzFile) context, (char *) &buffer[0], len);
1053 if (ret < 0) xmlIOErr(0, "gzwrite()");
1054 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001055}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001056#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001057
1058/**
1059 * xmlGzfileClose:
1060 * @context: the I/O context
1061 *
1062 * Close a compressed I/O channel
1063 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001064static int
Owen Taylor3473f882001-02-23 17:55:21 +00001065xmlGzfileClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001066 int ret;
1067
1068 ret = (gzclose((gzFile) context) == Z_OK ) ? 0 : -1;
1069 if (ret < 0) xmlIOErr(0, "gzclose()");
1070 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001071}
1072#endif /* HAVE_ZLIB_H */
1073
1074#ifdef LIBXML_HTTP_ENABLED
1075/************************************************************************
1076 * *
1077 * I/O for HTTP file accesses *
1078 * *
1079 ************************************************************************/
Daniel Veillardf012a642001-07-23 19:10:52 +00001080
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001081#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001082typedef struct xmlIOHTTPWriteCtxt_
1083{
1084 int compression;
1085
1086 char * uri;
1087
1088 void * doc_buff;
1089
1090} xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr;
1091
1092#ifdef HAVE_ZLIB_H
1093
1094#define DFLT_WBITS ( -15 )
1095#define DFLT_MEM_LVL ( 8 )
1096#define GZ_MAGIC1 ( 0x1f )
1097#define GZ_MAGIC2 ( 0x8b )
1098#define LXML_ZLIB_OS_CODE ( 0x03 )
1099#define INIT_HTTP_BUFF_SIZE ( 32768 )
1100#define DFLT_ZLIB_RATIO ( 5 )
1101
1102/*
1103** Data structure and functions to work with sending compressed data
1104** via HTTP.
1105*/
1106
1107typedef struct xmlZMemBuff_
1108{
1109 unsigned long size;
1110 unsigned long crc;
1111
1112 unsigned char * zbuff;
1113 z_stream zctrl;
1114
1115} xmlZMemBuff, *xmlZMemBuffPtr;
1116
1117/**
1118 * append_reverse_ulong
1119 * @buff: Compressed memory buffer
1120 * @data: Unsigned long to append
1121 *
1122 * Append a unsigned long in reverse byte order to the end of the
1123 * memory buffer.
1124 */
1125static void
1126append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) {
1127
1128 int idx;
1129
1130 if ( buff == NULL )
1131 return;
1132
1133 /*
1134 ** This is plagiarized from putLong in gzio.c (zlib source) where
1135 ** the number "4" is hardcoded. If zlib is ever patched to
1136 ** support 64 bit file sizes, this code would need to be patched
1137 ** as well.
1138 */
1139
1140 for ( idx = 0; idx < 4; idx++ ) {
1141 *buff->zctrl.next_out = ( data & 0xff );
1142 data >>= 8;
1143 buff->zctrl.next_out++;
1144 }
1145
1146 return;
1147}
1148
1149/**
1150 *
1151 * xmlFreeZMemBuff
1152 * @buff: The memory buffer context to clear
1153 *
1154 * Release all the resources associated with the compressed memory buffer.
1155 */
1156static void
1157xmlFreeZMemBuff( xmlZMemBuffPtr buff ) {
William M. Brack78637da2003-07-31 14:47:38 +00001158
1159#ifdef DEBUG_HTTP
Daniel Veillardf012a642001-07-23 19:10:52 +00001160 int z_err;
William M. Brack78637da2003-07-31 14:47:38 +00001161#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001162
1163 if ( buff == NULL )
1164 return;
1165
1166 xmlFree( buff->zbuff );
Daniel Veillardf012a642001-07-23 19:10:52 +00001167#ifdef DEBUG_HTTP
William M. Brack78637da2003-07-31 14:47:38 +00001168 z_err = deflateEnd( &buff->zctrl );
Daniel Veillardf012a642001-07-23 19:10:52 +00001169 if ( z_err != Z_OK )
1170 xmlGenericError( xmlGenericErrorContext,
1171 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
1172 z_err );
William M. Brack78637da2003-07-31 14:47:38 +00001173#else
1174 deflateEnd( &buff->zctrl );
William M. Brack779af002003-08-01 15:55:39 +00001175#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001176
1177 xmlFree( buff );
1178 return;
1179}
1180
1181/**
1182 * xmlCreateZMemBuff
1183 *@compression: Compression value to use
1184 *
1185 * Create a memory buffer to hold the compressed XML document. The
1186 * compressed document in memory will end up being identical to what
1187 * would be created if gzopen/gzwrite/gzclose were being used to
1188 * write the document to disk. The code for the header/trailer data to
1189 * the compression is plagiarized from the zlib source files.
1190 */
1191static void *
1192xmlCreateZMemBuff( int compression ) {
1193
1194 int z_err;
1195 int hdr_lgth;
1196 xmlZMemBuffPtr buff = NULL;
1197
1198 if ( ( compression < 1 ) || ( compression > 9 ) )
1199 return ( NULL );
1200
1201 /* Create the control and data areas */
1202
1203 buff = xmlMalloc( sizeof( xmlZMemBuff ) );
1204 if ( buff == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001205 xmlIOErrMemory("creating buffer context");
Daniel Veillardf012a642001-07-23 19:10:52 +00001206 return ( NULL );
1207 }
1208
1209 (void)memset( buff, 0, sizeof( xmlZMemBuff ) );
1210 buff->size = INIT_HTTP_BUFF_SIZE;
1211 buff->zbuff = xmlMalloc( buff->size );
1212 if ( buff->zbuff == NULL ) {
1213 xmlFreeZMemBuff( buff );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001214 xmlIOErrMemory("creating buffer");
Daniel Veillardf012a642001-07-23 19:10:52 +00001215 return ( NULL );
1216 }
1217
1218 z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
1219 DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
1220 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001221 xmlChar msg[500];
Daniel Veillardf012a642001-07-23 19:10:52 +00001222 xmlFreeZMemBuff( buff );
1223 buff = NULL;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001224 xmlStrPrintf(msg, 500,
1225 (const xmlChar *) "xmlCreateZMemBuff: %s %d\n",
1226 "Error initializing compression context. ZLIB error:",
1227 z_err );
1228 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001229 return ( NULL );
1230 }
1231
1232 /* Set the header data. The CRC will be needed for the trailer */
Daniel Veillard24505b02005-07-28 23:49:35 +00001233 buff->crc = crc32( 0L, NULL, 0 );
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001234 hdr_lgth = snprintf( (char *)buff->zbuff, buff->size,
1235 "%c%c%c%c%c%c%c%c%c%c",
Daniel Veillardf012a642001-07-23 19:10:52 +00001236 GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED,
1237 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE );
1238 buff->zctrl.next_out = buff->zbuff + hdr_lgth;
1239 buff->zctrl.avail_out = buff->size - hdr_lgth;
1240
1241 return ( buff );
1242}
1243
1244/**
1245 * xmlZMemBuffExtend
1246 * @buff: Buffer used to compress and consolidate data.
1247 * @ext_amt: Number of bytes to extend the buffer.
1248 *
1249 * Extend the internal buffer used to store the compressed data by the
1250 * specified amount.
1251 *
1252 * Returns 0 on success or -1 on failure to extend the buffer. On failure
1253 * the original buffer still exists at the original size.
1254 */
1255static int
1256xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) {
1257
1258 int rc = -1;
1259 size_t new_size;
1260 size_t cur_used;
1261
1262 unsigned char * tmp_ptr = NULL;
1263
1264 if ( buff == NULL )
1265 return ( -1 );
1266
1267 else if ( ext_amt == 0 )
1268 return ( 0 );
1269
1270 cur_used = buff->zctrl.next_out - buff->zbuff;
1271 new_size = buff->size + ext_amt;
1272
1273#ifdef DEBUG_HTTP
1274 if ( cur_used > new_size )
1275 xmlGenericError( xmlGenericErrorContext,
1276 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
1277 "Buffer overwrite detected during compressed memory",
1278 "buffer extension. Overflowed by",
1279 (cur_used - new_size ) );
1280#endif
1281
1282 tmp_ptr = xmlRealloc( buff->zbuff, new_size );
1283 if ( tmp_ptr != NULL ) {
1284 rc = 0;
1285 buff->size = new_size;
1286 buff->zbuff = tmp_ptr;
1287 buff->zctrl.next_out = tmp_ptr + cur_used;
1288 buff->zctrl.avail_out = new_size - cur_used;
1289 }
1290 else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001291 xmlChar msg[500];
1292 xmlStrPrintf(msg, 500,
1293 (const xmlChar *) "xmlZMemBuffExtend: %s %lu bytes.\n",
1294 "Allocation failure extending output buffer to",
1295 new_size );
1296 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001297 }
1298
1299 return ( rc );
1300}
1301
1302/**
1303 * xmlZMemBuffAppend
1304 * @buff: Buffer used to compress and consolidate data
1305 * @src: Uncompressed source content to append to buffer
1306 * @len: Length of source data to append to buffer
1307 *
1308 * Compress and append data to the internal buffer. The data buffer
1309 * will be expanded if needed to store the additional data.
1310 *
1311 * Returns the number of bytes appended to the buffer or -1 on error.
1312 */
1313static int
1314xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) {
1315
1316 int z_err;
1317 size_t min_accept;
1318
1319 if ( ( buff == NULL ) || ( src == NULL ) )
1320 return ( -1 );
1321
1322 buff->zctrl.avail_in = len;
1323 buff->zctrl.next_in = (unsigned char *)src;
1324 while ( buff->zctrl.avail_in > 0 ) {
1325 /*
1326 ** Extend the buffer prior to deflate call if a reasonable amount
1327 ** of output buffer space is not available.
1328 */
1329 min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO;
1330 if ( buff->zctrl.avail_out <= min_accept ) {
1331 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1332 return ( -1 );
1333 }
1334
1335 z_err = deflate( &buff->zctrl, Z_NO_FLUSH );
1336 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001337 xmlChar msg[500];
1338 xmlStrPrintf(msg, 500,
1339 (const xmlChar *) "xmlZMemBuffAppend: %s %d %s - %d",
Daniel Veillardf012a642001-07-23 19:10:52 +00001340 "Compression error while appending",
1341 len, "bytes to buffer. ZLIB error", z_err );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001342 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001343 return ( -1 );
1344 }
1345 }
1346
1347 buff->crc = crc32( buff->crc, (unsigned char *)src, len );
1348
1349 return ( len );
1350}
1351
1352/**
1353 * xmlZMemBuffGetContent
1354 * @buff: Compressed memory content buffer
1355 * @data_ref: Pointer reference to point to compressed content
1356 *
1357 * Flushes the compression buffers, appends gzip file trailers and
1358 * returns the compressed content and length of the compressed data.
1359 * NOTE: The gzip trailer code here is plagiarized from zlib source.
1360 *
1361 * Returns the length of the compressed data or -1 on error.
1362 */
1363static int
1364xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) {
1365
1366 int zlgth = -1;
1367 int z_err;
1368
1369 if ( ( buff == NULL ) || ( data_ref == NULL ) )
1370 return ( -1 );
1371
1372 /* Need to loop until compression output buffers are flushed */
1373
1374 do
1375 {
1376 z_err = deflate( &buff->zctrl, Z_FINISH );
1377 if ( z_err == Z_OK ) {
1378 /* In this case Z_OK means more buffer space needed */
1379
1380 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1381 return ( -1 );
1382 }
1383 }
1384 while ( z_err == Z_OK );
1385
1386 /* If the compression state is not Z_STREAM_END, some error occurred */
1387
1388 if ( z_err == Z_STREAM_END ) {
1389
1390 /* Need to append the gzip data trailer */
1391
1392 if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) {
1393 if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 )
1394 return ( -1 );
1395 }
1396
1397 /*
1398 ** For whatever reason, the CRC and length data are pushed out
1399 ** in reverse byte order. So a memcpy can't be used here.
1400 */
1401
1402 append_reverse_ulong( buff, buff->crc );
1403 append_reverse_ulong( buff, buff->zctrl.total_in );
1404
1405 zlgth = buff->zctrl.next_out - buff->zbuff;
1406 *data_ref = (char *)buff->zbuff;
1407 }
1408
Daniel Veillard05d987b2003-10-08 11:54:57 +00001409 else {
1410 xmlChar msg[500];
1411 xmlStrPrintf(msg, 500,
1412 (const xmlChar *) "xmlZMemBuffGetContent: %s - %d\n",
1413 "Error flushing zlib buffers. Error code", z_err );
1414 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1415 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001416
1417 return ( zlgth );
1418}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001419#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001420#endif /* HAVE_ZLIB_H */
1421
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001422#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001423/**
1424 * xmlFreeHTTPWriteCtxt
1425 * @ctxt: Context to cleanup
1426 *
1427 * Free allocated memory and reclaim system resources.
1428 *
1429 * No return value.
1430 */
1431static void
1432xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt )
1433{
1434 if ( ctxt->uri != NULL )
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001435 xmlFree( ctxt->uri );
Daniel Veillardf012a642001-07-23 19:10:52 +00001436
1437 if ( ctxt->doc_buff != NULL ) {
1438
1439#ifdef HAVE_ZLIB_H
1440 if ( ctxt->compression > 0 ) {
1441 xmlFreeZMemBuff( ctxt->doc_buff );
1442 }
1443 else
1444#endif
1445 {
1446 xmlOutputBufferClose( ctxt->doc_buff );
1447 }
1448 }
1449
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001450 xmlFree( ctxt );
Daniel Veillardf012a642001-07-23 19:10:52 +00001451 return;
1452}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001453#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001454
1455
Owen Taylor3473f882001-02-23 17:55:21 +00001456/**
1457 * xmlIOHTTPMatch:
1458 * @filename: the URI for matching
1459 *
1460 * check if the URI matches an HTTP one
1461 *
1462 * Returns 1 if matches, 0 otherwise
1463 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001464int
Owen Taylor3473f882001-02-23 17:55:21 +00001465xmlIOHTTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001466 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "http://", 7))
Owen Taylor3473f882001-02-23 17:55:21 +00001467 return(1);
1468 return(0);
1469}
1470
1471/**
1472 * xmlIOHTTPOpen:
1473 * @filename: the URI for matching
1474 *
1475 * open an HTTP I/O channel
1476 *
1477 * Returns an I/O context or NULL in case of error
1478 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001479void *
Owen Taylor3473f882001-02-23 17:55:21 +00001480xmlIOHTTPOpen (const char *filename) {
1481 return(xmlNanoHTTPOpen(filename, NULL));
1482}
1483
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001484#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001485/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001486 * xmlIOHTTPOpenW:
Daniel Veillardf012a642001-07-23 19:10:52 +00001487 * @post_uri: The destination URI for the document
1488 * @compression: The compression desired for the document.
1489 *
1490 * Open a temporary buffer to collect the document for a subsequent HTTP POST
1491 * request. Non-static as is called from the output buffer creation routine.
1492 *
1493 * Returns an I/O context or NULL in case of error.
1494 */
1495
1496void *
Daniel Veillard572577e2002-01-18 16:23:55 +00001497xmlIOHTTPOpenW(const char *post_uri, int compression)
1498{
Daniel Veillardf012a642001-07-23 19:10:52 +00001499
Daniel Veillard572577e2002-01-18 16:23:55 +00001500 xmlIOHTTPWriteCtxtPtr ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001501
Daniel Veillard572577e2002-01-18 16:23:55 +00001502 if (post_uri == NULL)
1503 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001504
Daniel Veillard572577e2002-01-18 16:23:55 +00001505 ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt));
1506 if (ctxt == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001507 xmlIOErrMemory("creating HTTP output context");
Daniel Veillard572577e2002-01-18 16:23:55 +00001508 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001509 }
1510
Daniel Veillard572577e2002-01-18 16:23:55 +00001511 (void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt));
Daniel Veillardf012a642001-07-23 19:10:52 +00001512
Daniel Veillard572577e2002-01-18 16:23:55 +00001513 ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri);
1514 if (ctxt->uri == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001515 xmlIOErrMemory("copying URI");
Daniel Veillard572577e2002-01-18 16:23:55 +00001516 xmlFreeHTTPWriteCtxt(ctxt);
1517 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001518 }
1519
1520 /*
Daniel Veillard572577e2002-01-18 16:23:55 +00001521 * ** Since the document length is required for an HTTP post,
1522 * ** need to put the document into a buffer. A memory buffer
1523 * ** is being used to avoid pushing the data to disk and back.
1524 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001525
1526#ifdef HAVE_ZLIB_H
Daniel Veillard572577e2002-01-18 16:23:55 +00001527 if ((compression > 0) && (compression <= 9)) {
1528
1529 ctxt->compression = compression;
1530 ctxt->doc_buff = xmlCreateZMemBuff(compression);
1531 } else
Daniel Veillardf012a642001-07-23 19:10:52 +00001532#endif
1533 {
Daniel Veillard572577e2002-01-18 16:23:55 +00001534 /* Any character conversions should have been done before this */
Daniel Veillardf012a642001-07-23 19:10:52 +00001535
Daniel Veillard572577e2002-01-18 16:23:55 +00001536 ctxt->doc_buff = xmlAllocOutputBuffer(NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001537 }
1538
Daniel Veillard572577e2002-01-18 16:23:55 +00001539 if (ctxt->doc_buff == NULL) {
1540 xmlFreeHTTPWriteCtxt(ctxt);
1541 ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001542 }
1543
Daniel Veillard572577e2002-01-18 16:23:55 +00001544 return (ctxt);
Daniel Veillardf012a642001-07-23 19:10:52 +00001545}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001546#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001547
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001548#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001549/**
1550 * xmlIOHTTPDfltOpenW
1551 * @post_uri: The destination URI for this document.
1552 *
1553 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
1554 * HTTP post command. This function should generally not be used as
1555 * the open callback is short circuited in xmlOutputBufferCreateFile.
1556 *
1557 * Returns a pointer to the new IO context.
1558 */
1559static void *
1560xmlIOHTTPDfltOpenW( const char * post_uri ) {
1561 return ( xmlIOHTTPOpenW( post_uri, 0 ) );
1562}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001563#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001564
1565/**
Owen Taylor3473f882001-02-23 17:55:21 +00001566 * xmlIOHTTPRead:
1567 * @context: the I/O context
1568 * @buffer: where to drop data
1569 * @len: number of bytes to write
1570 *
1571 * Read @len bytes to @buffer from the I/O channel.
1572 *
1573 * Returns the number of bytes written
1574 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001575int
Owen Taylor3473f882001-02-23 17:55:21 +00001576xmlIOHTTPRead(void * context, char * buffer, int len) {
Daniel Veillard5ea30d72004-11-08 11:54:28 +00001577 if ((buffer == NULL) || (len < 0)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001578 return(xmlNanoHTTPRead(context, &buffer[0], len));
1579}
1580
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001581#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001582/**
Daniel Veillardf012a642001-07-23 19:10:52 +00001583 * xmlIOHTTPWrite
1584 * @context: previously opened writing context
1585 * @buffer: data to output to temporary buffer
1586 * @len: bytes to output
1587 *
1588 * Collect data from memory buffer into a temporary file for later
1589 * processing.
1590 *
1591 * Returns number of bytes written.
1592 */
1593
1594static int
1595xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
1596
1597 xmlIOHTTPWriteCtxtPtr ctxt = context;
1598
1599 if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
1600 return ( -1 );
1601
1602 if ( len > 0 ) {
1603
1604 /* Use gzwrite or fwrite as previously setup in the open call */
1605
1606#ifdef HAVE_ZLIB_H
1607 if ( ctxt->compression > 0 )
1608 len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len );
1609
1610 else
1611#endif
1612 len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
1613
1614 if ( len < 0 ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001615 xmlChar msg[500];
1616 xmlStrPrintf(msg, 500,
1617 (const xmlChar *) "xmlIOHTTPWrite: %s\n%s '%s'.\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001618 "Error appending to internal buffer.",
1619 "Error sending document to URI",
1620 ctxt->uri );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001621 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001622 }
1623 }
1624
1625 return ( len );
1626}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001627#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001628
1629
1630/**
Owen Taylor3473f882001-02-23 17:55:21 +00001631 * xmlIOHTTPClose:
1632 * @context: the I/O context
1633 *
1634 * Close an HTTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001635 *
1636 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00001637 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001638int
Owen Taylor3473f882001-02-23 17:55:21 +00001639xmlIOHTTPClose (void * context) {
1640 xmlNanoHTTPClose(context);
Daniel Veillardf012a642001-07-23 19:10:52 +00001641 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001642}
Daniel Veillardf012a642001-07-23 19:10:52 +00001643
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001644#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001645/**
1646 * xmlIOHTTCloseWrite
1647 * @context: The I/O context
1648 * @http_mthd: The HTTP method to be used when sending the data
1649 *
1650 * Close the transmit HTTP I/O channel and actually send the data.
1651 */
1652static int
1653xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
1654
1655 int close_rc = -1;
1656 int http_rtn = 0;
1657 int content_lgth = 0;
1658 xmlIOHTTPWriteCtxtPtr ctxt = context;
1659
1660 char * http_content = NULL;
1661 char * content_encoding = NULL;
1662 char * content_type = (char *) "text/xml";
1663 void * http_ctxt = NULL;
1664
1665 if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
1666 return ( -1 );
1667
1668 /* Retrieve the content from the appropriate buffer */
1669
1670#ifdef HAVE_ZLIB_H
1671
1672 if ( ctxt->compression > 0 ) {
1673 content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
1674 content_encoding = (char *) "Content-Encoding: gzip";
1675 }
1676 else
1677#endif
1678 {
1679 /* Pull the data out of the memory output buffer */
1680
1681 xmlOutputBufferPtr dctxt = ctxt->doc_buff;
1682 http_content = (char *)dctxt->buffer->content;
1683 content_lgth = dctxt->buffer->use;
1684 }
1685
1686 if ( http_content == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001687 xmlChar msg[500];
1688 xmlStrPrintf(msg, 500,
1689 (const xmlChar *) "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
1690 "Error retrieving content.\nUnable to",
1691 http_mthd, "data to URI", ctxt->uri );
1692 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001693 }
1694
1695 else {
1696
1697 http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
1698 &content_type, content_encoding,
1699 content_lgth );
1700
1701 if ( http_ctxt != NULL ) {
1702#ifdef DEBUG_HTTP
1703 /* If testing/debugging - dump reply with request content */
1704
1705 FILE * tst_file = NULL;
1706 char buffer[ 4096 ];
1707 char * dump_name = NULL;
1708 int avail;
1709
1710 xmlGenericError( xmlGenericErrorContext,
1711 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
1712 http_mthd, ctxt->uri,
1713 xmlNanoHTTPReturnCode( http_ctxt ) );
1714
1715 /*
1716 ** Since either content or reply may be gzipped,
1717 ** dump them to separate files instead of the
1718 ** standard error context.
1719 */
1720
1721 dump_name = tempnam( NULL, "lxml" );
1722 if ( dump_name != NULL ) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001723 (void)snprintf( buffer, sizeof(buffer), "%s.content", dump_name );
Daniel Veillardf012a642001-07-23 19:10:52 +00001724
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00001725 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00001726 if ( tst_file != NULL ) {
1727 xmlGenericError( xmlGenericErrorContext,
1728 "Transmitted content saved in file: %s\n", buffer );
1729
1730 fwrite( http_content, sizeof( char ),
1731 content_lgth, tst_file );
1732 fclose( tst_file );
1733 }
1734
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001735 (void)snprintf( buffer, sizeof(buffer), "%s.reply", dump_name );
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00001736 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00001737 if ( tst_file != NULL ) {
1738 xmlGenericError( xmlGenericErrorContext,
1739 "Reply content saved in file: %s\n", buffer );
1740
1741
1742 while ( (avail = xmlNanoHTTPRead( http_ctxt,
1743 buffer, sizeof( buffer ) )) > 0 ) {
1744
1745 fwrite( buffer, sizeof( char ), avail, tst_file );
1746 }
1747
1748 fclose( tst_file );
1749 }
1750
1751 free( dump_name );
1752 }
1753#endif /* DEBUG_HTTP */
1754
1755 http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
1756 if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
1757 close_rc = 0;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001758 else {
1759 xmlChar msg[500];
1760 xmlStrPrintf(msg, 500,
1761 (const xmlChar *) "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001762 http_mthd, content_lgth,
1763 "bytes to URI", ctxt->uri,
1764 "failed. HTTP return code:", http_rtn );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001765 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1766 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001767
1768 xmlNanoHTTPClose( http_ctxt );
1769 xmlFree( content_type );
1770 }
1771 }
1772
1773 /* Final cleanups */
1774
1775 xmlFreeHTTPWriteCtxt( ctxt );
1776
1777 return ( close_rc );
1778}
1779
1780/**
1781 * xmlIOHTTPClosePut
1782 *
1783 * @context: The I/O context
1784 *
1785 * Close the transmit HTTP I/O channel and actually send data using a PUT
1786 * HTTP method.
1787 */
1788static int
1789xmlIOHTTPClosePut( void * ctxt ) {
1790 return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
1791}
1792
1793
1794/**
1795 * xmlIOHTTPClosePost
1796 *
1797 * @context: The I/O context
1798 *
1799 * Close the transmit HTTP I/O channel and actually send data using a POST
1800 * HTTP method.
1801 */
1802static int
1803xmlIOHTTPClosePost( void * ctxt ) {
1804 return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
1805}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001806#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001807
Owen Taylor3473f882001-02-23 17:55:21 +00001808#endif /* LIBXML_HTTP_ENABLED */
1809
1810#ifdef LIBXML_FTP_ENABLED
1811/************************************************************************
1812 * *
1813 * I/O for FTP file accesses *
1814 * *
1815 ************************************************************************/
1816/**
1817 * xmlIOFTPMatch:
1818 * @filename: the URI for matching
1819 *
1820 * check if the URI matches an FTP one
1821 *
1822 * Returns 1 if matches, 0 otherwise
1823 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001824int
Owen Taylor3473f882001-02-23 17:55:21 +00001825xmlIOFTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001826 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "ftp://", 6))
Owen Taylor3473f882001-02-23 17:55:21 +00001827 return(1);
1828 return(0);
1829}
1830
1831/**
1832 * xmlIOFTPOpen:
1833 * @filename: the URI for matching
1834 *
1835 * open an FTP I/O channel
1836 *
1837 * Returns an I/O context or NULL in case of error
1838 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001839void *
Owen Taylor3473f882001-02-23 17:55:21 +00001840xmlIOFTPOpen (const char *filename) {
1841 return(xmlNanoFTPOpen(filename));
1842}
1843
1844/**
1845 * xmlIOFTPRead:
1846 * @context: the I/O context
1847 * @buffer: where to drop data
1848 * @len: number of bytes to write
1849 *
1850 * Read @len bytes to @buffer from the I/O channel.
1851 *
1852 * Returns the number of bytes written
1853 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001854int
Owen Taylor3473f882001-02-23 17:55:21 +00001855xmlIOFTPRead(void * context, char * buffer, int len) {
Daniel Veillard5ea30d72004-11-08 11:54:28 +00001856 if ((buffer == NULL) || (len < 0)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001857 return(xmlNanoFTPRead(context, &buffer[0], len));
1858}
1859
1860/**
1861 * xmlIOFTPClose:
1862 * @context: the I/O context
1863 *
1864 * Close an FTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001865 *
1866 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00001867 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001868int
Owen Taylor3473f882001-02-23 17:55:21 +00001869xmlIOFTPClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001870 return ( xmlNanoFTPClose(context) );
Owen Taylor3473f882001-02-23 17:55:21 +00001871}
1872#endif /* LIBXML_FTP_ENABLED */
1873
1874
1875/**
1876 * xmlRegisterInputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001877 * @matchFunc: the xmlInputMatchCallback
1878 * @openFunc: the xmlInputOpenCallback
1879 * @readFunc: the xmlInputReadCallback
1880 * @closeFunc: the xmlInputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001881 *
1882 * Register a new set of I/O callback for handling parser input.
1883 *
1884 * Returns the registered handler number or -1 in case of error
1885 */
1886int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001887xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
1888 xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
1889 xmlInputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001890 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
1891 return(-1);
1892 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001893 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
1894 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
1895 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
1896 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00001897 xmlInputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00001898 return(xmlInputCallbackNr++);
1899}
1900
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001901#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001902/**
1903 * xmlRegisterOutputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001904 * @matchFunc: the xmlOutputMatchCallback
1905 * @openFunc: the xmlOutputOpenCallback
1906 * @writeFunc: the xmlOutputWriteCallback
1907 * @closeFunc: the xmlOutputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00001908 *
1909 * Register a new set of I/O callback for handling output.
1910 *
1911 * Returns the registered handler number or -1 in case of error
1912 */
1913int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001914xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
1915 xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
1916 xmlOutputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00001917 if (xmlOutputCallbackNr >= MAX_INPUT_CALLBACK) {
1918 return(-1);
1919 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001920 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
1921 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
1922 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
1923 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00001924 xmlOutputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00001925 return(xmlOutputCallbackNr++);
1926}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001927#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001928
1929/**
1930 * xmlRegisterDefaultInputCallbacks:
1931 *
1932 * Registers the default compiled-in I/O handlers.
1933 */
1934void
Owen Taylor3473f882001-02-23 17:55:21 +00001935xmlRegisterDefaultInputCallbacks
Owen Taylor3473f882001-02-23 17:55:21 +00001936(void) {
1937 if (xmlInputCallbackInitialized)
1938 return;
1939
1940 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
1941 xmlFileRead, xmlFileClose);
1942#ifdef HAVE_ZLIB_H
1943 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1944 xmlGzfileRead, xmlGzfileClose);
1945#endif /* HAVE_ZLIB_H */
1946
1947#ifdef LIBXML_HTTP_ENABLED
1948 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
1949 xmlIOHTTPRead, xmlIOHTTPClose);
1950#endif /* LIBXML_HTTP_ENABLED */
1951
1952#ifdef LIBXML_FTP_ENABLED
1953 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1954 xmlIOFTPRead, xmlIOFTPClose);
1955#endif /* LIBXML_FTP_ENABLED */
1956 xmlInputCallbackInitialized = 1;
1957}
1958
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001959#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001960/**
1961 * xmlRegisterDefaultOutputCallbacks:
1962 *
1963 * Registers the default compiled-in I/O handlers.
1964 */
1965void
Owen Taylor3473f882001-02-23 17:55:21 +00001966xmlRegisterDefaultOutputCallbacks
Owen Taylor3473f882001-02-23 17:55:21 +00001967(void) {
1968 if (xmlOutputCallbackInitialized)
1969 return;
1970
1971 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
1972 xmlFileWrite, xmlFileClose);
Daniel Veillardf012a642001-07-23 19:10:52 +00001973
1974#ifdef LIBXML_HTTP_ENABLED
1975 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
1976 xmlIOHTTPWrite, xmlIOHTTPClosePut);
1977#endif
1978
Owen Taylor3473f882001-02-23 17:55:21 +00001979/*********************************
1980 No way a-priori to distinguish between gzipped files from
1981 uncompressed ones except opening if existing then closing
1982 and saving with same compression ratio ... a pain.
1983
1984#ifdef HAVE_ZLIB_H
1985 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
1986 xmlGzfileWrite, xmlGzfileClose);
1987#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001988
1989 Nor FTP PUT ....
1990#ifdef LIBXML_FTP_ENABLED
1991 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
1992 xmlIOFTPWrite, xmlIOFTPClose);
1993#endif
1994 **********************************/
1995 xmlOutputCallbackInitialized = 1;
1996}
1997
Daniel Veillardf012a642001-07-23 19:10:52 +00001998#ifdef LIBXML_HTTP_ENABLED
1999/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00002000 * xmlRegisterHTTPPostCallbacks:
Daniel Veillardf012a642001-07-23 19:10:52 +00002001 *
2002 * By default, libxml submits HTTP output requests using the "PUT" method.
2003 * Calling this method changes the HTTP output method to use the "POST"
2004 * method instead.
2005 *
2006 */
2007void
2008xmlRegisterHTTPPostCallbacks( void ) {
2009
2010 /* Register defaults if not done previously */
2011
2012 if ( xmlOutputCallbackInitialized == 0 )
2013 xmlRegisterDefaultOutputCallbacks( );
2014
2015 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
2016 xmlIOHTTPWrite, xmlIOHTTPClosePost);
2017 return;
2018}
2019#endif
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002020#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00002021
Owen Taylor3473f882001-02-23 17:55:21 +00002022/**
2023 * xmlAllocParserInputBuffer:
2024 * @enc: the charset encoding if known
2025 *
2026 * Create a buffered parser input for progressive parsing
2027 *
2028 * Returns the new parser input or NULL
2029 */
2030xmlParserInputBufferPtr
2031xmlAllocParserInputBuffer(xmlCharEncoding enc) {
2032 xmlParserInputBufferPtr ret;
2033
2034 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2035 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002036 xmlIOErrMemory("creating input buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00002037 return(NULL);
2038 }
2039 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002040 ret->buffer = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00002041 if (ret->buffer == NULL) {
2042 xmlFree(ret);
2043 return(NULL);
2044 }
2045 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
2046 ret->encoder = xmlGetCharEncodingHandler(enc);
2047 if (ret->encoder != NULL)
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002048 ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00002049 else
2050 ret->raw = NULL;
2051 ret->readcallback = NULL;
2052 ret->closecallback = NULL;
2053 ret->context = NULL;
William M. Brackc07329e2003-09-08 01:57:30 +00002054 ret->compressed = -1;
Daniel Veillard36711902004-02-11 13:25:26 +00002055 ret->rawconsumed = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002056
2057 return(ret);
2058}
2059
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002060#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002061/**
2062 * xmlAllocOutputBuffer:
2063 * @encoder: the encoding converter or NULL
2064 *
2065 * Create a buffered parser output
2066 *
2067 * Returns the new parser output or NULL
2068 */
2069xmlOutputBufferPtr
2070xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
2071 xmlOutputBufferPtr ret;
2072
2073 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
2074 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002075 xmlIOErrMemory("creating output buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00002076 return(NULL);
2077 }
2078 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
2079 ret->buffer = xmlBufferCreate();
2080 if (ret->buffer == NULL) {
2081 xmlFree(ret);
2082 return(NULL);
2083 }
2084 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
2085 ret->encoder = encoder;
2086 if (encoder != NULL) {
2087 ret->conv = xmlBufferCreateSize(4000);
2088 /*
2089 * This call is designed to initiate the encoder state
2090 */
2091 xmlCharEncOutFunc(encoder, ret->conv, NULL);
2092 } else
2093 ret->conv = NULL;
2094 ret->writecallback = NULL;
2095 ret->closecallback = NULL;
2096 ret->context = NULL;
2097 ret->written = 0;
2098
2099 return(ret);
2100}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002101#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002102
2103/**
2104 * xmlFreeParserInputBuffer:
2105 * @in: a buffered parser input
2106 *
2107 * Free up the memory used by a buffered parser input
2108 */
2109void
2110xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
Daniel Veillard8d8bf2c2003-09-17 19:36:25 +00002111 if (in == NULL) return;
2112
Owen Taylor3473f882001-02-23 17:55:21 +00002113 if (in->raw) {
2114 xmlBufferFree(in->raw);
2115 in->raw = NULL;
2116 }
2117 if (in->encoder != NULL) {
2118 xmlCharEncCloseFunc(in->encoder);
2119 }
2120 if (in->closecallback != NULL) {
2121 in->closecallback(in->context);
2122 }
2123 if (in->buffer != NULL) {
2124 xmlBufferFree(in->buffer);
2125 in->buffer = NULL;
2126 }
2127
Owen Taylor3473f882001-02-23 17:55:21 +00002128 xmlFree(in);
2129}
2130
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002131#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002132/**
2133 * xmlOutputBufferClose:
2134 * @out: a buffered output
2135 *
2136 * flushes and close the output I/O channel
2137 * and free up all the associated resources
2138 *
2139 * Returns the number of byte written or -1 in case of error.
2140 */
2141int
Daniel Veillard828ce832003-10-08 19:19:10 +00002142xmlOutputBufferClose(xmlOutputBufferPtr out)
2143{
Owen Taylor3473f882001-02-23 17:55:21 +00002144 int written;
Daniel Veillardf012a642001-07-23 19:10:52 +00002145 int err_rc = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002146
2147 if (out == NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002148 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002149 if (out->writecallback != NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002150 xmlOutputBufferFlush(out);
Owen Taylor3473f882001-02-23 17:55:21 +00002151 if (out->closecallback != NULL) {
Daniel Veillard828ce832003-10-08 19:19:10 +00002152 err_rc = out->closecallback(out->context);
Owen Taylor3473f882001-02-23 17:55:21 +00002153 }
2154 written = out->written;
2155 if (out->conv) {
2156 xmlBufferFree(out->conv);
Daniel Veillard828ce832003-10-08 19:19:10 +00002157 out->conv = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002158 }
2159 if (out->encoder != NULL) {
2160 xmlCharEncCloseFunc(out->encoder);
2161 }
2162 if (out->buffer != NULL) {
2163 xmlBufferFree(out->buffer);
Daniel Veillard828ce832003-10-08 19:19:10 +00002164 out->buffer = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002165 }
2166
Daniel Veillard828ce832003-10-08 19:19:10 +00002167 if (out->error)
2168 err_rc = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00002169 xmlFree(out);
Daniel Veillard828ce832003-10-08 19:19:10 +00002170 return ((err_rc == 0) ? written : err_rc);
Owen Taylor3473f882001-02-23 17:55:21 +00002171}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002172#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002173
Daniel Veillard1b243b42004-06-08 10:16:42 +00002174xmlParserInputBufferPtr
Daniel Veillard0335a842004-06-02 16:18:40 +00002175__xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002176 xmlParserInputBufferPtr ret;
Daniel Veillard388236f2001-07-08 18:35:48 +00002177 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002178 void *context = NULL;
2179
2180 if (xmlInputCallbackInitialized == 0)
2181 xmlRegisterDefaultInputCallbacks();
2182
2183 if (URI == NULL) return(NULL);
2184
2185 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002186 * Try to find one of the input accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002187 * Go in reverse to give precedence to user defined handlers.
Daniel Veillard388236f2001-07-08 18:35:48 +00002188 */
2189 if (context == NULL) {
2190 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
2191 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
2192 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002193 context = xmlInputCallbackTable[i].opencallback(URI);
Daniel Veillard847332a2003-10-18 11:29:40 +00002194 if (context != NULL) {
Daniel Veillard388236f2001-07-08 18:35:48 +00002195 break;
Daniel Veillard847332a2003-10-18 11:29:40 +00002196 }
Daniel Veillard388236f2001-07-08 18:35:48 +00002197 }
Owen Taylor3473f882001-02-23 17:55:21 +00002198 }
2199 }
2200 if (context == NULL) {
2201 return(NULL);
2202 }
2203
2204 /*
2205 * Allocate the Input buffer front-end.
2206 */
2207 ret = xmlAllocParserInputBuffer(enc);
2208 if (ret != NULL) {
2209 ret->context = context;
2210 ret->readcallback = xmlInputCallbackTable[i].readcallback;
2211 ret->closecallback = xmlInputCallbackTable[i].closecallback;
William M. Brackc07329e2003-09-08 01:57:30 +00002212#ifdef HAVE_ZLIB_H
William M. Brackc5cbf992003-10-29 22:15:13 +00002213 if ((xmlInputCallbackTable[i].opencallback == xmlGzfileOpen) &&
2214 (strcmp(URI, "-") != 0)) {
William M. Brackc07329e2003-09-08 01:57:30 +00002215 if (((z_stream *)context)->avail_in > 4) {
2216 char *cptr, buff4[4];
Daniel Veillard07cb8222003-09-10 10:51:05 +00002217 cptr = (char *) ((z_stream *)context)->next_in;
William M. Brackc07329e2003-09-08 01:57:30 +00002218 if (gzread(context, buff4, 4) == 4) {
2219 if (strncmp(buff4, cptr, 4) == 0)
2220 ret->compressed = 0;
2221 else
2222 ret->compressed = 1;
2223 gzrewind(context);
2224 }
2225 }
2226 }
2227#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002228 }
William M. Brack42331a92004-07-29 07:07:16 +00002229 else
2230 xmlInputCallbackTable[i].closecallback (context);
2231
Owen Taylor3473f882001-02-23 17:55:21 +00002232 return(ret);
2233}
2234
2235/**
Daniel Veillard0335a842004-06-02 16:18:40 +00002236 * xmlParserInputBufferCreateFilename:
Owen Taylor3473f882001-02-23 17:55:21 +00002237 * @URI: a C string containing the URI or filename
Daniel Veillard0335a842004-06-02 16:18:40 +00002238 * @enc: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002239 *
Daniel Veillard0335a842004-06-02 16:18:40 +00002240 * Create a buffered parser input for the progressive parsing of a file
2241 * If filename is "-' then we use stdin as the input.
Owen Taylor3473f882001-02-23 17:55:21 +00002242 * Automatic support for ZLIB/Compress compressed document is provided
2243 * by default if found at compile-time.
Daniel Veillard0335a842004-06-02 16:18:40 +00002244 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
Owen Taylor3473f882001-02-23 17:55:21 +00002245 *
Daniel Veillard0335a842004-06-02 16:18:40 +00002246 * Returns the new parser input or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00002247 */
Daniel Veillard0335a842004-06-02 16:18:40 +00002248xmlParserInputBufferPtr
2249xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
2250 if ((xmlParserInputBufferCreateFilenameValue)) {
2251 return xmlParserInputBufferCreateFilenameValue(URI, enc);
2252 }
2253 return __xmlParserInputBufferCreateFilename(URI, enc);
2254}
2255
2256#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard1b243b42004-06-08 10:16:42 +00002257xmlOutputBufferPtr
Daniel Veillard0335a842004-06-02 16:18:40 +00002258__xmlOutputBufferCreateFilename(const char *URI,
Owen Taylor3473f882001-02-23 17:55:21 +00002259 xmlCharEncodingHandlerPtr encoder,
Daniel Veillard0335a842004-06-02 16:18:40 +00002260 int compression ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00002261 xmlOutputBufferPtr ret;
Daniel Veillard966a31e2004-05-09 02:58:44 +00002262 xmlURIPtr puri;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002263 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002264 void *context = NULL;
Daniel Veillard966a31e2004-05-09 02:58:44 +00002265 char *unescaped = NULL;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002266#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002267 int is_file_uri = 1;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002268#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00002269
Owen Taylor3473f882001-02-23 17:55:21 +00002270 if (xmlOutputCallbackInitialized == 0)
2271 xmlRegisterDefaultOutputCallbacks();
2272
2273 if (URI == NULL) return(NULL);
2274
Daniel Veillard966a31e2004-05-09 02:58:44 +00002275 puri = xmlParseURI(URI);
2276 if (puri != NULL) {
Daniel Veillard8fcd2ca2005-07-03 14:42:56 +00002277#ifdef HAVE_ZLIB_H
Daniel Veillard18a65092004-05-11 15:57:42 +00002278 if ((puri->scheme != NULL) &&
2279 (!xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
Daniel Veillard966a31e2004-05-09 02:58:44 +00002280 is_file_uri = 0;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002281#endif
Daniel Veillard966a31e2004-05-09 02:58:44 +00002282 /*
2283 * try to limit the damages of the URI unescaping code.
2284 */
2285 if (puri->scheme != NULL)
2286 unescaped = xmlURIUnescapeString(URI, 0, NULL);
2287 xmlFreeURI(puri);
2288 }
Owen Taylor3473f882001-02-23 17:55:21 +00002289
2290 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002291 * Try to find one of the output accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002292 * Go in reverse to give precedence to user defined handlers.
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002293 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00002294 */
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002295 if (unescaped != NULL) {
2296#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002297 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002298 context = xmlGzfileOpenW(unescaped, compression);
2299 if (context != NULL) {
2300 ret = xmlAllocOutputBuffer(encoder);
2301 if (ret != NULL) {
2302 ret->context = context;
2303 ret->writecallback = xmlGzfileWrite;
2304 ret->closecallback = xmlGzfileClose;
2305 }
2306 xmlFree(unescaped);
2307 return(ret);
2308 }
2309 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002310#endif
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002311 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2312 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
2313 (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
2314#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2315 /* Need to pass compression parameter into HTTP open calls */
2316 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2317 context = xmlIOHTTPOpenW(unescaped, compression);
2318 else
2319#endif
2320 context = xmlOutputCallbackTable[i].opencallback(unescaped);
2321 if (context != NULL)
2322 break;
2323 }
2324 }
2325 xmlFree(unescaped);
2326 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002327
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002328 /*
2329 * If this failed try with a non-escaped URI this may be a strange
2330 * filename
2331 */
2332 if (context == NULL) {
2333#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002334 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002335 context = xmlGzfileOpenW(URI, compression);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002336 if (context != NULL) {
2337 ret = xmlAllocOutputBuffer(encoder);
2338 if (ret != NULL) {
2339 ret->context = context;
2340 ret->writecallback = xmlGzfileWrite;
2341 ret->closecallback = xmlGzfileClose;
2342 }
2343 return(ret);
2344 }
2345 }
2346#endif
2347 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2348 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002349 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002350#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2351 /* Need to pass compression parameter into HTTP open calls */
2352 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2353 context = xmlIOHTTPOpenW(URI, compression);
2354 else
2355#endif
2356 context = xmlOutputCallbackTable[i].opencallback(URI);
2357 if (context != NULL)
2358 break;
2359 }
Owen Taylor3473f882001-02-23 17:55:21 +00002360 }
2361 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002362
Owen Taylor3473f882001-02-23 17:55:21 +00002363 if (context == NULL) {
2364 return(NULL);
2365 }
2366
2367 /*
2368 * Allocate the Output buffer front-end.
2369 */
2370 ret = xmlAllocOutputBuffer(encoder);
2371 if (ret != NULL) {
2372 ret->context = context;
2373 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
2374 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
2375 }
2376 return(ret);
2377}
Daniel Veillard0335a842004-06-02 16:18:40 +00002378
2379/**
2380 * xmlOutputBufferCreateFilename:
2381 * @URI: a C string containing the URI or filename
2382 * @encoder: the encoding converter or NULL
2383 * @compression: the compression ration (0 none, 9 max).
2384 *
2385 * Create a buffered output for the progressive saving of a file
2386 * If filename is "-' then we use stdout as the output.
2387 * Automatic support for ZLIB/Compress compressed document is provided
2388 * by default if found at compile-time.
2389 * TODO: currently if compression is set, the library only support
2390 * writing to a local file.
2391 *
2392 * Returns the new output or NULL
2393 */
2394xmlOutputBufferPtr
2395xmlOutputBufferCreateFilename(const char *URI,
2396 xmlCharEncodingHandlerPtr encoder,
2397 int compression ATTRIBUTE_UNUSED) {
2398 if ((xmlOutputBufferCreateFilenameValue)) {
2399 return xmlOutputBufferCreateFilenameValue(URI, encoder, compression);
2400 }
2401 return __xmlOutputBufferCreateFilename(URI, encoder, compression);
2402}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002403#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002404
2405/**
2406 * xmlParserInputBufferCreateFile:
2407 * @file: a FILE*
2408 * @enc: the charset encoding if known
2409 *
2410 * Create a buffered parser input for the progressive parsing of a FILE *
2411 * buffered C I/O
2412 *
2413 * Returns the new parser input or NULL
2414 */
2415xmlParserInputBufferPtr
2416xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
2417 xmlParserInputBufferPtr ret;
2418
2419 if (xmlInputCallbackInitialized == 0)
2420 xmlRegisterDefaultInputCallbacks();
2421
2422 if (file == NULL) return(NULL);
2423
2424 ret = xmlAllocParserInputBuffer(enc);
2425 if (ret != NULL) {
2426 ret->context = file;
2427 ret->readcallback = xmlFileRead;
2428 ret->closecallback = xmlFileFlush;
2429 }
2430
2431 return(ret);
2432}
2433
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002434#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002435/**
2436 * xmlOutputBufferCreateFile:
2437 * @file: a FILE*
2438 * @encoder: the encoding converter or NULL
2439 *
2440 * Create a buffered output for the progressive saving to a FILE *
2441 * buffered C I/O
2442 *
2443 * Returns the new parser output or NULL
2444 */
2445xmlOutputBufferPtr
2446xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
2447 xmlOutputBufferPtr ret;
2448
2449 if (xmlOutputCallbackInitialized == 0)
2450 xmlRegisterDefaultOutputCallbacks();
2451
2452 if (file == NULL) return(NULL);
2453
2454 ret = xmlAllocOutputBuffer(encoder);
2455 if (ret != NULL) {
2456 ret->context = file;
2457 ret->writecallback = xmlFileWrite;
2458 ret->closecallback = xmlFileFlush;
2459 }
2460
2461 return(ret);
2462}
Daniel Veillard9a00fd22005-11-09 08:56:26 +00002463
2464/**
2465 * xmlOutputBufferCreateBuffer:
2466 * @buffer: a xmlBufferPtr
2467 * @encoder: the encoding converter or NULL
2468 *
2469 * Create a buffered output for the progressive saving to a xmlBuffer
2470 *
2471 * Returns the new parser output or NULL
2472 */
2473xmlOutputBufferPtr
2474xmlOutputBufferCreateBuffer(xmlBufferPtr buffer,
2475 xmlCharEncodingHandlerPtr encoder) {
2476 xmlOutputBufferPtr ret;
2477
2478 if (buffer == NULL) return(NULL);
2479
Rob Richardsa44f2342005-11-09 18:03:45 +00002480 ret = xmlOutputBufferCreateIO((xmlOutputWriteCallback)
2481 xmlBufferWrite,
2482 (xmlOutputCloseCallback)
Daniel Veillard4d3866c2005-11-13 12:43:59 +00002483 NULL, (void *) buffer, encoder);
Daniel Veillard9a00fd22005-11-09 08:56:26 +00002484
2485 return(ret);
2486}
2487
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002488#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002489
2490/**
2491 * xmlParserInputBufferCreateFd:
2492 * @fd: a file descriptor number
2493 * @enc: the charset encoding if known
2494 *
2495 * Create a buffered parser input for the progressive parsing for the input
2496 * from a file descriptor
2497 *
2498 * Returns the new parser input or NULL
2499 */
2500xmlParserInputBufferPtr
2501xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
2502 xmlParserInputBufferPtr ret;
2503
2504 if (fd < 0) return(NULL);
2505
2506 ret = xmlAllocParserInputBuffer(enc);
2507 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002508 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002509 ret->readcallback = xmlFdRead;
2510 ret->closecallback = xmlFdClose;
2511 }
2512
2513 return(ret);
2514}
2515
2516/**
2517 * xmlParserInputBufferCreateMem:
2518 * @mem: the memory input
2519 * @size: the length of the memory block
2520 * @enc: the charset encoding if known
2521 *
2522 * Create a buffered parser input for the progressive parsing for the input
2523 * from a memory area.
2524 *
2525 * Returns the new parser input or NULL
2526 */
2527xmlParserInputBufferPtr
2528xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
2529 xmlParserInputBufferPtr ret;
William M. Bracka3215c72004-07-31 16:24:01 +00002530 int errcode;
Owen Taylor3473f882001-02-23 17:55:21 +00002531
2532 if (size <= 0) return(NULL);
2533 if (mem == NULL) return(NULL);
2534
2535 ret = xmlAllocParserInputBuffer(enc);
2536 if (ret != NULL) {
2537 ret->context = (void *) mem;
2538 ret->readcallback = (xmlInputReadCallback) xmlNop;
2539 ret->closecallback = NULL;
William M. Bracka3215c72004-07-31 16:24:01 +00002540 errcode = xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size);
2541 if (errcode != 0) {
2542 xmlFree(ret);
2543 return(NULL);
2544 }
Owen Taylor3473f882001-02-23 17:55:21 +00002545 }
2546
2547 return(ret);
2548}
2549
2550/**
Daniel Veillard53350552003-09-18 13:35:51 +00002551 * xmlParserInputBufferCreateStatic:
2552 * @mem: the memory input
2553 * @size: the length of the memory block
2554 * @enc: the charset encoding if known
2555 *
2556 * Create a buffered parser input for the progressive parsing for the input
2557 * from an immutable memory area. This will not copy the memory area to
2558 * the buffer, but the memory is expected to be available until the end of
2559 * the parsing, this is useful for example when using mmap'ed file.
2560 *
2561 * Returns the new parser input or NULL
2562 */
2563xmlParserInputBufferPtr
2564xmlParserInputBufferCreateStatic(const char *mem, int size,
2565 xmlCharEncoding enc) {
2566 xmlParserInputBufferPtr ret;
2567
2568 if (size <= 0) return(NULL);
2569 if (mem == NULL) return(NULL);
2570
2571 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2572 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002573 xmlIOErrMemory("creating input buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00002574 return(NULL);
2575 }
2576 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillarde72c5082003-09-19 12:44:05 +00002577 ret->buffer = xmlBufferCreateStatic((void *)mem, (size_t) size);
Daniel Veillard53350552003-09-18 13:35:51 +00002578 if (ret->buffer == NULL) {
2579 xmlFree(ret);
2580 return(NULL);
2581 }
2582 ret->encoder = xmlGetCharEncodingHandler(enc);
2583 if (ret->encoder != NULL)
2584 ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
2585 else
2586 ret->raw = NULL;
2587 ret->compressed = -1;
2588 ret->context = (void *) mem;
2589 ret->readcallback = NULL;
2590 ret->closecallback = NULL;
2591
2592 return(ret);
2593}
2594
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002595#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard53350552003-09-18 13:35:51 +00002596/**
Owen Taylor3473f882001-02-23 17:55:21 +00002597 * xmlOutputBufferCreateFd:
2598 * @fd: a file descriptor number
2599 * @encoder: the encoding converter or NULL
2600 *
2601 * Create a buffered output for the progressive saving
2602 * to a file descriptor
2603 *
2604 * Returns the new parser output or NULL
2605 */
2606xmlOutputBufferPtr
2607xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
2608 xmlOutputBufferPtr ret;
2609
2610 if (fd < 0) return(NULL);
2611
2612 ret = xmlAllocOutputBuffer(encoder);
2613 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002614 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002615 ret->writecallback = xmlFdWrite;
Daniel Veillard7db38712002-02-07 16:39:11 +00002616 ret->closecallback = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002617 }
2618
2619 return(ret);
2620}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002621#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002622
2623/**
2624 * xmlParserInputBufferCreateIO:
2625 * @ioread: an I/O read function
2626 * @ioclose: an I/O close function
2627 * @ioctx: an I/O handler
2628 * @enc: the charset encoding if known
2629 *
2630 * Create a buffered parser input for the progressive parsing for the input
2631 * from an I/O handler
2632 *
2633 * Returns the new parser input or NULL
2634 */
2635xmlParserInputBufferPtr
2636xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
2637 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
2638 xmlParserInputBufferPtr ret;
2639
2640 if (ioread == NULL) return(NULL);
2641
2642 ret = xmlAllocParserInputBuffer(enc);
2643 if (ret != NULL) {
2644 ret->context = (void *) ioctx;
2645 ret->readcallback = ioread;
2646 ret->closecallback = ioclose;
2647 }
2648
2649 return(ret);
2650}
2651
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002652#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002653/**
2654 * xmlOutputBufferCreateIO:
2655 * @iowrite: an I/O write function
2656 * @ioclose: an I/O close function
2657 * @ioctx: an I/O handler
Daniel Veillard9d06d302002-01-22 18:15:52 +00002658 * @encoder: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002659 *
2660 * Create a buffered output for the progressive saving
2661 * to an I/O handler
2662 *
2663 * Returns the new parser output or NULL
2664 */
2665xmlOutputBufferPtr
2666xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
2667 xmlOutputCloseCallback ioclose, void *ioctx,
2668 xmlCharEncodingHandlerPtr encoder) {
2669 xmlOutputBufferPtr ret;
2670
2671 if (iowrite == NULL) return(NULL);
2672
2673 ret = xmlAllocOutputBuffer(encoder);
2674 if (ret != NULL) {
2675 ret->context = (void *) ioctx;
2676 ret->writecallback = iowrite;
2677 ret->closecallback = ioclose;
2678 }
2679
2680 return(ret);
2681}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002682#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002683
2684/**
Daniel Veillard1b243b42004-06-08 10:16:42 +00002685 * xmlParserInputBufferCreateFilenameDefault:
2686 * @func: function pointer to the new ParserInputBufferCreateFilenameFunc
2687 *
2688 * Registers a callback for URI input file handling
2689 *
2690 * Returns the old value of the registration function
2691 */
2692xmlParserInputBufferCreateFilenameFunc
2693xmlParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func)
2694{
2695 xmlParserInputBufferCreateFilenameFunc old = xmlParserInputBufferCreateFilenameValue;
2696 if (old == NULL) {
2697 old = __xmlParserInputBufferCreateFilename;
2698 }
2699
2700 xmlParserInputBufferCreateFilenameValue = func;
2701 return(old);
2702}
2703
2704/**
2705 * xmlOutputBufferCreateFilenameDefault:
2706 * @func: function pointer to the new OutputBufferCreateFilenameFunc
2707 *
2708 * Registers a callback for URI output file handling
2709 *
2710 * Returns the old value of the registration function
2711 */
2712xmlOutputBufferCreateFilenameFunc
2713xmlOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func)
2714{
2715 xmlOutputBufferCreateFilenameFunc old = xmlOutputBufferCreateFilenameValue;
2716#ifdef LIBXML_OUTPUT_ENABLED
2717 if (old == NULL) {
2718 old = __xmlOutputBufferCreateFilename;
2719 }
2720#endif
2721 xmlOutputBufferCreateFilenameValue = func;
2722 return(old);
2723}
2724
2725/**
Owen Taylor3473f882001-02-23 17:55:21 +00002726 * xmlParserInputBufferPush:
2727 * @in: a buffered parser input
2728 * @len: the size in bytes of the array.
2729 * @buf: an char array
2730 *
2731 * Push the content of the arry in the input buffer
2732 * This routine handle the I18N transcoding to internal UTF-8
2733 * This is used when operating the parser in progressive (push) mode.
2734 *
2735 * Returns the number of chars read and stored in the buffer, or -1
2736 * in case of error.
2737 */
2738int
2739xmlParserInputBufferPush(xmlParserInputBufferPtr in,
2740 int len, const char *buf) {
2741 int nbchars = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00002742 int ret;
Owen Taylor3473f882001-02-23 17:55:21 +00002743
2744 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002745 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002746 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00002747 unsigned int use;
2748
Owen Taylor3473f882001-02-23 17:55:21 +00002749 /*
2750 * Store the data in the incoming raw buffer
2751 */
2752 if (in->raw == NULL) {
2753 in->raw = xmlBufferCreate();
2754 }
William M. Bracka3215c72004-07-31 16:24:01 +00002755 ret = xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
2756 if (ret != 0)
2757 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002758
2759 /*
2760 * convert as much as possible to the parser reading buffer.
2761 */
Daniel Veillard36711902004-02-11 13:25:26 +00002762 use = in->raw->use;
Owen Taylor3473f882001-02-23 17:55:21 +00002763 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2764 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002765 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002766 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002767 return(-1);
2768 }
Daniel Veillard36711902004-02-11 13:25:26 +00002769 in->rawconsumed += (use - in->raw->use);
Owen Taylor3473f882001-02-23 17:55:21 +00002770 } else {
2771 nbchars = len;
William M. Bracka3215c72004-07-31 16:24:01 +00002772 ret = xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
2773 if (ret != 0)
2774 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002775 }
2776#ifdef DEBUG_INPUT
2777 xmlGenericError(xmlGenericErrorContext,
2778 "I/O: pushed %d chars, buffer %d/%d\n",
2779 nbchars, in->buffer->use, in->buffer->size);
2780#endif
2781 return(nbchars);
2782}
2783
2784/**
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002785 * endOfInput:
2786 *
2787 * When reading from an Input channel indicated end of file or error
2788 * don't reread from it again.
2789 */
2790static int
2791endOfInput (void * context ATTRIBUTE_UNUSED,
2792 char * buffer ATTRIBUTE_UNUSED,
2793 int len ATTRIBUTE_UNUSED) {
2794 return(0);
2795}
2796
2797/**
Owen Taylor3473f882001-02-23 17:55:21 +00002798 * xmlParserInputBufferGrow:
2799 * @in: a buffered parser input
2800 * @len: indicative value of the amount of chars to read
2801 *
2802 * Grow up the content of the input buffer, the old data are preserved
2803 * This routine handle the I18N transcoding to internal UTF-8
2804 * This routine is used when operating the parser in normal (pull) mode
2805 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002806 * TODO: one should be able to remove one extra copy by copying directly
Owen Taylor3473f882001-02-23 17:55:21 +00002807 * onto in->buffer or in->raw
2808 *
2809 * Returns the number of chars read and stored in the buffer, or -1
2810 * in case of error.
2811 */
2812int
2813xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
2814 char *buffer = NULL;
2815 int res = 0;
2816 int nbchars = 0;
2817 int buffree;
Daniel Veillard9e412302002-06-10 15:59:44 +00002818 unsigned int needSize;
Owen Taylor3473f882001-02-23 17:55:21 +00002819
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002820 if ((in == NULL) || (in->error)) return(-1);
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002821 if ((len <= MINLEN) && (len != 4))
Owen Taylor3473f882001-02-23 17:55:21 +00002822 len = MINLEN;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002823
Owen Taylor3473f882001-02-23 17:55:21 +00002824 buffree = in->buffer->size - in->buffer->use;
2825 if (buffree <= 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002826 xmlIOErr(XML_IO_BUFFER_FULL, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002827 in->error = XML_IO_BUFFER_FULL;
William M. Bracka3215c72004-07-31 16:24:01 +00002828 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002829 }
Owen Taylor3473f882001-02-23 17:55:21 +00002830
Daniel Veillarde5354492002-05-16 08:43:22 +00002831 needSize = in->buffer->use + len + 1;
2832 if (needSize > in->buffer->size){
2833 if (!xmlBufferResize(in->buffer, needSize)){
Daniel Veillard05d987b2003-10-08 11:54:57 +00002834 xmlIOErrMemory("growing input buffer");
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002835 in->error = XML_ERR_NO_MEMORY;
William M. Bracka3215c72004-07-31 16:24:01 +00002836 return(-1);
Daniel Veillarde5354492002-05-16 08:43:22 +00002837 }
Owen Taylor3473f882001-02-23 17:55:21 +00002838 }
Daniel Veillarde5354492002-05-16 08:43:22 +00002839 buffer = (char *)&in->buffer->content[in->buffer->use];
Owen Taylor3473f882001-02-23 17:55:21 +00002840
2841 /*
2842 * Call the read method for this I/O type.
2843 */
2844 if (in->readcallback != NULL) {
2845 res = in->readcallback(in->context, &buffer[0], len);
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002846 if (res <= 0)
2847 in->readcallback = endOfInput;
Owen Taylor3473f882001-02-23 17:55:21 +00002848 } else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002849 xmlIOErr(XML_IO_NO_INPUT, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002850 in->error = XML_IO_NO_INPUT;
Owen Taylor3473f882001-02-23 17:55:21 +00002851 return(-1);
2852 }
2853 if (res < 0) {
Owen Taylor3473f882001-02-23 17:55:21 +00002854 return(-1);
2855 }
2856 len = res;
2857 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00002858 unsigned int use;
2859
Owen Taylor3473f882001-02-23 17:55:21 +00002860 /*
2861 * Store the data in the incoming raw buffer
2862 */
2863 if (in->raw == NULL) {
2864 in->raw = xmlBufferCreate();
2865 }
William M. Bracka3215c72004-07-31 16:24:01 +00002866 res = xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
2867 if (res != 0)
2868 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002869
2870 /*
2871 * convert as much as possible to the parser reading buffer.
2872 */
Daniel Veillard36711902004-02-11 13:25:26 +00002873 use = in->raw->use;
Owen Taylor3473f882001-02-23 17:55:21 +00002874 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2875 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002876 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002877 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002878 return(-1);
2879 }
Daniel Veillard36711902004-02-11 13:25:26 +00002880 in->rawconsumed += (use - in->raw->use);
Owen Taylor3473f882001-02-23 17:55:21 +00002881 } else {
2882 nbchars = len;
Daniel Veillarde5354492002-05-16 08:43:22 +00002883 in->buffer->use += nbchars;
2884 buffer[nbchars] = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002885 }
2886#ifdef DEBUG_INPUT
2887 xmlGenericError(xmlGenericErrorContext,
2888 "I/O: read %d chars, buffer %d/%d\n",
2889 nbchars, in->buffer->use, in->buffer->size);
2890#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002891 return(nbchars);
2892}
2893
2894/**
2895 * xmlParserInputBufferRead:
2896 * @in: a buffered parser input
2897 * @len: indicative value of the amount of chars to read
2898 *
2899 * Refresh the content of the input buffer, the old data are considered
2900 * consumed
2901 * This routine handle the I18N transcoding to internal UTF-8
2902 *
2903 * Returns the number of chars read and stored in the buffer, or -1
2904 * in case of error.
2905 */
2906int
2907xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002908 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002909 if (in->readcallback != NULL)
2910 return(xmlParserInputBufferGrow(in, len));
Daniel Veillard53350552003-09-18 13:35:51 +00002911 else if ((in->buffer != NULL) &&
2912 (in->buffer->alloc == XML_BUFFER_ALLOC_IMMUTABLE))
2913 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00002914 else
2915 return(-1);
2916}
2917
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002918#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002919/**
2920 * xmlOutputBufferWrite:
2921 * @out: a buffered parser output
2922 * @len: the size in bytes of the array.
2923 * @buf: an char array
2924 *
2925 * Write the content of the array in the output I/O buffer
2926 * This routine handle the I18N transcoding from internal UTF-8
2927 * The buffer is lossless, i.e. will store in case of partial
2928 * or delayed writes.
2929 *
2930 * Returns the number of chars immediately written, or -1
2931 * in case of error.
2932 */
2933int
2934xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
2935 int nbchars = 0; /* number of chars to output to I/O */
2936 int ret; /* return from function call */
2937 int written = 0; /* number of char written to I/O so far */
2938 int chunk; /* number of byte curreent processed from buf */
2939
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002940 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002941 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002942 if (out->error) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002943
2944 do {
2945 chunk = len;
2946 if (chunk > 4 * MINLEN)
2947 chunk = 4 * MINLEN;
2948
2949 /*
2950 * first handle encoding stuff.
2951 */
2952 if (out->encoder != NULL) {
2953 /*
2954 * Store the data in the incoming raw buffer
2955 */
2956 if (out->conv == NULL) {
2957 out->conv = xmlBufferCreate();
2958 }
William M. Bracka3215c72004-07-31 16:24:01 +00002959 ret = xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2960 if (ret != 0)
2961 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002962
2963 if ((out->buffer->use < MINLEN) && (chunk == len))
2964 goto done;
2965
2966 /*
2967 * convert as much as possible to the parser reading buffer.
2968 */
2969 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
Daniel Veillard809faa52003-02-10 15:43:53 +00002970 if ((ret < 0) && (ret != -3)) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002971 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002972 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002973 return(-1);
2974 }
2975 nbchars = out->conv->use;
2976 } else {
William M. Bracka3215c72004-07-31 16:24:01 +00002977 ret = xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
2978 if (ret != 0)
2979 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002980 nbchars = out->buffer->use;
2981 }
2982 buf += chunk;
2983 len -= chunk;
2984
2985 if ((nbchars < MINLEN) && (len <= 0))
2986 goto done;
2987
2988 if (out->writecallback) {
2989 /*
2990 * second write the stuff to the I/O channel
2991 */
2992 if (out->encoder != NULL) {
2993 ret = out->writecallback(out->context,
2994 (const char *)out->conv->content, nbchars);
2995 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00002996 xmlBufferShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00002997 } else {
2998 ret = out->writecallback(out->context,
2999 (const char *)out->buffer->content, nbchars);
3000 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00003001 xmlBufferShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003002 }
3003 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003004 xmlIOErr(XML_IO_WRITE, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003005 out->error = XML_IO_WRITE;
Owen Taylor3473f882001-02-23 17:55:21 +00003006 return(ret);
3007 }
3008 out->written += ret;
3009 }
3010 written += nbchars;
3011 } while (len > 0);
3012
3013done:
3014#ifdef DEBUG_INPUT
3015 xmlGenericError(xmlGenericErrorContext,
3016 "I/O: wrote %d chars\n", written);
3017#endif
3018 return(written);
3019}
3020
3021/**
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003022 * xmlEscapeContent:
3023 * @out: a pointer to an array of bytes to store the result
3024 * @outlen: the length of @out
3025 * @in: a pointer to an array of unescaped UTF-8 bytes
3026 * @inlen: the length of @in
3027 *
3028 * Take a block of UTF-8 chars in and escape them.
3029 * Returns 0 if success, or -1 otherwise
3030 * The value of @inlen after return is the number of octets consumed
3031 * if the return value is positive, else unpredictable.
3032 * The value of @outlen after return is the number of octets consumed.
3033 */
3034static int
3035xmlEscapeContent(unsigned char* out, int *outlen,
3036 const xmlChar* in, int *inlen) {
3037 unsigned char* outstart = out;
3038 const unsigned char* base = in;
3039 unsigned char* outend = out + *outlen;
3040 const unsigned char* inend;
3041
3042 inend = in + (*inlen);
3043
3044 while ((in < inend) && (out < outend)) {
3045 if (*in == '<') {
3046 if (outend - out < 4) break;
3047 *out++ = '&';
3048 *out++ = 'l';
3049 *out++ = 't';
3050 *out++ = ';';
3051 } else if (*in == '>') {
3052 if (outend - out < 4) break;
3053 *out++ = '&';
3054 *out++ = 'g';
3055 *out++ = 't';
3056 *out++ = ';';
3057 } else if (*in == '&') {
3058 if (outend - out < 5) break;
3059 *out++ = '&';
3060 *out++ = 'a';
3061 *out++ = 'm';
3062 *out++ = 'p';
3063 *out++ = ';';
3064 } else if (*in == '\r') {
3065 if (outend - out < 5) break;
3066 *out++ = '&';
3067 *out++ = '#';
3068 *out++ = '1';
3069 *out++ = '3';
3070 *out++ = ';';
3071 } else {
3072 *out++ = (unsigned char) *in;
3073 }
3074 ++in;
3075 }
3076 *outlen = out - outstart;
3077 *inlen = in - base;
3078 return(0);
3079}
3080
3081/**
3082 * xmlOutputBufferWriteEscape:
3083 * @out: a buffered parser output
3084 * @str: a zero terminated UTF-8 string
Daniel Veillardee8960b2004-05-14 03:25:14 +00003085 * @escaping: an optional escaping function (or NULL)
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003086 *
3087 * Write the content of the string in the output I/O buffer
3088 * This routine escapes the caracters and then handle the I18N
3089 * transcoding from internal UTF-8
3090 * The buffer is lossless, i.e. will store in case of partial
3091 * or delayed writes.
3092 *
3093 * Returns the number of chars immediately written, or -1
3094 * in case of error.
3095 */
3096int
Daniel Veillardee8960b2004-05-14 03:25:14 +00003097xmlOutputBufferWriteEscape(xmlOutputBufferPtr out, const xmlChar *str,
3098 xmlCharEncodingOutputFunc escaping) {
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003099 int nbchars = 0; /* number of chars to output to I/O */
3100 int ret; /* return from function call */
3101 int written = 0; /* number of char written to I/O so far */
Daniel Veillard71b95632004-08-31 12:15:36 +00003102 int oldwritten=0;/* loop guard */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003103 int chunk; /* number of byte currently processed from str */
3104 int len; /* number of bytes in str */
3105 int cons; /* byte from str consumed */
3106
Daniel Veillardce244ad2004-11-05 10:03:46 +00003107 if ((out == NULL) || (out->error) || (str == NULL) ||
3108 (out->buffer == NULL) ||
3109 (out->buffer->alloc == XML_BUFFER_ALLOC_IMMUTABLE)) return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003110 len = strlen((const char *)str);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003111 if (len < 0) return(0);
3112 if (out->error) return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003113 if (escaping == NULL) escaping = xmlEscapeContent;
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003114
3115 do {
Daniel Veillard71b95632004-08-31 12:15:36 +00003116 oldwritten = written;
3117
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003118 /*
3119 * how many bytes to consume and how many bytes to store.
3120 */
3121 cons = len;
3122 chunk = (out->buffer->size - out->buffer->use) - 1;
3123
3124 /*
3125 * first handle encoding stuff.
3126 */
3127 if (out->encoder != NULL) {
3128 /*
3129 * Store the data in the incoming raw buffer
3130 */
3131 if (out->conv == NULL) {
3132 out->conv = xmlBufferCreate();
3133 }
Daniel Veillardee8960b2004-05-14 03:25:14 +00003134 ret = escaping(out->buffer->content + out->buffer->use ,
3135 &chunk, str, &cons);
William M. Brack66e40b12004-11-26 15:45:19 +00003136 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003137 return(-1);
3138 out->buffer->use += chunk;
3139 out->buffer->content[out->buffer->use] = 0;
3140
3141 if ((out->buffer->use < MINLEN) && (cons == len))
3142 goto done;
3143
3144 /*
3145 * convert as much as possible to the output buffer.
3146 */
3147 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
3148 if ((ret < 0) && (ret != -3)) {
3149 xmlIOErr(XML_IO_ENCODER, NULL);
3150 out->error = XML_IO_ENCODER;
3151 return(-1);
3152 }
3153 nbchars = out->conv->use;
3154 } else {
Daniel Veillardee8960b2004-05-14 03:25:14 +00003155 ret = escaping(out->buffer->content + out->buffer->use ,
3156 &chunk, str, &cons);
William M. Brack66e40b12004-11-26 15:45:19 +00003157 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003158 return(-1);
3159 out->buffer->use += chunk;
3160 out->buffer->content[out->buffer->use] = 0;
3161 nbchars = out->buffer->use;
3162 }
3163 str += cons;
3164 len -= cons;
3165
3166 if ((nbchars < MINLEN) && (len <= 0))
3167 goto done;
3168
3169 if (out->writecallback) {
3170 /*
3171 * second write the stuff to the I/O channel
3172 */
3173 if (out->encoder != NULL) {
3174 ret = out->writecallback(out->context,
3175 (const char *)out->conv->content, nbchars);
3176 if (ret >= 0)
3177 xmlBufferShrink(out->conv, ret);
3178 } else {
3179 ret = out->writecallback(out->context,
3180 (const char *)out->buffer->content, nbchars);
3181 if (ret >= 0)
3182 xmlBufferShrink(out->buffer, ret);
3183 }
3184 if (ret < 0) {
3185 xmlIOErr(XML_IO_WRITE, NULL);
3186 out->error = XML_IO_WRITE;
3187 return(ret);
3188 }
3189 out->written += ret;
Daniel Veillard83a75e02004-05-14 21:50:42 +00003190 } else if (out->buffer->size - out->buffer->use < MINLEN) {
3191 xmlBufferResize(out->buffer, out->buffer->size + MINLEN);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003192 }
3193 written += nbchars;
Daniel Veillard71b95632004-08-31 12:15:36 +00003194 } while ((len > 0) && (oldwritten != written));
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003195
3196done:
3197#ifdef DEBUG_INPUT
3198 xmlGenericError(xmlGenericErrorContext,
3199 "I/O: wrote %d chars\n", written);
3200#endif
3201 return(written);
3202}
3203
3204/**
Owen Taylor3473f882001-02-23 17:55:21 +00003205 * xmlOutputBufferWriteString:
3206 * @out: a buffered parser output
3207 * @str: a zero terminated C string
3208 *
3209 * Write the content of the string in the output I/O buffer
3210 * This routine handle the I18N transcoding from internal UTF-8
3211 * The buffer is lossless, i.e. will store in case of partial
3212 * or delayed writes.
3213 *
3214 * Returns the number of chars immediately written, or -1
3215 * in case of error.
3216 */
3217int
3218xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
3219 int len;
3220
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003221 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003222 if (str == NULL)
3223 return(-1);
3224 len = strlen(str);
3225
3226 if (len > 0)
3227 return(xmlOutputBufferWrite(out, len, str));
3228 return(len);
3229}
3230
3231/**
3232 * xmlOutputBufferFlush:
3233 * @out: a buffered output
3234 *
3235 * flushes the output I/O channel
3236 *
3237 * Returns the number of byte written or -1 in case of error.
3238 */
3239int
3240xmlOutputBufferFlush(xmlOutputBufferPtr out) {
3241 int nbchars = 0, ret = 0;
3242
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003243 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003244 /*
3245 * first handle encoding stuff.
3246 */
3247 if ((out->conv != NULL) && (out->encoder != NULL)) {
3248 /*
3249 * convert as much as possible to the parser reading buffer.
3250 */
3251 nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
3252 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003253 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003254 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003255 return(-1);
3256 }
3257 }
3258
3259 /*
3260 * second flush the stuff to the I/O channel
3261 */
3262 if ((out->conv != NULL) && (out->encoder != NULL) &&
3263 (out->writecallback != NULL)) {
3264 ret = out->writecallback(out->context,
3265 (const char *)out->conv->content, out->conv->use);
3266 if (ret >= 0)
3267 xmlBufferShrink(out->conv, ret);
3268 } else if (out->writecallback != NULL) {
3269 ret = out->writecallback(out->context,
3270 (const char *)out->buffer->content, out->buffer->use);
3271 if (ret >= 0)
3272 xmlBufferShrink(out->buffer, ret);
3273 }
3274 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003275 xmlIOErr(XML_IO_FLUSH, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003276 out->error = XML_IO_FLUSH;
Owen Taylor3473f882001-02-23 17:55:21 +00003277 return(ret);
3278 }
3279 out->written += ret;
3280
3281#ifdef DEBUG_INPUT
3282 xmlGenericError(xmlGenericErrorContext,
3283 "I/O: flushed %d chars\n", ret);
3284#endif
3285 return(ret);
3286}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003287#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003288
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003289/**
Owen Taylor3473f882001-02-23 17:55:21 +00003290 * xmlParserGetDirectory:
3291 * @filename: the path to a file
3292 *
3293 * lookup the directory for that file
3294 *
3295 * Returns a new allocated string containing the directory, or NULL.
3296 */
3297char *
3298xmlParserGetDirectory(const char *filename) {
3299 char *ret = NULL;
3300 char dir[1024];
3301 char *cur;
3302 char sep = '/';
3303
Igor Zlatkovic9181cc02002-09-29 17:51:06 +00003304#ifdef _WIN32_WCE /* easy way by now ... wince does not have dirs! */
3305 return NULL;
3306#endif
3307
Owen Taylor3473f882001-02-23 17:55:21 +00003308 if (xmlInputCallbackInitialized == 0)
3309 xmlRegisterDefaultInputCallbacks();
3310
3311 if (filename == NULL) return(NULL);
Daniel Veillard3c5ed912002-01-08 10:36:16 +00003312#if defined(WIN32) && !defined(__CYGWIN__)
Owen Taylor3473f882001-02-23 17:55:21 +00003313 sep = '\\';
3314#endif
3315
3316 strncpy(dir, filename, 1023);
3317 dir[1023] = 0;
3318 cur = &dir[strlen(dir)];
3319 while (cur > dir) {
3320 if (*cur == sep) break;
3321 cur --;
3322 }
3323 if (*cur == sep) {
3324 if (cur == dir) dir[1] = 0;
3325 else *cur = 0;
3326 ret = xmlMemStrdup(dir);
3327 } else {
3328 if (getcwd(dir, 1024) != NULL) {
3329 dir[1023] = 0;
3330 ret = xmlMemStrdup(dir);
3331 }
3332 }
3333 return(ret);
3334}
3335
3336/****************************************************************
3337 * *
3338 * External entities loading *
3339 * *
3340 ****************************************************************/
3341
Daniel Veillarda840b692003-10-19 13:35:37 +00003342/**
3343 * xmlCheckHTTPInput:
3344 * @ctxt: an XML parser context
3345 * @ret: an XML parser input
3346 *
3347 * Check an input in case it was created from an HTTP stream, in that
3348 * case it will handle encoding and update of the base URL in case of
3349 * redirection. It also checks for HTTP errors in which case the input
3350 * is cleanly freed up and an appropriate error is raised in context
3351 *
3352 * Returns the input or NULL in case of HTTP error.
3353 */
3354xmlParserInputPtr
3355xmlCheckHTTPInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr ret) {
3356#ifdef LIBXML_HTTP_ENABLED
3357 if ((ret != NULL) && (ret->buf != NULL) &&
3358 (ret->buf->readcallback == xmlIOHTTPRead) &&
3359 (ret->buf->context != NULL)) {
3360 const char *encoding;
3361 const char *redir;
3362 const char *mime;
3363 int code;
3364
3365 code = xmlNanoHTTPReturnCode(ret->buf->context);
3366 if (code >= 400) {
3367 /* fatal error */
3368 if (ret->filename != NULL)
Daniel Veillarde8039df2003-10-27 11:25:13 +00003369 __xmlLoaderErr(ctxt, "failed to load HTTP resource \"%s\"\n",
Daniel Veillarda840b692003-10-19 13:35:37 +00003370 (const char *) ret->filename);
3371 else
Daniel Veillarde8039df2003-10-27 11:25:13 +00003372 __xmlLoaderErr(ctxt, "failed to load HTTP resource\n", NULL);
Daniel Veillarda840b692003-10-19 13:35:37 +00003373 xmlFreeInputStream(ret);
3374 ret = NULL;
3375 } else {
3376
3377 mime = xmlNanoHTTPMimeType(ret->buf->context);
3378 if ((xmlStrstr(BAD_CAST mime, BAD_CAST "/xml")) ||
3379 (xmlStrstr(BAD_CAST mime, BAD_CAST "+xml"))) {
3380 encoding = xmlNanoHTTPEncoding(ret->buf->context);
3381 if (encoding != NULL) {
3382 xmlCharEncodingHandlerPtr handler;
3383
3384 handler = xmlFindCharEncodingHandler(encoding);
3385 if (handler != NULL) {
3386 xmlSwitchInputEncoding(ctxt, ret, handler);
3387 } else {
3388 __xmlErrEncoding(ctxt, XML_ERR_UNKNOWN_ENCODING,
3389 "Unknown encoding %s",
3390 BAD_CAST encoding, NULL);
3391 }
3392 if (ret->encoding == NULL)
3393 ret->encoding = xmlStrdup(BAD_CAST encoding);
3394 }
3395#if 0
3396 } else if (xmlStrstr(BAD_CAST mime, BAD_CAST "html")) {
3397#endif
3398 }
3399 redir = xmlNanoHTTPRedir(ret->buf->context);
3400 if (redir != NULL) {
3401 if (ret->filename != NULL)
3402 xmlFree((xmlChar *) ret->filename);
3403 if (ret->directory != NULL) {
3404 xmlFree((xmlChar *) ret->directory);
3405 ret->directory = NULL;
3406 }
3407 ret->filename =
3408 (char *) xmlStrdup((const xmlChar *) redir);
3409 }
3410 }
3411 }
3412#endif
3413 return(ret);
3414}
3415
Daniel Veillard561b7f82002-03-20 21:55:57 +00003416static int xmlSysIDExists(const char *URL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003417#ifdef HAVE_STAT
3418 int ret;
3419 struct stat info;
3420 const char *path;
3421
3422 if (URL == NULL)
3423 return(0);
3424
Daniel Veillardf4862f02002-09-10 11:13:43 +00003425 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003426#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00003427 path = &URL[17];
3428#else
Daniel Veillard6990bf32001-08-23 21:17:48 +00003429 path = &URL[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00003430#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003431 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003432#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard6990bf32001-08-23 21:17:48 +00003433 path = &URL[8];
3434#else
3435 path = &URL[7];
3436#endif
3437 } else
3438 path = URL;
3439 ret = stat(path, &info);
Daniel Veillard561b7f82002-03-20 21:55:57 +00003440 if (ret == 0)
3441 return(1);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003442#endif
Daniel Veillard561b7f82002-03-20 21:55:57 +00003443 return(0);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003444}
Daniel Veillard6990bf32001-08-23 21:17:48 +00003445
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003446/**
Owen Taylor3473f882001-02-23 17:55:21 +00003447 * xmlDefaultExternalEntityLoader:
3448 * @URL: the URL for the entity to load
3449 * @ID: the System ID for the entity to load
3450 * @ctxt: the context in which the entity is called or NULL
3451 *
3452 * By default we don't load external entitites, yet.
3453 *
3454 * Returns a new allocated xmlParserInputPtr, or NULL.
3455 */
Daniel Veillarda840b692003-10-19 13:35:37 +00003456static xmlParserInputPtr
Owen Taylor3473f882001-02-23 17:55:21 +00003457xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
Daniel Veillarda840b692003-10-19 13:35:37 +00003458 xmlParserCtxtPtr ctxt)
3459{
Owen Taylor3473f882001-02-23 17:55:21 +00003460 xmlParserInputPtr ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003461 xmlChar *resource = NULL;
Daniel Veillarda840b692003-10-19 13:35:37 +00003462
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003463#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003464 xmlCatalogAllow pref;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003465#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003466
3467#ifdef DEBUG_EXTERNAL_ENTITIES
3468 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda840b692003-10-19 13:35:37 +00003469 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00003470#endif
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003471#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillard61b93382003-11-03 14:28:31 +00003472 if ((ctxt != NULL) && (ctxt->options & XML_PARSE_NONET)) {
3473 int options = ctxt->options;
3474
3475 ctxt->options -= XML_PARSE_NONET;
3476 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
3477 ctxt->options = options;
3478 return(ret);
3479 }
3480
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003481 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003482 * If the resource doesn't exists as a file,
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003483 * try to load it from the resource pointed in the catalogs
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003484 */
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003485 pref = xmlCatalogGetDefaults();
3486
Daniel Veillard561b7f82002-03-20 21:55:57 +00003487 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlSysIDExists(URL))) {
Daniel Veillarda840b692003-10-19 13:35:37 +00003488 /*
3489 * Do a local lookup
3490 */
Daniel Veillard42595322004-11-08 10:52:06 +00003491 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
Daniel Veillarda840b692003-10-19 13:35:37 +00003492 ((pref == XML_CATA_ALLOW_ALL) ||
3493 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3494 resource = xmlCatalogLocalResolve(ctxt->catalogs,
3495 (const xmlChar *) ID,
3496 (const xmlChar *) URL);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003497 }
Daniel Veillarda840b692003-10-19 13:35:37 +00003498 /*
3499 * Try a global lookup
3500 */
3501 if ((resource == NULL) &&
3502 ((pref == XML_CATA_ALLOW_ALL) ||
3503 (pref == XML_CATA_ALLOW_GLOBAL))) {
3504 resource = xmlCatalogResolve((const xmlChar *) ID,
3505 (const xmlChar *) URL);
3506 }
3507 if ((resource == NULL) && (URL != NULL))
3508 resource = xmlStrdup((const xmlChar *) URL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003509
Daniel Veillarda840b692003-10-19 13:35:37 +00003510 /*
3511 * TODO: do an URI lookup on the reference
3512 */
3513 if ((resource != NULL)
3514 && (!xmlSysIDExists((const char *) resource))) {
3515 xmlChar *tmp = NULL;
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003516
Daniel Veillard42595322004-11-08 10:52:06 +00003517 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
Daniel Veillarda840b692003-10-19 13:35:37 +00003518 ((pref == XML_CATA_ALLOW_ALL) ||
3519 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3520 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
3521 }
3522 if ((tmp == NULL) &&
3523 ((pref == XML_CATA_ALLOW_ALL) ||
3524 (pref == XML_CATA_ALLOW_GLOBAL))) {
3525 tmp = xmlCatalogResolveURI(resource);
3526 }
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003527
Daniel Veillarda840b692003-10-19 13:35:37 +00003528 if (tmp != NULL) {
3529 xmlFree(resource);
3530 resource = tmp;
3531 }
3532 }
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003533 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003534#endif
3535
3536 if (resource == NULL)
Daniel Veillarda840b692003-10-19 13:35:37 +00003537 resource = (xmlChar *) URL;
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003538
3539 if (resource == NULL) {
Daniel Veillarda840b692003-10-19 13:35:37 +00003540 if (ID == NULL)
3541 ID = "NULL";
Daniel Veillarde8039df2003-10-27 11:25:13 +00003542 __xmlLoaderErr(ctxt, "failed to load external entity \"%s\"\n", ID);
Daniel Veillarda840b692003-10-19 13:35:37 +00003543 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003544 }
Daniel Veillarda840b692003-10-19 13:35:37 +00003545 ret = xmlNewInputFromFile(ctxt, (const char *) resource);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003546 if ((resource != NULL) && (resource != (xmlChar *) URL))
Daniel Veillarda840b692003-10-19 13:35:37 +00003547 xmlFree(resource);
3548 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003549}
3550
3551static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
3552 xmlDefaultExternalEntityLoader;
3553
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003554/**
Owen Taylor3473f882001-02-23 17:55:21 +00003555 * xmlSetExternalEntityLoader:
3556 * @f: the new entity resolver function
3557 *
3558 * Changes the defaultexternal entity resolver function for the application
3559 */
3560void
3561xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
3562 xmlCurrentExternalEntityLoader = f;
3563}
3564
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003565/**
Owen Taylor3473f882001-02-23 17:55:21 +00003566 * xmlGetExternalEntityLoader:
3567 *
3568 * Get the default external entity resolver function for the application
3569 *
3570 * Returns the xmlExternalEntityLoader function pointer
3571 */
3572xmlExternalEntityLoader
3573xmlGetExternalEntityLoader(void) {
3574 return(xmlCurrentExternalEntityLoader);
3575}
3576
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003577/**
Owen Taylor3473f882001-02-23 17:55:21 +00003578 * xmlLoadExternalEntity:
3579 * @URL: the URL for the entity to load
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00003580 * @ID: the Public ID for the entity to load
Owen Taylor3473f882001-02-23 17:55:21 +00003581 * @ctxt: the context in which the entity is called or NULL
3582 *
3583 * Load an external entity, note that the use of this function for
3584 * unparsed entities may generate problems
Owen Taylor3473f882001-02-23 17:55:21 +00003585 *
3586 * Returns the xmlParserInputPtr or NULL
3587 */
3588xmlParserInputPtr
3589xmlLoadExternalEntity(const char *URL, const char *ID,
3590 xmlParserCtxtPtr ctxt) {
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00003591 if ((URL != NULL) && (xmlSysIDExists(URL) == 0)) {
3592 char *canonicFilename;
3593 xmlParserInputPtr ret;
3594
3595 canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL);
3596 if (canonicFilename == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003597 xmlIOErrMemory("building canonical path\n");
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00003598 return(NULL);
3599 }
3600
3601 ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt);
3602 xmlFree(canonicFilename);
3603 return(ret);
3604 }
Owen Taylor3473f882001-02-23 17:55:21 +00003605 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
3606}
3607
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003608/************************************************************************
3609 * *
3610 * Disabling Network access *
3611 * *
3612 ************************************************************************/
3613
3614#ifdef LIBXML_CATALOG_ENABLED
3615static int
3616xmlNoNetExists(const char *URL)
3617{
3618#ifdef HAVE_STAT
3619 int ret;
3620 struct stat info;
3621 const char *path;
3622
3623 if (URL == NULL)
3624 return (0);
3625
Daniel Veillardf4862f02002-09-10 11:13:43 +00003626 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003627#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00003628 path = &URL[17];
3629#else
3630 path = &URL[16];
3631#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003632 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003633#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003634 path = &URL[8];
3635#else
3636 path = &URL[7];
3637#endif
3638 } else
3639 path = URL;
3640 ret = stat(path, &info);
3641 if (ret == 0)
3642 return (1);
3643#endif
3644 return (0);
3645}
3646#endif
3647
3648/**
3649 * xmlNoNetExternalEntityLoader:
3650 * @URL: the URL for the entity to load
3651 * @ID: the System ID for the entity to load
3652 * @ctxt: the context in which the entity is called or NULL
3653 *
3654 * A specific entity loader disabling network accesses, though still
3655 * allowing local catalog accesses for resolution.
3656 *
3657 * Returns a new allocated xmlParserInputPtr, or NULL.
3658 */
3659xmlParserInputPtr
3660xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
3661 xmlParserCtxtPtr ctxt) {
3662 xmlParserInputPtr input = NULL;
3663 xmlChar *resource = NULL;
3664
3665#ifdef LIBXML_CATALOG_ENABLED
3666 xmlCatalogAllow pref;
3667
3668 /*
3669 * If the resource doesn't exists as a file,
3670 * try to load it from the resource pointed in the catalogs
3671 */
3672 pref = xmlCatalogGetDefaults();
3673
3674 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
3675 /*
3676 * Do a local lookup
3677 */
Daniel Veillard42595322004-11-08 10:52:06 +00003678 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003679 ((pref == XML_CATA_ALLOW_ALL) ||
3680 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3681 resource = xmlCatalogLocalResolve(ctxt->catalogs,
3682 (const xmlChar *)ID,
3683 (const xmlChar *)URL);
3684 }
3685 /*
3686 * Try a global lookup
3687 */
3688 if ((resource == NULL) &&
3689 ((pref == XML_CATA_ALLOW_ALL) ||
3690 (pref == XML_CATA_ALLOW_GLOBAL))) {
3691 resource = xmlCatalogResolve((const xmlChar *)ID,
3692 (const xmlChar *)URL);
3693 }
3694 if ((resource == NULL) && (URL != NULL))
3695 resource = xmlStrdup((const xmlChar *) URL);
3696
3697 /*
3698 * TODO: do an URI lookup on the reference
3699 */
3700 if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
3701 xmlChar *tmp = NULL;
3702
Daniel Veillard42595322004-11-08 10:52:06 +00003703 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003704 ((pref == XML_CATA_ALLOW_ALL) ||
3705 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3706 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
3707 }
3708 if ((tmp == NULL) &&
3709 ((pref == XML_CATA_ALLOW_ALL) ||
3710 (pref == XML_CATA_ALLOW_GLOBAL))) {
3711 tmp = xmlCatalogResolveURI(resource);
3712 }
3713
3714 if (tmp != NULL) {
3715 xmlFree(resource);
3716 resource = tmp;
3717 }
3718 }
3719 }
3720#endif
3721 if (resource == NULL)
3722 resource = (xmlChar *) URL;
3723
3724 if (resource != NULL) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003725 if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
3726 (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003727 xmlIOErr(XML_IO_NETWORK_ATTEMPT, (const char *) resource);
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003728 if (resource != (xmlChar *) URL)
3729 xmlFree(resource);
3730 return(NULL);
3731 }
3732 }
3733 input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
3734 if (resource != (xmlChar *) URL)
3735 xmlFree(resource);
3736 return(input);
3737}
3738
Daniel Veillard5d4644e2005-04-01 13:11:58 +00003739#define bottom_xmlIO
3740#include "elfgcchack.h"