blob: 73a995dd1b0da0a741d12467da92d0e684b667ad [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
Anders F Bjorklundeae52612011-09-18 16:59:13 +020038#ifdef HAVE_LZMA_H
39#include <lzma.h>
40#endif
Owen Taylor3473f882001-02-23 17:55:21 +000041
Daniel Veillard59d3ed82007-04-17 12:44:58 +000042#if defined(WIN32) || defined(_WIN32)
Daniel Veillardf7416012006-04-27 08:15:20 +000043#include <windows.h>
44#endif
45
Daniel Veillard59d3ed82007-04-17 12:44:58 +000046#if defined(_WIN32_WCE)
47#include <winnls.h> /* for CP_UTF8 */
48#endif
49
Owen Taylor3473f882001-02-23 17:55:21 +000050/* Figure a portable way to know if a file is a directory. */
51#ifndef HAVE_STAT
52# ifdef HAVE__STAT
Daniel Veillard50f34372001-08-03 12:06:36 +000053 /* MS C library seems to define stat and _stat. The definition
54 is identical. Still, mapping them to each other causes a warning. */
55# ifndef _MSC_VER
56# define stat(x,y) _stat(x,y)
57# endif
Owen Taylor3473f882001-02-23 17:55:21 +000058# define HAVE_STAT
59# endif
Daniel Veillard8ca85b22006-09-01 09:56:07 +000060#else
61# ifdef HAVE__STAT
Daniel Veillard0da41662006-10-10 09:05:36 +000062# if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
Daniel Veillard8ca85b22006-09-01 09:56:07 +000063# define stat _stat
Daniel Veillard0da41662006-10-10 09:05:36 +000064# endif
Daniel Veillard8ca85b22006-09-01 09:56:07 +000065# endif
Owen Taylor3473f882001-02-23 17:55:21 +000066#endif
67#ifdef HAVE_STAT
68# ifndef S_ISDIR
69# ifdef _S_ISDIR
70# define S_ISDIR(x) _S_ISDIR(x)
71# else
72# ifdef S_IFDIR
73# ifndef S_IFMT
74# ifdef _S_IFMT
75# define S_IFMT _S_IFMT
76# endif
77# endif
78# ifdef S_IFMT
79# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
80# endif
81# endif
82# endif
83# endif
84#endif
85
86#include <libxml/xmlmemory.h>
87#include <libxml/parser.h>
88#include <libxml/parserInternals.h>
89#include <libxml/xmlIO.h>
Daniel Veillard388236f2001-07-08 18:35:48 +000090#include <libxml/uri.h>
Owen Taylor3473f882001-02-23 17:55:21 +000091#include <libxml/nanohttp.h>
92#include <libxml/nanoftp.h>
93#include <libxml/xmlerror.h>
Daniel Veillard7d6fd212001-05-10 15:34:11 +000094#ifdef LIBXML_CATALOG_ENABLED
95#include <libxml/catalog.h>
96#endif
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000097#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000098
Daniel Veillardf012a642001-07-23 19:10:52 +000099/* #define VERBOSE_FAILURE */
Daniel Veillard1fd36d22001-07-04 22:54:28 +0000100/* #define DEBUG_EXTERNAL_ENTITIES */
Owen Taylor3473f882001-02-23 17:55:21 +0000101/* #define DEBUG_INPUT */
102
103#ifdef DEBUG_INPUT
104#define MINLEN 40
105#else
106#define MINLEN 4000
107#endif
108
109/*
110 * Input I/O callback sets
111 */
112typedef struct _xmlInputCallback {
113 xmlInputMatchCallback matchcallback;
114 xmlInputOpenCallback opencallback;
115 xmlInputReadCallback readcallback;
116 xmlInputCloseCallback closecallback;
117} xmlInputCallback;
118
119#define MAX_INPUT_CALLBACK 15
120
Daniel Veillard22090732001-07-16 00:06:07 +0000121static xmlInputCallback xmlInputCallbackTable[MAX_INPUT_CALLBACK];
122static int xmlInputCallbackNr = 0;
123static int xmlInputCallbackInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000124
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000125#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000126/*
127 * Output I/O callback sets
128 */
129typedef struct _xmlOutputCallback {
130 xmlOutputMatchCallback matchcallback;
131 xmlOutputOpenCallback opencallback;
132 xmlOutputWriteCallback writecallback;
133 xmlOutputCloseCallback closecallback;
134} xmlOutputCallback;
135
136#define MAX_OUTPUT_CALLBACK 15
137
Daniel Veillard22090732001-07-16 00:06:07 +0000138static xmlOutputCallback xmlOutputCallbackTable[MAX_OUTPUT_CALLBACK];
139static int xmlOutputCallbackNr = 0;
140static int xmlOutputCallbackInitialized = 0;
Daniel Veillardda3fee42008-09-01 13:08:57 +0000141
142xmlOutputBufferPtr
143xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder);
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000144#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000145
Daniel Veillard05d987b2003-10-08 11:54:57 +0000146/************************************************************************
147 * *
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200148 * Tree memory error handler *
Daniel Veillard05d987b2003-10-08 11:54:57 +0000149 * *
150 ************************************************************************/
Daniel Veillardf4862f02002-09-10 11:13:43 +0000151
Daniel Veillard05d987b2003-10-08 11:54:57 +0000152static const char *IOerr[] = {
Daniel Veillarda8856222003-10-08 19:26:03 +0000153 "Unknown IO error", /* UNKNOWN */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000154 "Permission denied", /* EACCES */
155 "Resource temporarily unavailable",/* EAGAIN */
156 "Bad file descriptor", /* EBADF */
157 "Bad message", /* EBADMSG */
158 "Resource busy", /* EBUSY */
159 "Operation canceled", /* ECANCELED */
160 "No child processes", /* ECHILD */
161 "Resource deadlock avoided",/* EDEADLK */
162 "Domain error", /* EDOM */
163 "File exists", /* EEXIST */
164 "Bad address", /* EFAULT */
165 "File too large", /* EFBIG */
166 "Operation in progress", /* EINPROGRESS */
167 "Interrupted function call",/* EINTR */
168 "Invalid argument", /* EINVAL */
169 "Input/output error", /* EIO */
170 "Is a directory", /* EISDIR */
171 "Too many open files", /* EMFILE */
172 "Too many links", /* EMLINK */
173 "Inappropriate message buffer length",/* EMSGSIZE */
174 "Filename too long", /* ENAMETOOLONG */
175 "Too many open files in system",/* ENFILE */
176 "No such device", /* ENODEV */
177 "No such file or directory",/* ENOENT */
178 "Exec format error", /* ENOEXEC */
179 "No locks available", /* ENOLCK */
180 "Not enough space", /* ENOMEM */
181 "No space left on device", /* ENOSPC */
182 "Function not implemented", /* ENOSYS */
183 "Not a directory", /* ENOTDIR */
184 "Directory not empty", /* ENOTEMPTY */
185 "Not supported", /* ENOTSUP */
186 "Inappropriate I/O control operation",/* ENOTTY */
187 "No such device or address",/* ENXIO */
188 "Operation not permitted", /* EPERM */
189 "Broken pipe", /* EPIPE */
190 "Result too large", /* ERANGE */
191 "Read-only file system", /* EROFS */
192 "Invalid seek", /* ESPIPE */
193 "No such process", /* ESRCH */
194 "Operation timed out", /* ETIMEDOUT */
195 "Improper link", /* EXDEV */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000196 "Attempt to load network entity %s", /* XML_IO_NETWORK_ATTEMPT */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000197 "encoder error", /* XML_IO_ENCODER */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000198 "flush error",
199 "write error",
200 "no input",
201 "buffer full",
202 "loading error",
203 "not a socket", /* ENOTSOCK */
204 "already connected", /* EISCONN */
Daniel Veillard29b17482004-08-16 00:39:03 +0000205 "connection refused", /* ECONNREFUSED */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000206 "unreachable network", /* ENETUNREACH */
207 "adddress in use", /* EADDRINUSE */
208 "already in use", /* EALREADY */
209 "unknown address familly", /* EAFNOSUPPORT */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000210};
211
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000212#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
Daniel Veillardf7416012006-04-27 08:15:20 +0000213/**
214 * __xmlIOWin32UTF8ToWChar:
215 * @u8String: uft-8 string
216 *
217 * Convert a string from utf-8 to wchar (WINDOWS ONLY!)
218 */
219static wchar_t *
220__xmlIOWin32UTF8ToWChar(const char *u8String)
221{
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +0000222 wchar_t *wString = NULL;
Daniel Veillardf7416012006-04-27 08:15:20 +0000223
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +0000224 if (u8String) {
225 int wLen =
226 MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, u8String,
227 -1, NULL, 0);
228 if (wLen) {
229 wString = xmlMalloc(wLen * sizeof(wchar_t));
230 if (wString) {
231 if (MultiByteToWideChar
232 (CP_UTF8, 0, u8String, -1, wString, wLen) == 0) {
233 xmlFree(wString);
234 wString = NULL;
235 }
236 }
237 }
238 }
239
240 return wString;
Daniel Veillardf7416012006-04-27 08:15:20 +0000241}
242#endif
243
Daniel Veillard05d987b2003-10-08 11:54:57 +0000244/**
245 * xmlIOErrMemory:
246 * @extra: extra informations
247 *
248 * Handle an out of memory condition
249 */
250static void
251xmlIOErrMemory(const char *extra)
252{
253 __xmlSimpleError(XML_FROM_IO, XML_ERR_NO_MEMORY, NULL, NULL, extra);
254}
255
256/**
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000257 * __xmlIOErr:
Daniel Veillard05d987b2003-10-08 11:54:57 +0000258 * @code: the error number
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000259 * @
Daniel Veillard05d987b2003-10-08 11:54:57 +0000260 * @extra: extra informations
261 *
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000262 * Handle an I/O error
Daniel Veillard05d987b2003-10-08 11:54:57 +0000263 */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000264void
265__xmlIOErr(int domain, int code, const char *extra)
Daniel Veillard05d987b2003-10-08 11:54:57 +0000266{
267 unsigned int idx;
268
269 if (code == 0) {
270#ifdef HAVE_ERRNO_H
271 if (errno == 0) code = 0;
272#ifdef EACCES
273 else if (errno == EACCES) code = XML_IO_EACCES;
274#endif
275#ifdef EAGAIN
276 else if (errno == EAGAIN) code = XML_IO_EAGAIN;
277#endif
278#ifdef EBADF
279 else if (errno == EBADF) code = XML_IO_EBADF;
280#endif
281#ifdef EBADMSG
282 else if (errno == EBADMSG) code = XML_IO_EBADMSG;
283#endif
284#ifdef EBUSY
285 else if (errno == EBUSY) code = XML_IO_EBUSY;
286#endif
287#ifdef ECANCELED
288 else if (errno == ECANCELED) code = XML_IO_ECANCELED;
289#endif
290#ifdef ECHILD
291 else if (errno == ECHILD) code = XML_IO_ECHILD;
292#endif
293#ifdef EDEADLK
294 else if (errno == EDEADLK) code = XML_IO_EDEADLK;
295#endif
296#ifdef EDOM
297 else if (errno == EDOM) code = XML_IO_EDOM;
298#endif
299#ifdef EEXIST
300 else if (errno == EEXIST) code = XML_IO_EEXIST;
301#endif
302#ifdef EFAULT
303 else if (errno == EFAULT) code = XML_IO_EFAULT;
304#endif
305#ifdef EFBIG
306 else if (errno == EFBIG) code = XML_IO_EFBIG;
307#endif
308#ifdef EINPROGRESS
309 else if (errno == EINPROGRESS) code = XML_IO_EINPROGRESS;
310#endif
311#ifdef EINTR
312 else if (errno == EINTR) code = XML_IO_EINTR;
313#endif
314#ifdef EINVAL
315 else if (errno == EINVAL) code = XML_IO_EINVAL;
316#endif
317#ifdef EIO
318 else if (errno == EIO) code = XML_IO_EIO;
319#endif
320#ifdef EISDIR
321 else if (errno == EISDIR) code = XML_IO_EISDIR;
322#endif
323#ifdef EMFILE
324 else if (errno == EMFILE) code = XML_IO_EMFILE;
325#endif
326#ifdef EMLINK
327 else if (errno == EMLINK) code = XML_IO_EMLINK;
328#endif
329#ifdef EMSGSIZE
330 else if (errno == EMSGSIZE) code = XML_IO_EMSGSIZE;
331#endif
332#ifdef ENAMETOOLONG
333 else if (errno == ENAMETOOLONG) code = XML_IO_ENAMETOOLONG;
334#endif
335#ifdef ENFILE
336 else if (errno == ENFILE) code = XML_IO_ENFILE;
337#endif
338#ifdef ENODEV
339 else if (errno == ENODEV) code = XML_IO_ENODEV;
340#endif
341#ifdef ENOENT
342 else if (errno == ENOENT) code = XML_IO_ENOENT;
343#endif
344#ifdef ENOEXEC
345 else if (errno == ENOEXEC) code = XML_IO_ENOEXEC;
346#endif
347#ifdef ENOLCK
348 else if (errno == ENOLCK) code = XML_IO_ENOLCK;
349#endif
350#ifdef ENOMEM
351 else if (errno == ENOMEM) code = XML_IO_ENOMEM;
352#endif
353#ifdef ENOSPC
354 else if (errno == ENOSPC) code = XML_IO_ENOSPC;
355#endif
356#ifdef ENOSYS
357 else if (errno == ENOSYS) code = XML_IO_ENOSYS;
358#endif
359#ifdef ENOTDIR
360 else if (errno == ENOTDIR) code = XML_IO_ENOTDIR;
361#endif
362#ifdef ENOTEMPTY
363 else if (errno == ENOTEMPTY) code = XML_IO_ENOTEMPTY;
364#endif
365#ifdef ENOTSUP
366 else if (errno == ENOTSUP) code = XML_IO_ENOTSUP;
367#endif
368#ifdef ENOTTY
369 else if (errno == ENOTTY) code = XML_IO_ENOTTY;
370#endif
371#ifdef ENXIO
372 else if (errno == ENXIO) code = XML_IO_ENXIO;
373#endif
374#ifdef EPERM
375 else if (errno == EPERM) code = XML_IO_EPERM;
376#endif
377#ifdef EPIPE
378 else if (errno == EPIPE) code = XML_IO_EPIPE;
379#endif
380#ifdef ERANGE
381 else if (errno == ERANGE) code = XML_IO_ERANGE;
382#endif
383#ifdef EROFS
384 else if (errno == EROFS) code = XML_IO_EROFS;
385#endif
386#ifdef ESPIPE
387 else if (errno == ESPIPE) code = XML_IO_ESPIPE;
388#endif
389#ifdef ESRCH
390 else if (errno == ESRCH) code = XML_IO_ESRCH;
391#endif
392#ifdef ETIMEDOUT
393 else if (errno == ETIMEDOUT) code = XML_IO_ETIMEDOUT;
394#endif
395#ifdef EXDEV
396 else if (errno == EXDEV) code = XML_IO_EXDEV;
397#endif
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000398#ifdef ENOTSOCK
399 else if (errno == ENOTSOCK) code = XML_IO_ENOTSOCK;
400#endif
401#ifdef EISCONN
402 else if (errno == EISCONN) code = XML_IO_EISCONN;
403#endif
404#ifdef ECONNREFUSED
405 else if (errno == ECONNREFUSED) code = XML_IO_ECONNREFUSED;
406#endif
407#ifdef ETIMEDOUT
408 else if (errno == ETIMEDOUT) code = XML_IO_ETIMEDOUT;
409#endif
410#ifdef ENETUNREACH
411 else if (errno == ENETUNREACH) code = XML_IO_ENETUNREACH;
412#endif
413#ifdef EADDRINUSE
414 else if (errno == EADDRINUSE) code = XML_IO_EADDRINUSE;
415#endif
416#ifdef EINPROGRESS
417 else if (errno == EINPROGRESS) code = XML_IO_EINPROGRESS;
418#endif
419#ifdef EALREADY
420 else if (errno == EALREADY) code = XML_IO_EALREADY;
421#endif
422#ifdef EAFNOSUPPORT
423 else if (errno == EAFNOSUPPORT) code = XML_IO_EAFNOSUPPORT;
424#endif
Daniel Veillard05d987b2003-10-08 11:54:57 +0000425 else code = XML_IO_UNKNOWN;
426#endif /* HAVE_ERRNO_H */
427 }
428 idx = 0;
429 if (code >= XML_IO_UNKNOWN) idx = code - XML_IO_UNKNOWN;
430 if (idx >= (sizeof(IOerr) / sizeof(IOerr[0]))) idx = 0;
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200431
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000432 __xmlSimpleError(domain, code, NULL, IOerr[idx], extra);
433}
434
435/**
436 * xmlIOErr:
437 * @code: the error number
438 * @extra: extra informations
439 *
440 * Handle an I/O error
441 */
442static void
443xmlIOErr(int code, const char *extra)
444{
445 __xmlIOErr(XML_FROM_IO, code, extra);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000446}
447
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000448/**
Daniel Veillarde8039df2003-10-27 11:25:13 +0000449 * __xmlLoaderErr:
450 * @ctx: the parser context
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000451 * @extra: extra informations
452 *
453 * Handle a resource access error
454 */
Daniel Veillarde8039df2003-10-27 11:25:13 +0000455void
456__xmlLoaderErr(void *ctx, const char *msg, const char *filename)
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000457{
Daniel Veillarde8039df2003-10-27 11:25:13 +0000458 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000459 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000460 xmlGenericErrorFunc channel = NULL;
461 void *data = NULL;
462 xmlErrorLevel level = XML_ERR_ERROR;
463
Daniel Veillard157fee02003-10-31 10:36:03 +0000464 if ((ctxt != NULL) && (ctxt->disableSAX != 0) &&
465 (ctxt->instate == XML_PARSER_EOF))
466 return;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000467 if ((ctxt != NULL) && (ctxt->sax != NULL)) {
468 if (ctxt->validate) {
469 channel = ctxt->sax->error;
470 level = XML_ERR_ERROR;
471 } else {
472 channel = ctxt->sax->warning;
473 level = XML_ERR_WARNING;
474 }
Daniel Veillard5ea30d72004-11-08 11:54:28 +0000475 if (ctxt->sax->initialized == XML_SAX2_MAGIC)
476 schannel = ctxt->sax->serror;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000477 data = ctxt->userData;
478 }
Daniel Veillard659e71e2003-10-10 14:10:40 +0000479 __xmlRaiseError(schannel, channel, data, ctxt, NULL, XML_FROM_IO,
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000480 XML_IO_LOAD_ERROR, level, NULL, 0,
481 filename, NULL, NULL, 0, 0,
482 msg, filename);
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200483
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000484}
485
Daniel Veillard05d987b2003-10-08 11:54:57 +0000486/************************************************************************
487 * *
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200488 * Tree memory error handler *
Daniel Veillard05d987b2003-10-08 11:54:57 +0000489 * *
490 ************************************************************************/
Daniel Veillardf4862f02002-09-10 11:13:43 +0000491/**
Daniel Veillard01c13b52002-12-10 15:19:08 +0000492 * xmlNormalizeWindowsPath:
Daniel Veillard33300b42003-04-17 09:09:19 +0000493 * @path: the input file path
Daniel Veillardf4862f02002-09-10 11:13:43 +0000494 *
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +0000495 * This function is obsolete. Please see xmlURIFromPath in uri.c for
496 * a better solution.
Daniel Veillard33300b42003-04-17 09:09:19 +0000497 *
498 * Returns a canonicalized version of the path
Daniel Veillardf4862f02002-09-10 11:13:43 +0000499 */
500xmlChar *
501xmlNormalizeWindowsPath(const xmlChar *path)
502{
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +0000503 return xmlCanonicPath(path);
Daniel Veillardf4862f02002-09-10 11:13:43 +0000504}
505
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000506/**
507 * xmlCleanupInputCallbacks:
508 *
509 * clears the entire input callback table. this includes the
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200510 * compiled-in I/O.
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000511 */
512void
513xmlCleanupInputCallbacks(void)
514{
515 int i;
516
517 if (!xmlInputCallbackInitialized)
518 return;
519
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000520 for (i = xmlInputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000521 xmlInputCallbackTable[i].matchcallback = NULL;
522 xmlInputCallbackTable[i].opencallback = NULL;
523 xmlInputCallbackTable[i].readcallback = NULL;
524 xmlInputCallbackTable[i].closecallback = NULL;
525 }
526
527 xmlInputCallbackNr = 0;
Aleksey Sanin9c45ba82002-06-06 21:46:13 +0000528 xmlInputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000529}
530
Daniel Veillardaecc0dc2004-05-08 02:32:07 +0000531/**
William M. Brack4e3a9fa2004-08-03 22:41:11 +0000532 * xmlPopInputCallbacks:
Daniel Veillardaecc0dc2004-05-08 02:32:07 +0000533 *
534 * Clear the top input callback from the input stack. this includes the
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200535 * compiled-in I/O.
Daniel Veillardaecc0dc2004-05-08 02:32:07 +0000536 *
537 * Returns the number of input callback registered or -1 in case of error.
538 */
539int
540xmlPopInputCallbacks(void)
541{
542 if (!xmlInputCallbackInitialized)
543 return(-1);
544
545 if (xmlInputCallbackNr <= 0)
546 return(-1);
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200547
Daniel Veillardaecc0dc2004-05-08 02:32:07 +0000548 xmlInputCallbackNr--;
549 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = NULL;
550 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = NULL;
551 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = NULL;
552 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = NULL;
553
554 return(xmlInputCallbackNr);
555}
556
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000557#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000558/**
559 * xmlCleanupOutputCallbacks:
560 *
561 * clears the entire output callback table. this includes the
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200562 * compiled-in I/O callbacks.
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000563 */
564void
565xmlCleanupOutputCallbacks(void)
566{
567 int i;
568
569 if (!xmlOutputCallbackInitialized)
570 return;
571
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000572 for (i = xmlOutputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000573 xmlOutputCallbackTable[i].matchcallback = NULL;
574 xmlOutputCallbackTable[i].opencallback = NULL;
575 xmlOutputCallbackTable[i].writecallback = NULL;
576 xmlOutputCallbackTable[i].closecallback = NULL;
577 }
578
579 xmlOutputCallbackNr = 0;
Aleksey Sanin9c45ba82002-06-06 21:46:13 +0000580 xmlOutputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000581}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000582#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000583
Owen Taylor3473f882001-02-23 17:55:21 +0000584/************************************************************************
585 * *
586 * Standard I/O for file accesses *
587 * *
588 ************************************************************************/
589
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000590#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
591
592/**
593 * xmlWrapOpenUtf8:
594 * @path: the path in utf-8 encoding
595 * @mode: type of access (0 - read, 1 - write)
596 *
597 * function opens the file specified by @path
598 *
599 */
600static FILE*
601xmlWrapOpenUtf8(const char *path,int mode)
602{
603 FILE *fd = NULL;
604 wchar_t *wPath;
605
606 wPath = __xmlIOWin32UTF8ToWChar(path);
607 if(wPath)
608 {
609 fd = _wfopen(wPath, mode ? L"wb" : L"rb");
610 xmlFree(wPath);
611 }
Daniel Veillard0da41662006-10-10 09:05:36 +0000612 /* maybe path in native encoding */
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000613 if(fd == NULL)
614 fd = fopen(path, mode ? "wb" : "rb");
615
616 return fd;
617}
618
Rob Richards6c61e022009-08-12 11:41:27 -0400619#ifdef HAVE_ZLIB_H
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200620static gzFile
621xmlWrapGzOpenUtf8(const char *path, const char *mode)
622{
623 gzFile fd;
624 wchar_t *wPath;
625
626 fd = gzopen (path, mode);
627 if (fd)
628 return fd;
629
630 wPath = __xmlIOWin32UTF8ToWChar(path);
631 if(wPath)
632 {
633 int d, m = (strstr(mode, "r") ? O_RDONLY : O_RDWR);
634#ifdef _O_BINARY
635 m |= (strstr(mode, "b") ? _O_BINARY : 0);
636#endif
637 d = _wopen(wPath, m);
638 if (d >= 0)
639 fd = gzdopen(d, mode);
640 xmlFree(wPath);
641 }
642
643 return fd;
644}
Rob Richards6c61e022009-08-12 11:41:27 -0400645#endif
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200646
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000647/**
648 * xmlWrapStatUtf8:
649 * @path: the path in utf-8 encoding
650 * @info: structure that stores results
651 *
652 * function obtains information about the file or directory
653 *
654 */
655static int
656xmlWrapStatUtf8(const char *path,struct stat *info)
657{
658#ifdef HAVE_STAT
659 int retval = -1;
660 wchar_t *wPath;
661
662 wPath = __xmlIOWin32UTF8ToWChar(path);
663 if (wPath)
664 {
665 retval = _wstat(wPath,info);
666 xmlFree(wPath);
667 }
Daniel Veillard0da41662006-10-10 09:05:36 +0000668 /* maybe path in native encoding */
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000669 if(retval < 0)
670 retval = stat(path,info);
671 return retval;
672#else
673 return -1;
674#endif
675}
676
677/**
678 * xmlWrapOpenNative:
679 * @path: the path
680 * @mode: type of access (0 - read, 1 - write)
681 *
682 * function opens the file specified by @path
683 *
684 */
685static FILE*
686xmlWrapOpenNative(const char *path,int mode)
687{
688 return fopen(path,mode ? "wb" : "rb");
689}
690
691/**
692 * xmlWrapStatNative:
693 * @path: the path
694 * @info: structure that stores results
695 *
696 * function obtains information about the file or directory
697 *
698 */
699static int
700xmlWrapStatNative(const char *path,struct stat *info)
701{
702#ifdef HAVE_STAT
703 return stat(path,info);
704#else
705 return -1;
706#endif
707}
708
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +0000709typedef int (* xmlWrapStatFunc) (const char *f, struct stat *s);
710static xmlWrapStatFunc xmlWrapStat = xmlWrapStatNative;
711typedef FILE* (* xmlWrapOpenFunc)(const char *f,int mode);
Rob Richards6460f922006-10-12 21:08:29 +0000712static xmlWrapOpenFunc xmlWrapOpen = xmlWrapOpenNative;
Rob Richards6c61e022009-08-12 11:41:27 -0400713#ifdef HAVE_ZLIB_H
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200714typedef gzFile (* xmlWrapGzOpenFunc) (const char *f, const char *mode);
715static xmlWrapGzOpenFunc xmlWrapGzOpen = gzopen;
Rob Richards6c61e022009-08-12 11:41:27 -0400716#endif
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000717/**
718 * xmlInitPlatformSpecificIo:
719 *
720 * Initialize platform specific features.
721 */
722static void
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +0000723xmlInitPlatformSpecificIo(void)
724{
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000725 static int xmlPlatformIoInitialized = 0;
726 OSVERSIONINFO osvi;
727
728 if(xmlPlatformIoInitialized)
729 return;
730
731 osvi.dwOSVersionInfoSize = sizeof(osvi);
732
733 if(GetVersionEx(&osvi) && (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)) {
734 xmlWrapStat = xmlWrapStatUtf8;
735 xmlWrapOpen = xmlWrapOpenUtf8;
Rob Richards6c61e022009-08-12 11:41:27 -0400736#ifdef HAVE_ZLIB_H
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200737 xmlWrapGzOpen = xmlWrapGzOpenUtf8;
Rob Richards6c61e022009-08-12 11:41:27 -0400738#endif
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000739 } else {
740 xmlWrapStat = xmlWrapStatNative;
741 xmlWrapOpen = xmlWrapOpenNative;
Rob Richards6c61e022009-08-12 11:41:27 -0400742#ifdef HAVE_ZLIB_H
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200743 xmlWrapGzOpen = gzopen;
Rob Richards6c61e022009-08-12 11:41:27 -0400744#endif
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000745 }
746
747 xmlPlatformIoInitialized = 1;
748 return;
749}
750
751#endif
752
Owen Taylor3473f882001-02-23 17:55:21 +0000753/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000754 * xmlCheckFilename:
Owen Taylor3473f882001-02-23 17:55:21 +0000755 * @path: the path to check
756 *
757 * function checks to see if @path is a valid source
758 * (file, socket...) for XML.
759 *
760 * if stat is not available on the target machine,
761 * returns 1. if stat fails, returns 0 (if calling
762 * stat on the filename fails, it can't be right).
763 * if stat succeeds and the file is a directory,
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000764 * returns 2. otherwise returns 1.
Owen Taylor3473f882001-02-23 17:55:21 +0000765 */
766
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000767int
Owen Taylor3473f882001-02-23 17:55:21 +0000768xmlCheckFilename (const char *path)
769{
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000770#ifdef HAVE_STAT
Daniel Veillard0b309952006-05-02 20:34:38 +0000771 struct stat stat_buffer;
772#endif
Daniel Veillardf7416012006-04-27 08:15:20 +0000773 if (path == NULL)
Daniel Veillard0b309952006-05-02 20:34:38 +0000774 return(0);
Daniel Veillarde5a3f372006-08-30 13:11:36 +0000775
Owen Taylor3473f882001-02-23 17:55:21 +0000776#ifdef HAVE_STAT
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000777#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
778 if (xmlWrapStat(path, &stat_buffer) == -1)
779 return 0;
780#else
Owen Taylor3473f882001-02-23 17:55:21 +0000781 if (stat(path, &stat_buffer) == -1)
782 return 0;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000783#endif
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000784#ifdef S_ISDIR
Daniel Veillardf7416012006-04-27 08:15:20 +0000785 if (S_ISDIR(stat_buffer.st_mode))
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000786 return 2;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000787#endif
Daniel Veillardf7416012006-04-27 08:15:20 +0000788#endif /* HAVE_STAT */
Owen Taylor3473f882001-02-23 17:55:21 +0000789 return 1;
790}
791
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000792static int
Owen Taylor3473f882001-02-23 17:55:21 +0000793xmlNop(void) {
794 return(0);
795}
796
797/**
Owen Taylor3473f882001-02-23 17:55:21 +0000798 * xmlFdRead:
799 * @context: the I/O context
800 * @buffer: where to drop data
801 * @len: number of bytes to read
802 *
803 * Read @len bytes to @buffer from the I/O channel.
804 *
805 * Returns the number of bytes written
806 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000807static int
Owen Taylor3473f882001-02-23 17:55:21 +0000808xmlFdRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000809 int ret;
810
811 ret = read((int) (long) context, &buffer[0], len);
812 if (ret < 0) xmlIOErr(0, "read()");
813 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000814}
815
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000816#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000817/**
818 * xmlFdWrite:
819 * @context: the I/O context
820 * @buffer: where to get data
821 * @len: number of bytes to write
822 *
823 * Write @len bytes from @buffer to the I/O channel.
824 *
825 * Returns the number of bytes written
826 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000827static int
Owen Taylor3473f882001-02-23 17:55:21 +0000828xmlFdWrite (void * context, const char * buffer, int len) {
Daniel Veillard9b693b42005-10-28 14:54:17 +0000829 int ret = 0;
Daniel Veillard05d987b2003-10-08 11:54:57 +0000830
Daniel Veillard9b693b42005-10-28 14:54:17 +0000831 if (len > 0) {
832 ret = write((int) (long) context, &buffer[0], len);
833 if (ret < 0) xmlIOErr(0, "write()");
834 }
Daniel Veillard05d987b2003-10-08 11:54:57 +0000835 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000836}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000837#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000838
839/**
840 * xmlFdClose:
841 * @context: the I/O context
842 *
843 * Close an I/O channel
Daniel Veillardf012a642001-07-23 19:10:52 +0000844 *
845 * Returns 0 in case of success and error code otherwise
Owen Taylor3473f882001-02-23 17:55:21 +0000846 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000847static int
Owen Taylor3473f882001-02-23 17:55:21 +0000848xmlFdClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000849 int ret;
850 ret = close((int) (long) context);
851 if (ret < 0) xmlIOErr(0, "close()");
852 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000853}
854
855/**
856 * xmlFileMatch:
857 * @filename: the URI for matching
858 *
859 * input from FILE *
860 *
861 * Returns 1 if matches, 0 otherwise
862 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000863int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000864xmlFileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000865 return(1);
866}
867
868/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000869 * xmlFileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +0000870 * @filename: the URI for matching
871 *
872 * input from FILE *, supports compressed input
873 * if @filename is " " then the standard input is used
874 *
875 * Returns an I/O context or NULL in case of error
876 */
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000877static void *
878xmlFileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +0000879 const char *path = NULL;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000880 FILE *fd;
Owen Taylor3473f882001-02-23 17:55:21 +0000881
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000882 if (filename == NULL)
883 return(NULL);
884
Owen Taylor3473f882001-02-23 17:55:21 +0000885 if (!strcmp(filename, "-")) {
886 fd = stdin;
887 return((void *) fd);
888 }
889
Daniel Veillard5cdbbd22007-06-12 09:39:14 +0000890 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000891#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000892 path = &filename[17];
893#else
Owen Taylor3473f882001-02-23 17:55:21 +0000894 path = &filename[16];
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000895#endif
Daniel Veillard5cdbbd22007-06-12 09:39:14 +0000896 } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000897#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000898 path = &filename[8];
899#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000900 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000901#endif
Daniel Veillard5cdbbd22007-06-12 09:39:14 +0000902 } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:/", 6)) {
903 /* lots of generators seems to lazy to read RFC 1738 */
904#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
905 path = &filename[6];
906#else
907 path = &filename[5];
908#endif
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200909 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000910 path = filename;
911
912 if (path == NULL)
913 return(NULL);
914 if (!xmlCheckFilename(path))
915 return(NULL);
916
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000917#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
918 fd = xmlWrapOpen(path, 0);
919#else
920 fd = fopen(path, "r");
Owen Taylor3473f882001-02-23 17:55:21 +0000921#endif /* WIN32 */
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000922 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +0000923 return((void *) fd);
924}
925
926/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000927 * xmlFileOpen:
928 * @filename: the URI for matching
929 *
930 * Wrapper around xmlFileOpen_real that try it with an unescaped
931 * version of @filename, if this fails fallback to @filename
Daniel Veillard71531f32003-02-05 13:19:53 +0000932 *
933 * Returns a handler or NULL in case or failure
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000934 */
935void *
936xmlFileOpen (const char *filename) {
937 char *unescaped;
938 void *retval;
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000939
Daniel Veillardbd672bc2007-03-30 12:39:25 +0000940 retval = xmlFileOpen_real(filename);
941 if (retval == NULL) {
942 unescaped = xmlURIUnescapeString(filename, 0, NULL);
943 if (unescaped != NULL) {
944 retval = xmlFileOpen_real(unescaped);
945 xmlFree(unescaped);
946 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000947 }
Daniel Veillardbd672bc2007-03-30 12:39:25 +0000948
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000949 return retval;
950}
951
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000952#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000953/**
Owen Taylor3473f882001-02-23 17:55:21 +0000954 * xmlFileOpenW:
955 * @filename: the URI for matching
956 *
957 * output to from FILE *,
958 * if @filename is "-" then the standard output is used
959 *
960 * Returns an I/O context or NULL in case of error
961 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000962static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000963xmlFileOpenW (const char *filename) {
964 const char *path = NULL;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000965 FILE *fd;
Owen Taylor3473f882001-02-23 17:55:21 +0000966
967 if (!strcmp(filename, "-")) {
968 fd = stdout;
969 return((void *) fd);
970 }
971
Daniel Veillardf4862f02002-09-10 11:13:43 +0000972 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000973#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000974 path = &filename[17];
975#else
Owen Taylor3473f882001-02-23 17:55:21 +0000976 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000977#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000978 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000979#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000980 path = &filename[8];
981#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000982 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000983#endif
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200984 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000985 path = filename;
986
987 if (path == NULL)
988 return(NULL);
989
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000990#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
991 fd = xmlWrapOpen(path, 1);
992#else
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200993 fd = fopen(path, "wb");
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000994#endif /* WIN32 */
Daniel Veillarde5a3f372006-08-30 13:11:36 +0000995
Daniel Veillardf7416012006-04-27 08:15:20 +0000996 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +0000997 return((void *) fd);
998}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000999#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001000
1001/**
1002 * xmlFileRead:
1003 * @context: the I/O context
1004 * @buffer: where to drop data
1005 * @len: number of bytes to write
1006 *
1007 * Read @len bytes to @buffer from the I/O channel.
1008 *
Daniel Veillardce682bc2004-11-05 17:22:25 +00001009 * Returns the number of bytes written or < 0 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +00001010 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001011int
Owen Taylor3473f882001-02-23 17:55:21 +00001012xmlFileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001013 int ret;
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001014 if ((context == NULL) || (buffer == NULL))
Daniel Veillardce682bc2004-11-05 17:22:25 +00001015 return(-1);
Daniel Veillard05d987b2003-10-08 11:54:57 +00001016 ret = fread(&buffer[0], 1, len, (FILE *) context);
1017 if (ret < 0) xmlIOErr(0, "fread()");
1018 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001019}
1020
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001021#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001022/**
1023 * xmlFileWrite:
1024 * @context: the I/O context
1025 * @buffer: where to drop data
1026 * @len: number of bytes to write
1027 *
1028 * Write @len bytes from @buffer to the I/O channel.
1029 *
1030 * Returns the number of bytes written
1031 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001032static int
Owen Taylor3473f882001-02-23 17:55:21 +00001033xmlFileWrite (void * context, const char * buffer, int len) {
Daniel Veillard4a6d39b2002-12-17 18:33:01 +00001034 int items;
1035
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001036 if ((context == NULL) || (buffer == NULL))
Daniel Veillardce682bc2004-11-05 17:22:25 +00001037 return(-1);
Daniel Veillard4a6d39b2002-12-17 18:33:01 +00001038 items = fwrite(&buffer[0], len, 1, (FILE *) context);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00001039 if ((items == 0) && (ferror((FILE *) context))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001040 xmlIOErr(0, "fwrite()");
Daniel Veillard97bf4d02003-10-08 18:58:28 +00001041 return(-1);
1042 }
Daniel Veillard4a6d39b2002-12-17 18:33:01 +00001043 return(items * len);
Owen Taylor3473f882001-02-23 17:55:21 +00001044}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001045#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001046
1047/**
1048 * xmlFileClose:
1049 * @context: the I/O context
1050 *
1051 * Close an I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001052 *
1053 * Returns 0 or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +00001054 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001055int
Owen Taylor3473f882001-02-23 17:55:21 +00001056xmlFileClose (void * context) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001057 FILE *fil;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001058 int ret;
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001059
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +00001060 if (context == NULL)
1061 return(-1);
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001062 fil = (FILE *) context;
Daniel Veillard500a1de2004-03-22 15:22:58 +00001063 if ((fil == stdout) || (fil == stderr)) {
1064 ret = fflush(fil);
1065 if (ret < 0)
1066 xmlIOErr(0, "fflush()");
1067 return(0);
1068 }
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001069 if (fil == stdin)
1070 return(0);
Daniel Veillard05d987b2003-10-08 11:54:57 +00001071 ret = ( fclose((FILE *) context) == EOF ) ? -1 : 0;
1072 if (ret < 0)
1073 xmlIOErr(0, "fclose()");
1074 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001075}
1076
1077/**
1078 * xmlFileFlush:
1079 * @context: the I/O context
1080 *
1081 * Flush an I/O channel
1082 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001083static int
Owen Taylor3473f882001-02-23 17:55:21 +00001084xmlFileFlush (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001085 int ret;
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +00001086
1087 if (context == NULL)
1088 return(-1);
Daniel Veillard05d987b2003-10-08 11:54:57 +00001089 ret = ( fflush((FILE *) context) == EOF ) ? -1 : 0;
1090 if (ret < 0)
1091 xmlIOErr(0, "fflush()");
1092 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001093}
1094
Daniel Veillard9a00fd22005-11-09 08:56:26 +00001095#ifdef LIBXML_OUTPUT_ENABLED
1096/**
1097 * xmlBufferWrite:
1098 * @context: the xmlBuffer
1099 * @buffer: the data to write
1100 * @len: number of bytes to write
1101 *
1102 * Write @len bytes from @buffer to the xml buffer
1103 *
1104 * Returns the number of bytes written
1105 */
1106static int
1107xmlBufferWrite (void * context, const char * buffer, int len) {
1108 int ret;
1109
1110 ret = xmlBufferAdd((xmlBufferPtr) context, (const xmlChar *) buffer, len);
1111 if (ret != 0)
1112 return(-1);
1113 return(len);
1114}
Daniel Veillard9a00fd22005-11-09 08:56:26 +00001115#endif
1116
Owen Taylor3473f882001-02-23 17:55:21 +00001117#ifdef HAVE_ZLIB_H
1118/************************************************************************
1119 * *
1120 * I/O for compressed file accesses *
1121 * *
1122 ************************************************************************/
1123/**
1124 * xmlGzfileMatch:
1125 * @filename: the URI for matching
1126 *
1127 * input from compressed file test
1128 *
1129 * Returns 1 if matches, 0 otherwise
1130 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001131static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00001132xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00001133 return(1);
1134}
1135
1136/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001137 * xmlGzfileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +00001138 * @filename: the URI for matching
1139 *
1140 * input from compressed file open
1141 * if @filename is " " then the standard input is used
1142 *
1143 * Returns an I/O context or NULL in case of error
1144 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001145static void *
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001146xmlGzfileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +00001147 const char *path = NULL;
1148 gzFile fd;
1149
1150 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001151 fd = gzdopen(dup(0), "rb");
Owen Taylor3473f882001-02-23 17:55:21 +00001152 return((void *) fd);
1153 }
1154
Daniel Veillardf4862f02002-09-10 11:13:43 +00001155 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001156#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00001157 path = &filename[17];
1158#else
Owen Taylor3473f882001-02-23 17:55:21 +00001159 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00001160#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001161 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001162#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +00001163 path = &filename[8];
1164#else
Owen Taylor3473f882001-02-23 17:55:21 +00001165 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +00001166#endif
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001167 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001168 path = filename;
1169
1170 if (path == NULL)
1171 return(NULL);
1172 if (!xmlCheckFilename(path))
1173 return(NULL);
1174
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001175#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
1176 fd = xmlWrapGzOpen(path, "rb");
1177#else
Owen Taylor3473f882001-02-23 17:55:21 +00001178 fd = gzopen(path, "rb");
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001179#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001180 return((void *) fd);
1181}
1182
1183/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001184 * xmlGzfileOpen:
1185 * @filename: the URI for matching
1186 *
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00001187 * Wrapper around xmlGzfileOpen if the open fais, it will
1188 * try to unescape @filename
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001189 */
1190static void *
1191xmlGzfileOpen (const char *filename) {
1192 char *unescaped;
1193 void *retval;
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00001194
1195 retval = xmlGzfileOpen_real(filename);
1196 if (retval == NULL) {
1197 unescaped = xmlURIUnescapeString(filename, 0, NULL);
1198 if (unescaped != NULL) {
1199 retval = xmlGzfileOpen_real(unescaped);
1200 }
1201 xmlFree(unescaped);
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001202 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001203 return retval;
1204}
1205
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001206#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001207/**
Owen Taylor3473f882001-02-23 17:55:21 +00001208 * xmlGzfileOpenW:
1209 * @filename: the URI for matching
1210 * @compression: the compression factor (0 - 9 included)
1211 *
1212 * input from compressed file open
1213 * if @filename is " " then the standard input is used
1214 *
1215 * Returns an I/O context or NULL in case of error
1216 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001217static void *
Owen Taylor3473f882001-02-23 17:55:21 +00001218xmlGzfileOpenW (const char *filename, int compression) {
1219 const char *path = NULL;
1220 char mode[15];
1221 gzFile fd;
1222
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001223 snprintf(mode, sizeof(mode), "wb%d", compression);
Owen Taylor3473f882001-02-23 17:55:21 +00001224 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001225 fd = gzdopen(dup(1), mode);
Owen Taylor3473f882001-02-23 17:55:21 +00001226 return((void *) fd);
1227 }
1228
Daniel Veillardf4862f02002-09-10 11:13:43 +00001229 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001230#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00001231 path = &filename[17];
1232#else
Owen Taylor3473f882001-02-23 17:55:21 +00001233 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00001234#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001235 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001236#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +00001237 path = &filename[8];
1238#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +00001239 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +00001240#endif
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001241 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001242 path = filename;
1243
1244 if (path == NULL)
1245 return(NULL);
1246
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001247#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
1248 fd = xmlWrapGzOpen(path, mode);
1249#else
Owen Taylor3473f882001-02-23 17:55:21 +00001250 fd = gzopen(path, mode);
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001251#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001252 return((void *) fd);
1253}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001254#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001255
1256/**
1257 * xmlGzfileRead:
1258 * @context: the I/O context
1259 * @buffer: where to drop data
1260 * @len: number of bytes to write
1261 *
1262 * Read @len bytes to @buffer from the compressed I/O channel.
1263 *
1264 * Returns the number of bytes written
1265 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001266static int
Owen Taylor3473f882001-02-23 17:55:21 +00001267xmlGzfileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001268 int ret;
1269
1270 ret = gzread((gzFile) context, &buffer[0], len);
1271 if (ret < 0) xmlIOErr(0, "gzread()");
1272 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001273}
1274
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001275#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001276/**
1277 * xmlGzfileWrite:
1278 * @context: the I/O context
1279 * @buffer: where to drop data
1280 * @len: number of bytes to write
1281 *
1282 * Write @len bytes from @buffer to the compressed I/O channel.
1283 *
1284 * Returns the number of bytes written
1285 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001286static int
Owen Taylor3473f882001-02-23 17:55:21 +00001287xmlGzfileWrite (void * context, const char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001288 int ret;
1289
1290 ret = gzwrite((gzFile) context, (char *) &buffer[0], len);
1291 if (ret < 0) xmlIOErr(0, "gzwrite()");
1292 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001293}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001294#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001295
1296/**
1297 * xmlGzfileClose:
1298 * @context: the I/O context
1299 *
1300 * Close a compressed I/O channel
1301 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001302static int
Owen Taylor3473f882001-02-23 17:55:21 +00001303xmlGzfileClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001304 int ret;
1305
1306 ret = (gzclose((gzFile) context) == Z_OK ) ? 0 : -1;
1307 if (ret < 0) xmlIOErr(0, "gzclose()");
1308 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001309}
1310#endif /* HAVE_ZLIB_H */
1311
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001312#ifdef HAVE_LZMA_H
1313/************************************************************************
1314 * *
1315 * I/O for compressed file accesses *
1316 * *
1317 ************************************************************************/
Daniel Veillardadf5ec92012-01-26 16:56:22 +08001318#include "xzlib.h"
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001319/**
1320 * xmlXzfileMatch:
1321 * @filename: the URI for matching
1322 *
1323 * input from compressed file test
1324 *
1325 * Returns 1 if matches, 0 otherwise
1326 */
1327static int
1328xmlXzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
1329 return(1);
1330}
1331
1332/**
1333 * xmlXzFileOpen_real:
1334 * @filename: the URI for matching
1335 *
1336 * input from compressed file open
1337 * if @filename is " " then the standard input is used
1338 *
1339 * Returns an I/O context or NULL in case of error
1340 */
1341static void *
1342xmlXzfileOpen_real (const char *filename) {
1343 const char *path = NULL;
1344 xzFile fd;
1345
1346 if (!strcmp(filename, "-")) {
Daniel Veillardadf5ec92012-01-26 16:56:22 +08001347 fd = __libxml2_xzdopen(dup(0), "rb");
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001348 return((void *) fd);
1349 }
1350
1351 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) {
1352 path = &filename[16];
1353 } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
1354 path = &filename[7];
1355 } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:/", 6)) {
1356 /* lots of generators seems to lazy to read RFC 1738 */
1357 path = &filename[5];
1358 } else
1359 path = filename;
1360
1361 if (path == NULL)
1362 return(NULL);
1363 if (!xmlCheckFilename(path))
1364 return(NULL);
1365
Daniel Veillardadf5ec92012-01-26 16:56:22 +08001366 fd = __libxml2_xzopen(path, "rb");
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001367 return((void *) fd);
1368}
1369
1370/**
1371 * xmlXzfileOpen:
1372 * @filename: the URI for matching
1373 *
1374 * Wrapper around xmlXzfileOpen_real that try it with an unescaped
1375 * version of @filename, if this fails fallback to @filename
1376 *
1377 * Returns a handler or NULL in case or failure
1378 */
1379static void *
1380xmlXzfileOpen (const char *filename) {
1381 char *unescaped;
1382 void *retval;
1383
1384 retval = xmlXzfileOpen_real(filename);
1385 if (retval == NULL) {
1386 unescaped = xmlURIUnescapeString(filename, 0, NULL);
1387 if (unescaped != NULL) {
1388 retval = xmlXzfileOpen_real(unescaped);
1389 }
1390 xmlFree(unescaped);
1391 }
1392
1393 return retval;
1394}
1395
1396/**
1397 * xmlXzfileRead:
1398 * @context: the I/O context
1399 * @buffer: where to drop data
1400 * @len: number of bytes to write
1401 *
1402 * Read @len bytes to @buffer from the compressed I/O channel.
1403 *
1404 * Returns the number of bytes written
1405 */
1406static int
1407xmlXzfileRead (void * context, char * buffer, int len) {
1408 int ret;
1409
Daniel Veillardadf5ec92012-01-26 16:56:22 +08001410 ret = __libxml2_xzread((xzFile) context, &buffer[0], len);
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001411 if (ret < 0) xmlIOErr(0, "xzread()");
1412 return(ret);
1413}
1414
1415/**
1416 * xmlXzfileClose:
1417 * @context: the I/O context
1418 *
1419 * Close a compressed I/O channel
1420 */
1421static int
1422xmlXzfileClose (void * context) {
1423 int ret;
1424
Daniel Veillardadf5ec92012-01-26 16:56:22 +08001425 ret = (__libxml2_xzclose((xzFile) context) == LZMA_OK ) ? 0 : -1;
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001426 if (ret < 0) xmlIOErr(0, "xzclose()");
1427 return(ret);
1428}
1429#endif /* HAVE_LZMA_H */
1430
Owen Taylor3473f882001-02-23 17:55:21 +00001431#ifdef LIBXML_HTTP_ENABLED
1432/************************************************************************
1433 * *
1434 * I/O for HTTP file accesses *
1435 * *
1436 ************************************************************************/
Daniel Veillardf012a642001-07-23 19:10:52 +00001437
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001438#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001439typedef struct xmlIOHTTPWriteCtxt_
1440{
1441 int compression;
1442
1443 char * uri;
1444
1445 void * doc_buff;
1446
1447} xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr;
1448
1449#ifdef HAVE_ZLIB_H
1450
1451#define DFLT_WBITS ( -15 )
1452#define DFLT_MEM_LVL ( 8 )
1453#define GZ_MAGIC1 ( 0x1f )
1454#define GZ_MAGIC2 ( 0x8b )
1455#define LXML_ZLIB_OS_CODE ( 0x03 )
1456#define INIT_HTTP_BUFF_SIZE ( 32768 )
1457#define DFLT_ZLIB_RATIO ( 5 )
1458
1459/*
1460** Data structure and functions to work with sending compressed data
1461** via HTTP.
1462*/
1463
1464typedef struct xmlZMemBuff_
1465{
1466 unsigned long size;
1467 unsigned long crc;
1468
1469 unsigned char * zbuff;
1470 z_stream zctrl;
1471
1472} xmlZMemBuff, *xmlZMemBuffPtr;
1473
1474/**
1475 * append_reverse_ulong
1476 * @buff: Compressed memory buffer
1477 * @data: Unsigned long to append
1478 *
1479 * Append a unsigned long in reverse byte order to the end of the
1480 * memory buffer.
1481 */
1482static void
1483append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) {
1484
1485 int idx;
1486
1487 if ( buff == NULL )
1488 return;
1489
1490 /*
1491 ** This is plagiarized from putLong in gzio.c (zlib source) where
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001492 ** the number "4" is hardcoded. If zlib is ever patched to
Daniel Veillardf012a642001-07-23 19:10:52 +00001493 ** support 64 bit file sizes, this code would need to be patched
1494 ** as well.
1495 */
1496
1497 for ( idx = 0; idx < 4; idx++ ) {
1498 *buff->zctrl.next_out = ( data & 0xff );
1499 data >>= 8;
1500 buff->zctrl.next_out++;
1501 }
1502
1503 return;
1504}
1505
1506/**
1507 *
1508 * xmlFreeZMemBuff
1509 * @buff: The memory buffer context to clear
1510 *
1511 * Release all the resources associated with the compressed memory buffer.
1512 */
1513static void
1514xmlFreeZMemBuff( xmlZMemBuffPtr buff ) {
William M. Brack78637da2003-07-31 14:47:38 +00001515
1516#ifdef DEBUG_HTTP
Daniel Veillardf012a642001-07-23 19:10:52 +00001517 int z_err;
William M. Brack78637da2003-07-31 14:47:38 +00001518#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001519
1520 if ( buff == NULL )
1521 return;
1522
1523 xmlFree( buff->zbuff );
Daniel Veillardf012a642001-07-23 19:10:52 +00001524#ifdef DEBUG_HTTP
William M. Brack78637da2003-07-31 14:47:38 +00001525 z_err = deflateEnd( &buff->zctrl );
Daniel Veillardf012a642001-07-23 19:10:52 +00001526 if ( z_err != Z_OK )
1527 xmlGenericError( xmlGenericErrorContext,
1528 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
1529 z_err );
William M. Brack78637da2003-07-31 14:47:38 +00001530#else
1531 deflateEnd( &buff->zctrl );
William M. Brack779af002003-08-01 15:55:39 +00001532#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001533
1534 xmlFree( buff );
1535 return;
1536}
1537
1538/**
1539 * xmlCreateZMemBuff
1540 *@compression: Compression value to use
1541 *
1542 * Create a memory buffer to hold the compressed XML document. The
1543 * compressed document in memory will end up being identical to what
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001544 * would be created if gzopen/gzwrite/gzclose were being used to
Daniel Veillardf012a642001-07-23 19:10:52 +00001545 * write the document to disk. The code for the header/trailer data to
1546 * the compression is plagiarized from the zlib source files.
1547 */
1548static void *
1549xmlCreateZMemBuff( int compression ) {
1550
1551 int z_err;
1552 int hdr_lgth;
1553 xmlZMemBuffPtr buff = NULL;
1554
1555 if ( ( compression < 1 ) || ( compression > 9 ) )
1556 return ( NULL );
1557
1558 /* Create the control and data areas */
1559
1560 buff = xmlMalloc( sizeof( xmlZMemBuff ) );
1561 if ( buff == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001562 xmlIOErrMemory("creating buffer context");
Daniel Veillardf012a642001-07-23 19:10:52 +00001563 return ( NULL );
1564 }
1565
1566 (void)memset( buff, 0, sizeof( xmlZMemBuff ) );
1567 buff->size = INIT_HTTP_BUFF_SIZE;
1568 buff->zbuff = xmlMalloc( buff->size );
1569 if ( buff->zbuff == NULL ) {
1570 xmlFreeZMemBuff( buff );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001571 xmlIOErrMemory("creating buffer");
Daniel Veillardf012a642001-07-23 19:10:52 +00001572 return ( NULL );
1573 }
1574
1575 z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
1576 DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
1577 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001578 xmlChar msg[500];
Daniel Veillardf012a642001-07-23 19:10:52 +00001579 xmlFreeZMemBuff( buff );
1580 buff = NULL;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001581 xmlStrPrintf(msg, 500,
1582 (const xmlChar *) "xmlCreateZMemBuff: %s %d\n",
1583 "Error initializing compression context. ZLIB error:",
1584 z_err );
1585 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001586 return ( NULL );
1587 }
1588
1589 /* Set the header data. The CRC will be needed for the trailer */
Daniel Veillard24505b02005-07-28 23:49:35 +00001590 buff->crc = crc32( 0L, NULL, 0 );
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001591 hdr_lgth = snprintf( (char *)buff->zbuff, buff->size,
1592 "%c%c%c%c%c%c%c%c%c%c",
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001593 GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED,
Daniel Veillardf012a642001-07-23 19:10:52 +00001594 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE );
1595 buff->zctrl.next_out = buff->zbuff + hdr_lgth;
1596 buff->zctrl.avail_out = buff->size - hdr_lgth;
1597
1598 return ( buff );
1599}
1600
1601/**
1602 * xmlZMemBuffExtend
1603 * @buff: Buffer used to compress and consolidate data.
1604 * @ext_amt: Number of bytes to extend the buffer.
1605 *
1606 * Extend the internal buffer used to store the compressed data by the
1607 * specified amount.
1608 *
1609 * Returns 0 on success or -1 on failure to extend the buffer. On failure
1610 * the original buffer still exists at the original size.
1611 */
1612static int
1613xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) {
1614
1615 int rc = -1;
1616 size_t new_size;
1617 size_t cur_used;
1618
1619 unsigned char * tmp_ptr = NULL;
1620
1621 if ( buff == NULL )
1622 return ( -1 );
1623
1624 else if ( ext_amt == 0 )
1625 return ( 0 );
1626
1627 cur_used = buff->zctrl.next_out - buff->zbuff;
1628 new_size = buff->size + ext_amt;
1629
1630#ifdef DEBUG_HTTP
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001631 if ( cur_used > new_size )
Daniel Veillardf012a642001-07-23 19:10:52 +00001632 xmlGenericError( xmlGenericErrorContext,
1633 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
1634 "Buffer overwrite detected during compressed memory",
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001635 "buffer extension. Overflowed by",
Daniel Veillardf012a642001-07-23 19:10:52 +00001636 (cur_used - new_size ) );
1637#endif
1638
1639 tmp_ptr = xmlRealloc( buff->zbuff, new_size );
1640 if ( tmp_ptr != NULL ) {
1641 rc = 0;
1642 buff->size = new_size;
1643 buff->zbuff = tmp_ptr;
1644 buff->zctrl.next_out = tmp_ptr + cur_used;
1645 buff->zctrl.avail_out = new_size - cur_used;
1646 }
1647 else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001648 xmlChar msg[500];
1649 xmlStrPrintf(msg, 500,
1650 (const xmlChar *) "xmlZMemBuffExtend: %s %lu bytes.\n",
1651 "Allocation failure extending output buffer to",
1652 new_size );
1653 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001654 }
1655
1656 return ( rc );
1657}
1658
1659/**
1660 * xmlZMemBuffAppend
1661 * @buff: Buffer used to compress and consolidate data
1662 * @src: Uncompressed source content to append to buffer
1663 * @len: Length of source data to append to buffer
1664 *
1665 * Compress and append data to the internal buffer. The data buffer
1666 * will be expanded if needed to store the additional data.
1667 *
1668 * Returns the number of bytes appended to the buffer or -1 on error.
1669 */
1670static int
1671xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) {
1672
1673 int z_err;
1674 size_t min_accept;
1675
1676 if ( ( buff == NULL ) || ( src == NULL ) )
1677 return ( -1 );
1678
1679 buff->zctrl.avail_in = len;
1680 buff->zctrl.next_in = (unsigned char *)src;
1681 while ( buff->zctrl.avail_in > 0 ) {
1682 /*
1683 ** Extend the buffer prior to deflate call if a reasonable amount
1684 ** of output buffer space is not available.
1685 */
1686 min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO;
1687 if ( buff->zctrl.avail_out <= min_accept ) {
1688 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1689 return ( -1 );
1690 }
1691
1692 z_err = deflate( &buff->zctrl, Z_NO_FLUSH );
1693 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001694 xmlChar msg[500];
1695 xmlStrPrintf(msg, 500,
1696 (const xmlChar *) "xmlZMemBuffAppend: %s %d %s - %d",
Daniel Veillardf012a642001-07-23 19:10:52 +00001697 "Compression error while appending",
1698 len, "bytes to buffer. ZLIB error", z_err );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001699 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001700 return ( -1 );
1701 }
1702 }
1703
1704 buff->crc = crc32( buff->crc, (unsigned char *)src, len );
1705
1706 return ( len );
1707}
1708
1709/**
1710 * xmlZMemBuffGetContent
1711 * @buff: Compressed memory content buffer
1712 * @data_ref: Pointer reference to point to compressed content
1713 *
1714 * Flushes the compression buffers, appends gzip file trailers and
1715 * returns the compressed content and length of the compressed data.
1716 * NOTE: The gzip trailer code here is plagiarized from zlib source.
1717 *
1718 * Returns the length of the compressed data or -1 on error.
1719 */
1720static int
1721xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) {
1722
1723 int zlgth = -1;
1724 int z_err;
1725
1726 if ( ( buff == NULL ) || ( data_ref == NULL ) )
1727 return ( -1 );
1728
1729 /* Need to loop until compression output buffers are flushed */
1730
1731 do
1732 {
1733 z_err = deflate( &buff->zctrl, Z_FINISH );
1734 if ( z_err == Z_OK ) {
1735 /* In this case Z_OK means more buffer space needed */
1736
1737 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1738 return ( -1 );
1739 }
1740 }
1741 while ( z_err == Z_OK );
1742
1743 /* If the compression state is not Z_STREAM_END, some error occurred */
1744
1745 if ( z_err == Z_STREAM_END ) {
1746
1747 /* Need to append the gzip data trailer */
1748
1749 if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) {
1750 if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 )
1751 return ( -1 );
1752 }
1753
1754 /*
1755 ** For whatever reason, the CRC and length data are pushed out
1756 ** in reverse byte order. So a memcpy can't be used here.
1757 */
1758
1759 append_reverse_ulong( buff, buff->crc );
1760 append_reverse_ulong( buff, buff->zctrl.total_in );
1761
1762 zlgth = buff->zctrl.next_out - buff->zbuff;
1763 *data_ref = (char *)buff->zbuff;
1764 }
1765
Daniel Veillard05d987b2003-10-08 11:54:57 +00001766 else {
1767 xmlChar msg[500];
1768 xmlStrPrintf(msg, 500,
1769 (const xmlChar *) "xmlZMemBuffGetContent: %s - %d\n",
1770 "Error flushing zlib buffers. Error code", z_err );
1771 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1772 }
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001773
Daniel Veillardf012a642001-07-23 19:10:52 +00001774 return ( zlgth );
1775}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001776#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001777#endif /* HAVE_ZLIB_H */
1778
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001779#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001780/**
1781 * xmlFreeHTTPWriteCtxt
1782 * @ctxt: Context to cleanup
1783 *
1784 * Free allocated memory and reclaim system resources.
1785 *
1786 * No return value.
1787 */
1788static void
1789xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt )
1790{
1791 if ( ctxt->uri != NULL )
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001792 xmlFree( ctxt->uri );
Daniel Veillardf012a642001-07-23 19:10:52 +00001793
1794 if ( ctxt->doc_buff != NULL ) {
1795
1796#ifdef HAVE_ZLIB_H
1797 if ( ctxt->compression > 0 ) {
1798 xmlFreeZMemBuff( ctxt->doc_buff );
1799 }
1800 else
1801#endif
1802 {
1803 xmlOutputBufferClose( ctxt->doc_buff );
1804 }
1805 }
1806
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001807 xmlFree( ctxt );
Daniel Veillardf012a642001-07-23 19:10:52 +00001808 return;
1809}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001810#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001811
1812
Owen Taylor3473f882001-02-23 17:55:21 +00001813/**
1814 * xmlIOHTTPMatch:
1815 * @filename: the URI for matching
1816 *
1817 * check if the URI matches an HTTP one
1818 *
1819 * Returns 1 if matches, 0 otherwise
1820 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001821int
Owen Taylor3473f882001-02-23 17:55:21 +00001822xmlIOHTTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001823 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "http://", 7))
Owen Taylor3473f882001-02-23 17:55:21 +00001824 return(1);
1825 return(0);
1826}
1827
1828/**
1829 * xmlIOHTTPOpen:
1830 * @filename: the URI for matching
1831 *
1832 * open an HTTP I/O channel
1833 *
1834 * Returns an I/O context or NULL in case of error
1835 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001836void *
Owen Taylor3473f882001-02-23 17:55:21 +00001837xmlIOHTTPOpen (const char *filename) {
1838 return(xmlNanoHTTPOpen(filename, NULL));
1839}
1840
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001841#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001842/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001843 * xmlIOHTTPOpenW:
Daniel Veillardf012a642001-07-23 19:10:52 +00001844 * @post_uri: The destination URI for the document
1845 * @compression: The compression desired for the document.
1846 *
1847 * Open a temporary buffer to collect the document for a subsequent HTTP POST
1848 * request. Non-static as is called from the output buffer creation routine.
1849 *
1850 * Returns an I/O context or NULL in case of error.
1851 */
1852
1853void *
Daniel Veillard572577e2002-01-18 16:23:55 +00001854xmlIOHTTPOpenW(const char *post_uri, int compression)
1855{
Daniel Veillardf012a642001-07-23 19:10:52 +00001856
Daniel Veillard572577e2002-01-18 16:23:55 +00001857 xmlIOHTTPWriteCtxtPtr ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001858
Daniel Veillard572577e2002-01-18 16:23:55 +00001859 if (post_uri == NULL)
1860 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001861
Daniel Veillard572577e2002-01-18 16:23:55 +00001862 ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt));
1863 if (ctxt == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001864 xmlIOErrMemory("creating HTTP output context");
Daniel Veillard572577e2002-01-18 16:23:55 +00001865 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001866 }
1867
Daniel Veillard572577e2002-01-18 16:23:55 +00001868 (void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt));
Daniel Veillardf012a642001-07-23 19:10:52 +00001869
Daniel Veillard572577e2002-01-18 16:23:55 +00001870 ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri);
1871 if (ctxt->uri == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001872 xmlIOErrMemory("copying URI");
Daniel Veillard572577e2002-01-18 16:23:55 +00001873 xmlFreeHTTPWriteCtxt(ctxt);
1874 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001875 }
1876
1877 /*
Daniel Veillard572577e2002-01-18 16:23:55 +00001878 * ** Since the document length is required for an HTTP post,
1879 * ** need to put the document into a buffer. A memory buffer
1880 * ** is being used to avoid pushing the data to disk and back.
1881 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001882
1883#ifdef HAVE_ZLIB_H
Daniel Veillard572577e2002-01-18 16:23:55 +00001884 if ((compression > 0) && (compression <= 9)) {
1885
1886 ctxt->compression = compression;
1887 ctxt->doc_buff = xmlCreateZMemBuff(compression);
1888 } else
Daniel Veillardf012a642001-07-23 19:10:52 +00001889#endif
1890 {
Daniel Veillard572577e2002-01-18 16:23:55 +00001891 /* Any character conversions should have been done before this */
Daniel Veillardf012a642001-07-23 19:10:52 +00001892
Daniel Veillardda3fee42008-09-01 13:08:57 +00001893 ctxt->doc_buff = xmlAllocOutputBufferInternal(NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001894 }
1895
Daniel Veillard572577e2002-01-18 16:23:55 +00001896 if (ctxt->doc_buff == NULL) {
1897 xmlFreeHTTPWriteCtxt(ctxt);
1898 ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001899 }
1900
Daniel Veillard572577e2002-01-18 16:23:55 +00001901 return (ctxt);
Daniel Veillardf012a642001-07-23 19:10:52 +00001902}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001903#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardda3fee42008-09-01 13:08:57 +00001904
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001905#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001906/**
1907 * xmlIOHTTPDfltOpenW
1908 * @post_uri: The destination URI for this document.
1909 *
1910 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
1911 * HTTP post command. This function should generally not be used as
1912 * the open callback is short circuited in xmlOutputBufferCreateFile.
1913 *
1914 * Returns a pointer to the new IO context.
1915 */
1916static void *
1917xmlIOHTTPDfltOpenW( const char * post_uri ) {
1918 return ( xmlIOHTTPOpenW( post_uri, 0 ) );
1919}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001920#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001921
1922/**
Owen Taylor3473f882001-02-23 17:55:21 +00001923 * xmlIOHTTPRead:
1924 * @context: the I/O context
1925 * @buffer: where to drop data
1926 * @len: number of bytes to write
1927 *
1928 * Read @len bytes to @buffer from the I/O channel.
1929 *
1930 * Returns the number of bytes written
1931 */
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001932int
Owen Taylor3473f882001-02-23 17:55:21 +00001933xmlIOHTTPRead(void * context, char * buffer, int len) {
Daniel Veillard5ea30d72004-11-08 11:54:28 +00001934 if ((buffer == NULL) || (len < 0)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001935 return(xmlNanoHTTPRead(context, &buffer[0], len));
1936}
1937
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001938#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001939/**
Daniel Veillardf012a642001-07-23 19:10:52 +00001940 * xmlIOHTTPWrite
1941 * @context: previously opened writing context
1942 * @buffer: data to output to temporary buffer
1943 * @len: bytes to output
1944 *
1945 * Collect data from memory buffer into a temporary file for later
1946 * processing.
1947 *
1948 * Returns number of bytes written.
1949 */
1950
1951static int
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001952xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001953
1954 xmlIOHTTPWriteCtxtPtr ctxt = context;
1955
1956 if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
1957 return ( -1 );
1958
1959 if ( len > 0 ) {
1960
1961 /* Use gzwrite or fwrite as previously setup in the open call */
1962
1963#ifdef HAVE_ZLIB_H
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001964 if ( ctxt->compression > 0 )
Daniel Veillardf012a642001-07-23 19:10:52 +00001965 len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len );
1966
1967 else
1968#endif
1969 len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
1970
1971 if ( len < 0 ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001972 xmlChar msg[500];
1973 xmlStrPrintf(msg, 500,
1974 (const xmlChar *) "xmlIOHTTPWrite: %s\n%s '%s'.\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001975 "Error appending to internal buffer.",
1976 "Error sending document to URI",
1977 ctxt->uri );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001978 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001979 }
1980 }
1981
1982 return ( len );
1983}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001984#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001985
1986
1987/**
Owen Taylor3473f882001-02-23 17:55:21 +00001988 * xmlIOHTTPClose:
1989 * @context: the I/O context
1990 *
1991 * Close an HTTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001992 *
1993 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00001994 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001995int
Owen Taylor3473f882001-02-23 17:55:21 +00001996xmlIOHTTPClose (void * context) {
1997 xmlNanoHTTPClose(context);
Daniel Veillardf012a642001-07-23 19:10:52 +00001998 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001999}
Daniel Veillardf012a642001-07-23 19:10:52 +00002000
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002001#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00002002/**
2003 * xmlIOHTTCloseWrite
2004 * @context: The I/O context
2005 * @http_mthd: The HTTP method to be used when sending the data
2006 *
2007 * Close the transmit HTTP I/O channel and actually send the data.
2008 */
2009static int
2010xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
2011
2012 int close_rc = -1;
2013 int http_rtn = 0;
2014 int content_lgth = 0;
2015 xmlIOHTTPWriteCtxtPtr ctxt = context;
2016
2017 char * http_content = NULL;
2018 char * content_encoding = NULL;
2019 char * content_type = (char *) "text/xml";
2020 void * http_ctxt = NULL;
2021
2022 if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
2023 return ( -1 );
2024
2025 /* Retrieve the content from the appropriate buffer */
2026
2027#ifdef HAVE_ZLIB_H
2028
2029 if ( ctxt->compression > 0 ) {
2030 content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
2031 content_encoding = (char *) "Content-Encoding: gzip";
2032 }
2033 else
2034#endif
2035 {
2036 /* Pull the data out of the memory output buffer */
2037
2038 xmlOutputBufferPtr dctxt = ctxt->doc_buff;
2039 http_content = (char *)dctxt->buffer->content;
2040 content_lgth = dctxt->buffer->use;
2041 }
2042
2043 if ( http_content == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002044 xmlChar msg[500];
2045 xmlStrPrintf(msg, 500,
2046 (const xmlChar *) "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
2047 "Error retrieving content.\nUnable to",
2048 http_mthd, "data to URI", ctxt->uri );
2049 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00002050 }
2051
2052 else {
2053
2054 http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
Hans Breuer2ad41ca2009-08-11 17:51:22 +02002055 &content_type, content_encoding,
Daniel Veillardf012a642001-07-23 19:10:52 +00002056 content_lgth );
2057
2058 if ( http_ctxt != NULL ) {
2059#ifdef DEBUG_HTTP
2060 /* If testing/debugging - dump reply with request content */
2061
2062 FILE * tst_file = NULL;
2063 char buffer[ 4096 ];
2064 char * dump_name = NULL;
2065 int avail;
2066
2067 xmlGenericError( xmlGenericErrorContext,
2068 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
2069 http_mthd, ctxt->uri,
2070 xmlNanoHTTPReturnCode( http_ctxt ) );
2071
2072 /*
2073 ** Since either content or reply may be gzipped,
Hans Breuer2ad41ca2009-08-11 17:51:22 +02002074 ** dump them to separate files instead of the
Daniel Veillardf012a642001-07-23 19:10:52 +00002075 ** standard error context.
2076 */
2077
2078 dump_name = tempnam( NULL, "lxml" );
2079 if ( dump_name != NULL ) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002080 (void)snprintf( buffer, sizeof(buffer), "%s.content", dump_name );
Daniel Veillardf012a642001-07-23 19:10:52 +00002081
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00002082 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00002083 if ( tst_file != NULL ) {
2084 xmlGenericError( xmlGenericErrorContext,
2085 "Transmitted content saved in file: %s\n", buffer );
2086
2087 fwrite( http_content, sizeof( char ),
2088 content_lgth, tst_file );
2089 fclose( tst_file );
2090 }
2091
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002092 (void)snprintf( buffer, sizeof(buffer), "%s.reply", dump_name );
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00002093 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00002094 if ( tst_file != NULL ) {
2095 xmlGenericError( xmlGenericErrorContext,
2096 "Reply content saved in file: %s\n", buffer );
2097
2098
2099 while ( (avail = xmlNanoHTTPRead( http_ctxt,
2100 buffer, sizeof( buffer ) )) > 0 ) {
2101
2102 fwrite( buffer, sizeof( char ), avail, tst_file );
2103 }
2104
2105 fclose( tst_file );
2106 }
2107
2108 free( dump_name );
2109 }
2110#endif /* DEBUG_HTTP */
2111
2112 http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
2113 if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
2114 close_rc = 0;
Daniel Veillard05d987b2003-10-08 11:54:57 +00002115 else {
2116 xmlChar msg[500];
2117 xmlStrPrintf(msg, 500,
2118 (const xmlChar *) "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00002119 http_mthd, content_lgth,
2120 "bytes to URI", ctxt->uri,
2121 "failed. HTTP return code:", http_rtn );
Daniel Veillard05d987b2003-10-08 11:54:57 +00002122 xmlIOErr(XML_IO_WRITE, (const char *) msg);
2123 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002124
2125 xmlNanoHTTPClose( http_ctxt );
2126 xmlFree( content_type );
2127 }
2128 }
2129
2130 /* Final cleanups */
2131
2132 xmlFreeHTTPWriteCtxt( ctxt );
2133
2134 return ( close_rc );
2135}
2136
2137/**
2138 * xmlIOHTTPClosePut
2139 *
2140 * @context: The I/O context
2141 *
2142 * Close the transmit HTTP I/O channel and actually send data using a PUT
2143 * HTTP method.
2144 */
2145static int
2146xmlIOHTTPClosePut( void * ctxt ) {
2147 return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
2148}
2149
2150
2151/**
2152 * xmlIOHTTPClosePost
2153 *
2154 * @context: The I/O context
2155 *
2156 * Close the transmit HTTP I/O channel and actually send data using a POST
2157 * HTTP method.
2158 */
2159static int
2160xmlIOHTTPClosePost( void * ctxt ) {
2161 return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
2162}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002163#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00002164
Owen Taylor3473f882001-02-23 17:55:21 +00002165#endif /* LIBXML_HTTP_ENABLED */
2166
2167#ifdef LIBXML_FTP_ENABLED
2168/************************************************************************
2169 * *
2170 * I/O for FTP file accesses *
2171 * *
2172 ************************************************************************/
2173/**
2174 * xmlIOFTPMatch:
2175 * @filename: the URI for matching
2176 *
2177 * check if the URI matches an FTP one
2178 *
2179 * Returns 1 if matches, 0 otherwise
2180 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002181int
Owen Taylor3473f882001-02-23 17:55:21 +00002182xmlIOFTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002183 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "ftp://", 6))
Owen Taylor3473f882001-02-23 17:55:21 +00002184 return(1);
2185 return(0);
2186}
2187
2188/**
2189 * xmlIOFTPOpen:
2190 * @filename: the URI for matching
2191 *
2192 * open an FTP I/O channel
2193 *
2194 * Returns an I/O context or NULL in case of error
2195 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002196void *
Owen Taylor3473f882001-02-23 17:55:21 +00002197xmlIOFTPOpen (const char *filename) {
2198 return(xmlNanoFTPOpen(filename));
2199}
2200
2201/**
2202 * xmlIOFTPRead:
2203 * @context: the I/O context
2204 * @buffer: where to drop data
2205 * @len: number of bytes to write
2206 *
2207 * Read @len bytes to @buffer from the I/O channel.
2208 *
2209 * Returns the number of bytes written
2210 */
Hans Breuer2ad41ca2009-08-11 17:51:22 +02002211int
Owen Taylor3473f882001-02-23 17:55:21 +00002212xmlIOFTPRead(void * context, char * buffer, int len) {
Daniel Veillard5ea30d72004-11-08 11:54:28 +00002213 if ((buffer == NULL) || (len < 0)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002214 return(xmlNanoFTPRead(context, &buffer[0], len));
2215}
2216
2217/**
2218 * xmlIOFTPClose:
2219 * @context: the I/O context
2220 *
2221 * Close an FTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00002222 *
2223 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00002224 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002225int
Owen Taylor3473f882001-02-23 17:55:21 +00002226xmlIOFTPClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +00002227 return ( xmlNanoFTPClose(context) );
Owen Taylor3473f882001-02-23 17:55:21 +00002228}
2229#endif /* LIBXML_FTP_ENABLED */
2230
2231
2232/**
2233 * xmlRegisterInputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002234 * @matchFunc: the xmlInputMatchCallback
2235 * @openFunc: the xmlInputOpenCallback
2236 * @readFunc: the xmlInputReadCallback
2237 * @closeFunc: the xmlInputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00002238 *
2239 * Register a new set of I/O callback for handling parser input.
2240 *
2241 * Returns the registered handler number or -1 in case of error
2242 */
2243int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002244xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
2245 xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
2246 xmlInputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002247 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
2248 return(-1);
2249 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002250 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
2251 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
2252 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
2253 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00002254 xmlInputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002255 return(xmlInputCallbackNr++);
2256}
2257
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002258#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002259/**
2260 * xmlRegisterOutputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002261 * @matchFunc: the xmlOutputMatchCallback
2262 * @openFunc: the xmlOutputOpenCallback
2263 * @writeFunc: the xmlOutputWriteCallback
2264 * @closeFunc: the xmlOutputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00002265 *
2266 * Register a new set of I/O callback for handling output.
2267 *
2268 * Returns the registered handler number or -1 in case of error
2269 */
2270int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002271xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
2272 xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
2273 xmlOutputCloseCallback closeFunc) {
Daniel Veillard0d5e58f2009-08-24 13:52:23 +02002274 if (xmlOutputCallbackNr >= MAX_OUTPUT_CALLBACK) {
Owen Taylor3473f882001-02-23 17:55:21 +00002275 return(-1);
2276 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002277 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
2278 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
2279 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
2280 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00002281 xmlOutputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002282 return(xmlOutputCallbackNr++);
2283}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002284#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002285
2286/**
2287 * xmlRegisterDefaultInputCallbacks:
2288 *
2289 * Registers the default compiled-in I/O handlers.
2290 */
2291void
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +00002292xmlRegisterDefaultInputCallbacks(void) {
Owen Taylor3473f882001-02-23 17:55:21 +00002293 if (xmlInputCallbackInitialized)
2294 return;
2295
Daniel Veillard8ca85b22006-09-01 09:56:07 +00002296#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
2297 xmlInitPlatformSpecificIo();
2298#endif
2299
Owen Taylor3473f882001-02-23 17:55:21 +00002300 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
2301 xmlFileRead, xmlFileClose);
2302#ifdef HAVE_ZLIB_H
2303 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
2304 xmlGzfileRead, xmlGzfileClose);
2305#endif /* HAVE_ZLIB_H */
Anders F Bjorklundeae52612011-09-18 16:59:13 +02002306#ifdef HAVE_LZMA_H
2307 xmlRegisterInputCallbacks(xmlXzfileMatch, xmlXzfileOpen,
2308 xmlXzfileRead, xmlXzfileClose);
2309#endif /* HAVE_ZLIB_H */
Owen Taylor3473f882001-02-23 17:55:21 +00002310
2311#ifdef LIBXML_HTTP_ENABLED
2312 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
2313 xmlIOHTTPRead, xmlIOHTTPClose);
2314#endif /* LIBXML_HTTP_ENABLED */
2315
2316#ifdef LIBXML_FTP_ENABLED
2317 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
2318 xmlIOFTPRead, xmlIOFTPClose);
2319#endif /* LIBXML_FTP_ENABLED */
2320 xmlInputCallbackInitialized = 1;
2321}
2322
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002323#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002324/**
2325 * xmlRegisterDefaultOutputCallbacks:
2326 *
2327 * Registers the default compiled-in I/O handlers.
2328 */
2329void
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +00002330xmlRegisterDefaultOutputCallbacks (void) {
Owen Taylor3473f882001-02-23 17:55:21 +00002331 if (xmlOutputCallbackInitialized)
2332 return;
2333
Daniel Veillard8ca85b22006-09-01 09:56:07 +00002334#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
2335 xmlInitPlatformSpecificIo();
2336#endif
2337
Owen Taylor3473f882001-02-23 17:55:21 +00002338 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
2339 xmlFileWrite, xmlFileClose);
Daniel Veillardf012a642001-07-23 19:10:52 +00002340
2341#ifdef LIBXML_HTTP_ENABLED
2342 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
2343 xmlIOHTTPWrite, xmlIOHTTPClosePut);
2344#endif
2345
Owen Taylor3473f882001-02-23 17:55:21 +00002346/*********************************
2347 No way a-priori to distinguish between gzipped files from
2348 uncompressed ones except opening if existing then closing
2349 and saving with same compression ratio ... a pain.
2350
2351#ifdef HAVE_ZLIB_H
2352 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
2353 xmlGzfileWrite, xmlGzfileClose);
2354#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002355
2356 Nor FTP PUT ....
2357#ifdef LIBXML_FTP_ENABLED
2358 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
2359 xmlIOFTPWrite, xmlIOFTPClose);
2360#endif
2361 **********************************/
2362 xmlOutputCallbackInitialized = 1;
2363}
2364
Daniel Veillardf012a642001-07-23 19:10:52 +00002365#ifdef LIBXML_HTTP_ENABLED
2366/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00002367 * xmlRegisterHTTPPostCallbacks:
Daniel Veillardf012a642001-07-23 19:10:52 +00002368 *
2369 * By default, libxml submits HTTP output requests using the "PUT" method.
2370 * Calling this method changes the HTTP output method to use the "POST"
2371 * method instead.
2372 *
2373 */
2374void
2375xmlRegisterHTTPPostCallbacks( void ) {
2376
2377 /* Register defaults if not done previously */
2378
2379 if ( xmlOutputCallbackInitialized == 0 )
2380 xmlRegisterDefaultOutputCallbacks( );
2381
2382 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
2383 xmlIOHTTPWrite, xmlIOHTTPClosePost);
2384 return;
2385}
2386#endif
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002387#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00002388
Owen Taylor3473f882001-02-23 17:55:21 +00002389/**
2390 * xmlAllocParserInputBuffer:
2391 * @enc: the charset encoding if known
2392 *
2393 * Create a buffered parser input for progressive parsing
2394 *
2395 * Returns the new parser input or NULL
2396 */
2397xmlParserInputBufferPtr
2398xmlAllocParserInputBuffer(xmlCharEncoding enc) {
2399 xmlParserInputBufferPtr ret;
2400
2401 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2402 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002403 xmlIOErrMemory("creating input buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00002404 return(NULL);
2405 }
2406 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002407 ret->buffer = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00002408 if (ret->buffer == NULL) {
2409 xmlFree(ret);
2410 return(NULL);
2411 }
2412 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
2413 ret->encoder = xmlGetCharEncodingHandler(enc);
2414 if (ret->encoder != NULL)
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002415 ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00002416 else
2417 ret->raw = NULL;
2418 ret->readcallback = NULL;
2419 ret->closecallback = NULL;
2420 ret->context = NULL;
William M. Brackc07329e2003-09-08 01:57:30 +00002421 ret->compressed = -1;
Daniel Veillard36711902004-02-11 13:25:26 +00002422 ret->rawconsumed = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002423
2424 return(ret);
2425}
2426
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002427#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002428/**
2429 * xmlAllocOutputBuffer:
2430 * @encoder: the encoding converter or NULL
2431 *
2432 * Create a buffered parser output
2433 *
2434 * Returns the new parser output or NULL
2435 */
2436xmlOutputBufferPtr
2437xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
2438 xmlOutputBufferPtr ret;
2439
2440 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
2441 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002442 xmlIOErrMemory("creating output buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00002443 return(NULL);
2444 }
2445 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
2446 ret->buffer = xmlBufferCreate();
2447 if (ret->buffer == NULL) {
2448 xmlFree(ret);
2449 return(NULL);
2450 }
Daniel Veillarde83e93e2008-08-30 12:52:26 +00002451
Daniel Veillard43bc89c2009-03-23 19:32:04 +00002452 /* try to avoid a performance problem with Windows realloc() */
2453 if (ret->buffer->alloc == XML_BUFFER_ALLOC_EXACT)
2454 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
2455
Daniel Veillardda3fee42008-09-01 13:08:57 +00002456 ret->encoder = encoder;
2457 if (encoder != NULL) {
2458 ret->conv = xmlBufferCreateSize(4000);
2459 if (ret->conv == NULL) {
2460 xmlFree(ret);
2461 return(NULL);
2462 }
2463
2464 /*
2465 * This call is designed to initiate the encoder state
2466 */
Hans Breuer2ad41ca2009-08-11 17:51:22 +02002467 xmlCharEncOutFunc(encoder, ret->conv, NULL);
Daniel Veillardda3fee42008-09-01 13:08:57 +00002468 } else
2469 ret->conv = NULL;
2470 ret->writecallback = NULL;
2471 ret->closecallback = NULL;
2472 ret->context = NULL;
2473 ret->written = 0;
2474
2475 return(ret);
2476}
2477
2478/**
2479 * xmlAllocOutputBufferInternal:
2480 * @encoder: the encoding converter or NULL
2481 *
2482 * Create a buffered parser output
2483 *
2484 * Returns the new parser output or NULL
2485 */
2486xmlOutputBufferPtr
2487xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder) {
2488 xmlOutputBufferPtr ret;
2489
2490 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
2491 if (ret == NULL) {
2492 xmlIOErrMemory("creating output buffer");
2493 return(NULL);
2494 }
2495 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
2496 ret->buffer = xmlBufferCreate();
2497 if (ret->buffer == NULL) {
2498 xmlFree(ret);
2499 return(NULL);
2500 }
2501
2502
Daniel Veillarde83e93e2008-08-30 12:52:26 +00002503 /*
2504 * For conversion buffers we use the special IO handling
Daniel Veillardda3fee42008-09-01 13:08:57 +00002505 * We don't do that from the exported API to avoid confusing
2506 * user's code.
Daniel Veillarde83e93e2008-08-30 12:52:26 +00002507 */
2508 ret->buffer->alloc = XML_BUFFER_ALLOC_IO;
2509 ret->buffer->contentIO = ret->buffer->content;
2510
Owen Taylor3473f882001-02-23 17:55:21 +00002511 ret->encoder = encoder;
2512 if (encoder != NULL) {
2513 ret->conv = xmlBufferCreateSize(4000);
Daniel Veillarde83e93e2008-08-30 12:52:26 +00002514 if (ret->conv == NULL) {
2515 xmlFree(ret);
2516 return(NULL);
2517 }
2518
Owen Taylor3473f882001-02-23 17:55:21 +00002519 /*
2520 * This call is designed to initiate the encoder state
2521 */
Hans Breuer2ad41ca2009-08-11 17:51:22 +02002522 xmlCharEncOutFunc(encoder, ret->conv, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00002523 } else
2524 ret->conv = NULL;
2525 ret->writecallback = NULL;
2526 ret->closecallback = NULL;
2527 ret->context = NULL;
2528 ret->written = 0;
2529
2530 return(ret);
2531}
Daniel Veillardda3fee42008-09-01 13:08:57 +00002532
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002533#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002534
2535/**
2536 * xmlFreeParserInputBuffer:
2537 * @in: a buffered parser input
2538 *
2539 * Free up the memory used by a buffered parser input
2540 */
2541void
2542xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
Daniel Veillard8d8bf2c2003-09-17 19:36:25 +00002543 if (in == NULL) return;
2544
Owen Taylor3473f882001-02-23 17:55:21 +00002545 if (in->raw) {
2546 xmlBufferFree(in->raw);
2547 in->raw = NULL;
2548 }
2549 if (in->encoder != NULL) {
2550 xmlCharEncCloseFunc(in->encoder);
2551 }
2552 if (in->closecallback != NULL) {
2553 in->closecallback(in->context);
2554 }
2555 if (in->buffer != NULL) {
2556 xmlBufferFree(in->buffer);
2557 in->buffer = NULL;
2558 }
2559
Owen Taylor3473f882001-02-23 17:55:21 +00002560 xmlFree(in);
2561}
2562
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002563#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002564/**
2565 * xmlOutputBufferClose:
2566 * @out: a buffered output
2567 *
2568 * flushes and close the output I/O channel
2569 * and free up all the associated resources
2570 *
2571 * Returns the number of byte written or -1 in case of error.
2572 */
2573int
Daniel Veillard828ce832003-10-08 19:19:10 +00002574xmlOutputBufferClose(xmlOutputBufferPtr out)
2575{
Owen Taylor3473f882001-02-23 17:55:21 +00002576 int written;
Daniel Veillardf012a642001-07-23 19:10:52 +00002577 int err_rc = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002578
2579 if (out == NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002580 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002581 if (out->writecallback != NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002582 xmlOutputBufferFlush(out);
Owen Taylor3473f882001-02-23 17:55:21 +00002583 if (out->closecallback != NULL) {
Daniel Veillard828ce832003-10-08 19:19:10 +00002584 err_rc = out->closecallback(out->context);
Owen Taylor3473f882001-02-23 17:55:21 +00002585 }
2586 written = out->written;
2587 if (out->conv) {
2588 xmlBufferFree(out->conv);
Daniel Veillard828ce832003-10-08 19:19:10 +00002589 out->conv = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002590 }
2591 if (out->encoder != NULL) {
2592 xmlCharEncCloseFunc(out->encoder);
2593 }
2594 if (out->buffer != NULL) {
2595 xmlBufferFree(out->buffer);
Daniel Veillard828ce832003-10-08 19:19:10 +00002596 out->buffer = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002597 }
2598
Daniel Veillard828ce832003-10-08 19:19:10 +00002599 if (out->error)
2600 err_rc = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00002601 xmlFree(out);
Daniel Veillard828ce832003-10-08 19:19:10 +00002602 return ((err_rc == 0) ? written : err_rc);
Owen Taylor3473f882001-02-23 17:55:21 +00002603}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002604#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002605
Daniel Veillard1b243b42004-06-08 10:16:42 +00002606xmlParserInputBufferPtr
Daniel Veillard0335a842004-06-02 16:18:40 +00002607__xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002608 xmlParserInputBufferPtr ret;
Daniel Veillard388236f2001-07-08 18:35:48 +00002609 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002610 void *context = NULL;
2611
2612 if (xmlInputCallbackInitialized == 0)
2613 xmlRegisterDefaultInputCallbacks();
2614
2615 if (URI == NULL) return(NULL);
2616
2617 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002618 * Try to find one of the input accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002619 * Go in reverse to give precedence to user defined handlers.
Daniel Veillard388236f2001-07-08 18:35:48 +00002620 */
2621 if (context == NULL) {
2622 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
2623 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
2624 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002625 context = xmlInputCallbackTable[i].opencallback(URI);
Daniel Veillard847332a2003-10-18 11:29:40 +00002626 if (context != NULL) {
Daniel Veillard388236f2001-07-08 18:35:48 +00002627 break;
Daniel Veillard847332a2003-10-18 11:29:40 +00002628 }
Daniel Veillard388236f2001-07-08 18:35:48 +00002629 }
Owen Taylor3473f882001-02-23 17:55:21 +00002630 }
2631 }
2632 if (context == NULL) {
2633 return(NULL);
2634 }
2635
2636 /*
2637 * Allocate the Input buffer front-end.
2638 */
2639 ret = xmlAllocParserInputBuffer(enc);
2640 if (ret != NULL) {
2641 ret->context = context;
2642 ret->readcallback = xmlInputCallbackTable[i].readcallback;
2643 ret->closecallback = xmlInputCallbackTable[i].closecallback;
William M. Brackc07329e2003-09-08 01:57:30 +00002644#ifdef HAVE_ZLIB_H
William M. Brackc5cbf992003-10-29 22:15:13 +00002645 if ((xmlInputCallbackTable[i].opencallback == xmlGzfileOpen) &&
2646 (strcmp(URI, "-") != 0)) {
Mark Adlera7e79f22010-01-19 16:28:48 +01002647#if defined(ZLIB_VERNUM) && ZLIB_VERNUM >= 0x1230
2648 ret->compressed = !gzdirect(context);
2649#else
William M. Brackc07329e2003-09-08 01:57:30 +00002650 if (((z_stream *)context)->avail_in > 4) {
2651 char *cptr, buff4[4];
Daniel Veillard07cb8222003-09-10 10:51:05 +00002652 cptr = (char *) ((z_stream *)context)->next_in;
William M. Brackc07329e2003-09-08 01:57:30 +00002653 if (gzread(context, buff4, 4) == 4) {
2654 if (strncmp(buff4, cptr, 4) == 0)
2655 ret->compressed = 0;
2656 else
2657 ret->compressed = 1;
2658 gzrewind(context);
2659 }
2660 }
Mark Adlera7e79f22010-01-19 16:28:48 +01002661#endif
William M. Brackc07329e2003-09-08 01:57:30 +00002662 }
2663#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002664 }
William M. Brack42331a92004-07-29 07:07:16 +00002665 else
2666 xmlInputCallbackTable[i].closecallback (context);
2667
Owen Taylor3473f882001-02-23 17:55:21 +00002668 return(ret);
2669}
2670
2671/**
Daniel Veillard0335a842004-06-02 16:18:40 +00002672 * xmlParserInputBufferCreateFilename:
Owen Taylor3473f882001-02-23 17:55:21 +00002673 * @URI: a C string containing the URI or filename
Daniel Veillard0335a842004-06-02 16:18:40 +00002674 * @enc: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002675 *
Daniel Veillard0335a842004-06-02 16:18:40 +00002676 * Create a buffered parser input for the progressive parsing of a file
2677 * If filename is "-' then we use stdin as the input.
Owen Taylor3473f882001-02-23 17:55:21 +00002678 * Automatic support for ZLIB/Compress compressed document is provided
2679 * by default if found at compile-time.
Daniel Veillard0335a842004-06-02 16:18:40 +00002680 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
Owen Taylor3473f882001-02-23 17:55:21 +00002681 *
Daniel Veillard0335a842004-06-02 16:18:40 +00002682 * Returns the new parser input or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00002683 */
Daniel Veillard0335a842004-06-02 16:18:40 +00002684xmlParserInputBufferPtr
2685xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
2686 if ((xmlParserInputBufferCreateFilenameValue)) {
2687 return xmlParserInputBufferCreateFilenameValue(URI, enc);
2688 }
2689 return __xmlParserInputBufferCreateFilename(URI, enc);
2690}
2691
2692#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard1b243b42004-06-08 10:16:42 +00002693xmlOutputBufferPtr
Daniel Veillard0335a842004-06-02 16:18:40 +00002694__xmlOutputBufferCreateFilename(const char *URI,
Owen Taylor3473f882001-02-23 17:55:21 +00002695 xmlCharEncodingHandlerPtr encoder,
Daniel Veillard0335a842004-06-02 16:18:40 +00002696 int compression ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00002697 xmlOutputBufferPtr ret;
Daniel Veillard966a31e2004-05-09 02:58:44 +00002698 xmlURIPtr puri;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002699 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002700 void *context = NULL;
Daniel Veillard966a31e2004-05-09 02:58:44 +00002701 char *unescaped = NULL;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002702#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002703 int is_file_uri = 1;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002704#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00002705
Owen Taylor3473f882001-02-23 17:55:21 +00002706 if (xmlOutputCallbackInitialized == 0)
2707 xmlRegisterDefaultOutputCallbacks();
2708
2709 if (URI == NULL) return(NULL);
2710
Daniel Veillard966a31e2004-05-09 02:58:44 +00002711 puri = xmlParseURI(URI);
2712 if (puri != NULL) {
Daniel Veillard8fcd2ca2005-07-03 14:42:56 +00002713#ifdef HAVE_ZLIB_H
Daniel Veillard18a65092004-05-11 15:57:42 +00002714 if ((puri->scheme != NULL) &&
2715 (!xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
Daniel Veillard966a31e2004-05-09 02:58:44 +00002716 is_file_uri = 0;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002717#endif
Daniel Veillard966a31e2004-05-09 02:58:44 +00002718 /*
2719 * try to limit the damages of the URI unescaping code.
2720 */
Daniel Veillarde8967e02006-10-11 09:15:00 +00002721 if ((puri->scheme == NULL) ||
2722 (xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
Daniel Veillard966a31e2004-05-09 02:58:44 +00002723 unescaped = xmlURIUnescapeString(URI, 0, NULL);
2724 xmlFreeURI(puri);
2725 }
Owen Taylor3473f882001-02-23 17:55:21 +00002726
2727 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002728 * Try to find one of the output accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002729 * Go in reverse to give precedence to user defined handlers.
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002730 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00002731 */
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002732 if (unescaped != NULL) {
2733#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002734 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002735 context = xmlGzfileOpenW(unescaped, compression);
2736 if (context != NULL) {
Daniel Veillardda3fee42008-09-01 13:08:57 +00002737 ret = xmlAllocOutputBufferInternal(encoder);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002738 if (ret != NULL) {
2739 ret->context = context;
2740 ret->writecallback = xmlGzfileWrite;
2741 ret->closecallback = xmlGzfileClose;
2742 }
2743 xmlFree(unescaped);
2744 return(ret);
2745 }
2746 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002747#endif
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002748 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2749 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
2750 (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
2751#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2752 /* Need to pass compression parameter into HTTP open calls */
2753 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2754 context = xmlIOHTTPOpenW(unescaped, compression);
2755 else
2756#endif
2757 context = xmlOutputCallbackTable[i].opencallback(unescaped);
2758 if (context != NULL)
2759 break;
2760 }
2761 }
2762 xmlFree(unescaped);
2763 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002764
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002765 /*
2766 * If this failed try with a non-escaped URI this may be a strange
2767 * filename
2768 */
2769 if (context == NULL) {
2770#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002771 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002772 context = xmlGzfileOpenW(URI, compression);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002773 if (context != NULL) {
Daniel Veillardda3fee42008-09-01 13:08:57 +00002774 ret = xmlAllocOutputBufferInternal(encoder);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002775 if (ret != NULL) {
2776 ret->context = context;
2777 ret->writecallback = xmlGzfileWrite;
2778 ret->closecallback = xmlGzfileClose;
2779 }
2780 return(ret);
2781 }
2782 }
2783#endif
2784 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2785 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002786 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002787#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2788 /* Need to pass compression parameter into HTTP open calls */
2789 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2790 context = xmlIOHTTPOpenW(URI, compression);
2791 else
2792#endif
2793 context = xmlOutputCallbackTable[i].opencallback(URI);
2794 if (context != NULL)
2795 break;
2796 }
Owen Taylor3473f882001-02-23 17:55:21 +00002797 }
2798 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002799
Owen Taylor3473f882001-02-23 17:55:21 +00002800 if (context == NULL) {
2801 return(NULL);
2802 }
2803
2804 /*
2805 * Allocate the Output buffer front-end.
2806 */
Daniel Veillardda3fee42008-09-01 13:08:57 +00002807 ret = xmlAllocOutputBufferInternal(encoder);
Owen Taylor3473f882001-02-23 17:55:21 +00002808 if (ret != NULL) {
2809 ret->context = context;
2810 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
2811 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
2812 }
2813 return(ret);
2814}
Daniel Veillard0335a842004-06-02 16:18:40 +00002815
2816/**
2817 * xmlOutputBufferCreateFilename:
2818 * @URI: a C string containing the URI or filename
2819 * @encoder: the encoding converter or NULL
2820 * @compression: the compression ration (0 none, 9 max).
2821 *
2822 * Create a buffered output for the progressive saving of a file
2823 * If filename is "-' then we use stdout as the output.
2824 * Automatic support for ZLIB/Compress compressed document is provided
2825 * by default if found at compile-time.
2826 * TODO: currently if compression is set, the library only support
2827 * writing to a local file.
2828 *
2829 * Returns the new output or NULL
2830 */
2831xmlOutputBufferPtr
2832xmlOutputBufferCreateFilename(const char *URI,
2833 xmlCharEncodingHandlerPtr encoder,
2834 int compression ATTRIBUTE_UNUSED) {
2835 if ((xmlOutputBufferCreateFilenameValue)) {
2836 return xmlOutputBufferCreateFilenameValue(URI, encoder, compression);
2837 }
2838 return __xmlOutputBufferCreateFilename(URI, encoder, compression);
2839}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002840#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002841
2842/**
2843 * xmlParserInputBufferCreateFile:
Hans Breuer2ad41ca2009-08-11 17:51:22 +02002844 * @file: a FILE*
Owen Taylor3473f882001-02-23 17:55:21 +00002845 * @enc: the charset encoding if known
2846 *
2847 * Create a buffered parser input for the progressive parsing of a FILE *
2848 * buffered C I/O
2849 *
2850 * Returns the new parser input or NULL
2851 */
2852xmlParserInputBufferPtr
2853xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
2854 xmlParserInputBufferPtr ret;
2855
2856 if (xmlInputCallbackInitialized == 0)
2857 xmlRegisterDefaultInputCallbacks();
2858
2859 if (file == NULL) return(NULL);
2860
2861 ret = xmlAllocParserInputBuffer(enc);
2862 if (ret != NULL) {
2863 ret->context = file;
2864 ret->readcallback = xmlFileRead;
2865 ret->closecallback = xmlFileFlush;
2866 }
2867
2868 return(ret);
2869}
2870
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002871#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002872/**
2873 * xmlOutputBufferCreateFile:
Hans Breuer2ad41ca2009-08-11 17:51:22 +02002874 * @file: a FILE*
Owen Taylor3473f882001-02-23 17:55:21 +00002875 * @encoder: the encoding converter or NULL
2876 *
2877 * Create a buffered output for the progressive saving to a FILE *
2878 * buffered C I/O
2879 *
2880 * Returns the new parser output or NULL
2881 */
2882xmlOutputBufferPtr
2883xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
2884 xmlOutputBufferPtr ret;
2885
2886 if (xmlOutputCallbackInitialized == 0)
2887 xmlRegisterDefaultOutputCallbacks();
2888
2889 if (file == NULL) return(NULL);
2890
Daniel Veillardda3fee42008-09-01 13:08:57 +00002891 ret = xmlAllocOutputBufferInternal(encoder);
Owen Taylor3473f882001-02-23 17:55:21 +00002892 if (ret != NULL) {
2893 ret->context = file;
2894 ret->writecallback = xmlFileWrite;
2895 ret->closecallback = xmlFileFlush;
2896 }
2897
2898 return(ret);
2899}
Daniel Veillard9a00fd22005-11-09 08:56:26 +00002900
2901/**
2902 * xmlOutputBufferCreateBuffer:
2903 * @buffer: a xmlBufferPtr
2904 * @encoder: the encoding converter or NULL
2905 *
2906 * Create a buffered output for the progressive saving to a xmlBuffer
2907 *
2908 * Returns the new parser output or NULL
2909 */
2910xmlOutputBufferPtr
2911xmlOutputBufferCreateBuffer(xmlBufferPtr buffer,
2912 xmlCharEncodingHandlerPtr encoder) {
2913 xmlOutputBufferPtr ret;
2914
2915 if (buffer == NULL) return(NULL);
2916
Rob Richardsa44f2342005-11-09 18:03:45 +00002917 ret = xmlOutputBufferCreateIO((xmlOutputWriteCallback)
2918 xmlBufferWrite,
2919 (xmlOutputCloseCallback)
Daniel Veillard4d3866c2005-11-13 12:43:59 +00002920 NULL, (void *) buffer, encoder);
Daniel Veillard9a00fd22005-11-09 08:56:26 +00002921
2922 return(ret);
2923}
2924
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002925#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002926
2927/**
2928 * xmlParserInputBufferCreateFd:
2929 * @fd: a file descriptor number
2930 * @enc: the charset encoding if known
2931 *
2932 * Create a buffered parser input for the progressive parsing for the input
2933 * from a file descriptor
2934 *
2935 * Returns the new parser input or NULL
2936 */
2937xmlParserInputBufferPtr
2938xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
2939 xmlParserInputBufferPtr ret;
2940
2941 if (fd < 0) return(NULL);
2942
2943 ret = xmlAllocParserInputBuffer(enc);
2944 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002945 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002946 ret->readcallback = xmlFdRead;
2947 ret->closecallback = xmlFdClose;
2948 }
2949
2950 return(ret);
2951}
2952
2953/**
2954 * xmlParserInputBufferCreateMem:
2955 * @mem: the memory input
2956 * @size: the length of the memory block
2957 * @enc: the charset encoding if known
2958 *
2959 * Create a buffered parser input for the progressive parsing for the input
2960 * from a memory area.
2961 *
2962 * Returns the new parser input or NULL
2963 */
2964xmlParserInputBufferPtr
2965xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
2966 xmlParserInputBufferPtr ret;
William M. Bracka3215c72004-07-31 16:24:01 +00002967 int errcode;
Owen Taylor3473f882001-02-23 17:55:21 +00002968
2969 if (size <= 0) return(NULL);
2970 if (mem == NULL) return(NULL);
2971
2972 ret = xmlAllocParserInputBuffer(enc);
2973 if (ret != NULL) {
2974 ret->context = (void *) mem;
2975 ret->readcallback = (xmlInputReadCallback) xmlNop;
2976 ret->closecallback = NULL;
William M. Bracka3215c72004-07-31 16:24:01 +00002977 errcode = xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size);
2978 if (errcode != 0) {
2979 xmlFree(ret);
2980 return(NULL);
2981 }
Owen Taylor3473f882001-02-23 17:55:21 +00002982 }
2983
2984 return(ret);
2985}
2986
2987/**
Daniel Veillard53350552003-09-18 13:35:51 +00002988 * xmlParserInputBufferCreateStatic:
2989 * @mem: the memory input
2990 * @size: the length of the memory block
2991 * @enc: the charset encoding if known
2992 *
2993 * Create a buffered parser input for the progressive parsing for the input
2994 * from an immutable memory area. This will not copy the memory area to
2995 * the buffer, but the memory is expected to be available until the end of
2996 * the parsing, this is useful for example when using mmap'ed file.
2997 *
2998 * Returns the new parser input or NULL
2999 */
3000xmlParserInputBufferPtr
3001xmlParserInputBufferCreateStatic(const char *mem, int size,
3002 xmlCharEncoding enc) {
3003 xmlParserInputBufferPtr ret;
3004
3005 if (size <= 0) return(NULL);
3006 if (mem == NULL) return(NULL);
3007
3008 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
3009 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003010 xmlIOErrMemory("creating input buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00003011 return(NULL);
3012 }
3013 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillarde72c5082003-09-19 12:44:05 +00003014 ret->buffer = xmlBufferCreateStatic((void *)mem, (size_t) size);
Daniel Veillard53350552003-09-18 13:35:51 +00003015 if (ret->buffer == NULL) {
3016 xmlFree(ret);
3017 return(NULL);
3018 }
3019 ret->encoder = xmlGetCharEncodingHandler(enc);
3020 if (ret->encoder != NULL)
3021 ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
3022 else
3023 ret->raw = NULL;
3024 ret->compressed = -1;
3025 ret->context = (void *) mem;
3026 ret->readcallback = NULL;
3027 ret->closecallback = NULL;
3028
3029 return(ret);
3030}
3031
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003032#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard53350552003-09-18 13:35:51 +00003033/**
Owen Taylor3473f882001-02-23 17:55:21 +00003034 * xmlOutputBufferCreateFd:
3035 * @fd: a file descriptor number
3036 * @encoder: the encoding converter or NULL
3037 *
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003038 * Create a buffered output for the progressive saving
Owen Taylor3473f882001-02-23 17:55:21 +00003039 * to a file descriptor
3040 *
3041 * Returns the new parser output or NULL
3042 */
3043xmlOutputBufferPtr
3044xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
3045 xmlOutputBufferPtr ret;
3046
3047 if (fd < 0) return(NULL);
3048
Daniel Veillardda3fee42008-09-01 13:08:57 +00003049 ret = xmlAllocOutputBufferInternal(encoder);
Owen Taylor3473f882001-02-23 17:55:21 +00003050 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00003051 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00003052 ret->writecallback = xmlFdWrite;
Daniel Veillard7db38712002-02-07 16:39:11 +00003053 ret->closecallback = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003054 }
3055
3056 return(ret);
3057}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003058#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003059
3060/**
3061 * xmlParserInputBufferCreateIO:
3062 * @ioread: an I/O read function
3063 * @ioclose: an I/O close function
3064 * @ioctx: an I/O handler
3065 * @enc: the charset encoding if known
3066 *
3067 * Create a buffered parser input for the progressive parsing for the input
3068 * from an I/O handler
3069 *
3070 * Returns the new parser input or NULL
3071 */
3072xmlParserInputBufferPtr
3073xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
3074 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
3075 xmlParserInputBufferPtr ret;
3076
3077 if (ioread == NULL) return(NULL);
3078
3079 ret = xmlAllocParserInputBuffer(enc);
3080 if (ret != NULL) {
3081 ret->context = (void *) ioctx;
3082 ret->readcallback = ioread;
3083 ret->closecallback = ioclose;
3084 }
3085
3086 return(ret);
3087}
3088
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003089#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003090/**
3091 * xmlOutputBufferCreateIO:
3092 * @iowrite: an I/O write function
3093 * @ioclose: an I/O close function
3094 * @ioctx: an I/O handler
Daniel Veillard9d06d302002-01-22 18:15:52 +00003095 * @encoder: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00003096 *
3097 * Create a buffered output for the progressive saving
3098 * to an I/O handler
3099 *
3100 * Returns the new parser output or NULL
3101 */
3102xmlOutputBufferPtr
3103xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
3104 xmlOutputCloseCallback ioclose, void *ioctx,
3105 xmlCharEncodingHandlerPtr encoder) {
3106 xmlOutputBufferPtr ret;
3107
3108 if (iowrite == NULL) return(NULL);
3109
Daniel Veillardda3fee42008-09-01 13:08:57 +00003110 ret = xmlAllocOutputBufferInternal(encoder);
Owen Taylor3473f882001-02-23 17:55:21 +00003111 if (ret != NULL) {
3112 ret->context = (void *) ioctx;
3113 ret->writecallback = iowrite;
3114 ret->closecallback = ioclose;
3115 }
3116
3117 return(ret);
3118}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003119#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003120
3121/**
Daniel Veillard1b243b42004-06-08 10:16:42 +00003122 * xmlParserInputBufferCreateFilenameDefault:
3123 * @func: function pointer to the new ParserInputBufferCreateFilenameFunc
3124 *
3125 * Registers a callback for URI input file handling
3126 *
3127 * Returns the old value of the registration function
3128 */
3129xmlParserInputBufferCreateFilenameFunc
3130xmlParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func)
3131{
3132 xmlParserInputBufferCreateFilenameFunc old = xmlParserInputBufferCreateFilenameValue;
3133 if (old == NULL) {
3134 old = __xmlParserInputBufferCreateFilename;
3135 }
3136
3137 xmlParserInputBufferCreateFilenameValue = func;
3138 return(old);
3139}
3140
3141/**
3142 * xmlOutputBufferCreateFilenameDefault:
3143 * @func: function pointer to the new OutputBufferCreateFilenameFunc
3144 *
3145 * Registers a callback for URI output file handling
3146 *
3147 * Returns the old value of the registration function
3148 */
3149xmlOutputBufferCreateFilenameFunc
3150xmlOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func)
3151{
3152 xmlOutputBufferCreateFilenameFunc old = xmlOutputBufferCreateFilenameValue;
3153#ifdef LIBXML_OUTPUT_ENABLED
3154 if (old == NULL) {
3155 old = __xmlOutputBufferCreateFilename;
3156 }
3157#endif
3158 xmlOutputBufferCreateFilenameValue = func;
3159 return(old);
3160}
3161
3162/**
Owen Taylor3473f882001-02-23 17:55:21 +00003163 * xmlParserInputBufferPush:
3164 * @in: a buffered parser input
3165 * @len: the size in bytes of the array.
3166 * @buf: an char array
3167 *
3168 * Push the content of the arry in the input buffer
3169 * This routine handle the I18N transcoding to internal UTF-8
3170 * This is used when operating the parser in progressive (push) mode.
3171 *
3172 * Returns the number of chars read and stored in the buffer, or -1
3173 * in case of error.
3174 */
3175int
3176xmlParserInputBufferPush(xmlParserInputBufferPtr in,
3177 int len, const char *buf) {
3178 int nbchars = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00003179 int ret;
Owen Taylor3473f882001-02-23 17:55:21 +00003180
3181 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003182 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003183 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00003184 unsigned int use;
3185
Owen Taylor3473f882001-02-23 17:55:21 +00003186 /*
3187 * Store the data in the incoming raw buffer
3188 */
3189 if (in->raw == NULL) {
3190 in->raw = xmlBufferCreate();
3191 }
William M. Bracka3215c72004-07-31 16:24:01 +00003192 ret = xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
3193 if (ret != 0)
3194 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003195
3196 /*
3197 * convert as much as possible to the parser reading buffer.
3198 */
Daniel Veillard36711902004-02-11 13:25:26 +00003199 use = in->raw->use;
Owen Taylor3473f882001-02-23 17:55:21 +00003200 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
3201 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003202 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003203 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003204 return(-1);
3205 }
Daniel Veillard36711902004-02-11 13:25:26 +00003206 in->rawconsumed += (use - in->raw->use);
Owen Taylor3473f882001-02-23 17:55:21 +00003207 } else {
3208 nbchars = len;
William M. Bracka3215c72004-07-31 16:24:01 +00003209 ret = xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
3210 if (ret != 0)
3211 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003212 }
3213#ifdef DEBUG_INPUT
3214 xmlGenericError(xmlGenericErrorContext,
3215 "I/O: pushed %d chars, buffer %d/%d\n",
3216 nbchars, in->buffer->use, in->buffer->size);
3217#endif
3218 return(nbchars);
3219}
3220
3221/**
Daniel Veillardddffd2a2002-03-05 20:28:20 +00003222 * endOfInput:
3223 *
3224 * When reading from an Input channel indicated end of file or error
3225 * don't reread from it again.
3226 */
3227static int
3228endOfInput (void * context ATTRIBUTE_UNUSED,
3229 char * buffer ATTRIBUTE_UNUSED,
3230 int len ATTRIBUTE_UNUSED) {
3231 return(0);
3232}
3233
3234/**
Owen Taylor3473f882001-02-23 17:55:21 +00003235 * xmlParserInputBufferGrow:
3236 * @in: a buffered parser input
3237 * @len: indicative value of the amount of chars to read
3238 *
3239 * Grow up the content of the input buffer, the old data are preserved
3240 * This routine handle the I18N transcoding to internal UTF-8
3241 * This routine is used when operating the parser in normal (pull) mode
3242 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003243 * TODO: one should be able to remove one extra copy by copying directly
Owen Taylor3473f882001-02-23 17:55:21 +00003244 * onto in->buffer or in->raw
3245 *
3246 * Returns the number of chars read and stored in the buffer, or -1
3247 * in case of error.
3248 */
3249int
3250xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
3251 char *buffer = NULL;
3252 int res = 0;
3253 int nbchars = 0;
3254 int buffree;
Daniel Veillard9e412302002-06-10 15:59:44 +00003255 unsigned int needSize;
Owen Taylor3473f882001-02-23 17:55:21 +00003256
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003257 if ((in == NULL) || (in->error)) return(-1);
Daniel Veillard6155d8a2003-08-19 15:01:28 +00003258 if ((len <= MINLEN) && (len != 4))
Owen Taylor3473f882001-02-23 17:55:21 +00003259 len = MINLEN;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00003260
Owen Taylor3473f882001-02-23 17:55:21 +00003261 buffree = in->buffer->size - in->buffer->use;
3262 if (buffree <= 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003263 xmlIOErr(XML_IO_BUFFER_FULL, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003264 in->error = XML_IO_BUFFER_FULL;
William M. Bracka3215c72004-07-31 16:24:01 +00003265 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003266 }
Owen Taylor3473f882001-02-23 17:55:21 +00003267
Daniel Veillarde5354492002-05-16 08:43:22 +00003268 needSize = in->buffer->use + len + 1;
3269 if (needSize > in->buffer->size){
3270 if (!xmlBufferResize(in->buffer, needSize)){
Daniel Veillard05d987b2003-10-08 11:54:57 +00003271 xmlIOErrMemory("growing input buffer");
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003272 in->error = XML_ERR_NO_MEMORY;
William M. Bracka3215c72004-07-31 16:24:01 +00003273 return(-1);
Daniel Veillarde5354492002-05-16 08:43:22 +00003274 }
Owen Taylor3473f882001-02-23 17:55:21 +00003275 }
Daniel Veillarde5354492002-05-16 08:43:22 +00003276 buffer = (char *)&in->buffer->content[in->buffer->use];
Owen Taylor3473f882001-02-23 17:55:21 +00003277
3278 /*
3279 * Call the read method for this I/O type.
3280 */
3281 if (in->readcallback != NULL) {
3282 res = in->readcallback(in->context, &buffer[0], len);
Daniel Veillardddffd2a2002-03-05 20:28:20 +00003283 if (res <= 0)
3284 in->readcallback = endOfInput;
Owen Taylor3473f882001-02-23 17:55:21 +00003285 } else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003286 xmlIOErr(XML_IO_NO_INPUT, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003287 in->error = XML_IO_NO_INPUT;
Owen Taylor3473f882001-02-23 17:55:21 +00003288 return(-1);
3289 }
3290 if (res < 0) {
Owen Taylor3473f882001-02-23 17:55:21 +00003291 return(-1);
3292 }
3293 len = res;
3294 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00003295 unsigned int use;
3296
Owen Taylor3473f882001-02-23 17:55:21 +00003297 /*
3298 * Store the data in the incoming raw buffer
3299 */
3300 if (in->raw == NULL) {
3301 in->raw = xmlBufferCreate();
3302 }
William M. Bracka3215c72004-07-31 16:24:01 +00003303 res = xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
3304 if (res != 0)
3305 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003306
3307 /*
3308 * convert as much as possible to the parser reading buffer.
3309 */
Daniel Veillard36711902004-02-11 13:25:26 +00003310 use = in->raw->use;
Owen Taylor3473f882001-02-23 17:55:21 +00003311 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
3312 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003313 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003314 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003315 return(-1);
3316 }
Daniel Veillard36711902004-02-11 13:25:26 +00003317 in->rawconsumed += (use - in->raw->use);
Owen Taylor3473f882001-02-23 17:55:21 +00003318 } else {
3319 nbchars = len;
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003320 in->buffer->use += nbchars;
Daniel Veillarde5354492002-05-16 08:43:22 +00003321 buffer[nbchars] = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003322 }
3323#ifdef DEBUG_INPUT
3324 xmlGenericError(xmlGenericErrorContext,
3325 "I/O: read %d chars, buffer %d/%d\n",
3326 nbchars, in->buffer->use, in->buffer->size);
3327#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003328 return(nbchars);
3329}
3330
3331/**
3332 * xmlParserInputBufferRead:
3333 * @in: a buffered parser input
3334 * @len: indicative value of the amount of chars to read
3335 *
3336 * Refresh the content of the input buffer, the old data are considered
3337 * consumed
3338 * This routine handle the I18N transcoding to internal UTF-8
3339 *
3340 * Returns the number of chars read and stored in the buffer, or -1
3341 * in case of error.
3342 */
3343int
3344xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003345 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003346 if (in->readcallback != NULL)
3347 return(xmlParserInputBufferGrow(in, len));
Daniel Veillard53350552003-09-18 13:35:51 +00003348 else if ((in->buffer != NULL) &&
3349 (in->buffer->alloc == XML_BUFFER_ALLOC_IMMUTABLE))
3350 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003351 else
3352 return(-1);
3353}
3354
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003355#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003356/**
3357 * xmlOutputBufferWrite:
3358 * @out: a buffered parser output
3359 * @len: the size in bytes of the array.
3360 * @buf: an char array
3361 *
3362 * Write the content of the array in the output I/O buffer
3363 * This routine handle the I18N transcoding from internal UTF-8
3364 * The buffer is lossless, i.e. will store in case of partial
3365 * or delayed writes.
3366 *
3367 * Returns the number of chars immediately written, or -1
3368 * in case of error.
3369 */
3370int
3371xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
3372 int nbchars = 0; /* number of chars to output to I/O */
3373 int ret; /* return from function call */
3374 int written = 0; /* number of char written to I/O so far */
3375 int chunk; /* number of byte curreent processed from buf */
3376
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003377 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003378 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003379 if (out->error) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003380
3381 do {
3382 chunk = len;
3383 if (chunk > 4 * MINLEN)
3384 chunk = 4 * MINLEN;
3385
3386 /*
3387 * first handle encoding stuff.
3388 */
3389 if (out->encoder != NULL) {
3390 /*
3391 * Store the data in the incoming raw buffer
3392 */
3393 if (out->conv == NULL) {
3394 out->conv = xmlBufferCreate();
3395 }
William M. Bracka3215c72004-07-31 16:24:01 +00003396 ret = xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
3397 if (ret != 0)
3398 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003399
3400 if ((out->buffer->use < MINLEN) && (chunk == len))
3401 goto done;
3402
3403 /*
3404 * convert as much as possible to the parser reading buffer.
3405 */
3406 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
Daniel Veillard809faa52003-02-10 15:43:53 +00003407 if ((ret < 0) && (ret != -3)) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003408 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003409 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003410 return(-1);
3411 }
3412 nbchars = out->conv->use;
3413 } else {
William M. Bracka3215c72004-07-31 16:24:01 +00003414 ret = xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
3415 if (ret != 0)
3416 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003417 nbchars = out->buffer->use;
3418 }
3419 buf += chunk;
3420 len -= chunk;
3421
3422 if ((nbchars < MINLEN) && (len <= 0))
3423 goto done;
3424
3425 if (out->writecallback) {
3426 /*
3427 * second write the stuff to the I/O channel
3428 */
3429 if (out->encoder != NULL) {
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003430 ret = out->writecallback(out->context,
Owen Taylor3473f882001-02-23 17:55:21 +00003431 (const char *)out->conv->content, nbchars);
3432 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00003433 xmlBufferShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003434 } else {
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003435 ret = out->writecallback(out->context,
Owen Taylor3473f882001-02-23 17:55:21 +00003436 (const char *)out->buffer->content, nbchars);
3437 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00003438 xmlBufferShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003439 }
3440 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003441 xmlIOErr(XML_IO_WRITE, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003442 out->error = XML_IO_WRITE;
Owen Taylor3473f882001-02-23 17:55:21 +00003443 return(ret);
3444 }
3445 out->written += ret;
3446 }
3447 written += nbchars;
3448 } while (len > 0);
3449
3450done:
3451#ifdef DEBUG_INPUT
3452 xmlGenericError(xmlGenericErrorContext,
3453 "I/O: wrote %d chars\n", written);
3454#endif
3455 return(written);
3456}
3457
3458/**
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003459 * xmlEscapeContent:
3460 * @out: a pointer to an array of bytes to store the result
3461 * @outlen: the length of @out
3462 * @in: a pointer to an array of unescaped UTF-8 bytes
3463 * @inlen: the length of @in
3464 *
3465 * Take a block of UTF-8 chars in and escape them.
3466 * Returns 0 if success, or -1 otherwise
3467 * The value of @inlen after return is the number of octets consumed
3468 * if the return value is positive, else unpredictable.
3469 * The value of @outlen after return is the number of octets consumed.
3470 */
3471static int
3472xmlEscapeContent(unsigned char* out, int *outlen,
3473 const xmlChar* in, int *inlen) {
3474 unsigned char* outstart = out;
3475 const unsigned char* base = in;
3476 unsigned char* outend = out + *outlen;
3477 const unsigned char* inend;
3478
3479 inend = in + (*inlen);
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003480
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003481 while ((in < inend) && (out < outend)) {
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003482 if (*in == '<') {
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003483 if (outend - out < 4) break;
3484 *out++ = '&';
3485 *out++ = 'l';
3486 *out++ = 't';
3487 *out++ = ';';
3488 } else if (*in == '>') {
3489 if (outend - out < 4) break;
3490 *out++ = '&';
3491 *out++ = 'g';
3492 *out++ = 't';
3493 *out++ = ';';
3494 } else if (*in == '&') {
3495 if (outend - out < 5) break;
3496 *out++ = '&';
3497 *out++ = 'a';
3498 *out++ = 'm';
3499 *out++ = 'p';
3500 *out++ = ';';
3501 } else if (*in == '\r') {
3502 if (outend - out < 5) break;
3503 *out++ = '&';
3504 *out++ = '#';
3505 *out++ = '1';
3506 *out++ = '3';
3507 *out++ = ';';
3508 } else {
3509 *out++ = (unsigned char) *in;
3510 }
3511 ++in;
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003512 }
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003513 *outlen = out - outstart;
3514 *inlen = in - base;
3515 return(0);
3516}
3517
3518/**
3519 * xmlOutputBufferWriteEscape:
3520 * @out: a buffered parser output
3521 * @str: a zero terminated UTF-8 string
Daniel Veillardee8960b2004-05-14 03:25:14 +00003522 * @escaping: an optional escaping function (or NULL)
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003523 *
3524 * Write the content of the string in the output I/O buffer
3525 * This routine escapes the caracters and then handle the I18N
3526 * transcoding from internal UTF-8
3527 * The buffer is lossless, i.e. will store in case of partial
3528 * or delayed writes.
3529 *
3530 * Returns the number of chars immediately written, or -1
3531 * in case of error.
3532 */
3533int
Daniel Veillardee8960b2004-05-14 03:25:14 +00003534xmlOutputBufferWriteEscape(xmlOutputBufferPtr out, const xmlChar *str,
3535 xmlCharEncodingOutputFunc escaping) {
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003536 int nbchars = 0; /* number of chars to output to I/O */
3537 int ret; /* return from function call */
3538 int written = 0; /* number of char written to I/O so far */
Daniel Veillard71b95632004-08-31 12:15:36 +00003539 int oldwritten=0;/* loop guard */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003540 int chunk; /* number of byte currently processed from str */
3541 int len; /* number of bytes in str */
3542 int cons; /* byte from str consumed */
3543
Daniel Veillardce244ad2004-11-05 10:03:46 +00003544 if ((out == NULL) || (out->error) || (str == NULL) ||
3545 (out->buffer == NULL) ||
3546 (out->buffer->alloc == XML_BUFFER_ALLOC_IMMUTABLE)) return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003547 len = strlen((const char *)str);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003548 if (len < 0) return(0);
3549 if (out->error) return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003550 if (escaping == NULL) escaping = xmlEscapeContent;
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003551
3552 do {
Daniel Veillard71b95632004-08-31 12:15:36 +00003553 oldwritten = written;
3554
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003555 /*
3556 * how many bytes to consume and how many bytes to store.
3557 */
3558 cons = len;
3559 chunk = (out->buffer->size - out->buffer->use) - 1;
3560
Daniel Veillardc4ba8a42008-02-16 10:08:14 +00003561 /*
3562 * make sure we have enough room to save first, if this is
3563 * not the case force a flush, but make sure we stay in the loop
3564 */
3565 if (chunk < 40) {
Daniel Veillarde83e93e2008-08-30 12:52:26 +00003566 if (xmlBufferGrow(out->buffer, out->buffer->size + 100) < 0)
3567 return(-1);
3568 oldwritten = -1;
3569 continue;
Daniel Veillardc4ba8a42008-02-16 10:08:14 +00003570 }
3571
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003572 /*
3573 * first handle encoding stuff.
3574 */
3575 if (out->encoder != NULL) {
3576 /*
3577 * Store the data in the incoming raw buffer
3578 */
3579 if (out->conv == NULL) {
3580 out->conv = xmlBufferCreate();
3581 }
Daniel Veillardee8960b2004-05-14 03:25:14 +00003582 ret = escaping(out->buffer->content + out->buffer->use ,
3583 &chunk, str, &cons);
William M. Brack66e40b12004-11-26 15:45:19 +00003584 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003585 return(-1);
3586 out->buffer->use += chunk;
3587 out->buffer->content[out->buffer->use] = 0;
3588
3589 if ((out->buffer->use < MINLEN) && (cons == len))
3590 goto done;
3591
3592 /*
3593 * convert as much as possible to the output buffer.
3594 */
3595 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
3596 if ((ret < 0) && (ret != -3)) {
3597 xmlIOErr(XML_IO_ENCODER, NULL);
3598 out->error = XML_IO_ENCODER;
3599 return(-1);
3600 }
3601 nbchars = out->conv->use;
3602 } else {
Daniel Veillardee8960b2004-05-14 03:25:14 +00003603 ret = escaping(out->buffer->content + out->buffer->use ,
3604 &chunk, str, &cons);
William M. Brack66e40b12004-11-26 15:45:19 +00003605 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003606 return(-1);
3607 out->buffer->use += chunk;
3608 out->buffer->content[out->buffer->use] = 0;
3609 nbchars = out->buffer->use;
3610 }
3611 str += cons;
3612 len -= cons;
3613
3614 if ((nbchars < MINLEN) && (len <= 0))
3615 goto done;
3616
3617 if (out->writecallback) {
3618 /*
3619 * second write the stuff to the I/O channel
3620 */
3621 if (out->encoder != NULL) {
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003622 ret = out->writecallback(out->context,
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003623 (const char *)out->conv->content, nbchars);
3624 if (ret >= 0)
3625 xmlBufferShrink(out->conv, ret);
3626 } else {
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003627 ret = out->writecallback(out->context,
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003628 (const char *)out->buffer->content, nbchars);
3629 if (ret >= 0)
3630 xmlBufferShrink(out->buffer, ret);
3631 }
3632 if (ret < 0) {
3633 xmlIOErr(XML_IO_WRITE, NULL);
3634 out->error = XML_IO_WRITE;
3635 return(ret);
3636 }
3637 out->written += ret;
Daniel Veillard83a75e02004-05-14 21:50:42 +00003638 } else if (out->buffer->size - out->buffer->use < MINLEN) {
3639 xmlBufferResize(out->buffer, out->buffer->size + MINLEN);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003640 }
3641 written += nbchars;
Daniel Veillard71b95632004-08-31 12:15:36 +00003642 } while ((len > 0) && (oldwritten != written));
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003643
3644done:
3645#ifdef DEBUG_INPUT
3646 xmlGenericError(xmlGenericErrorContext,
3647 "I/O: wrote %d chars\n", written);
3648#endif
3649 return(written);
3650}
3651
3652/**
Owen Taylor3473f882001-02-23 17:55:21 +00003653 * xmlOutputBufferWriteString:
3654 * @out: a buffered parser output
3655 * @str: a zero terminated C string
3656 *
3657 * Write the content of the string in the output I/O buffer
3658 * This routine handle the I18N transcoding from internal UTF-8
3659 * The buffer is lossless, i.e. will store in case of partial
3660 * or delayed writes.
3661 *
3662 * Returns the number of chars immediately written, or -1
3663 * in case of error.
3664 */
3665int
3666xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
3667 int len;
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003668
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003669 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003670 if (str == NULL)
3671 return(-1);
3672 len = strlen(str);
3673
3674 if (len > 0)
3675 return(xmlOutputBufferWrite(out, len, str));
3676 return(len);
3677}
3678
3679/**
3680 * xmlOutputBufferFlush:
3681 * @out: a buffered output
3682 *
3683 * flushes the output I/O channel
3684 *
3685 * Returns the number of byte written or -1 in case of error.
3686 */
3687int
3688xmlOutputBufferFlush(xmlOutputBufferPtr out) {
3689 int nbchars = 0, ret = 0;
3690
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003691 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003692 /*
3693 * first handle encoding stuff.
3694 */
3695 if ((out->conv != NULL) && (out->encoder != NULL)) {
3696 /*
3697 * convert as much as possible to the parser reading buffer.
3698 */
3699 nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
3700 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003701 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003702 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003703 return(-1);
3704 }
3705 }
3706
3707 /*
3708 * second flush the stuff to the I/O channel
3709 */
3710 if ((out->conv != NULL) && (out->encoder != NULL) &&
3711 (out->writecallback != NULL)) {
3712 ret = out->writecallback(out->context,
3713 (const char *)out->conv->content, out->conv->use);
3714 if (ret >= 0)
3715 xmlBufferShrink(out->conv, ret);
3716 } else if (out->writecallback != NULL) {
3717 ret = out->writecallback(out->context,
3718 (const char *)out->buffer->content, out->buffer->use);
3719 if (ret >= 0)
3720 xmlBufferShrink(out->buffer, ret);
3721 }
3722 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003723 xmlIOErr(XML_IO_FLUSH, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003724 out->error = XML_IO_FLUSH;
Owen Taylor3473f882001-02-23 17:55:21 +00003725 return(ret);
3726 }
3727 out->written += ret;
3728
3729#ifdef DEBUG_INPUT
3730 xmlGenericError(xmlGenericErrorContext,
3731 "I/O: flushed %d chars\n", ret);
3732#endif
3733 return(ret);
3734}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003735#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003736
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003737/**
Owen Taylor3473f882001-02-23 17:55:21 +00003738 * xmlParserGetDirectory:
3739 * @filename: the path to a file
3740 *
3741 * lookup the directory for that file
3742 *
3743 * Returns a new allocated string containing the directory, or NULL.
3744 */
3745char *
3746xmlParserGetDirectory(const char *filename) {
3747 char *ret = NULL;
3748 char dir[1024];
3749 char *cur;
Owen Taylor3473f882001-02-23 17:55:21 +00003750
Igor Zlatkovic9181cc02002-09-29 17:51:06 +00003751#ifdef _WIN32_WCE /* easy way by now ... wince does not have dirs! */
3752 return NULL;
3753#endif
3754
Owen Taylor3473f882001-02-23 17:55:21 +00003755 if (xmlInputCallbackInitialized == 0)
3756 xmlRegisterDefaultInputCallbacks();
3757
3758 if (filename == NULL) return(NULL);
Rob Richardsf779da32007-08-14 09:41:21 +00003759
Daniel Veillard3c5ed912002-01-08 10:36:16 +00003760#if defined(WIN32) && !defined(__CYGWIN__)
Rob Richardsf779da32007-08-14 09:41:21 +00003761# define IS_XMLPGD_SEP(ch) ((ch=='/')||(ch=='\\'))
3762#else
3763# define IS_XMLPGD_SEP(ch) (ch=='/')
Owen Taylor3473f882001-02-23 17:55:21 +00003764#endif
3765
3766 strncpy(dir, filename, 1023);
3767 dir[1023] = 0;
3768 cur = &dir[strlen(dir)];
3769 while (cur > dir) {
Rob Richardsf779da32007-08-14 09:41:21 +00003770 if (IS_XMLPGD_SEP(*cur)) break;
Owen Taylor3473f882001-02-23 17:55:21 +00003771 cur --;
3772 }
Rob Richardsf779da32007-08-14 09:41:21 +00003773 if (IS_XMLPGD_SEP(*cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003774 if (cur == dir) dir[1] = 0;
3775 else *cur = 0;
3776 ret = xmlMemStrdup(dir);
3777 } else {
3778 if (getcwd(dir, 1024) != NULL) {
3779 dir[1023] = 0;
3780 ret = xmlMemStrdup(dir);
3781 }
3782 }
3783 return(ret);
Rob Richardsf779da32007-08-14 09:41:21 +00003784#undef IS_XMLPGD_SEP
Owen Taylor3473f882001-02-23 17:55:21 +00003785}
3786
3787/****************************************************************
3788 * *
3789 * External entities loading *
3790 * *
3791 ****************************************************************/
3792
Daniel Veillarda840b692003-10-19 13:35:37 +00003793/**
3794 * xmlCheckHTTPInput:
3795 * @ctxt: an XML parser context
3796 * @ret: an XML parser input
3797 *
3798 * Check an input in case it was created from an HTTP stream, in that
3799 * case it will handle encoding and update of the base URL in case of
3800 * redirection. It also checks for HTTP errors in which case the input
3801 * is cleanly freed up and an appropriate error is raised in context
3802 *
3803 * Returns the input or NULL in case of HTTP error.
3804 */
3805xmlParserInputPtr
3806xmlCheckHTTPInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr ret) {
3807#ifdef LIBXML_HTTP_ENABLED
3808 if ((ret != NULL) && (ret->buf != NULL) &&
3809 (ret->buf->readcallback == xmlIOHTTPRead) &&
3810 (ret->buf->context != NULL)) {
3811 const char *encoding;
3812 const char *redir;
3813 const char *mime;
3814 int code;
3815
3816 code = xmlNanoHTTPReturnCode(ret->buf->context);
3817 if (code >= 400) {
3818 /* fatal error */
3819 if (ret->filename != NULL)
Daniel Veillarde8039df2003-10-27 11:25:13 +00003820 __xmlLoaderErr(ctxt, "failed to load HTTP resource \"%s\"\n",
Daniel Veillarda840b692003-10-19 13:35:37 +00003821 (const char *) ret->filename);
3822 else
Daniel Veillarde8039df2003-10-27 11:25:13 +00003823 __xmlLoaderErr(ctxt, "failed to load HTTP resource\n", NULL);
Daniel Veillarda840b692003-10-19 13:35:37 +00003824 xmlFreeInputStream(ret);
3825 ret = NULL;
3826 } else {
3827
3828 mime = xmlNanoHTTPMimeType(ret->buf->context);
3829 if ((xmlStrstr(BAD_CAST mime, BAD_CAST "/xml")) ||
3830 (xmlStrstr(BAD_CAST mime, BAD_CAST "+xml"))) {
3831 encoding = xmlNanoHTTPEncoding(ret->buf->context);
3832 if (encoding != NULL) {
3833 xmlCharEncodingHandlerPtr handler;
3834
3835 handler = xmlFindCharEncodingHandler(encoding);
3836 if (handler != NULL) {
3837 xmlSwitchInputEncoding(ctxt, ret, handler);
3838 } else {
3839 __xmlErrEncoding(ctxt, XML_ERR_UNKNOWN_ENCODING,
3840 "Unknown encoding %s",
3841 BAD_CAST encoding, NULL);
3842 }
3843 if (ret->encoding == NULL)
3844 ret->encoding = xmlStrdup(BAD_CAST encoding);
3845 }
3846#if 0
3847 } else if (xmlStrstr(BAD_CAST mime, BAD_CAST "html")) {
3848#endif
3849 }
3850 redir = xmlNanoHTTPRedir(ret->buf->context);
3851 if (redir != NULL) {
3852 if (ret->filename != NULL)
3853 xmlFree((xmlChar *) ret->filename);
3854 if (ret->directory != NULL) {
3855 xmlFree((xmlChar *) ret->directory);
3856 ret->directory = NULL;
3857 }
3858 ret->filename =
3859 (char *) xmlStrdup((const xmlChar *) redir);
3860 }
3861 }
3862 }
3863#endif
3864 return(ret);
3865}
3866
Daniel Veillarde5a3f372006-08-30 13:11:36 +00003867static int xmlNoNetExists(const char *URL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003868 const char *path;
3869
3870 if (URL == NULL)
3871 return(0);
3872
Daniel Veillardf4862f02002-09-10 11:13:43 +00003873 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003874#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00003875 path = &URL[17];
3876#else
Daniel Veillard6990bf32001-08-23 21:17:48 +00003877 path = &URL[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00003878#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003879 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003880#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard6990bf32001-08-23 21:17:48 +00003881 path = &URL[8];
3882#else
3883 path = &URL[7];
3884#endif
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003885 } else
Daniel Veillard6990bf32001-08-23 21:17:48 +00003886 path = URL;
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003887
Daniel Veillarde5a3f372006-08-30 13:11:36 +00003888 return xmlCheckFilename(path);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003889}
Daniel Veillard6990bf32001-08-23 21:17:48 +00003890
Daniel Veillardad4e2962006-09-21 08:36:38 +00003891#ifdef LIBXML_CATALOG_ENABLED
3892
3893/**
3894 * xmlResolveResourceFromCatalog:
3895 * @URL: the URL for the entity to load
3896 * @ID: the System ID for the entity to load
3897 * @ctxt: the context in which the entity is called or NULL
3898 *
3899 * Resolves the URL and ID against the appropriate catalog.
3900 * This function is used by xmlDefaultExternalEntityLoader and
3901 * xmlNoNetExternalEntityLoader.
3902 *
3903 * Returns a new allocated URL, or NULL.
3904 */
William M. Brack38d452a2007-05-22 16:00:06 +00003905static xmlChar *
Daniel Veillardad4e2962006-09-21 08:36:38 +00003906xmlResolveResourceFromCatalog(const char *URL, const char *ID,
3907 xmlParserCtxtPtr ctxt) {
3908 xmlChar *resource = NULL;
3909 xmlCatalogAllow pref;
3910
3911 /*
3912 * If the resource doesn't exists as a file,
3913 * try to load it from the resource pointed in the catalogs
3914 */
3915 pref = xmlCatalogGetDefaults();
3916
3917 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
3918 /*
3919 * Do a local lookup
3920 */
3921 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
3922 ((pref == XML_CATA_ALLOW_ALL) ||
3923 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3924 resource = xmlCatalogLocalResolve(ctxt->catalogs,
3925 (const xmlChar *)ID,
3926 (const xmlChar *)URL);
3927 }
3928 /*
3929 * Try a global lookup
3930 */
3931 if ((resource == NULL) &&
3932 ((pref == XML_CATA_ALLOW_ALL) ||
3933 (pref == XML_CATA_ALLOW_GLOBAL))) {
3934 resource = xmlCatalogResolve((const xmlChar *)ID,
3935 (const xmlChar *)URL);
3936 }
3937 if ((resource == NULL) && (URL != NULL))
3938 resource = xmlStrdup((const xmlChar *) URL);
3939
3940 /*
3941 * TODO: do an URI lookup on the reference
3942 */
3943 if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
3944 xmlChar *tmp = NULL;
3945
3946 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
3947 ((pref == XML_CATA_ALLOW_ALL) ||
3948 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3949 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
3950 }
3951 if ((tmp == NULL) &&
3952 ((pref == XML_CATA_ALLOW_ALL) ||
3953 (pref == XML_CATA_ALLOW_GLOBAL))) {
3954 tmp = xmlCatalogResolveURI(resource);
3955 }
3956
3957 if (tmp != NULL) {
3958 xmlFree(resource);
3959 resource = tmp;
3960 }
3961 }
3962 }
3963
3964 return resource;
3965}
3966
3967#endif
3968
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003969/**
Owen Taylor3473f882001-02-23 17:55:21 +00003970 * xmlDefaultExternalEntityLoader:
3971 * @URL: the URL for the entity to load
3972 * @ID: the System ID for the entity to load
3973 * @ctxt: the context in which the entity is called or NULL
3974 *
3975 * By default we don't load external entitites, yet.
3976 *
3977 * Returns a new allocated xmlParserInputPtr, or NULL.
3978 */
Daniel Veillarda840b692003-10-19 13:35:37 +00003979static xmlParserInputPtr
Owen Taylor3473f882001-02-23 17:55:21 +00003980xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
Daniel Veillarda840b692003-10-19 13:35:37 +00003981 xmlParserCtxtPtr ctxt)
3982{
Owen Taylor3473f882001-02-23 17:55:21 +00003983 xmlParserInputPtr ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003984 xmlChar *resource = NULL;
Daniel Veillarda840b692003-10-19 13:35:37 +00003985
Owen Taylor3473f882001-02-23 17:55:21 +00003986#ifdef DEBUG_EXTERNAL_ENTITIES
3987 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda840b692003-10-19 13:35:37 +00003988 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00003989#endif
Daniel Veillard61b93382003-11-03 14:28:31 +00003990 if ((ctxt != NULL) && (ctxt->options & XML_PARSE_NONET)) {
3991 int options = ctxt->options;
3992
3993 ctxt->options -= XML_PARSE_NONET;
3994 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
3995 ctxt->options = options;
3996 return(ret);
3997 }
Daniel Veillardad4e2962006-09-21 08:36:38 +00003998#ifdef LIBXML_CATALOG_ENABLED
3999 resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
Daniel Veillard7d6fd212001-05-10 15:34:11 +00004000#endif
4001
4002 if (resource == NULL)
Daniel Veillarda840b692003-10-19 13:35:37 +00004003 resource = (xmlChar *) URL;
Daniel Veillard7d6fd212001-05-10 15:34:11 +00004004
4005 if (resource == NULL) {
Daniel Veillarda840b692003-10-19 13:35:37 +00004006 if (ID == NULL)
4007 ID = "NULL";
Daniel Veillarde8039df2003-10-27 11:25:13 +00004008 __xmlLoaderErr(ctxt, "failed to load external entity \"%s\"\n", ID);
Daniel Veillarda840b692003-10-19 13:35:37 +00004009 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004010 }
Daniel Veillarda840b692003-10-19 13:35:37 +00004011 ret = xmlNewInputFromFile(ctxt, (const char *) resource);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00004012 if ((resource != NULL) && (resource != (xmlChar *) URL))
Daniel Veillarda840b692003-10-19 13:35:37 +00004013 xmlFree(resource);
4014 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004015}
4016
4017static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
4018 xmlDefaultExternalEntityLoader;
4019
Daniel Veillard5e2dace2001-07-18 19:30:27 +00004020/**
Owen Taylor3473f882001-02-23 17:55:21 +00004021 * xmlSetExternalEntityLoader:
4022 * @f: the new entity resolver function
4023 *
4024 * Changes the defaultexternal entity resolver function for the application
4025 */
4026void
4027xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
4028 xmlCurrentExternalEntityLoader = f;
4029}
4030
Daniel Veillard5e2dace2001-07-18 19:30:27 +00004031/**
Owen Taylor3473f882001-02-23 17:55:21 +00004032 * xmlGetExternalEntityLoader:
4033 *
4034 * Get the default external entity resolver function for the application
4035 *
4036 * Returns the xmlExternalEntityLoader function pointer
4037 */
4038xmlExternalEntityLoader
4039xmlGetExternalEntityLoader(void) {
4040 return(xmlCurrentExternalEntityLoader);
4041}
4042
Daniel Veillard5e2dace2001-07-18 19:30:27 +00004043/**
Owen Taylor3473f882001-02-23 17:55:21 +00004044 * xmlLoadExternalEntity:
4045 * @URL: the URL for the entity to load
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00004046 * @ID: the Public ID for the entity to load
Owen Taylor3473f882001-02-23 17:55:21 +00004047 * @ctxt: the context in which the entity is called or NULL
4048 *
4049 * Load an external entity, note that the use of this function for
4050 * unparsed entities may generate problems
Owen Taylor3473f882001-02-23 17:55:21 +00004051 *
4052 * Returns the xmlParserInputPtr or NULL
4053 */
4054xmlParserInputPtr
4055xmlLoadExternalEntity(const char *URL, const char *ID,
4056 xmlParserCtxtPtr ctxt) {
Daniel Veillarde5a3f372006-08-30 13:11:36 +00004057 if ((URL != NULL) && (xmlNoNetExists(URL) == 0)) {
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00004058 char *canonicFilename;
4059 xmlParserInputPtr ret;
4060
4061 canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL);
4062 if (canonicFilename == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00004063 xmlIOErrMemory("building canonical path\n");
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00004064 return(NULL);
4065 }
4066
4067 ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt);
4068 xmlFree(canonicFilename);
4069 return(ret);
4070 }
Owen Taylor3473f882001-02-23 17:55:21 +00004071 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
4072}
4073
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004074/************************************************************************
Hans Breuer2ad41ca2009-08-11 17:51:22 +02004075 * *
4076 * Disabling Network access *
4077 * *
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004078 ************************************************************************/
4079
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004080/**
4081 * xmlNoNetExternalEntityLoader:
4082 * @URL: the URL for the entity to load
4083 * @ID: the System ID for the entity to load
4084 * @ctxt: the context in which the entity is called or NULL
4085 *
4086 * A specific entity loader disabling network accesses, though still
4087 * allowing local catalog accesses for resolution.
4088 *
4089 * Returns a new allocated xmlParserInputPtr, or NULL.
4090 */
4091xmlParserInputPtr
4092xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
4093 xmlParserCtxtPtr ctxt) {
4094 xmlParserInputPtr input = NULL;
4095 xmlChar *resource = NULL;
4096
4097#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillardad4e2962006-09-21 08:36:38 +00004098 resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004099#endif
Daniel Veillardad4e2962006-09-21 08:36:38 +00004100
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004101 if (resource == NULL)
4102 resource = (xmlChar *) URL;
4103
4104 if (resource != NULL) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00004105 if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
4106 (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00004107 xmlIOErr(XML_IO_NETWORK_ATTEMPT, (const char *) resource);
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004108 if (resource != (xmlChar *) URL)
4109 xmlFree(resource);
4110 return(NULL);
4111 }
4112 }
4113 input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
4114 if (resource != (xmlChar *) URL)
4115 xmlFree(resource);
4116 return(input);
4117}
4118
Daniel Veillard5d4644e2005-04-01 13:11:58 +00004119#define bottom_xmlIO
4120#include "elfgcchack.h"