blob: 53bd8bfefac370706578aa3bbd2d79992b169f95 [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 Veillarda6a6e702012-07-16 14:22:54 +080099#include "buf.h"
100#include "enc.h"
101
Daniel Veillardf012a642001-07-23 19:10:52 +0000102/* #define VERBOSE_FAILURE */
Daniel Veillard1fd36d22001-07-04 22:54:28 +0000103/* #define DEBUG_EXTERNAL_ENTITIES */
Owen Taylor3473f882001-02-23 17:55:21 +0000104/* #define DEBUG_INPUT */
105
106#ifdef DEBUG_INPUT
107#define MINLEN 40
108#else
109#define MINLEN 4000
110#endif
111
112/*
113 * Input I/O callback sets
114 */
115typedef struct _xmlInputCallback {
116 xmlInputMatchCallback matchcallback;
117 xmlInputOpenCallback opencallback;
118 xmlInputReadCallback readcallback;
119 xmlInputCloseCallback closecallback;
120} xmlInputCallback;
121
122#define MAX_INPUT_CALLBACK 15
123
Daniel Veillard22090732001-07-16 00:06:07 +0000124static xmlInputCallback xmlInputCallbackTable[MAX_INPUT_CALLBACK];
125static int xmlInputCallbackNr = 0;
126static int xmlInputCallbackInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000127
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000128#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000129/*
130 * Output I/O callback sets
131 */
132typedef struct _xmlOutputCallback {
133 xmlOutputMatchCallback matchcallback;
134 xmlOutputOpenCallback opencallback;
135 xmlOutputWriteCallback writecallback;
136 xmlOutputCloseCallback closecallback;
137} xmlOutputCallback;
138
139#define MAX_OUTPUT_CALLBACK 15
140
Daniel Veillard22090732001-07-16 00:06:07 +0000141static xmlOutputCallback xmlOutputCallbackTable[MAX_OUTPUT_CALLBACK];
142static int xmlOutputCallbackNr = 0;
143static int xmlOutputCallbackInitialized = 0;
Daniel Veillardda3fee42008-09-01 13:08:57 +0000144
145xmlOutputBufferPtr
146xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder);
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000147#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000148
Daniel Veillard05d987b2003-10-08 11:54:57 +0000149/************************************************************************
150 * *
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200151 * Tree memory error handler *
Daniel Veillard05d987b2003-10-08 11:54:57 +0000152 * *
153 ************************************************************************/
Daniel Veillardf4862f02002-09-10 11:13:43 +0000154
Daniel Veillard05d987b2003-10-08 11:54:57 +0000155static const char *IOerr[] = {
Daniel Veillarda8856222003-10-08 19:26:03 +0000156 "Unknown IO error", /* UNKNOWN */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000157 "Permission denied", /* EACCES */
158 "Resource temporarily unavailable",/* EAGAIN */
159 "Bad file descriptor", /* EBADF */
160 "Bad message", /* EBADMSG */
161 "Resource busy", /* EBUSY */
162 "Operation canceled", /* ECANCELED */
163 "No child processes", /* ECHILD */
164 "Resource deadlock avoided",/* EDEADLK */
165 "Domain error", /* EDOM */
166 "File exists", /* EEXIST */
167 "Bad address", /* EFAULT */
168 "File too large", /* EFBIG */
169 "Operation in progress", /* EINPROGRESS */
170 "Interrupted function call",/* EINTR */
171 "Invalid argument", /* EINVAL */
172 "Input/output error", /* EIO */
173 "Is a directory", /* EISDIR */
174 "Too many open files", /* EMFILE */
175 "Too many links", /* EMLINK */
176 "Inappropriate message buffer length",/* EMSGSIZE */
177 "Filename too long", /* ENAMETOOLONG */
178 "Too many open files in system",/* ENFILE */
179 "No such device", /* ENODEV */
180 "No such file or directory",/* ENOENT */
181 "Exec format error", /* ENOEXEC */
182 "No locks available", /* ENOLCK */
183 "Not enough space", /* ENOMEM */
184 "No space left on device", /* ENOSPC */
185 "Function not implemented", /* ENOSYS */
186 "Not a directory", /* ENOTDIR */
187 "Directory not empty", /* ENOTEMPTY */
188 "Not supported", /* ENOTSUP */
189 "Inappropriate I/O control operation",/* ENOTTY */
190 "No such device or address",/* ENXIO */
191 "Operation not permitted", /* EPERM */
192 "Broken pipe", /* EPIPE */
193 "Result too large", /* ERANGE */
194 "Read-only file system", /* EROFS */
195 "Invalid seek", /* ESPIPE */
196 "No such process", /* ESRCH */
197 "Operation timed out", /* ETIMEDOUT */
198 "Improper link", /* EXDEV */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000199 "Attempt to load network entity %s", /* XML_IO_NETWORK_ATTEMPT */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000200 "encoder error", /* XML_IO_ENCODER */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000201 "flush error",
202 "write error",
203 "no input",
204 "buffer full",
205 "loading error",
206 "not a socket", /* ENOTSOCK */
207 "already connected", /* EISCONN */
Daniel Veillard29b17482004-08-16 00:39:03 +0000208 "connection refused", /* ECONNREFUSED */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000209 "unreachable network", /* ENETUNREACH */
210 "adddress in use", /* EADDRINUSE */
211 "already in use", /* EALREADY */
212 "unknown address familly", /* EAFNOSUPPORT */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000213};
214
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000215#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
Daniel Veillardf7416012006-04-27 08:15:20 +0000216/**
217 * __xmlIOWin32UTF8ToWChar:
218 * @u8String: uft-8 string
219 *
220 * Convert a string from utf-8 to wchar (WINDOWS ONLY!)
221 */
222static wchar_t *
223__xmlIOWin32UTF8ToWChar(const char *u8String)
224{
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +0000225 wchar_t *wString = NULL;
Daniel Veillardf7416012006-04-27 08:15:20 +0000226
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +0000227 if (u8String) {
228 int wLen =
229 MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, u8String,
230 -1, NULL, 0);
231 if (wLen) {
232 wString = xmlMalloc(wLen * sizeof(wchar_t));
233 if (wString) {
234 if (MultiByteToWideChar
235 (CP_UTF8, 0, u8String, -1, wString, wLen) == 0) {
236 xmlFree(wString);
237 wString = NULL;
238 }
239 }
240 }
241 }
242
243 return wString;
Daniel Veillardf7416012006-04-27 08:15:20 +0000244}
245#endif
246
Daniel Veillard05d987b2003-10-08 11:54:57 +0000247/**
248 * xmlIOErrMemory:
249 * @extra: extra informations
250 *
251 * Handle an out of memory condition
252 */
253static void
254xmlIOErrMemory(const char *extra)
255{
256 __xmlSimpleError(XML_FROM_IO, XML_ERR_NO_MEMORY, NULL, NULL, extra);
257}
258
259/**
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000260 * __xmlIOErr:
Daniel Veillard05d987b2003-10-08 11:54:57 +0000261 * @code: the error number
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000262 * @
Daniel Veillard05d987b2003-10-08 11:54:57 +0000263 * @extra: extra informations
264 *
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000265 * Handle an I/O error
Daniel Veillard05d987b2003-10-08 11:54:57 +0000266 */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000267void
268__xmlIOErr(int domain, int code, const char *extra)
Daniel Veillard05d987b2003-10-08 11:54:57 +0000269{
270 unsigned int idx;
271
272 if (code == 0) {
273#ifdef HAVE_ERRNO_H
274 if (errno == 0) code = 0;
275#ifdef EACCES
276 else if (errno == EACCES) code = XML_IO_EACCES;
277#endif
278#ifdef EAGAIN
279 else if (errno == EAGAIN) code = XML_IO_EAGAIN;
280#endif
281#ifdef EBADF
282 else if (errno == EBADF) code = XML_IO_EBADF;
283#endif
284#ifdef EBADMSG
285 else if (errno == EBADMSG) code = XML_IO_EBADMSG;
286#endif
287#ifdef EBUSY
288 else if (errno == EBUSY) code = XML_IO_EBUSY;
289#endif
290#ifdef ECANCELED
291 else if (errno == ECANCELED) code = XML_IO_ECANCELED;
292#endif
293#ifdef ECHILD
294 else if (errno == ECHILD) code = XML_IO_ECHILD;
295#endif
296#ifdef EDEADLK
297 else if (errno == EDEADLK) code = XML_IO_EDEADLK;
298#endif
299#ifdef EDOM
300 else if (errno == EDOM) code = XML_IO_EDOM;
301#endif
302#ifdef EEXIST
303 else if (errno == EEXIST) code = XML_IO_EEXIST;
304#endif
305#ifdef EFAULT
306 else if (errno == EFAULT) code = XML_IO_EFAULT;
307#endif
308#ifdef EFBIG
309 else if (errno == EFBIG) code = XML_IO_EFBIG;
310#endif
311#ifdef EINPROGRESS
312 else if (errno == EINPROGRESS) code = XML_IO_EINPROGRESS;
313#endif
314#ifdef EINTR
315 else if (errno == EINTR) code = XML_IO_EINTR;
316#endif
317#ifdef EINVAL
318 else if (errno == EINVAL) code = XML_IO_EINVAL;
319#endif
320#ifdef EIO
321 else if (errno == EIO) code = XML_IO_EIO;
322#endif
323#ifdef EISDIR
324 else if (errno == EISDIR) code = XML_IO_EISDIR;
325#endif
326#ifdef EMFILE
327 else if (errno == EMFILE) code = XML_IO_EMFILE;
328#endif
329#ifdef EMLINK
330 else if (errno == EMLINK) code = XML_IO_EMLINK;
331#endif
332#ifdef EMSGSIZE
333 else if (errno == EMSGSIZE) code = XML_IO_EMSGSIZE;
334#endif
335#ifdef ENAMETOOLONG
336 else if (errno == ENAMETOOLONG) code = XML_IO_ENAMETOOLONG;
337#endif
338#ifdef ENFILE
339 else if (errno == ENFILE) code = XML_IO_ENFILE;
340#endif
341#ifdef ENODEV
342 else if (errno == ENODEV) code = XML_IO_ENODEV;
343#endif
344#ifdef ENOENT
345 else if (errno == ENOENT) code = XML_IO_ENOENT;
346#endif
347#ifdef ENOEXEC
348 else if (errno == ENOEXEC) code = XML_IO_ENOEXEC;
349#endif
350#ifdef ENOLCK
351 else if (errno == ENOLCK) code = XML_IO_ENOLCK;
352#endif
353#ifdef ENOMEM
354 else if (errno == ENOMEM) code = XML_IO_ENOMEM;
355#endif
356#ifdef ENOSPC
357 else if (errno == ENOSPC) code = XML_IO_ENOSPC;
358#endif
359#ifdef ENOSYS
360 else if (errno == ENOSYS) code = XML_IO_ENOSYS;
361#endif
362#ifdef ENOTDIR
363 else if (errno == ENOTDIR) code = XML_IO_ENOTDIR;
364#endif
365#ifdef ENOTEMPTY
366 else if (errno == ENOTEMPTY) code = XML_IO_ENOTEMPTY;
367#endif
368#ifdef ENOTSUP
369 else if (errno == ENOTSUP) code = XML_IO_ENOTSUP;
370#endif
371#ifdef ENOTTY
372 else if (errno == ENOTTY) code = XML_IO_ENOTTY;
373#endif
374#ifdef ENXIO
375 else if (errno == ENXIO) code = XML_IO_ENXIO;
376#endif
377#ifdef EPERM
378 else if (errno == EPERM) code = XML_IO_EPERM;
379#endif
380#ifdef EPIPE
381 else if (errno == EPIPE) code = XML_IO_EPIPE;
382#endif
383#ifdef ERANGE
384 else if (errno == ERANGE) code = XML_IO_ERANGE;
385#endif
386#ifdef EROFS
387 else if (errno == EROFS) code = XML_IO_EROFS;
388#endif
389#ifdef ESPIPE
390 else if (errno == ESPIPE) code = XML_IO_ESPIPE;
391#endif
392#ifdef ESRCH
393 else if (errno == ESRCH) code = XML_IO_ESRCH;
394#endif
395#ifdef ETIMEDOUT
396 else if (errno == ETIMEDOUT) code = XML_IO_ETIMEDOUT;
397#endif
398#ifdef EXDEV
399 else if (errno == EXDEV) code = XML_IO_EXDEV;
400#endif
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000401#ifdef ENOTSOCK
402 else if (errno == ENOTSOCK) code = XML_IO_ENOTSOCK;
403#endif
404#ifdef EISCONN
405 else if (errno == EISCONN) code = XML_IO_EISCONN;
406#endif
407#ifdef ECONNREFUSED
408 else if (errno == ECONNREFUSED) code = XML_IO_ECONNREFUSED;
409#endif
410#ifdef ETIMEDOUT
411 else if (errno == ETIMEDOUT) code = XML_IO_ETIMEDOUT;
412#endif
413#ifdef ENETUNREACH
414 else if (errno == ENETUNREACH) code = XML_IO_ENETUNREACH;
415#endif
416#ifdef EADDRINUSE
417 else if (errno == EADDRINUSE) code = XML_IO_EADDRINUSE;
418#endif
419#ifdef EINPROGRESS
420 else if (errno == EINPROGRESS) code = XML_IO_EINPROGRESS;
421#endif
422#ifdef EALREADY
423 else if (errno == EALREADY) code = XML_IO_EALREADY;
424#endif
425#ifdef EAFNOSUPPORT
426 else if (errno == EAFNOSUPPORT) code = XML_IO_EAFNOSUPPORT;
427#endif
Daniel Veillard05d987b2003-10-08 11:54:57 +0000428 else code = XML_IO_UNKNOWN;
429#endif /* HAVE_ERRNO_H */
430 }
431 idx = 0;
432 if (code >= XML_IO_UNKNOWN) idx = code - XML_IO_UNKNOWN;
433 if (idx >= (sizeof(IOerr) / sizeof(IOerr[0]))) idx = 0;
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200434
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000435 __xmlSimpleError(domain, code, NULL, IOerr[idx], extra);
436}
437
438/**
439 * xmlIOErr:
440 * @code: the error number
441 * @extra: extra informations
442 *
443 * Handle an I/O error
444 */
445static void
446xmlIOErr(int code, const char *extra)
447{
448 __xmlIOErr(XML_FROM_IO, code, extra);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000449}
450
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000451/**
Daniel Veillarde8039df2003-10-27 11:25:13 +0000452 * __xmlLoaderErr:
453 * @ctx: the parser context
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000454 * @extra: extra informations
455 *
456 * Handle a resource access error
457 */
Daniel Veillarde8039df2003-10-27 11:25:13 +0000458void
459__xmlLoaderErr(void *ctx, const char *msg, const char *filename)
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000460{
Daniel Veillarde8039df2003-10-27 11:25:13 +0000461 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000462 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000463 xmlGenericErrorFunc channel = NULL;
464 void *data = NULL;
465 xmlErrorLevel level = XML_ERR_ERROR;
466
Daniel Veillard157fee02003-10-31 10:36:03 +0000467 if ((ctxt != NULL) && (ctxt->disableSAX != 0) &&
468 (ctxt->instate == XML_PARSER_EOF))
469 return;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000470 if ((ctxt != NULL) && (ctxt->sax != NULL)) {
471 if (ctxt->validate) {
472 channel = ctxt->sax->error;
473 level = XML_ERR_ERROR;
474 } else {
475 channel = ctxt->sax->warning;
476 level = XML_ERR_WARNING;
477 }
Daniel Veillard5ea30d72004-11-08 11:54:28 +0000478 if (ctxt->sax->initialized == XML_SAX2_MAGIC)
479 schannel = ctxt->sax->serror;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000480 data = ctxt->userData;
481 }
Daniel Veillard659e71e2003-10-10 14:10:40 +0000482 __xmlRaiseError(schannel, channel, data, ctxt, NULL, XML_FROM_IO,
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000483 XML_IO_LOAD_ERROR, level, NULL, 0,
484 filename, NULL, NULL, 0, 0,
485 msg, filename);
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200486
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000487}
488
Daniel Veillard05d987b2003-10-08 11:54:57 +0000489/************************************************************************
490 * *
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200491 * Tree memory error handler *
Daniel Veillard05d987b2003-10-08 11:54:57 +0000492 * *
493 ************************************************************************/
Daniel Veillardf4862f02002-09-10 11:13:43 +0000494/**
Daniel Veillard01c13b52002-12-10 15:19:08 +0000495 * xmlNormalizeWindowsPath:
Daniel Veillard33300b42003-04-17 09:09:19 +0000496 * @path: the input file path
Daniel Veillardf4862f02002-09-10 11:13:43 +0000497 *
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +0000498 * This function is obsolete. Please see xmlURIFromPath in uri.c for
499 * a better solution.
Daniel Veillard33300b42003-04-17 09:09:19 +0000500 *
501 * Returns a canonicalized version of the path
Daniel Veillardf4862f02002-09-10 11:13:43 +0000502 */
503xmlChar *
504xmlNormalizeWindowsPath(const xmlChar *path)
505{
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +0000506 return xmlCanonicPath(path);
Daniel Veillardf4862f02002-09-10 11:13:43 +0000507}
508
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000509/**
510 * xmlCleanupInputCallbacks:
511 *
512 * clears the entire input callback table. this includes the
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200513 * compiled-in I/O.
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000514 */
515void
516xmlCleanupInputCallbacks(void)
517{
518 int i;
519
520 if (!xmlInputCallbackInitialized)
521 return;
522
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000523 for (i = xmlInputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000524 xmlInputCallbackTable[i].matchcallback = NULL;
525 xmlInputCallbackTable[i].opencallback = NULL;
526 xmlInputCallbackTable[i].readcallback = NULL;
527 xmlInputCallbackTable[i].closecallback = NULL;
528 }
529
530 xmlInputCallbackNr = 0;
Aleksey Sanin9c45ba82002-06-06 21:46:13 +0000531 xmlInputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000532}
533
Daniel Veillardaecc0dc2004-05-08 02:32:07 +0000534/**
William M. Brack4e3a9fa2004-08-03 22:41:11 +0000535 * xmlPopInputCallbacks:
Daniel Veillardaecc0dc2004-05-08 02:32:07 +0000536 *
537 * Clear the top input callback from the input stack. this includes the
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200538 * compiled-in I/O.
Daniel Veillardaecc0dc2004-05-08 02:32:07 +0000539 *
540 * Returns the number of input callback registered or -1 in case of error.
541 */
542int
543xmlPopInputCallbacks(void)
544{
545 if (!xmlInputCallbackInitialized)
546 return(-1);
547
548 if (xmlInputCallbackNr <= 0)
549 return(-1);
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200550
Daniel Veillardaecc0dc2004-05-08 02:32:07 +0000551 xmlInputCallbackNr--;
552 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = NULL;
553 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = NULL;
554 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = NULL;
555 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = NULL;
556
557 return(xmlInputCallbackNr);
558}
559
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000560#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000561/**
562 * xmlCleanupOutputCallbacks:
563 *
564 * clears the entire output callback table. this includes the
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200565 * compiled-in I/O callbacks.
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000566 */
567void
568xmlCleanupOutputCallbacks(void)
569{
570 int i;
571
572 if (!xmlOutputCallbackInitialized)
573 return;
574
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000575 for (i = xmlOutputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000576 xmlOutputCallbackTable[i].matchcallback = NULL;
577 xmlOutputCallbackTable[i].opencallback = NULL;
578 xmlOutputCallbackTable[i].writecallback = NULL;
579 xmlOutputCallbackTable[i].closecallback = NULL;
580 }
581
582 xmlOutputCallbackNr = 0;
Aleksey Sanin9c45ba82002-06-06 21:46:13 +0000583 xmlOutputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000584}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000585#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000586
Owen Taylor3473f882001-02-23 17:55:21 +0000587/************************************************************************
588 * *
589 * Standard I/O for file accesses *
590 * *
591 ************************************************************************/
592
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000593#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
594
595/**
596 * xmlWrapOpenUtf8:
597 * @path: the path in utf-8 encoding
598 * @mode: type of access (0 - read, 1 - write)
599 *
600 * function opens the file specified by @path
601 *
602 */
603static FILE*
604xmlWrapOpenUtf8(const char *path,int mode)
605{
606 FILE *fd = NULL;
607 wchar_t *wPath;
608
609 wPath = __xmlIOWin32UTF8ToWChar(path);
610 if(wPath)
611 {
612 fd = _wfopen(wPath, mode ? L"wb" : L"rb");
613 xmlFree(wPath);
614 }
Daniel Veillard0da41662006-10-10 09:05:36 +0000615 /* maybe path in native encoding */
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000616 if(fd == NULL)
617 fd = fopen(path, mode ? "wb" : "rb");
618
619 return fd;
620}
621
Rob Richards6c61e022009-08-12 11:41:27 -0400622#ifdef HAVE_ZLIB_H
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200623static gzFile
624xmlWrapGzOpenUtf8(const char *path, const char *mode)
625{
626 gzFile fd;
627 wchar_t *wPath;
628
629 fd = gzopen (path, mode);
630 if (fd)
631 return fd;
632
633 wPath = __xmlIOWin32UTF8ToWChar(path);
634 if(wPath)
635 {
636 int d, m = (strstr(mode, "r") ? O_RDONLY : O_RDWR);
637#ifdef _O_BINARY
638 m |= (strstr(mode, "b") ? _O_BINARY : 0);
639#endif
640 d = _wopen(wPath, m);
641 if (d >= 0)
642 fd = gzdopen(d, mode);
643 xmlFree(wPath);
644 }
645
646 return fd;
647}
Rob Richards6c61e022009-08-12 11:41:27 -0400648#endif
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200649
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000650/**
651 * xmlWrapStatUtf8:
652 * @path: the path in utf-8 encoding
653 * @info: structure that stores results
654 *
655 * function obtains information about the file or directory
656 *
657 */
658static int
659xmlWrapStatUtf8(const char *path,struct stat *info)
660{
661#ifdef HAVE_STAT
662 int retval = -1;
663 wchar_t *wPath;
664
665 wPath = __xmlIOWin32UTF8ToWChar(path);
666 if (wPath)
667 {
668 retval = _wstat(wPath,info);
669 xmlFree(wPath);
670 }
Daniel Veillard0da41662006-10-10 09:05:36 +0000671 /* maybe path in native encoding */
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000672 if(retval < 0)
673 retval = stat(path,info);
674 return retval;
675#else
676 return -1;
677#endif
678}
679
680/**
681 * xmlWrapOpenNative:
682 * @path: the path
683 * @mode: type of access (0 - read, 1 - write)
684 *
685 * function opens the file specified by @path
686 *
687 */
688static FILE*
689xmlWrapOpenNative(const char *path,int mode)
690{
691 return fopen(path,mode ? "wb" : "rb");
692}
693
694/**
695 * xmlWrapStatNative:
696 * @path: the path
697 * @info: structure that stores results
698 *
699 * function obtains information about the file or directory
700 *
701 */
702static int
703xmlWrapStatNative(const char *path,struct stat *info)
704{
705#ifdef HAVE_STAT
706 return stat(path,info);
707#else
708 return -1;
709#endif
710}
711
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +0000712typedef int (* xmlWrapStatFunc) (const char *f, struct stat *s);
713static xmlWrapStatFunc xmlWrapStat = xmlWrapStatNative;
714typedef FILE* (* xmlWrapOpenFunc)(const char *f,int mode);
Rob Richards6460f922006-10-12 21:08:29 +0000715static xmlWrapOpenFunc xmlWrapOpen = xmlWrapOpenNative;
Rob Richards6c61e022009-08-12 11:41:27 -0400716#ifdef HAVE_ZLIB_H
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200717typedef gzFile (* xmlWrapGzOpenFunc) (const char *f, const char *mode);
718static xmlWrapGzOpenFunc xmlWrapGzOpen = gzopen;
Rob Richards6c61e022009-08-12 11:41:27 -0400719#endif
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000720/**
721 * xmlInitPlatformSpecificIo:
722 *
723 * Initialize platform specific features.
724 */
725static void
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +0000726xmlInitPlatformSpecificIo(void)
727{
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000728 static int xmlPlatformIoInitialized = 0;
729 OSVERSIONINFO osvi;
730
731 if(xmlPlatformIoInitialized)
732 return;
733
734 osvi.dwOSVersionInfoSize = sizeof(osvi);
735
736 if(GetVersionEx(&osvi) && (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)) {
737 xmlWrapStat = xmlWrapStatUtf8;
738 xmlWrapOpen = xmlWrapOpenUtf8;
Rob Richards6c61e022009-08-12 11:41:27 -0400739#ifdef HAVE_ZLIB_H
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200740 xmlWrapGzOpen = xmlWrapGzOpenUtf8;
Rob Richards6c61e022009-08-12 11:41:27 -0400741#endif
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000742 } else {
743 xmlWrapStat = xmlWrapStatNative;
744 xmlWrapOpen = xmlWrapOpenNative;
Rob Richards6c61e022009-08-12 11:41:27 -0400745#ifdef HAVE_ZLIB_H
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200746 xmlWrapGzOpen = gzopen;
Rob Richards6c61e022009-08-12 11:41:27 -0400747#endif
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000748 }
749
750 xmlPlatformIoInitialized = 1;
751 return;
752}
753
754#endif
755
Owen Taylor3473f882001-02-23 17:55:21 +0000756/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000757 * xmlCheckFilename:
Owen Taylor3473f882001-02-23 17:55:21 +0000758 * @path: the path to check
759 *
760 * function checks to see if @path is a valid source
761 * (file, socket...) for XML.
762 *
763 * if stat is not available on the target machine,
764 * returns 1. if stat fails, returns 0 (if calling
765 * stat on the filename fails, it can't be right).
766 * if stat succeeds and the file is a directory,
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000767 * returns 2. otherwise returns 1.
Owen Taylor3473f882001-02-23 17:55:21 +0000768 */
769
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000770int
Owen Taylor3473f882001-02-23 17:55:21 +0000771xmlCheckFilename (const char *path)
772{
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000773#ifdef HAVE_STAT
Daniel Veillard0b309952006-05-02 20:34:38 +0000774 struct stat stat_buffer;
775#endif
Daniel Veillardf7416012006-04-27 08:15:20 +0000776 if (path == NULL)
Daniel Veillard0b309952006-05-02 20:34:38 +0000777 return(0);
Daniel Veillarde5a3f372006-08-30 13:11:36 +0000778
Owen Taylor3473f882001-02-23 17:55:21 +0000779#ifdef HAVE_STAT
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000780#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
781 if (xmlWrapStat(path, &stat_buffer) == -1)
782 return 0;
783#else
Owen Taylor3473f882001-02-23 17:55:21 +0000784 if (stat(path, &stat_buffer) == -1)
785 return 0;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000786#endif
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000787#ifdef S_ISDIR
Daniel Veillardf7416012006-04-27 08:15:20 +0000788 if (S_ISDIR(stat_buffer.st_mode))
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000789 return 2;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000790#endif
Daniel Veillardf7416012006-04-27 08:15:20 +0000791#endif /* HAVE_STAT */
Owen Taylor3473f882001-02-23 17:55:21 +0000792 return 1;
793}
794
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000795static int
Owen Taylor3473f882001-02-23 17:55:21 +0000796xmlNop(void) {
797 return(0);
798}
799
800/**
Owen Taylor3473f882001-02-23 17:55:21 +0000801 * xmlFdRead:
802 * @context: the I/O context
803 * @buffer: where to drop data
804 * @len: number of bytes to read
805 *
806 * Read @len bytes to @buffer from the I/O channel.
807 *
808 * Returns the number of bytes written
809 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000810static int
Owen Taylor3473f882001-02-23 17:55:21 +0000811xmlFdRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000812 int ret;
813
814 ret = read((int) (long) context, &buffer[0], len);
815 if (ret < 0) xmlIOErr(0, "read()");
816 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000817}
818
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000819#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000820/**
821 * xmlFdWrite:
822 * @context: the I/O context
823 * @buffer: where to get data
824 * @len: number of bytes to write
825 *
826 * Write @len bytes from @buffer to the I/O channel.
827 *
828 * Returns the number of bytes written
829 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000830static int
Owen Taylor3473f882001-02-23 17:55:21 +0000831xmlFdWrite (void * context, const char * buffer, int len) {
Daniel Veillard9b693b42005-10-28 14:54:17 +0000832 int ret = 0;
Daniel Veillard05d987b2003-10-08 11:54:57 +0000833
Daniel Veillard9b693b42005-10-28 14:54:17 +0000834 if (len > 0) {
835 ret = write((int) (long) context, &buffer[0], len);
836 if (ret < 0) xmlIOErr(0, "write()");
837 }
Daniel Veillard05d987b2003-10-08 11:54:57 +0000838 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000839}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000840#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000841
842/**
843 * xmlFdClose:
844 * @context: the I/O context
845 *
846 * Close an I/O channel
Daniel Veillardf012a642001-07-23 19:10:52 +0000847 *
848 * Returns 0 in case of success and error code otherwise
Owen Taylor3473f882001-02-23 17:55:21 +0000849 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000850static int
Owen Taylor3473f882001-02-23 17:55:21 +0000851xmlFdClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000852 int ret;
853 ret = close((int) (long) context);
854 if (ret < 0) xmlIOErr(0, "close()");
855 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000856}
857
858/**
859 * xmlFileMatch:
860 * @filename: the URI for matching
861 *
862 * input from FILE *
863 *
864 * Returns 1 if matches, 0 otherwise
865 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000866int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000867xmlFileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000868 return(1);
869}
870
871/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000872 * xmlFileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +0000873 * @filename: the URI for matching
874 *
875 * input from FILE *, supports compressed input
876 * if @filename is " " then the standard input is used
877 *
878 * Returns an I/O context or NULL in case of error
879 */
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000880static void *
881xmlFileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +0000882 const char *path = NULL;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000883 FILE *fd;
Owen Taylor3473f882001-02-23 17:55:21 +0000884
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000885 if (filename == NULL)
886 return(NULL);
887
Owen Taylor3473f882001-02-23 17:55:21 +0000888 if (!strcmp(filename, "-")) {
889 fd = stdin;
890 return((void *) fd);
891 }
892
Daniel Veillard5cdbbd22007-06-12 09:39:14 +0000893 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000894#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000895 path = &filename[17];
896#else
Owen Taylor3473f882001-02-23 17:55:21 +0000897 path = &filename[16];
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000898#endif
Daniel Veillard5cdbbd22007-06-12 09:39:14 +0000899 } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000900#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000901 path = &filename[8];
902#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000903 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000904#endif
Daniel Veillard5cdbbd22007-06-12 09:39:14 +0000905 } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:/", 6)) {
906 /* lots of generators seems to lazy to read RFC 1738 */
907#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
908 path = &filename[6];
909#else
910 path = &filename[5];
911#endif
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200912 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000913 path = filename;
914
915 if (path == NULL)
916 return(NULL);
917 if (!xmlCheckFilename(path))
918 return(NULL);
919
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000920#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
921 fd = xmlWrapOpen(path, 0);
922#else
923 fd = fopen(path, "r");
Owen Taylor3473f882001-02-23 17:55:21 +0000924#endif /* WIN32 */
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000925 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +0000926 return((void *) fd);
927}
928
929/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000930 * xmlFileOpen:
931 * @filename: the URI for matching
932 *
933 * Wrapper around xmlFileOpen_real that try it with an unescaped
934 * version of @filename, if this fails fallback to @filename
Daniel Veillard71531f32003-02-05 13:19:53 +0000935 *
936 * Returns a handler or NULL in case or failure
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000937 */
938void *
939xmlFileOpen (const char *filename) {
940 char *unescaped;
941 void *retval;
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000942
Daniel Veillardbd672bc2007-03-30 12:39:25 +0000943 retval = xmlFileOpen_real(filename);
944 if (retval == NULL) {
945 unescaped = xmlURIUnescapeString(filename, 0, NULL);
946 if (unescaped != NULL) {
947 retval = xmlFileOpen_real(unescaped);
948 xmlFree(unescaped);
949 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000950 }
Daniel Veillardbd672bc2007-03-30 12:39:25 +0000951
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000952 return retval;
953}
954
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000955#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000956/**
Owen Taylor3473f882001-02-23 17:55:21 +0000957 * xmlFileOpenW:
958 * @filename: the URI for matching
959 *
960 * output to from FILE *,
961 * if @filename is "-" then the standard output is used
962 *
963 * Returns an I/O context or NULL in case of error
964 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000965static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000966xmlFileOpenW (const char *filename) {
967 const char *path = NULL;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000968 FILE *fd;
Owen Taylor3473f882001-02-23 17:55:21 +0000969
970 if (!strcmp(filename, "-")) {
971 fd = stdout;
972 return((void *) fd);
973 }
974
Daniel Veillardf4862f02002-09-10 11:13:43 +0000975 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000976#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000977 path = &filename[17];
978#else
Owen Taylor3473f882001-02-23 17:55:21 +0000979 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000980#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000981 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000982#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000983 path = &filename[8];
984#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000985 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000986#endif
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200987 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000988 path = filename;
989
990 if (path == NULL)
991 return(NULL);
992
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000993#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
994 fd = xmlWrapOpen(path, 1);
995#else
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200996 fd = fopen(path, "wb");
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000997#endif /* WIN32 */
Daniel Veillarde5a3f372006-08-30 13:11:36 +0000998
Daniel Veillardf7416012006-04-27 08:15:20 +0000999 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +00001000 return((void *) fd);
1001}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001002#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001003
1004/**
1005 * xmlFileRead:
1006 * @context: the I/O context
1007 * @buffer: where to drop data
1008 * @len: number of bytes to write
1009 *
1010 * Read @len bytes to @buffer from the I/O channel.
1011 *
Daniel Veillardce682bc2004-11-05 17:22:25 +00001012 * Returns the number of bytes written or < 0 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +00001013 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001014int
Owen Taylor3473f882001-02-23 17:55:21 +00001015xmlFileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001016 int ret;
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001017 if ((context == NULL) || (buffer == NULL))
Daniel Veillardce682bc2004-11-05 17:22:25 +00001018 return(-1);
Daniel Veillard05d987b2003-10-08 11:54:57 +00001019 ret = fread(&buffer[0], 1, len, (FILE *) context);
1020 if (ret < 0) xmlIOErr(0, "fread()");
1021 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001022}
1023
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001024#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001025/**
1026 * xmlFileWrite:
1027 * @context: the I/O context
1028 * @buffer: where to drop data
1029 * @len: number of bytes to write
1030 *
1031 * Write @len bytes from @buffer to the I/O channel.
1032 *
1033 * Returns the number of bytes written
1034 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001035static int
Owen Taylor3473f882001-02-23 17:55:21 +00001036xmlFileWrite (void * context, const char * buffer, int len) {
Daniel Veillard4a6d39b2002-12-17 18:33:01 +00001037 int items;
1038
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001039 if ((context == NULL) || (buffer == NULL))
Daniel Veillardce682bc2004-11-05 17:22:25 +00001040 return(-1);
Daniel Veillard4a6d39b2002-12-17 18:33:01 +00001041 items = fwrite(&buffer[0], len, 1, (FILE *) context);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00001042 if ((items == 0) && (ferror((FILE *) context))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001043 xmlIOErr(0, "fwrite()");
Daniel Veillard97bf4d02003-10-08 18:58:28 +00001044 return(-1);
1045 }
Daniel Veillard4a6d39b2002-12-17 18:33:01 +00001046 return(items * len);
Owen Taylor3473f882001-02-23 17:55:21 +00001047}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001048#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001049
1050/**
1051 * xmlFileClose:
1052 * @context: the I/O context
1053 *
1054 * Close an I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001055 *
1056 * Returns 0 or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +00001057 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001058int
Owen Taylor3473f882001-02-23 17:55:21 +00001059xmlFileClose (void * context) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001060 FILE *fil;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001061 int ret;
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001062
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +00001063 if (context == NULL)
1064 return(-1);
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001065 fil = (FILE *) context;
Daniel Veillard500a1de2004-03-22 15:22:58 +00001066 if ((fil == stdout) || (fil == stderr)) {
1067 ret = fflush(fil);
1068 if (ret < 0)
1069 xmlIOErr(0, "fflush()");
1070 return(0);
1071 }
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001072 if (fil == stdin)
1073 return(0);
Daniel Veillard05d987b2003-10-08 11:54:57 +00001074 ret = ( fclose((FILE *) context) == EOF ) ? -1 : 0;
1075 if (ret < 0)
1076 xmlIOErr(0, "fclose()");
1077 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001078}
1079
1080/**
1081 * xmlFileFlush:
1082 * @context: the I/O context
1083 *
1084 * Flush an I/O channel
1085 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001086static int
Owen Taylor3473f882001-02-23 17:55:21 +00001087xmlFileFlush (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001088 int ret;
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +00001089
1090 if (context == NULL)
1091 return(-1);
Daniel Veillard05d987b2003-10-08 11:54:57 +00001092 ret = ( fflush((FILE *) context) == EOF ) ? -1 : 0;
1093 if (ret < 0)
1094 xmlIOErr(0, "fflush()");
1095 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001096}
1097
Daniel Veillard9a00fd22005-11-09 08:56:26 +00001098#ifdef LIBXML_OUTPUT_ENABLED
1099/**
1100 * xmlBufferWrite:
1101 * @context: the xmlBuffer
1102 * @buffer: the data to write
1103 * @len: number of bytes to write
1104 *
1105 * Write @len bytes from @buffer to the xml buffer
1106 *
1107 * Returns the number of bytes written
1108 */
1109static int
1110xmlBufferWrite (void * context, const char * buffer, int len) {
1111 int ret;
1112
1113 ret = xmlBufferAdd((xmlBufferPtr) context, (const xmlChar *) buffer, len);
1114 if (ret != 0)
1115 return(-1);
1116 return(len);
1117}
Daniel Veillard9a00fd22005-11-09 08:56:26 +00001118#endif
1119
Owen Taylor3473f882001-02-23 17:55:21 +00001120#ifdef HAVE_ZLIB_H
1121/************************************************************************
1122 * *
1123 * I/O for compressed file accesses *
1124 * *
1125 ************************************************************************/
1126/**
1127 * xmlGzfileMatch:
1128 * @filename: the URI for matching
1129 *
1130 * input from compressed file test
1131 *
1132 * Returns 1 if matches, 0 otherwise
1133 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001134static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00001135xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00001136 return(1);
1137}
1138
1139/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001140 * xmlGzfileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +00001141 * @filename: the URI for matching
1142 *
1143 * input from compressed file open
1144 * if @filename is " " then the standard input is used
1145 *
1146 * Returns an I/O context or NULL in case of error
1147 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001148static void *
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001149xmlGzfileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +00001150 const char *path = NULL;
1151 gzFile fd;
1152
1153 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001154 fd = gzdopen(dup(0), "rb");
Owen Taylor3473f882001-02-23 17:55:21 +00001155 return((void *) fd);
1156 }
1157
Daniel Veillardf4862f02002-09-10 11:13:43 +00001158 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001159#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00001160 path = &filename[17];
1161#else
Owen Taylor3473f882001-02-23 17:55:21 +00001162 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00001163#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001164 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001165#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +00001166 path = &filename[8];
1167#else
Owen Taylor3473f882001-02-23 17:55:21 +00001168 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +00001169#endif
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001170 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001171 path = filename;
1172
1173 if (path == NULL)
1174 return(NULL);
1175 if (!xmlCheckFilename(path))
1176 return(NULL);
1177
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001178#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
1179 fd = xmlWrapGzOpen(path, "rb");
1180#else
Owen Taylor3473f882001-02-23 17:55:21 +00001181 fd = gzopen(path, "rb");
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001182#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001183 return((void *) fd);
1184}
1185
1186/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001187 * xmlGzfileOpen:
1188 * @filename: the URI for matching
1189 *
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00001190 * Wrapper around xmlGzfileOpen if the open fais, it will
1191 * try to unescape @filename
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001192 */
1193static void *
1194xmlGzfileOpen (const char *filename) {
1195 char *unescaped;
1196 void *retval;
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00001197
1198 retval = xmlGzfileOpen_real(filename);
1199 if (retval == NULL) {
1200 unescaped = xmlURIUnescapeString(filename, 0, NULL);
1201 if (unescaped != NULL) {
1202 retval = xmlGzfileOpen_real(unescaped);
1203 }
1204 xmlFree(unescaped);
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001205 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001206 return retval;
1207}
1208
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001209#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001210/**
Owen Taylor3473f882001-02-23 17:55:21 +00001211 * xmlGzfileOpenW:
1212 * @filename: the URI for matching
1213 * @compression: the compression factor (0 - 9 included)
1214 *
1215 * input from compressed file open
1216 * if @filename is " " then the standard input is used
1217 *
1218 * Returns an I/O context or NULL in case of error
1219 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001220static void *
Owen Taylor3473f882001-02-23 17:55:21 +00001221xmlGzfileOpenW (const char *filename, int compression) {
1222 const char *path = NULL;
1223 char mode[15];
1224 gzFile fd;
1225
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001226 snprintf(mode, sizeof(mode), "wb%d", compression);
Owen Taylor3473f882001-02-23 17:55:21 +00001227 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001228 fd = gzdopen(dup(1), mode);
Owen Taylor3473f882001-02-23 17:55:21 +00001229 return((void *) fd);
1230 }
1231
Daniel Veillardf4862f02002-09-10 11:13:43 +00001232 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001233#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00001234 path = &filename[17];
1235#else
Owen Taylor3473f882001-02-23 17:55:21 +00001236 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00001237#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001238 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001239#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +00001240 path = &filename[8];
1241#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +00001242 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +00001243#endif
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001244 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001245 path = filename;
1246
1247 if (path == NULL)
1248 return(NULL);
1249
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001250#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
1251 fd = xmlWrapGzOpen(path, mode);
1252#else
Owen Taylor3473f882001-02-23 17:55:21 +00001253 fd = gzopen(path, mode);
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001254#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001255 return((void *) fd);
1256}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001257#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001258
1259/**
1260 * xmlGzfileRead:
1261 * @context: the I/O context
1262 * @buffer: where to drop data
1263 * @len: number of bytes to write
1264 *
1265 * Read @len bytes to @buffer from the compressed I/O channel.
1266 *
1267 * Returns the number of bytes written
1268 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001269static int
Owen Taylor3473f882001-02-23 17:55:21 +00001270xmlGzfileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001271 int ret;
1272
1273 ret = gzread((gzFile) context, &buffer[0], len);
1274 if (ret < 0) xmlIOErr(0, "gzread()");
1275 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001276}
1277
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001278#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001279/**
1280 * xmlGzfileWrite:
1281 * @context: the I/O context
1282 * @buffer: where to drop data
1283 * @len: number of bytes to write
1284 *
1285 * Write @len bytes from @buffer to the compressed I/O channel.
1286 *
1287 * Returns the number of bytes written
1288 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001289static int
Owen Taylor3473f882001-02-23 17:55:21 +00001290xmlGzfileWrite (void * context, const char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001291 int ret;
1292
1293 ret = gzwrite((gzFile) context, (char *) &buffer[0], len);
1294 if (ret < 0) xmlIOErr(0, "gzwrite()");
1295 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001296}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001297#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001298
1299/**
1300 * xmlGzfileClose:
1301 * @context: the I/O context
1302 *
1303 * Close a compressed I/O channel
1304 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001305static int
Owen Taylor3473f882001-02-23 17:55:21 +00001306xmlGzfileClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001307 int ret;
1308
1309 ret = (gzclose((gzFile) context) == Z_OK ) ? 0 : -1;
1310 if (ret < 0) xmlIOErr(0, "gzclose()");
1311 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001312}
1313#endif /* HAVE_ZLIB_H */
1314
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001315#ifdef HAVE_LZMA_H
1316/************************************************************************
1317 * *
1318 * I/O for compressed file accesses *
1319 * *
1320 ************************************************************************/
Daniel Veillardadf5ec92012-01-26 16:56:22 +08001321#include "xzlib.h"
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001322/**
1323 * xmlXzfileMatch:
1324 * @filename: the URI for matching
1325 *
1326 * input from compressed file test
1327 *
1328 * Returns 1 if matches, 0 otherwise
1329 */
1330static int
1331xmlXzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
1332 return(1);
1333}
1334
1335/**
1336 * xmlXzFileOpen_real:
1337 * @filename: the URI for matching
1338 *
1339 * input from compressed file open
1340 * if @filename is " " then the standard input is used
1341 *
1342 * Returns an I/O context or NULL in case of error
1343 */
1344static void *
1345xmlXzfileOpen_real (const char *filename) {
1346 const char *path = NULL;
1347 xzFile fd;
1348
1349 if (!strcmp(filename, "-")) {
Daniel Veillardadf5ec92012-01-26 16:56:22 +08001350 fd = __libxml2_xzdopen(dup(0), "rb");
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001351 return((void *) fd);
1352 }
1353
1354 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) {
1355 path = &filename[16];
1356 } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
1357 path = &filename[7];
1358 } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:/", 6)) {
1359 /* lots of generators seems to lazy to read RFC 1738 */
1360 path = &filename[5];
1361 } else
1362 path = filename;
1363
1364 if (path == NULL)
1365 return(NULL);
1366 if (!xmlCheckFilename(path))
1367 return(NULL);
1368
Daniel Veillardadf5ec92012-01-26 16:56:22 +08001369 fd = __libxml2_xzopen(path, "rb");
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001370 return((void *) fd);
1371}
1372
1373/**
1374 * xmlXzfileOpen:
1375 * @filename: the URI for matching
1376 *
1377 * Wrapper around xmlXzfileOpen_real that try it with an unescaped
1378 * version of @filename, if this fails fallback to @filename
1379 *
1380 * Returns a handler or NULL in case or failure
1381 */
1382static void *
1383xmlXzfileOpen (const char *filename) {
1384 char *unescaped;
1385 void *retval;
1386
1387 retval = xmlXzfileOpen_real(filename);
1388 if (retval == NULL) {
1389 unescaped = xmlURIUnescapeString(filename, 0, NULL);
1390 if (unescaped != NULL) {
1391 retval = xmlXzfileOpen_real(unescaped);
1392 }
1393 xmlFree(unescaped);
1394 }
1395
1396 return retval;
1397}
1398
1399/**
1400 * xmlXzfileRead:
1401 * @context: the I/O context
1402 * @buffer: where to drop data
1403 * @len: number of bytes to write
1404 *
1405 * Read @len bytes to @buffer from the compressed I/O channel.
1406 *
1407 * Returns the number of bytes written
1408 */
1409static int
1410xmlXzfileRead (void * context, char * buffer, int len) {
1411 int ret;
1412
Daniel Veillardadf5ec92012-01-26 16:56:22 +08001413 ret = __libxml2_xzread((xzFile) context, &buffer[0], len);
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001414 if (ret < 0) xmlIOErr(0, "xzread()");
1415 return(ret);
1416}
1417
1418/**
1419 * xmlXzfileClose:
1420 * @context: the I/O context
1421 *
1422 * Close a compressed I/O channel
1423 */
1424static int
1425xmlXzfileClose (void * context) {
1426 int ret;
1427
Daniel Veillardadf5ec92012-01-26 16:56:22 +08001428 ret = (__libxml2_xzclose((xzFile) context) == LZMA_OK ) ? 0 : -1;
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001429 if (ret < 0) xmlIOErr(0, "xzclose()");
1430 return(ret);
1431}
1432#endif /* HAVE_LZMA_H */
1433
Owen Taylor3473f882001-02-23 17:55:21 +00001434#ifdef LIBXML_HTTP_ENABLED
1435/************************************************************************
1436 * *
1437 * I/O for HTTP file accesses *
1438 * *
1439 ************************************************************************/
Daniel Veillardf012a642001-07-23 19:10:52 +00001440
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001441#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001442typedef struct xmlIOHTTPWriteCtxt_
1443{
1444 int compression;
1445
1446 char * uri;
1447
1448 void * doc_buff;
1449
1450} xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr;
1451
1452#ifdef HAVE_ZLIB_H
1453
1454#define DFLT_WBITS ( -15 )
1455#define DFLT_MEM_LVL ( 8 )
1456#define GZ_MAGIC1 ( 0x1f )
1457#define GZ_MAGIC2 ( 0x8b )
1458#define LXML_ZLIB_OS_CODE ( 0x03 )
1459#define INIT_HTTP_BUFF_SIZE ( 32768 )
1460#define DFLT_ZLIB_RATIO ( 5 )
1461
1462/*
1463** Data structure and functions to work with sending compressed data
1464** via HTTP.
1465*/
1466
1467typedef struct xmlZMemBuff_
1468{
1469 unsigned long size;
1470 unsigned long crc;
1471
1472 unsigned char * zbuff;
1473 z_stream zctrl;
1474
1475} xmlZMemBuff, *xmlZMemBuffPtr;
1476
1477/**
1478 * append_reverse_ulong
1479 * @buff: Compressed memory buffer
1480 * @data: Unsigned long to append
1481 *
1482 * Append a unsigned long in reverse byte order to the end of the
1483 * memory buffer.
1484 */
1485static void
1486append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) {
1487
1488 int idx;
1489
1490 if ( buff == NULL )
1491 return;
1492
1493 /*
1494 ** This is plagiarized from putLong in gzio.c (zlib source) where
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001495 ** the number "4" is hardcoded. If zlib is ever patched to
Daniel Veillardf012a642001-07-23 19:10:52 +00001496 ** support 64 bit file sizes, this code would need to be patched
1497 ** as well.
1498 */
1499
1500 for ( idx = 0; idx < 4; idx++ ) {
1501 *buff->zctrl.next_out = ( data & 0xff );
1502 data >>= 8;
1503 buff->zctrl.next_out++;
1504 }
1505
1506 return;
1507}
1508
1509/**
1510 *
1511 * xmlFreeZMemBuff
1512 * @buff: The memory buffer context to clear
1513 *
1514 * Release all the resources associated with the compressed memory buffer.
1515 */
1516static void
1517xmlFreeZMemBuff( xmlZMemBuffPtr buff ) {
William M. Brack78637da2003-07-31 14:47:38 +00001518
1519#ifdef DEBUG_HTTP
Daniel Veillardf012a642001-07-23 19:10:52 +00001520 int z_err;
William M. Brack78637da2003-07-31 14:47:38 +00001521#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001522
1523 if ( buff == NULL )
1524 return;
1525
1526 xmlFree( buff->zbuff );
Daniel Veillardf012a642001-07-23 19:10:52 +00001527#ifdef DEBUG_HTTP
William M. Brack78637da2003-07-31 14:47:38 +00001528 z_err = deflateEnd( &buff->zctrl );
Daniel Veillardf012a642001-07-23 19:10:52 +00001529 if ( z_err != Z_OK )
1530 xmlGenericError( xmlGenericErrorContext,
1531 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
1532 z_err );
William M. Brack78637da2003-07-31 14:47:38 +00001533#else
1534 deflateEnd( &buff->zctrl );
William M. Brack779af002003-08-01 15:55:39 +00001535#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001536
1537 xmlFree( buff );
1538 return;
1539}
1540
1541/**
1542 * xmlCreateZMemBuff
1543 *@compression: Compression value to use
1544 *
1545 * Create a memory buffer to hold the compressed XML document. The
1546 * compressed document in memory will end up being identical to what
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001547 * would be created if gzopen/gzwrite/gzclose were being used to
Daniel Veillardf012a642001-07-23 19:10:52 +00001548 * write the document to disk. The code for the header/trailer data to
1549 * the compression is plagiarized from the zlib source files.
1550 */
1551static void *
1552xmlCreateZMemBuff( int compression ) {
1553
1554 int z_err;
1555 int hdr_lgth;
1556 xmlZMemBuffPtr buff = NULL;
1557
1558 if ( ( compression < 1 ) || ( compression > 9 ) )
1559 return ( NULL );
1560
1561 /* Create the control and data areas */
1562
1563 buff = xmlMalloc( sizeof( xmlZMemBuff ) );
1564 if ( buff == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001565 xmlIOErrMemory("creating buffer context");
Daniel Veillardf012a642001-07-23 19:10:52 +00001566 return ( NULL );
1567 }
1568
1569 (void)memset( buff, 0, sizeof( xmlZMemBuff ) );
1570 buff->size = INIT_HTTP_BUFF_SIZE;
1571 buff->zbuff = xmlMalloc( buff->size );
1572 if ( buff->zbuff == NULL ) {
1573 xmlFreeZMemBuff( buff );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001574 xmlIOErrMemory("creating buffer");
Daniel Veillardf012a642001-07-23 19:10:52 +00001575 return ( NULL );
1576 }
1577
1578 z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
1579 DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
1580 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001581 xmlChar msg[500];
Daniel Veillardf012a642001-07-23 19:10:52 +00001582 xmlFreeZMemBuff( buff );
1583 buff = NULL;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001584 xmlStrPrintf(msg, 500,
1585 (const xmlChar *) "xmlCreateZMemBuff: %s %d\n",
1586 "Error initializing compression context. ZLIB error:",
1587 z_err );
1588 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001589 return ( NULL );
1590 }
1591
1592 /* Set the header data. The CRC will be needed for the trailer */
Daniel Veillard24505b02005-07-28 23:49:35 +00001593 buff->crc = crc32( 0L, NULL, 0 );
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001594 hdr_lgth = snprintf( (char *)buff->zbuff, buff->size,
1595 "%c%c%c%c%c%c%c%c%c%c",
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001596 GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED,
Daniel Veillardf012a642001-07-23 19:10:52 +00001597 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE );
1598 buff->zctrl.next_out = buff->zbuff + hdr_lgth;
1599 buff->zctrl.avail_out = buff->size - hdr_lgth;
1600
1601 return ( buff );
1602}
1603
1604/**
1605 * xmlZMemBuffExtend
1606 * @buff: Buffer used to compress and consolidate data.
1607 * @ext_amt: Number of bytes to extend the buffer.
1608 *
1609 * Extend the internal buffer used to store the compressed data by the
1610 * specified amount.
1611 *
1612 * Returns 0 on success or -1 on failure to extend the buffer. On failure
1613 * the original buffer still exists at the original size.
1614 */
1615static int
1616xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) {
1617
1618 int rc = -1;
1619 size_t new_size;
1620 size_t cur_used;
1621
1622 unsigned char * tmp_ptr = NULL;
1623
1624 if ( buff == NULL )
1625 return ( -1 );
1626
1627 else if ( ext_amt == 0 )
1628 return ( 0 );
1629
1630 cur_used = buff->zctrl.next_out - buff->zbuff;
1631 new_size = buff->size + ext_amt;
1632
1633#ifdef DEBUG_HTTP
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001634 if ( cur_used > new_size )
Daniel Veillardf012a642001-07-23 19:10:52 +00001635 xmlGenericError( xmlGenericErrorContext,
1636 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
1637 "Buffer overwrite detected during compressed memory",
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001638 "buffer extension. Overflowed by",
Daniel Veillardf012a642001-07-23 19:10:52 +00001639 (cur_used - new_size ) );
1640#endif
1641
1642 tmp_ptr = xmlRealloc( buff->zbuff, new_size );
1643 if ( tmp_ptr != NULL ) {
1644 rc = 0;
1645 buff->size = new_size;
1646 buff->zbuff = tmp_ptr;
1647 buff->zctrl.next_out = tmp_ptr + cur_used;
1648 buff->zctrl.avail_out = new_size - cur_used;
1649 }
1650 else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001651 xmlChar msg[500];
1652 xmlStrPrintf(msg, 500,
1653 (const xmlChar *) "xmlZMemBuffExtend: %s %lu bytes.\n",
1654 "Allocation failure extending output buffer to",
1655 new_size );
1656 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001657 }
1658
1659 return ( rc );
1660}
1661
1662/**
1663 * xmlZMemBuffAppend
1664 * @buff: Buffer used to compress and consolidate data
1665 * @src: Uncompressed source content to append to buffer
1666 * @len: Length of source data to append to buffer
1667 *
1668 * Compress and append data to the internal buffer. The data buffer
1669 * will be expanded if needed to store the additional data.
1670 *
1671 * Returns the number of bytes appended to the buffer or -1 on error.
1672 */
1673static int
1674xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) {
1675
1676 int z_err;
1677 size_t min_accept;
1678
1679 if ( ( buff == NULL ) || ( src == NULL ) )
1680 return ( -1 );
1681
1682 buff->zctrl.avail_in = len;
1683 buff->zctrl.next_in = (unsigned char *)src;
1684 while ( buff->zctrl.avail_in > 0 ) {
1685 /*
1686 ** Extend the buffer prior to deflate call if a reasonable amount
1687 ** of output buffer space is not available.
1688 */
1689 min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO;
1690 if ( buff->zctrl.avail_out <= min_accept ) {
1691 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1692 return ( -1 );
1693 }
1694
1695 z_err = deflate( &buff->zctrl, Z_NO_FLUSH );
1696 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001697 xmlChar msg[500];
1698 xmlStrPrintf(msg, 500,
1699 (const xmlChar *) "xmlZMemBuffAppend: %s %d %s - %d",
Daniel Veillardf012a642001-07-23 19:10:52 +00001700 "Compression error while appending",
1701 len, "bytes to buffer. ZLIB error", z_err );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001702 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001703 return ( -1 );
1704 }
1705 }
1706
1707 buff->crc = crc32( buff->crc, (unsigned char *)src, len );
1708
1709 return ( len );
1710}
1711
1712/**
1713 * xmlZMemBuffGetContent
1714 * @buff: Compressed memory content buffer
1715 * @data_ref: Pointer reference to point to compressed content
1716 *
1717 * Flushes the compression buffers, appends gzip file trailers and
1718 * returns the compressed content and length of the compressed data.
1719 * NOTE: The gzip trailer code here is plagiarized from zlib source.
1720 *
1721 * Returns the length of the compressed data or -1 on error.
1722 */
1723static int
1724xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) {
1725
1726 int zlgth = -1;
1727 int z_err;
1728
1729 if ( ( buff == NULL ) || ( data_ref == NULL ) )
1730 return ( -1 );
1731
1732 /* Need to loop until compression output buffers are flushed */
1733
1734 do
1735 {
1736 z_err = deflate( &buff->zctrl, Z_FINISH );
1737 if ( z_err == Z_OK ) {
1738 /* In this case Z_OK means more buffer space needed */
1739
1740 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1741 return ( -1 );
1742 }
1743 }
1744 while ( z_err == Z_OK );
1745
1746 /* If the compression state is not Z_STREAM_END, some error occurred */
1747
1748 if ( z_err == Z_STREAM_END ) {
1749
1750 /* Need to append the gzip data trailer */
1751
1752 if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) {
1753 if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 )
1754 return ( -1 );
1755 }
1756
1757 /*
1758 ** For whatever reason, the CRC and length data are pushed out
1759 ** in reverse byte order. So a memcpy can't be used here.
1760 */
1761
1762 append_reverse_ulong( buff, buff->crc );
1763 append_reverse_ulong( buff, buff->zctrl.total_in );
1764
1765 zlgth = buff->zctrl.next_out - buff->zbuff;
1766 *data_ref = (char *)buff->zbuff;
1767 }
1768
Daniel Veillard05d987b2003-10-08 11:54:57 +00001769 else {
1770 xmlChar msg[500];
1771 xmlStrPrintf(msg, 500,
1772 (const xmlChar *) "xmlZMemBuffGetContent: %s - %d\n",
1773 "Error flushing zlib buffers. Error code", z_err );
1774 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1775 }
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001776
Daniel Veillardf012a642001-07-23 19:10:52 +00001777 return ( zlgth );
1778}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001779#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001780#endif /* HAVE_ZLIB_H */
1781
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001782#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001783/**
1784 * xmlFreeHTTPWriteCtxt
1785 * @ctxt: Context to cleanup
1786 *
1787 * Free allocated memory and reclaim system resources.
1788 *
1789 * No return value.
1790 */
1791static void
1792xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt )
1793{
1794 if ( ctxt->uri != NULL )
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001795 xmlFree( ctxt->uri );
Daniel Veillardf012a642001-07-23 19:10:52 +00001796
1797 if ( ctxt->doc_buff != NULL ) {
1798
1799#ifdef HAVE_ZLIB_H
1800 if ( ctxt->compression > 0 ) {
1801 xmlFreeZMemBuff( ctxt->doc_buff );
1802 }
1803 else
1804#endif
1805 {
1806 xmlOutputBufferClose( ctxt->doc_buff );
1807 }
1808 }
1809
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001810 xmlFree( ctxt );
Daniel Veillardf012a642001-07-23 19:10:52 +00001811 return;
1812}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001813#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001814
1815
Owen Taylor3473f882001-02-23 17:55:21 +00001816/**
1817 * xmlIOHTTPMatch:
1818 * @filename: the URI for matching
1819 *
1820 * check if the URI matches an HTTP one
1821 *
1822 * Returns 1 if matches, 0 otherwise
1823 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001824int
Owen Taylor3473f882001-02-23 17:55:21 +00001825xmlIOHTTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001826 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "http://", 7))
Owen Taylor3473f882001-02-23 17:55:21 +00001827 return(1);
1828 return(0);
1829}
1830
1831/**
1832 * xmlIOHTTPOpen:
1833 * @filename: the URI for matching
1834 *
1835 * open an HTTP I/O channel
1836 *
1837 * Returns an I/O context or NULL in case of error
1838 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001839void *
Owen Taylor3473f882001-02-23 17:55:21 +00001840xmlIOHTTPOpen (const char *filename) {
1841 return(xmlNanoHTTPOpen(filename, NULL));
1842}
1843
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001844#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001845/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001846 * xmlIOHTTPOpenW:
Daniel Veillardf012a642001-07-23 19:10:52 +00001847 * @post_uri: The destination URI for the document
1848 * @compression: The compression desired for the document.
1849 *
1850 * Open a temporary buffer to collect the document for a subsequent HTTP POST
1851 * request. Non-static as is called from the output buffer creation routine.
1852 *
1853 * Returns an I/O context or NULL in case of error.
1854 */
1855
1856void *
Daniel Veillard572577e2002-01-18 16:23:55 +00001857xmlIOHTTPOpenW(const char *post_uri, int compression)
1858{
Daniel Veillardf012a642001-07-23 19:10:52 +00001859
Daniel Veillard572577e2002-01-18 16:23:55 +00001860 xmlIOHTTPWriteCtxtPtr ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001861
Daniel Veillard572577e2002-01-18 16:23:55 +00001862 if (post_uri == NULL)
1863 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001864
Daniel Veillard572577e2002-01-18 16:23:55 +00001865 ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt));
1866 if (ctxt == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001867 xmlIOErrMemory("creating HTTP output context");
Daniel Veillard572577e2002-01-18 16:23:55 +00001868 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001869 }
1870
Daniel Veillard572577e2002-01-18 16:23:55 +00001871 (void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt));
Daniel Veillardf012a642001-07-23 19:10:52 +00001872
Daniel Veillard572577e2002-01-18 16:23:55 +00001873 ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri);
1874 if (ctxt->uri == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001875 xmlIOErrMemory("copying URI");
Daniel Veillard572577e2002-01-18 16:23:55 +00001876 xmlFreeHTTPWriteCtxt(ctxt);
1877 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001878 }
1879
1880 /*
Daniel Veillard572577e2002-01-18 16:23:55 +00001881 * ** Since the document length is required for an HTTP post,
1882 * ** need to put the document into a buffer. A memory buffer
1883 * ** is being used to avoid pushing the data to disk and back.
1884 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001885
1886#ifdef HAVE_ZLIB_H
Daniel Veillard572577e2002-01-18 16:23:55 +00001887 if ((compression > 0) && (compression <= 9)) {
1888
1889 ctxt->compression = compression;
1890 ctxt->doc_buff = xmlCreateZMemBuff(compression);
1891 } else
Daniel Veillardf012a642001-07-23 19:10:52 +00001892#endif
1893 {
Daniel Veillard572577e2002-01-18 16:23:55 +00001894 /* Any character conversions should have been done before this */
Daniel Veillardf012a642001-07-23 19:10:52 +00001895
Daniel Veillardda3fee42008-09-01 13:08:57 +00001896 ctxt->doc_buff = xmlAllocOutputBufferInternal(NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001897 }
1898
Daniel Veillard572577e2002-01-18 16:23:55 +00001899 if (ctxt->doc_buff == NULL) {
1900 xmlFreeHTTPWriteCtxt(ctxt);
1901 ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001902 }
1903
Daniel Veillard572577e2002-01-18 16:23:55 +00001904 return (ctxt);
Daniel Veillardf012a642001-07-23 19:10:52 +00001905}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001906#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardda3fee42008-09-01 13:08:57 +00001907
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001908#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001909/**
1910 * xmlIOHTTPDfltOpenW
1911 * @post_uri: The destination URI for this document.
1912 *
1913 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
1914 * HTTP post command. This function should generally not be used as
1915 * the open callback is short circuited in xmlOutputBufferCreateFile.
1916 *
1917 * Returns a pointer to the new IO context.
1918 */
1919static void *
1920xmlIOHTTPDfltOpenW( const char * post_uri ) {
1921 return ( xmlIOHTTPOpenW( post_uri, 0 ) );
1922}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001923#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001924
1925/**
Owen Taylor3473f882001-02-23 17:55:21 +00001926 * xmlIOHTTPRead:
1927 * @context: the I/O context
1928 * @buffer: where to drop data
1929 * @len: number of bytes to write
1930 *
1931 * Read @len bytes to @buffer from the I/O channel.
1932 *
1933 * Returns the number of bytes written
1934 */
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001935int
Owen Taylor3473f882001-02-23 17:55:21 +00001936xmlIOHTTPRead(void * context, char * buffer, int len) {
Daniel Veillard5ea30d72004-11-08 11:54:28 +00001937 if ((buffer == NULL) || (len < 0)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001938 return(xmlNanoHTTPRead(context, &buffer[0], len));
1939}
1940
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001941#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001942/**
Daniel Veillardf012a642001-07-23 19:10:52 +00001943 * xmlIOHTTPWrite
1944 * @context: previously opened writing context
1945 * @buffer: data to output to temporary buffer
1946 * @len: bytes to output
1947 *
1948 * Collect data from memory buffer into a temporary file for later
1949 * processing.
1950 *
1951 * Returns number of bytes written.
1952 */
1953
1954static int
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001955xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001956
1957 xmlIOHTTPWriteCtxtPtr ctxt = context;
1958
1959 if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
1960 return ( -1 );
1961
1962 if ( len > 0 ) {
1963
1964 /* Use gzwrite or fwrite as previously setup in the open call */
1965
1966#ifdef HAVE_ZLIB_H
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001967 if ( ctxt->compression > 0 )
Daniel Veillardf012a642001-07-23 19:10:52 +00001968 len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len );
1969
1970 else
1971#endif
1972 len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
1973
1974 if ( len < 0 ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001975 xmlChar msg[500];
1976 xmlStrPrintf(msg, 500,
1977 (const xmlChar *) "xmlIOHTTPWrite: %s\n%s '%s'.\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001978 "Error appending to internal buffer.",
1979 "Error sending document to URI",
1980 ctxt->uri );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001981 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001982 }
1983 }
1984
1985 return ( len );
1986}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001987#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001988
1989
1990/**
Owen Taylor3473f882001-02-23 17:55:21 +00001991 * xmlIOHTTPClose:
1992 * @context: the I/O context
1993 *
1994 * Close an HTTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001995 *
1996 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00001997 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001998int
Owen Taylor3473f882001-02-23 17:55:21 +00001999xmlIOHTTPClose (void * context) {
2000 xmlNanoHTTPClose(context);
Daniel Veillardf012a642001-07-23 19:10:52 +00002001 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002002}
Daniel Veillardf012a642001-07-23 19:10:52 +00002003
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002004#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00002005/**
2006 * xmlIOHTTCloseWrite
2007 * @context: The I/O context
2008 * @http_mthd: The HTTP method to be used when sending the data
2009 *
2010 * Close the transmit HTTP I/O channel and actually send the data.
2011 */
2012static int
2013xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
2014
2015 int close_rc = -1;
2016 int http_rtn = 0;
2017 int content_lgth = 0;
2018 xmlIOHTTPWriteCtxtPtr ctxt = context;
2019
2020 char * http_content = NULL;
2021 char * content_encoding = NULL;
2022 char * content_type = (char *) "text/xml";
2023 void * http_ctxt = NULL;
2024
2025 if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
2026 return ( -1 );
2027
2028 /* Retrieve the content from the appropriate buffer */
2029
2030#ifdef HAVE_ZLIB_H
2031
2032 if ( ctxt->compression > 0 ) {
2033 content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
2034 content_encoding = (char *) "Content-Encoding: gzip";
2035 }
2036 else
2037#endif
2038 {
2039 /* Pull the data out of the memory output buffer */
2040
2041 xmlOutputBufferPtr dctxt = ctxt->doc_buff;
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002042 http_content = (char *) xmlBufContent(dctxt->buffer);
2043 content_lgth = xmlBufUse(dctxt->buffer);
Daniel Veillardf012a642001-07-23 19:10:52 +00002044 }
2045
2046 if ( http_content == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002047 xmlChar msg[500];
2048 xmlStrPrintf(msg, 500,
2049 (const xmlChar *) "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
2050 "Error retrieving content.\nUnable to",
2051 http_mthd, "data to URI", ctxt->uri );
2052 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00002053 }
2054
2055 else {
2056
2057 http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
Hans Breuer2ad41ca2009-08-11 17:51:22 +02002058 &content_type, content_encoding,
Daniel Veillardf012a642001-07-23 19:10:52 +00002059 content_lgth );
2060
2061 if ( http_ctxt != NULL ) {
2062#ifdef DEBUG_HTTP
2063 /* If testing/debugging - dump reply with request content */
2064
2065 FILE * tst_file = NULL;
2066 char buffer[ 4096 ];
2067 char * dump_name = NULL;
2068 int avail;
2069
2070 xmlGenericError( xmlGenericErrorContext,
2071 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
2072 http_mthd, ctxt->uri,
2073 xmlNanoHTTPReturnCode( http_ctxt ) );
2074
2075 /*
2076 ** Since either content or reply may be gzipped,
Hans Breuer2ad41ca2009-08-11 17:51:22 +02002077 ** dump them to separate files instead of the
Daniel Veillardf012a642001-07-23 19:10:52 +00002078 ** standard error context.
2079 */
2080
2081 dump_name = tempnam( NULL, "lxml" );
2082 if ( dump_name != NULL ) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002083 (void)snprintf( buffer, sizeof(buffer), "%s.content", dump_name );
Daniel Veillardf012a642001-07-23 19:10:52 +00002084
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00002085 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00002086 if ( tst_file != NULL ) {
2087 xmlGenericError( xmlGenericErrorContext,
2088 "Transmitted content saved in file: %s\n", buffer );
2089
2090 fwrite( http_content, sizeof( char ),
2091 content_lgth, tst_file );
2092 fclose( tst_file );
2093 }
2094
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002095 (void)snprintf( buffer, sizeof(buffer), "%s.reply", dump_name );
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00002096 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00002097 if ( tst_file != NULL ) {
2098 xmlGenericError( xmlGenericErrorContext,
2099 "Reply content saved in file: %s\n", buffer );
2100
2101
2102 while ( (avail = xmlNanoHTTPRead( http_ctxt,
2103 buffer, sizeof( buffer ) )) > 0 ) {
2104
2105 fwrite( buffer, sizeof( char ), avail, tst_file );
2106 }
2107
2108 fclose( tst_file );
2109 }
2110
2111 free( dump_name );
2112 }
2113#endif /* DEBUG_HTTP */
2114
2115 http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
2116 if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
2117 close_rc = 0;
Daniel Veillard05d987b2003-10-08 11:54:57 +00002118 else {
2119 xmlChar msg[500];
2120 xmlStrPrintf(msg, 500,
2121 (const xmlChar *) "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00002122 http_mthd, content_lgth,
2123 "bytes to URI", ctxt->uri,
2124 "failed. HTTP return code:", http_rtn );
Daniel Veillard05d987b2003-10-08 11:54:57 +00002125 xmlIOErr(XML_IO_WRITE, (const char *) msg);
2126 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002127
2128 xmlNanoHTTPClose( http_ctxt );
2129 xmlFree( content_type );
2130 }
2131 }
2132
2133 /* Final cleanups */
2134
2135 xmlFreeHTTPWriteCtxt( ctxt );
2136
2137 return ( close_rc );
2138}
2139
2140/**
2141 * xmlIOHTTPClosePut
2142 *
2143 * @context: The I/O context
2144 *
2145 * Close the transmit HTTP I/O channel and actually send data using a PUT
2146 * HTTP method.
2147 */
2148static int
2149xmlIOHTTPClosePut( void * ctxt ) {
2150 return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
2151}
2152
2153
2154/**
2155 * xmlIOHTTPClosePost
2156 *
2157 * @context: The I/O context
2158 *
2159 * Close the transmit HTTP I/O channel and actually send data using a POST
2160 * HTTP method.
2161 */
2162static int
2163xmlIOHTTPClosePost( void * ctxt ) {
2164 return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
2165}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002166#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00002167
Owen Taylor3473f882001-02-23 17:55:21 +00002168#endif /* LIBXML_HTTP_ENABLED */
2169
2170#ifdef LIBXML_FTP_ENABLED
2171/************************************************************************
2172 * *
2173 * I/O for FTP file accesses *
2174 * *
2175 ************************************************************************/
2176/**
2177 * xmlIOFTPMatch:
2178 * @filename: the URI for matching
2179 *
2180 * check if the URI matches an FTP one
2181 *
2182 * Returns 1 if matches, 0 otherwise
2183 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002184int
Owen Taylor3473f882001-02-23 17:55:21 +00002185xmlIOFTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002186 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "ftp://", 6))
Owen Taylor3473f882001-02-23 17:55:21 +00002187 return(1);
2188 return(0);
2189}
2190
2191/**
2192 * xmlIOFTPOpen:
2193 * @filename: the URI for matching
2194 *
2195 * open an FTP I/O channel
2196 *
2197 * Returns an I/O context or NULL in case of error
2198 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002199void *
Owen Taylor3473f882001-02-23 17:55:21 +00002200xmlIOFTPOpen (const char *filename) {
2201 return(xmlNanoFTPOpen(filename));
2202}
2203
2204/**
2205 * xmlIOFTPRead:
2206 * @context: the I/O context
2207 * @buffer: where to drop data
2208 * @len: number of bytes to write
2209 *
2210 * Read @len bytes to @buffer from the I/O channel.
2211 *
2212 * Returns the number of bytes written
2213 */
Hans Breuer2ad41ca2009-08-11 17:51:22 +02002214int
Owen Taylor3473f882001-02-23 17:55:21 +00002215xmlIOFTPRead(void * context, char * buffer, int len) {
Daniel Veillard5ea30d72004-11-08 11:54:28 +00002216 if ((buffer == NULL) || (len < 0)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002217 return(xmlNanoFTPRead(context, &buffer[0], len));
2218}
2219
2220/**
2221 * xmlIOFTPClose:
2222 * @context: the I/O context
2223 *
2224 * Close an FTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00002225 *
2226 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00002227 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002228int
Owen Taylor3473f882001-02-23 17:55:21 +00002229xmlIOFTPClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +00002230 return ( xmlNanoFTPClose(context) );
Owen Taylor3473f882001-02-23 17:55:21 +00002231}
2232#endif /* LIBXML_FTP_ENABLED */
2233
2234
2235/**
2236 * xmlRegisterInputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002237 * @matchFunc: the xmlInputMatchCallback
2238 * @openFunc: the xmlInputOpenCallback
2239 * @readFunc: the xmlInputReadCallback
2240 * @closeFunc: the xmlInputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00002241 *
2242 * Register a new set of I/O callback for handling parser input.
2243 *
2244 * Returns the registered handler number or -1 in case of error
2245 */
2246int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002247xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
2248 xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
2249 xmlInputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002250 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
2251 return(-1);
2252 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002253 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
2254 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
2255 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
2256 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00002257 xmlInputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002258 return(xmlInputCallbackNr++);
2259}
2260
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002261#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002262/**
2263 * xmlRegisterOutputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002264 * @matchFunc: the xmlOutputMatchCallback
2265 * @openFunc: the xmlOutputOpenCallback
2266 * @writeFunc: the xmlOutputWriteCallback
2267 * @closeFunc: the xmlOutputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00002268 *
2269 * Register a new set of I/O callback for handling output.
2270 *
2271 * Returns the registered handler number or -1 in case of error
2272 */
2273int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002274xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
2275 xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
2276 xmlOutputCloseCallback closeFunc) {
Daniel Veillard0d5e58f2009-08-24 13:52:23 +02002277 if (xmlOutputCallbackNr >= MAX_OUTPUT_CALLBACK) {
Owen Taylor3473f882001-02-23 17:55:21 +00002278 return(-1);
2279 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002280 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
2281 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
2282 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
2283 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00002284 xmlOutputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002285 return(xmlOutputCallbackNr++);
2286}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002287#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002288
2289/**
2290 * xmlRegisterDefaultInputCallbacks:
2291 *
2292 * Registers the default compiled-in I/O handlers.
2293 */
2294void
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +00002295xmlRegisterDefaultInputCallbacks(void) {
Owen Taylor3473f882001-02-23 17:55:21 +00002296 if (xmlInputCallbackInitialized)
2297 return;
2298
Daniel Veillard8ca85b22006-09-01 09:56:07 +00002299#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
2300 xmlInitPlatformSpecificIo();
2301#endif
2302
Owen Taylor3473f882001-02-23 17:55:21 +00002303 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
2304 xmlFileRead, xmlFileClose);
2305#ifdef HAVE_ZLIB_H
2306 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
2307 xmlGzfileRead, xmlGzfileClose);
2308#endif /* HAVE_ZLIB_H */
Anders F Bjorklundeae52612011-09-18 16:59:13 +02002309#ifdef HAVE_LZMA_H
2310 xmlRegisterInputCallbacks(xmlXzfileMatch, xmlXzfileOpen,
2311 xmlXzfileRead, xmlXzfileClose);
2312#endif /* HAVE_ZLIB_H */
Owen Taylor3473f882001-02-23 17:55:21 +00002313
2314#ifdef LIBXML_HTTP_ENABLED
2315 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
2316 xmlIOHTTPRead, xmlIOHTTPClose);
2317#endif /* LIBXML_HTTP_ENABLED */
2318
2319#ifdef LIBXML_FTP_ENABLED
2320 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
2321 xmlIOFTPRead, xmlIOFTPClose);
2322#endif /* LIBXML_FTP_ENABLED */
2323 xmlInputCallbackInitialized = 1;
2324}
2325
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002326#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002327/**
2328 * xmlRegisterDefaultOutputCallbacks:
2329 *
2330 * Registers the default compiled-in I/O handlers.
2331 */
2332void
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +00002333xmlRegisterDefaultOutputCallbacks (void) {
Owen Taylor3473f882001-02-23 17:55:21 +00002334 if (xmlOutputCallbackInitialized)
2335 return;
2336
Daniel Veillard8ca85b22006-09-01 09:56:07 +00002337#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
2338 xmlInitPlatformSpecificIo();
2339#endif
2340
Owen Taylor3473f882001-02-23 17:55:21 +00002341 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
2342 xmlFileWrite, xmlFileClose);
Daniel Veillardf012a642001-07-23 19:10:52 +00002343
2344#ifdef LIBXML_HTTP_ENABLED
2345 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
2346 xmlIOHTTPWrite, xmlIOHTTPClosePut);
2347#endif
2348
Owen Taylor3473f882001-02-23 17:55:21 +00002349/*********************************
2350 No way a-priori to distinguish between gzipped files from
2351 uncompressed ones except opening if existing then closing
2352 and saving with same compression ratio ... a pain.
2353
2354#ifdef HAVE_ZLIB_H
2355 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
2356 xmlGzfileWrite, xmlGzfileClose);
2357#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002358
2359 Nor FTP PUT ....
2360#ifdef LIBXML_FTP_ENABLED
2361 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
2362 xmlIOFTPWrite, xmlIOFTPClose);
2363#endif
2364 **********************************/
2365 xmlOutputCallbackInitialized = 1;
2366}
2367
Daniel Veillardf012a642001-07-23 19:10:52 +00002368#ifdef LIBXML_HTTP_ENABLED
2369/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00002370 * xmlRegisterHTTPPostCallbacks:
Daniel Veillardf012a642001-07-23 19:10:52 +00002371 *
2372 * By default, libxml submits HTTP output requests using the "PUT" method.
2373 * Calling this method changes the HTTP output method to use the "POST"
2374 * method instead.
2375 *
2376 */
2377void
2378xmlRegisterHTTPPostCallbacks( void ) {
2379
2380 /* Register defaults if not done previously */
2381
2382 if ( xmlOutputCallbackInitialized == 0 )
2383 xmlRegisterDefaultOutputCallbacks( );
2384
2385 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
2386 xmlIOHTTPWrite, xmlIOHTTPClosePost);
2387 return;
2388}
2389#endif
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002390#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00002391
Owen Taylor3473f882001-02-23 17:55:21 +00002392/**
2393 * xmlAllocParserInputBuffer:
2394 * @enc: the charset encoding if known
2395 *
2396 * Create a buffered parser input for progressive parsing
2397 *
2398 * Returns the new parser input or NULL
2399 */
2400xmlParserInputBufferPtr
2401xmlAllocParserInputBuffer(xmlCharEncoding enc) {
2402 xmlParserInputBufferPtr ret;
2403
2404 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2405 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002406 xmlIOErrMemory("creating input buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00002407 return(NULL);
2408 }
2409 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002410 ret->buffer = xmlBufCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00002411 if (ret->buffer == NULL) {
2412 xmlFree(ret);
2413 return(NULL);
2414 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002415 xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_DOUBLEIT);
Owen Taylor3473f882001-02-23 17:55:21 +00002416 ret->encoder = xmlGetCharEncodingHandler(enc);
2417 if (ret->encoder != NULL)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002418 ret->raw = xmlBufCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00002419 else
2420 ret->raw = NULL;
2421 ret->readcallback = NULL;
2422 ret->closecallback = NULL;
2423 ret->context = NULL;
William M. Brackc07329e2003-09-08 01:57:30 +00002424 ret->compressed = -1;
Daniel Veillard36711902004-02-11 13:25:26 +00002425 ret->rawconsumed = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002426
2427 return(ret);
2428}
2429
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002430#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002431/**
2432 * xmlAllocOutputBuffer:
2433 * @encoder: the encoding converter or NULL
2434 *
2435 * Create a buffered parser output
2436 *
2437 * Returns the new parser output or NULL
2438 */
2439xmlOutputBufferPtr
2440xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
2441 xmlOutputBufferPtr ret;
2442
2443 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
2444 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002445 xmlIOErrMemory("creating output buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00002446 return(NULL);
2447 }
2448 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002449 ret->buffer = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00002450 if (ret->buffer == NULL) {
2451 xmlFree(ret);
2452 return(NULL);
2453 }
Daniel Veillarde83e93e2008-08-30 12:52:26 +00002454
Daniel Veillard43bc89c2009-03-23 19:32:04 +00002455 /* try to avoid a performance problem with Windows realloc() */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002456 if (xmlBufGetAllocationScheme(ret->buffer) == XML_BUFFER_ALLOC_EXACT)
2457 xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_DOUBLEIT);
Daniel Veillard43bc89c2009-03-23 19:32:04 +00002458
Daniel Veillardda3fee42008-09-01 13:08:57 +00002459 ret->encoder = encoder;
2460 if (encoder != NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002461 ret->conv = xmlBufCreateSize(4000);
Daniel Veillardda3fee42008-09-01 13:08:57 +00002462 if (ret->conv == NULL) {
2463 xmlFree(ret);
2464 return(NULL);
2465 }
2466
2467 /*
2468 * This call is designed to initiate the encoder state
2469 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002470 xmlCharEncOutput(ret, 1);
Daniel Veillardda3fee42008-09-01 13:08:57 +00002471 } else
2472 ret->conv = NULL;
2473 ret->writecallback = NULL;
2474 ret->closecallback = NULL;
2475 ret->context = NULL;
2476 ret->written = 0;
2477
2478 return(ret);
2479}
2480
2481/**
2482 * xmlAllocOutputBufferInternal:
2483 * @encoder: the encoding converter or NULL
2484 *
2485 * Create a buffered parser output
2486 *
2487 * Returns the new parser output or NULL
2488 */
2489xmlOutputBufferPtr
2490xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder) {
2491 xmlOutputBufferPtr ret;
2492
2493 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
2494 if (ret == NULL) {
2495 xmlIOErrMemory("creating output buffer");
2496 return(NULL);
2497 }
2498 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002499 ret->buffer = xmlBufCreate();
Daniel Veillardda3fee42008-09-01 13:08:57 +00002500 if (ret->buffer == NULL) {
2501 xmlFree(ret);
2502 return(NULL);
2503 }
2504
2505
Daniel Veillarde83e93e2008-08-30 12:52:26 +00002506 /*
2507 * For conversion buffers we use the special IO handling
2508 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002509 xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_IO);
Daniel Veillarde83e93e2008-08-30 12:52:26 +00002510
Owen Taylor3473f882001-02-23 17:55:21 +00002511 ret->encoder = encoder;
2512 if (encoder != NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002513 ret->conv = xmlBufCreateSize(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 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002522 xmlCharEncOutput(ret, 1);
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) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002546 xmlBufFree(in->raw);
Owen Taylor3473f882001-02-23 17:55:21 +00002547 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) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002556 xmlBufFree(in->buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00002557 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) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002588 xmlBufFree(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) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002595 xmlBufFree(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 Veillarde258ade2012-08-06 11:16:30 +08002925/**
2926 * xmlOutputBufferGetContent:
2927 * @out: an xmlOutputBufferPtr
2928 *
2929 * Gives a pointer to the data currently held in the output buffer
2930 *
2931 * Returns a pointer to the data or NULL in case of error
2932 */
2933const xmlChar *
2934xmlOutputBufferGetContent(xmlOutputBufferPtr out) {
2935 if ((out == NULL) || (out->buffer == NULL))
2936 return(NULL);
2937
2938 return(xmlBufContent(out->buffer));
2939}
2940
2941/**
2942 * xmlOutputBufferGetSize:
2943 * @out: an xmlOutputBufferPtr
2944 *
2945 * Gives the length of the data currently held in the output buffer
2946 *
2947 * Returns 0 in case or error or no data is held, the size otherwise
2948 */
2949size_t
2950xmlOutputBufferGetSize(xmlOutputBufferPtr out) {
2951 if ((out == NULL) || (out->buffer == NULL))
2952 return(0);
2953
2954 return(xmlBufUse(out->buffer));
2955}
2956
2957
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002958#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002959
2960/**
2961 * xmlParserInputBufferCreateFd:
2962 * @fd: a file descriptor number
2963 * @enc: the charset encoding if known
2964 *
2965 * Create a buffered parser input for the progressive parsing for the input
2966 * from a file descriptor
2967 *
2968 * Returns the new parser input or NULL
2969 */
2970xmlParserInputBufferPtr
2971xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
2972 xmlParserInputBufferPtr ret;
2973
2974 if (fd < 0) return(NULL);
2975
2976 ret = xmlAllocParserInputBuffer(enc);
2977 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002978 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002979 ret->readcallback = xmlFdRead;
2980 ret->closecallback = xmlFdClose;
2981 }
2982
2983 return(ret);
2984}
2985
2986/**
2987 * xmlParserInputBufferCreateMem:
2988 * @mem: the memory input
2989 * @size: the length of the memory block
2990 * @enc: the charset encoding if known
2991 *
2992 * Create a buffered parser input for the progressive parsing for the input
2993 * from a memory area.
2994 *
2995 * Returns the new parser input or NULL
2996 */
2997xmlParserInputBufferPtr
2998xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
2999 xmlParserInputBufferPtr ret;
William M. Bracka3215c72004-07-31 16:24:01 +00003000 int errcode;
Owen Taylor3473f882001-02-23 17:55:21 +00003001
3002 if (size <= 0) return(NULL);
3003 if (mem == NULL) return(NULL);
3004
3005 ret = xmlAllocParserInputBuffer(enc);
3006 if (ret != NULL) {
3007 ret->context = (void *) mem;
3008 ret->readcallback = (xmlInputReadCallback) xmlNop;
3009 ret->closecallback = NULL;
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003010 errcode = xmlBufAdd(ret->buffer, (const xmlChar *) mem, size);
William M. Bracka3215c72004-07-31 16:24:01 +00003011 if (errcode != 0) {
3012 xmlFree(ret);
3013 return(NULL);
3014 }
Owen Taylor3473f882001-02-23 17:55:21 +00003015 }
3016
3017 return(ret);
3018}
3019
3020/**
Daniel Veillard53350552003-09-18 13:35:51 +00003021 * xmlParserInputBufferCreateStatic:
3022 * @mem: the memory input
3023 * @size: the length of the memory block
3024 * @enc: the charset encoding if known
3025 *
3026 * Create a buffered parser input for the progressive parsing for the input
3027 * from an immutable memory area. This will not copy the memory area to
3028 * the buffer, but the memory is expected to be available until the end of
3029 * the parsing, this is useful for example when using mmap'ed file.
3030 *
3031 * Returns the new parser input or NULL
3032 */
3033xmlParserInputBufferPtr
3034xmlParserInputBufferCreateStatic(const char *mem, int size,
3035 xmlCharEncoding enc) {
3036 xmlParserInputBufferPtr ret;
3037
3038 if (size <= 0) return(NULL);
3039 if (mem == NULL) return(NULL);
3040
3041 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
3042 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003043 xmlIOErrMemory("creating input buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00003044 return(NULL);
3045 }
3046 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003047 ret->buffer = xmlBufCreateStatic((void *)mem, (size_t) size);
Daniel Veillard53350552003-09-18 13:35:51 +00003048 if (ret->buffer == NULL) {
3049 xmlFree(ret);
3050 return(NULL);
3051 }
3052 ret->encoder = xmlGetCharEncodingHandler(enc);
3053 if (ret->encoder != NULL)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003054 ret->raw = xmlBufCreateSize(2 * xmlDefaultBufferSize);
Daniel Veillard53350552003-09-18 13:35:51 +00003055 else
3056 ret->raw = NULL;
3057 ret->compressed = -1;
3058 ret->context = (void *) mem;
3059 ret->readcallback = NULL;
3060 ret->closecallback = NULL;
3061
3062 return(ret);
3063}
3064
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003065#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard53350552003-09-18 13:35:51 +00003066/**
Owen Taylor3473f882001-02-23 17:55:21 +00003067 * xmlOutputBufferCreateFd:
3068 * @fd: a file descriptor number
3069 * @encoder: the encoding converter or NULL
3070 *
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003071 * Create a buffered output for the progressive saving
Owen Taylor3473f882001-02-23 17:55:21 +00003072 * to a file descriptor
3073 *
3074 * Returns the new parser output or NULL
3075 */
3076xmlOutputBufferPtr
3077xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
3078 xmlOutputBufferPtr ret;
3079
3080 if (fd < 0) return(NULL);
3081
Daniel Veillardda3fee42008-09-01 13:08:57 +00003082 ret = xmlAllocOutputBufferInternal(encoder);
Owen Taylor3473f882001-02-23 17:55:21 +00003083 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00003084 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00003085 ret->writecallback = xmlFdWrite;
Daniel Veillard7db38712002-02-07 16:39:11 +00003086 ret->closecallback = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003087 }
3088
3089 return(ret);
3090}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003091#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003092
3093/**
3094 * xmlParserInputBufferCreateIO:
3095 * @ioread: an I/O read function
3096 * @ioclose: an I/O close function
3097 * @ioctx: an I/O handler
3098 * @enc: the charset encoding if known
3099 *
3100 * Create a buffered parser input for the progressive parsing for the input
3101 * from an I/O handler
3102 *
3103 * Returns the new parser input or NULL
3104 */
3105xmlParserInputBufferPtr
3106xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
3107 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
3108 xmlParserInputBufferPtr ret;
3109
3110 if (ioread == NULL) return(NULL);
3111
3112 ret = xmlAllocParserInputBuffer(enc);
3113 if (ret != NULL) {
3114 ret->context = (void *) ioctx;
3115 ret->readcallback = ioread;
3116 ret->closecallback = ioclose;
3117 }
3118
3119 return(ret);
3120}
3121
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003122#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003123/**
3124 * xmlOutputBufferCreateIO:
3125 * @iowrite: an I/O write function
3126 * @ioclose: an I/O close function
3127 * @ioctx: an I/O handler
Daniel Veillard9d06d302002-01-22 18:15:52 +00003128 * @encoder: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00003129 *
3130 * Create a buffered output for the progressive saving
3131 * to an I/O handler
3132 *
3133 * Returns the new parser output or NULL
3134 */
3135xmlOutputBufferPtr
3136xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
3137 xmlOutputCloseCallback ioclose, void *ioctx,
3138 xmlCharEncodingHandlerPtr encoder) {
3139 xmlOutputBufferPtr ret;
3140
3141 if (iowrite == NULL) return(NULL);
3142
Daniel Veillardda3fee42008-09-01 13:08:57 +00003143 ret = xmlAllocOutputBufferInternal(encoder);
Owen Taylor3473f882001-02-23 17:55:21 +00003144 if (ret != NULL) {
3145 ret->context = (void *) ioctx;
3146 ret->writecallback = iowrite;
3147 ret->closecallback = ioclose;
3148 }
3149
3150 return(ret);
3151}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003152#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003153
3154/**
Daniel Veillard1b243b42004-06-08 10:16:42 +00003155 * xmlParserInputBufferCreateFilenameDefault:
3156 * @func: function pointer to the new ParserInputBufferCreateFilenameFunc
3157 *
3158 * Registers a callback for URI input file handling
3159 *
3160 * Returns the old value of the registration function
3161 */
3162xmlParserInputBufferCreateFilenameFunc
3163xmlParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func)
3164{
3165 xmlParserInputBufferCreateFilenameFunc old = xmlParserInputBufferCreateFilenameValue;
3166 if (old == NULL) {
3167 old = __xmlParserInputBufferCreateFilename;
3168 }
3169
3170 xmlParserInputBufferCreateFilenameValue = func;
3171 return(old);
3172}
3173
3174/**
3175 * xmlOutputBufferCreateFilenameDefault:
3176 * @func: function pointer to the new OutputBufferCreateFilenameFunc
3177 *
3178 * Registers a callback for URI output file handling
3179 *
3180 * Returns the old value of the registration function
3181 */
3182xmlOutputBufferCreateFilenameFunc
3183xmlOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func)
3184{
3185 xmlOutputBufferCreateFilenameFunc old = xmlOutputBufferCreateFilenameValue;
3186#ifdef LIBXML_OUTPUT_ENABLED
3187 if (old == NULL) {
3188 old = __xmlOutputBufferCreateFilename;
3189 }
3190#endif
3191 xmlOutputBufferCreateFilenameValue = func;
3192 return(old);
3193}
3194
3195/**
Owen Taylor3473f882001-02-23 17:55:21 +00003196 * xmlParserInputBufferPush:
3197 * @in: a buffered parser input
3198 * @len: the size in bytes of the array.
3199 * @buf: an char array
3200 *
3201 * Push the content of the arry in the input buffer
3202 * This routine handle the I18N transcoding to internal UTF-8
3203 * This is used when operating the parser in progressive (push) mode.
3204 *
3205 * Returns the number of chars read and stored in the buffer, or -1
3206 * in case of error.
3207 */
3208int
3209xmlParserInputBufferPush(xmlParserInputBufferPtr in,
3210 int len, const char *buf) {
3211 int nbchars = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00003212 int ret;
Owen Taylor3473f882001-02-23 17:55:21 +00003213
3214 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003215 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003216 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00003217 unsigned int use;
3218
Owen Taylor3473f882001-02-23 17:55:21 +00003219 /*
3220 * Store the data in the incoming raw buffer
3221 */
3222 if (in->raw == NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003223 in->raw = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00003224 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003225 ret = xmlBufAdd(in->raw, (const xmlChar *) buf, len);
William M. Bracka3215c72004-07-31 16:24:01 +00003226 if (ret != 0)
3227 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003228
3229 /*
3230 * convert as much as possible to the parser reading buffer.
3231 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003232 use = xmlBufUse(in->raw);
3233 nbchars = xmlCharEncInput(in);
Owen Taylor3473f882001-02-23 17:55:21 +00003234 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003235 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003236 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003237 return(-1);
3238 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003239 in->rawconsumed += (use - xmlBufUse(in->raw));
Owen Taylor3473f882001-02-23 17:55:21 +00003240 } else {
3241 nbchars = len;
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003242 ret = xmlBufAdd(in->buffer, (xmlChar *) buf, nbchars);
William M. Bracka3215c72004-07-31 16:24:01 +00003243 if (ret != 0)
3244 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003245 }
3246#ifdef DEBUG_INPUT
3247 xmlGenericError(xmlGenericErrorContext,
3248 "I/O: pushed %d chars, buffer %d/%d\n",
3249 nbchars, in->buffer->use, in->buffer->size);
3250#endif
3251 return(nbchars);
3252}
3253
3254/**
Daniel Veillardddffd2a2002-03-05 20:28:20 +00003255 * endOfInput:
3256 *
3257 * When reading from an Input channel indicated end of file or error
3258 * don't reread from it again.
3259 */
3260static int
3261endOfInput (void * context ATTRIBUTE_UNUSED,
3262 char * buffer ATTRIBUTE_UNUSED,
3263 int len ATTRIBUTE_UNUSED) {
3264 return(0);
3265}
3266
3267/**
Owen Taylor3473f882001-02-23 17:55:21 +00003268 * xmlParserInputBufferGrow:
3269 * @in: a buffered parser input
3270 * @len: indicative value of the amount of chars to read
3271 *
3272 * Grow up the content of the input buffer, the old data are preserved
3273 * This routine handle the I18N transcoding to internal UTF-8
3274 * This routine is used when operating the parser in normal (pull) mode
3275 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003276 * TODO: one should be able to remove one extra copy by copying directly
Owen Taylor3473f882001-02-23 17:55:21 +00003277 * onto in->buffer or in->raw
3278 *
3279 * Returns the number of chars read and stored in the buffer, or -1
3280 * in case of error.
3281 */
3282int
3283xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
3284 char *buffer = NULL;
3285 int res = 0;
3286 int nbchars = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003287
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003288 if ((in == NULL) || (in->error)) return(-1);
Daniel Veillard6155d8a2003-08-19 15:01:28 +00003289 if ((len <= MINLEN) && (len != 4))
Owen Taylor3473f882001-02-23 17:55:21 +00003290 len = MINLEN;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00003291
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003292 if (xmlBufAvail(in->buffer) <= 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003293 xmlIOErr(XML_IO_BUFFER_FULL, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003294 in->error = XML_IO_BUFFER_FULL;
William M. Bracka3215c72004-07-31 16:24:01 +00003295 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003296 }
Owen Taylor3473f882001-02-23 17:55:21 +00003297
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003298 if (xmlBufGrow(in->buffer, len + 1) < 0) {
3299 xmlIOErrMemory("growing input buffer");
3300 in->error = XML_ERR_NO_MEMORY;
3301 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003302 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003303 buffer = (char *)xmlBufEnd(in->buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00003304
3305 /*
3306 * Call the read method for this I/O type.
3307 */
3308 if (in->readcallback != NULL) {
3309 res = in->readcallback(in->context, &buffer[0], len);
Daniel Veillardddffd2a2002-03-05 20:28:20 +00003310 if (res <= 0)
3311 in->readcallback = endOfInput;
Owen Taylor3473f882001-02-23 17:55:21 +00003312 } else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003313 xmlIOErr(XML_IO_NO_INPUT, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003314 in->error = XML_IO_NO_INPUT;
Owen Taylor3473f882001-02-23 17:55:21 +00003315 return(-1);
3316 }
3317 if (res < 0) {
Owen Taylor3473f882001-02-23 17:55:21 +00003318 return(-1);
3319 }
3320 len = res;
3321 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00003322 unsigned int use;
3323
Owen Taylor3473f882001-02-23 17:55:21 +00003324 /*
3325 * Store the data in the incoming raw buffer
3326 */
3327 if (in->raw == NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003328 in->raw = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00003329 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003330 res = xmlBufAdd(in->raw, (const xmlChar *) buffer, len);
William M. Bracka3215c72004-07-31 16:24:01 +00003331 if (res != 0)
3332 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003333
3334 /*
3335 * convert as much as possible to the parser reading buffer.
3336 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003337 use = xmlBufUse(in->raw);
3338 nbchars = xmlCharEncInput(in);
Owen Taylor3473f882001-02-23 17:55:21 +00003339 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003340 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003341 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003342 return(-1);
3343 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003344 in->rawconsumed += (use - xmlBufUse(in->raw));
Owen Taylor3473f882001-02-23 17:55:21 +00003345 } else {
3346 nbchars = len;
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003347 xmlBufAddLen(in->buffer, nbchars);
Owen Taylor3473f882001-02-23 17:55:21 +00003348 }
3349#ifdef DEBUG_INPUT
3350 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003351 "I/O: read %d chars, buffer %d\n",
3352 nbchars, xmlBufUse(in->buffer));
Owen Taylor3473f882001-02-23 17:55:21 +00003353#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003354 return(nbchars);
3355}
3356
3357/**
3358 * xmlParserInputBufferRead:
3359 * @in: a buffered parser input
3360 * @len: indicative value of the amount of chars to read
3361 *
3362 * Refresh the content of the input buffer, the old data are considered
3363 * consumed
3364 * This routine handle the I18N transcoding to internal UTF-8
3365 *
3366 * Returns the number of chars read and stored in the buffer, or -1
3367 * in case of error.
3368 */
3369int
3370xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003371 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003372 if (in->readcallback != NULL)
3373 return(xmlParserInputBufferGrow(in, len));
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003374 else if (xmlBufGetAllocationScheme(in->buffer) == XML_BUFFER_ALLOC_IMMUTABLE)
Daniel Veillard53350552003-09-18 13:35:51 +00003375 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003376 else
3377 return(-1);
3378}
3379
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003380#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003381/**
3382 * xmlOutputBufferWrite:
3383 * @out: a buffered parser output
3384 * @len: the size in bytes of the array.
3385 * @buf: an char array
3386 *
3387 * Write the content of the array in the output I/O buffer
3388 * This routine handle the I18N transcoding from internal UTF-8
3389 * The buffer is lossless, i.e. will store in case of partial
3390 * or delayed writes.
3391 *
3392 * Returns the number of chars immediately written, or -1
3393 * in case of error.
3394 */
3395int
3396xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
3397 int nbchars = 0; /* number of chars to output to I/O */
3398 int ret; /* return from function call */
3399 int written = 0; /* number of char written to I/O so far */
3400 int chunk; /* number of byte curreent processed from buf */
3401
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003402 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003403 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003404 if (out->error) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003405
3406 do {
3407 chunk = len;
3408 if (chunk > 4 * MINLEN)
3409 chunk = 4 * MINLEN;
3410
3411 /*
3412 * first handle encoding stuff.
3413 */
3414 if (out->encoder != NULL) {
3415 /*
3416 * Store the data in the incoming raw buffer
3417 */
3418 if (out->conv == NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003419 out->conv = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00003420 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003421 ret = xmlBufAdd(out->buffer, (const xmlChar *) buf, chunk);
William M. Bracka3215c72004-07-31 16:24:01 +00003422 if (ret != 0)
3423 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003424
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003425 if ((xmlBufUse(out->buffer) < MINLEN) && (chunk == len))
Owen Taylor3473f882001-02-23 17:55:21 +00003426 goto done;
3427
3428 /*
3429 * convert as much as possible to the parser reading buffer.
3430 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003431 ret = xmlCharEncOutput(out, 0);
Daniel Veillard809faa52003-02-10 15:43:53 +00003432 if ((ret < 0) && (ret != -3)) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003433 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003434 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003435 return(-1);
3436 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003437 nbchars = xmlBufUse(out->conv);
Owen Taylor3473f882001-02-23 17:55:21 +00003438 } else {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003439 ret = xmlBufAdd(out->buffer, (const xmlChar *) buf, chunk);
William M. Bracka3215c72004-07-31 16:24:01 +00003440 if (ret != 0)
3441 return(-1);
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003442 nbchars = xmlBufUse(out->buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00003443 }
3444 buf += chunk;
3445 len -= chunk;
3446
3447 if ((nbchars < MINLEN) && (len <= 0))
3448 goto done;
3449
3450 if (out->writecallback) {
3451 /*
3452 * second write the stuff to the I/O channel
3453 */
3454 if (out->encoder != NULL) {
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003455 ret = out->writecallback(out->context,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003456 (const char *)xmlBufContent(out->conv), nbchars);
Owen Taylor3473f882001-02-23 17:55:21 +00003457 if (ret >= 0)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003458 xmlBufShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003459 } else {
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003460 ret = out->writecallback(out->context,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003461 (const char *)xmlBufContent(out->buffer), nbchars);
Owen Taylor3473f882001-02-23 17:55:21 +00003462 if (ret >= 0)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003463 xmlBufShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003464 }
3465 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003466 xmlIOErr(XML_IO_WRITE, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003467 out->error = XML_IO_WRITE;
Owen Taylor3473f882001-02-23 17:55:21 +00003468 return(ret);
3469 }
3470 out->written += ret;
3471 }
3472 written += nbchars;
3473 } while (len > 0);
3474
3475done:
3476#ifdef DEBUG_INPUT
3477 xmlGenericError(xmlGenericErrorContext,
3478 "I/O: wrote %d chars\n", written);
3479#endif
3480 return(written);
3481}
3482
3483/**
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003484 * xmlEscapeContent:
3485 * @out: a pointer to an array of bytes to store the result
3486 * @outlen: the length of @out
3487 * @in: a pointer to an array of unescaped UTF-8 bytes
3488 * @inlen: the length of @in
3489 *
3490 * Take a block of UTF-8 chars in and escape them.
3491 * Returns 0 if success, or -1 otherwise
3492 * The value of @inlen after return is the number of octets consumed
3493 * if the return value is positive, else unpredictable.
3494 * The value of @outlen after return is the number of octets consumed.
3495 */
3496static int
3497xmlEscapeContent(unsigned char* out, int *outlen,
3498 const xmlChar* in, int *inlen) {
3499 unsigned char* outstart = out;
3500 const unsigned char* base = in;
3501 unsigned char* outend = out + *outlen;
3502 const unsigned char* inend;
3503
3504 inend = in + (*inlen);
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003505
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003506 while ((in < inend) && (out < outend)) {
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003507 if (*in == '<') {
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003508 if (outend - out < 4) break;
3509 *out++ = '&';
3510 *out++ = 'l';
3511 *out++ = 't';
3512 *out++ = ';';
3513 } else if (*in == '>') {
3514 if (outend - out < 4) break;
3515 *out++ = '&';
3516 *out++ = 'g';
3517 *out++ = 't';
3518 *out++ = ';';
3519 } else if (*in == '&') {
3520 if (outend - out < 5) break;
3521 *out++ = '&';
3522 *out++ = 'a';
3523 *out++ = 'm';
3524 *out++ = 'p';
3525 *out++ = ';';
3526 } else if (*in == '\r') {
3527 if (outend - out < 5) break;
3528 *out++ = '&';
3529 *out++ = '#';
3530 *out++ = '1';
3531 *out++ = '3';
3532 *out++ = ';';
3533 } else {
3534 *out++ = (unsigned char) *in;
3535 }
3536 ++in;
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003537 }
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003538 *outlen = out - outstart;
3539 *inlen = in - base;
3540 return(0);
3541}
3542
3543/**
3544 * xmlOutputBufferWriteEscape:
3545 * @out: a buffered parser output
3546 * @str: a zero terminated UTF-8 string
Daniel Veillardee8960b2004-05-14 03:25:14 +00003547 * @escaping: an optional escaping function (or NULL)
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003548 *
3549 * Write the content of the string in the output I/O buffer
3550 * This routine escapes the caracters and then handle the I18N
3551 * transcoding from internal UTF-8
3552 * The buffer is lossless, i.e. will store in case of partial
3553 * or delayed writes.
3554 *
3555 * Returns the number of chars immediately written, or -1
3556 * in case of error.
3557 */
3558int
Daniel Veillardee8960b2004-05-14 03:25:14 +00003559xmlOutputBufferWriteEscape(xmlOutputBufferPtr out, const xmlChar *str,
3560 xmlCharEncodingOutputFunc escaping) {
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003561 int nbchars = 0; /* number of chars to output to I/O */
3562 int ret; /* return from function call */
3563 int written = 0; /* number of char written to I/O so far */
Daniel Veillard71b95632004-08-31 12:15:36 +00003564 int oldwritten=0;/* loop guard */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003565 int chunk; /* number of byte currently processed from str */
3566 int len; /* number of bytes in str */
3567 int cons; /* byte from str consumed */
3568
Daniel Veillardce244ad2004-11-05 10:03:46 +00003569 if ((out == NULL) || (out->error) || (str == NULL) ||
3570 (out->buffer == NULL) ||
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003571 (xmlBufGetAllocationScheme(out->buffer) == XML_BUFFER_ALLOC_IMMUTABLE))
3572 return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003573 len = strlen((const char *)str);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003574 if (len < 0) return(0);
3575 if (out->error) return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003576 if (escaping == NULL) escaping = xmlEscapeContent;
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003577
3578 do {
Daniel Veillard71b95632004-08-31 12:15:36 +00003579 oldwritten = written;
3580
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003581 /*
3582 * how many bytes to consume and how many bytes to store.
3583 */
3584 cons = len;
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003585 chunk = xmlBufAvail(out->buffer) - 1;
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003586
Daniel Veillardc4ba8a42008-02-16 10:08:14 +00003587 /*
3588 * make sure we have enough room to save first, if this is
3589 * not the case force a flush, but make sure we stay in the loop
3590 */
3591 if (chunk < 40) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003592 if (xmlBufGrow(out->buffer, 100) < 0)
Daniel Veillarde83e93e2008-08-30 12:52:26 +00003593 return(-1);
3594 oldwritten = -1;
3595 continue;
Daniel Veillardc4ba8a42008-02-16 10:08:14 +00003596 }
3597
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003598 /*
3599 * first handle encoding stuff.
3600 */
3601 if (out->encoder != NULL) {
3602 /*
3603 * Store the data in the incoming raw buffer
3604 */
3605 if (out->conv == NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003606 out->conv = xmlBufCreate();
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003607 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003608 ret = escaping(xmlBufEnd(out->buffer) ,
Daniel Veillardee8960b2004-05-14 03:25:14 +00003609 &chunk, str, &cons);
William M. Brack66e40b12004-11-26 15:45:19 +00003610 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003611 return(-1);
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003612 xmlBufAddLen(out->buffer, chunk);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003613
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003614 if ((xmlBufUse(out->buffer) < MINLEN) && (cons == len))
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003615 goto done;
3616
3617 /*
3618 * convert as much as possible to the output buffer.
3619 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003620 ret = xmlCharEncOutput(out, 0);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003621 if ((ret < 0) && (ret != -3)) {
3622 xmlIOErr(XML_IO_ENCODER, NULL);
3623 out->error = XML_IO_ENCODER;
3624 return(-1);
3625 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003626 nbchars = xmlBufUse(out->conv);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003627 } else {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003628 ret = escaping(xmlBufEnd(out->buffer), &chunk, str, &cons);
William M. Brack66e40b12004-11-26 15:45:19 +00003629 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003630 return(-1);
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003631 xmlBufAddLen(out->buffer, chunk);
3632 nbchars = xmlBufUse(out->buffer);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003633 }
3634 str += cons;
3635 len -= cons;
3636
3637 if ((nbchars < MINLEN) && (len <= 0))
3638 goto done;
3639
3640 if (out->writecallback) {
3641 /*
3642 * second write the stuff to the I/O channel
3643 */
3644 if (out->encoder != NULL) {
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003645 ret = out->writecallback(out->context,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003646 (const char *)xmlBufContent(out->conv), nbchars);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003647 if (ret >= 0)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003648 xmlBufShrink(out->conv, ret);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003649 } else {
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003650 ret = out->writecallback(out->context,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003651 (const char *)xmlBufContent(out->buffer), nbchars);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003652 if (ret >= 0)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003653 xmlBufShrink(out->buffer, ret);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003654 }
3655 if (ret < 0) {
3656 xmlIOErr(XML_IO_WRITE, NULL);
3657 out->error = XML_IO_WRITE;
3658 return(ret);
3659 }
3660 out->written += ret;
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003661 } else if (xmlBufAvail(out->buffer) < MINLEN) {
3662 xmlBufGrow(out->buffer, MINLEN);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003663 }
3664 written += nbchars;
Daniel Veillard71b95632004-08-31 12:15:36 +00003665 } while ((len > 0) && (oldwritten != written));
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003666
3667done:
3668#ifdef DEBUG_INPUT
3669 xmlGenericError(xmlGenericErrorContext,
3670 "I/O: wrote %d chars\n", written);
3671#endif
3672 return(written);
3673}
3674
3675/**
Owen Taylor3473f882001-02-23 17:55:21 +00003676 * xmlOutputBufferWriteString:
3677 * @out: a buffered parser output
3678 * @str: a zero terminated C string
3679 *
3680 * Write the content of the string in the output I/O buffer
3681 * This routine handle the I18N transcoding from internal UTF-8
3682 * The buffer is lossless, i.e. will store in case of partial
3683 * or delayed writes.
3684 *
3685 * Returns the number of chars immediately written, or -1
3686 * in case of error.
3687 */
3688int
3689xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
3690 int len;
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003691
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003692 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003693 if (str == NULL)
3694 return(-1);
3695 len = strlen(str);
3696
3697 if (len > 0)
3698 return(xmlOutputBufferWrite(out, len, str));
3699 return(len);
3700}
3701
3702/**
3703 * xmlOutputBufferFlush:
3704 * @out: a buffered output
3705 *
3706 * flushes the output I/O channel
3707 *
3708 * Returns the number of byte written or -1 in case of error.
3709 */
3710int
3711xmlOutputBufferFlush(xmlOutputBufferPtr out) {
3712 int nbchars = 0, ret = 0;
3713
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003714 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003715 /*
3716 * first handle encoding stuff.
3717 */
3718 if ((out->conv != NULL) && (out->encoder != NULL)) {
3719 /*
3720 * convert as much as possible to the parser reading buffer.
3721 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003722 nbchars = xmlCharEncOutput(out, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00003723 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003724 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003725 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003726 return(-1);
3727 }
3728 }
3729
3730 /*
3731 * second flush the stuff to the I/O channel
3732 */
3733 if ((out->conv != NULL) && (out->encoder != NULL) &&
3734 (out->writecallback != NULL)) {
3735 ret = out->writecallback(out->context,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003736 (const char *)xmlBufContent(out->conv),
3737 xmlBufUse(out->conv));
Owen Taylor3473f882001-02-23 17:55:21 +00003738 if (ret >= 0)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003739 xmlBufShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003740 } else if (out->writecallback != NULL) {
3741 ret = out->writecallback(out->context,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003742 (const char *)xmlBufContent(out->buffer),
3743 xmlBufUse(out->buffer));
Owen Taylor3473f882001-02-23 17:55:21 +00003744 if (ret >= 0)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003745 xmlBufShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003746 }
3747 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003748 xmlIOErr(XML_IO_FLUSH, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003749 out->error = XML_IO_FLUSH;
Owen Taylor3473f882001-02-23 17:55:21 +00003750 return(ret);
3751 }
3752 out->written += ret;
3753
3754#ifdef DEBUG_INPUT
3755 xmlGenericError(xmlGenericErrorContext,
3756 "I/O: flushed %d chars\n", ret);
3757#endif
3758 return(ret);
3759}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003760#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003761
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003762/**
Owen Taylor3473f882001-02-23 17:55:21 +00003763 * xmlParserGetDirectory:
3764 * @filename: the path to a file
3765 *
3766 * lookup the directory for that file
3767 *
3768 * Returns a new allocated string containing the directory, or NULL.
3769 */
3770char *
3771xmlParserGetDirectory(const char *filename) {
3772 char *ret = NULL;
3773 char dir[1024];
3774 char *cur;
Owen Taylor3473f882001-02-23 17:55:21 +00003775
Igor Zlatkovic9181cc02002-09-29 17:51:06 +00003776#ifdef _WIN32_WCE /* easy way by now ... wince does not have dirs! */
3777 return NULL;
3778#endif
3779
Owen Taylor3473f882001-02-23 17:55:21 +00003780 if (xmlInputCallbackInitialized == 0)
3781 xmlRegisterDefaultInputCallbacks();
3782
3783 if (filename == NULL) return(NULL);
Rob Richardsf779da32007-08-14 09:41:21 +00003784
Daniel Veillard3c5ed912002-01-08 10:36:16 +00003785#if defined(WIN32) && !defined(__CYGWIN__)
Rob Richardsf779da32007-08-14 09:41:21 +00003786# define IS_XMLPGD_SEP(ch) ((ch=='/')||(ch=='\\'))
3787#else
3788# define IS_XMLPGD_SEP(ch) (ch=='/')
Owen Taylor3473f882001-02-23 17:55:21 +00003789#endif
3790
3791 strncpy(dir, filename, 1023);
3792 dir[1023] = 0;
3793 cur = &dir[strlen(dir)];
3794 while (cur > dir) {
Rob Richardsf779da32007-08-14 09:41:21 +00003795 if (IS_XMLPGD_SEP(*cur)) break;
Owen Taylor3473f882001-02-23 17:55:21 +00003796 cur --;
3797 }
Rob Richardsf779da32007-08-14 09:41:21 +00003798 if (IS_XMLPGD_SEP(*cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003799 if (cur == dir) dir[1] = 0;
3800 else *cur = 0;
3801 ret = xmlMemStrdup(dir);
3802 } else {
3803 if (getcwd(dir, 1024) != NULL) {
3804 dir[1023] = 0;
3805 ret = xmlMemStrdup(dir);
3806 }
3807 }
3808 return(ret);
Rob Richardsf779da32007-08-14 09:41:21 +00003809#undef IS_XMLPGD_SEP
Owen Taylor3473f882001-02-23 17:55:21 +00003810}
3811
3812/****************************************************************
3813 * *
3814 * External entities loading *
3815 * *
3816 ****************************************************************/
3817
Daniel Veillarda840b692003-10-19 13:35:37 +00003818/**
3819 * xmlCheckHTTPInput:
3820 * @ctxt: an XML parser context
3821 * @ret: an XML parser input
3822 *
3823 * Check an input in case it was created from an HTTP stream, in that
3824 * case it will handle encoding and update of the base URL in case of
3825 * redirection. It also checks for HTTP errors in which case the input
3826 * is cleanly freed up and an appropriate error is raised in context
3827 *
3828 * Returns the input or NULL in case of HTTP error.
3829 */
3830xmlParserInputPtr
3831xmlCheckHTTPInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr ret) {
3832#ifdef LIBXML_HTTP_ENABLED
3833 if ((ret != NULL) && (ret->buf != NULL) &&
3834 (ret->buf->readcallback == xmlIOHTTPRead) &&
3835 (ret->buf->context != NULL)) {
3836 const char *encoding;
3837 const char *redir;
3838 const char *mime;
3839 int code;
3840
3841 code = xmlNanoHTTPReturnCode(ret->buf->context);
3842 if (code >= 400) {
3843 /* fatal error */
3844 if (ret->filename != NULL)
Daniel Veillarde8039df2003-10-27 11:25:13 +00003845 __xmlLoaderErr(ctxt, "failed to load HTTP resource \"%s\"\n",
Daniel Veillarda840b692003-10-19 13:35:37 +00003846 (const char *) ret->filename);
3847 else
Daniel Veillarde8039df2003-10-27 11:25:13 +00003848 __xmlLoaderErr(ctxt, "failed to load HTTP resource\n", NULL);
Daniel Veillarda840b692003-10-19 13:35:37 +00003849 xmlFreeInputStream(ret);
3850 ret = NULL;
3851 } else {
3852
3853 mime = xmlNanoHTTPMimeType(ret->buf->context);
3854 if ((xmlStrstr(BAD_CAST mime, BAD_CAST "/xml")) ||
3855 (xmlStrstr(BAD_CAST mime, BAD_CAST "+xml"))) {
3856 encoding = xmlNanoHTTPEncoding(ret->buf->context);
3857 if (encoding != NULL) {
3858 xmlCharEncodingHandlerPtr handler;
3859
3860 handler = xmlFindCharEncodingHandler(encoding);
3861 if (handler != NULL) {
3862 xmlSwitchInputEncoding(ctxt, ret, handler);
3863 } else {
3864 __xmlErrEncoding(ctxt, XML_ERR_UNKNOWN_ENCODING,
3865 "Unknown encoding %s",
3866 BAD_CAST encoding, NULL);
3867 }
3868 if (ret->encoding == NULL)
3869 ret->encoding = xmlStrdup(BAD_CAST encoding);
3870 }
3871#if 0
3872 } else if (xmlStrstr(BAD_CAST mime, BAD_CAST "html")) {
3873#endif
3874 }
3875 redir = xmlNanoHTTPRedir(ret->buf->context);
3876 if (redir != NULL) {
3877 if (ret->filename != NULL)
3878 xmlFree((xmlChar *) ret->filename);
3879 if (ret->directory != NULL) {
3880 xmlFree((xmlChar *) ret->directory);
3881 ret->directory = NULL;
3882 }
3883 ret->filename =
3884 (char *) xmlStrdup((const xmlChar *) redir);
3885 }
3886 }
3887 }
3888#endif
3889 return(ret);
3890}
3891
Daniel Veillarde5a3f372006-08-30 13:11:36 +00003892static int xmlNoNetExists(const char *URL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003893 const char *path;
3894
3895 if (URL == NULL)
3896 return(0);
3897
Daniel Veillardf4862f02002-09-10 11:13:43 +00003898 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003899#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00003900 path = &URL[17];
3901#else
Daniel Veillard6990bf32001-08-23 21:17:48 +00003902 path = &URL[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00003903#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003904 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003905#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard6990bf32001-08-23 21:17:48 +00003906 path = &URL[8];
3907#else
3908 path = &URL[7];
3909#endif
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003910 } else
Daniel Veillard6990bf32001-08-23 21:17:48 +00003911 path = URL;
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003912
Daniel Veillarde5a3f372006-08-30 13:11:36 +00003913 return xmlCheckFilename(path);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003914}
Daniel Veillard6990bf32001-08-23 21:17:48 +00003915
Daniel Veillardad4e2962006-09-21 08:36:38 +00003916#ifdef LIBXML_CATALOG_ENABLED
3917
3918/**
3919 * xmlResolveResourceFromCatalog:
3920 * @URL: the URL for the entity to load
3921 * @ID: the System ID for the entity to load
3922 * @ctxt: the context in which the entity is called or NULL
3923 *
3924 * Resolves the URL and ID against the appropriate catalog.
3925 * This function is used by xmlDefaultExternalEntityLoader and
3926 * xmlNoNetExternalEntityLoader.
3927 *
3928 * Returns a new allocated URL, or NULL.
3929 */
William M. Brack38d452a2007-05-22 16:00:06 +00003930static xmlChar *
Daniel Veillardad4e2962006-09-21 08:36:38 +00003931xmlResolveResourceFromCatalog(const char *URL, const char *ID,
3932 xmlParserCtxtPtr ctxt) {
3933 xmlChar *resource = NULL;
3934 xmlCatalogAllow pref;
3935
3936 /*
3937 * If the resource doesn't exists as a file,
3938 * try to load it from the resource pointed in the catalogs
3939 */
3940 pref = xmlCatalogGetDefaults();
3941
3942 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
3943 /*
3944 * Do a local lookup
3945 */
3946 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
3947 ((pref == XML_CATA_ALLOW_ALL) ||
3948 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3949 resource = xmlCatalogLocalResolve(ctxt->catalogs,
3950 (const xmlChar *)ID,
3951 (const xmlChar *)URL);
3952 }
3953 /*
3954 * Try a global lookup
3955 */
3956 if ((resource == NULL) &&
3957 ((pref == XML_CATA_ALLOW_ALL) ||
3958 (pref == XML_CATA_ALLOW_GLOBAL))) {
3959 resource = xmlCatalogResolve((const xmlChar *)ID,
3960 (const xmlChar *)URL);
3961 }
3962 if ((resource == NULL) && (URL != NULL))
3963 resource = xmlStrdup((const xmlChar *) URL);
3964
3965 /*
3966 * TODO: do an URI lookup on the reference
3967 */
3968 if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
3969 xmlChar *tmp = NULL;
3970
3971 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
3972 ((pref == XML_CATA_ALLOW_ALL) ||
3973 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3974 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
3975 }
3976 if ((tmp == NULL) &&
3977 ((pref == XML_CATA_ALLOW_ALL) ||
3978 (pref == XML_CATA_ALLOW_GLOBAL))) {
3979 tmp = xmlCatalogResolveURI(resource);
3980 }
3981
3982 if (tmp != NULL) {
3983 xmlFree(resource);
3984 resource = tmp;
3985 }
3986 }
3987 }
3988
3989 return resource;
3990}
3991
3992#endif
3993
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003994/**
Owen Taylor3473f882001-02-23 17:55:21 +00003995 * xmlDefaultExternalEntityLoader:
3996 * @URL: the URL for the entity to load
3997 * @ID: the System ID for the entity to load
3998 * @ctxt: the context in which the entity is called or NULL
3999 *
4000 * By default we don't load external entitites, yet.
4001 *
4002 * Returns a new allocated xmlParserInputPtr, or NULL.
4003 */
Daniel Veillarda840b692003-10-19 13:35:37 +00004004static xmlParserInputPtr
Owen Taylor3473f882001-02-23 17:55:21 +00004005xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
Daniel Veillarda840b692003-10-19 13:35:37 +00004006 xmlParserCtxtPtr ctxt)
4007{
Owen Taylor3473f882001-02-23 17:55:21 +00004008 xmlParserInputPtr ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00004009 xmlChar *resource = NULL;
Daniel Veillarda840b692003-10-19 13:35:37 +00004010
Owen Taylor3473f882001-02-23 17:55:21 +00004011#ifdef DEBUG_EXTERNAL_ENTITIES
4012 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda840b692003-10-19 13:35:37 +00004013 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00004014#endif
Daniel Veillard61b93382003-11-03 14:28:31 +00004015 if ((ctxt != NULL) && (ctxt->options & XML_PARSE_NONET)) {
4016 int options = ctxt->options;
4017
4018 ctxt->options -= XML_PARSE_NONET;
4019 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
4020 ctxt->options = options;
4021 return(ret);
4022 }
Daniel Veillardad4e2962006-09-21 08:36:38 +00004023#ifdef LIBXML_CATALOG_ENABLED
4024 resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
Daniel Veillard7d6fd212001-05-10 15:34:11 +00004025#endif
4026
4027 if (resource == NULL)
Daniel Veillarda840b692003-10-19 13:35:37 +00004028 resource = (xmlChar *) URL;
Daniel Veillard7d6fd212001-05-10 15:34:11 +00004029
4030 if (resource == NULL) {
Daniel Veillarda840b692003-10-19 13:35:37 +00004031 if (ID == NULL)
4032 ID = "NULL";
Daniel Veillarde8039df2003-10-27 11:25:13 +00004033 __xmlLoaderErr(ctxt, "failed to load external entity \"%s\"\n", ID);
Daniel Veillarda840b692003-10-19 13:35:37 +00004034 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004035 }
Daniel Veillarda840b692003-10-19 13:35:37 +00004036 ret = xmlNewInputFromFile(ctxt, (const char *) resource);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00004037 if ((resource != NULL) && (resource != (xmlChar *) URL))
Daniel Veillarda840b692003-10-19 13:35:37 +00004038 xmlFree(resource);
4039 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004040}
4041
4042static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
4043 xmlDefaultExternalEntityLoader;
4044
Daniel Veillard5e2dace2001-07-18 19:30:27 +00004045/**
Owen Taylor3473f882001-02-23 17:55:21 +00004046 * xmlSetExternalEntityLoader:
4047 * @f: the new entity resolver function
4048 *
4049 * Changes the defaultexternal entity resolver function for the application
4050 */
4051void
4052xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
4053 xmlCurrentExternalEntityLoader = f;
4054}
4055
Daniel Veillard5e2dace2001-07-18 19:30:27 +00004056/**
Owen Taylor3473f882001-02-23 17:55:21 +00004057 * xmlGetExternalEntityLoader:
4058 *
4059 * Get the default external entity resolver function for the application
4060 *
4061 * Returns the xmlExternalEntityLoader function pointer
4062 */
4063xmlExternalEntityLoader
4064xmlGetExternalEntityLoader(void) {
4065 return(xmlCurrentExternalEntityLoader);
4066}
4067
Daniel Veillard5e2dace2001-07-18 19:30:27 +00004068/**
Owen Taylor3473f882001-02-23 17:55:21 +00004069 * xmlLoadExternalEntity:
4070 * @URL: the URL for the entity to load
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00004071 * @ID: the Public ID for the entity to load
Owen Taylor3473f882001-02-23 17:55:21 +00004072 * @ctxt: the context in which the entity is called or NULL
4073 *
4074 * Load an external entity, note that the use of this function for
4075 * unparsed entities may generate problems
Owen Taylor3473f882001-02-23 17:55:21 +00004076 *
4077 * Returns the xmlParserInputPtr or NULL
4078 */
4079xmlParserInputPtr
4080xmlLoadExternalEntity(const char *URL, const char *ID,
4081 xmlParserCtxtPtr ctxt) {
Daniel Veillarde5a3f372006-08-30 13:11:36 +00004082 if ((URL != NULL) && (xmlNoNetExists(URL) == 0)) {
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00004083 char *canonicFilename;
4084 xmlParserInputPtr ret;
4085
4086 canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL);
4087 if (canonicFilename == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00004088 xmlIOErrMemory("building canonical path\n");
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00004089 return(NULL);
4090 }
4091
4092 ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt);
4093 xmlFree(canonicFilename);
4094 return(ret);
4095 }
Owen Taylor3473f882001-02-23 17:55:21 +00004096 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
4097}
4098
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004099/************************************************************************
Hans Breuer2ad41ca2009-08-11 17:51:22 +02004100 * *
4101 * Disabling Network access *
4102 * *
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004103 ************************************************************************/
4104
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004105/**
4106 * xmlNoNetExternalEntityLoader:
4107 * @URL: the URL for the entity to load
4108 * @ID: the System ID for the entity to load
4109 * @ctxt: the context in which the entity is called or NULL
4110 *
4111 * A specific entity loader disabling network accesses, though still
4112 * allowing local catalog accesses for resolution.
4113 *
4114 * Returns a new allocated xmlParserInputPtr, or NULL.
4115 */
4116xmlParserInputPtr
4117xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
4118 xmlParserCtxtPtr ctxt) {
4119 xmlParserInputPtr input = NULL;
4120 xmlChar *resource = NULL;
4121
4122#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillardad4e2962006-09-21 08:36:38 +00004123 resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004124#endif
Daniel Veillardad4e2962006-09-21 08:36:38 +00004125
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004126 if (resource == NULL)
4127 resource = (xmlChar *) URL;
4128
4129 if (resource != NULL) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00004130 if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
4131 (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00004132 xmlIOErr(XML_IO_NETWORK_ATTEMPT, (const char *) resource);
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004133 if (resource != (xmlChar *) URL)
4134 xmlFree(resource);
4135 return(NULL);
4136 }
4137 }
4138 input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
4139 if (resource != (xmlChar *) URL)
4140 xmlFree(resource);
4141 return(input);
4142}
4143
Daniel Veillard5d4644e2005-04-01 13:11:58 +00004144#define bottom_xmlIO
4145#include "elfgcchack.h"