blob: 0e1092dcc323c7503d635318e629f8c663b98943 [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
Michael Stahl55b899a2012-09-07 12:14:00 +0800774 struct stat stat_buffer;
Daniel Veillard0b309952006-05-02 20:34:38 +0000775#endif
Michael Stahl55b899a2012-09-07 12:14:00 +0800776 if (path == NULL)
777 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__)
Michael Stahl55b899a2012-09-07 12:14:00 +0800781 /*
782 * On Windows stat and wstat do not work with long pathname,
783 * which start with '\\?\'
784 */
785 if ((path[0] == '\\') && (path[1] == '\\') && (path[2] == '?') &&
786 (path[3] == '\\') )
787 return 1;
788
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000789 if (xmlWrapStat(path, &stat_buffer) == -1)
790 return 0;
791#else
Owen Taylor3473f882001-02-23 17:55:21 +0000792 if (stat(path, &stat_buffer) == -1)
793 return 0;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000794#endif
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000795#ifdef S_ISDIR
Daniel Veillardf7416012006-04-27 08:15:20 +0000796 if (S_ISDIR(stat_buffer.st_mode))
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000797 return 2;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000798#endif
Daniel Veillardf7416012006-04-27 08:15:20 +0000799#endif /* HAVE_STAT */
Owen Taylor3473f882001-02-23 17:55:21 +0000800 return 1;
801}
802
Daniel Veillard153cf152012-10-26 13:50:47 +0800803int
Owen Taylor3473f882001-02-23 17:55:21 +0000804xmlNop(void) {
805 return(0);
806}
807
808/**
Owen Taylor3473f882001-02-23 17:55:21 +0000809 * xmlFdRead:
810 * @context: the I/O context
811 * @buffer: where to drop data
812 * @len: number of bytes to read
813 *
814 * Read @len bytes to @buffer from the I/O channel.
815 *
816 * Returns the number of bytes written
817 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000818static int
Owen Taylor3473f882001-02-23 17:55:21 +0000819xmlFdRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000820 int ret;
821
822 ret = read((int) (long) context, &buffer[0], len);
823 if (ret < 0) xmlIOErr(0, "read()");
824 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000825}
826
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000827#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000828/**
829 * xmlFdWrite:
830 * @context: the I/O context
831 * @buffer: where to get data
832 * @len: number of bytes to write
833 *
834 * Write @len bytes from @buffer to the I/O channel.
835 *
836 * Returns the number of bytes written
837 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000838static int
Owen Taylor3473f882001-02-23 17:55:21 +0000839xmlFdWrite (void * context, const char * buffer, int len) {
Daniel Veillard9b693b42005-10-28 14:54:17 +0000840 int ret = 0;
Daniel Veillard05d987b2003-10-08 11:54:57 +0000841
Daniel Veillard9b693b42005-10-28 14:54:17 +0000842 if (len > 0) {
843 ret = write((int) (long) context, &buffer[0], len);
844 if (ret < 0) xmlIOErr(0, "write()");
845 }
Daniel Veillard05d987b2003-10-08 11:54:57 +0000846 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000847}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000848#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000849
850/**
851 * xmlFdClose:
852 * @context: the I/O context
853 *
854 * Close an I/O channel
Daniel Veillardf012a642001-07-23 19:10:52 +0000855 *
856 * Returns 0 in case of success and error code otherwise
Owen Taylor3473f882001-02-23 17:55:21 +0000857 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000858static int
Owen Taylor3473f882001-02-23 17:55:21 +0000859xmlFdClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000860 int ret;
861 ret = close((int) (long) context);
862 if (ret < 0) xmlIOErr(0, "close()");
863 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000864}
865
866/**
867 * xmlFileMatch:
868 * @filename: the URI for matching
869 *
870 * input from FILE *
871 *
872 * Returns 1 if matches, 0 otherwise
873 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000874int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000875xmlFileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000876 return(1);
877}
878
879/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000880 * xmlFileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +0000881 * @filename: the URI for matching
882 *
883 * input from FILE *, supports compressed input
884 * if @filename is " " then the standard input is used
885 *
886 * Returns an I/O context or NULL in case of error
887 */
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000888static void *
889xmlFileOpen_real (const char *filename) {
Gaurav Guptab8480ae2014-07-26 21:14:53 +0800890 const char *path = filename;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000891 FILE *fd;
Owen Taylor3473f882001-02-23 17:55:21 +0000892
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000893 if (filename == NULL)
894 return(NULL);
895
Owen Taylor3473f882001-02-23 17:55:21 +0000896 if (!strcmp(filename, "-")) {
897 fd = stdin;
898 return((void *) fd);
899 }
900
Daniel Veillard5cdbbd22007-06-12 09:39:14 +0000901 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000902#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000903 path = &filename[17];
904#else
Owen Taylor3473f882001-02-23 17:55:21 +0000905 path = &filename[16];
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000906#endif
Daniel Veillard5cdbbd22007-06-12 09:39:14 +0000907 } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000908#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000909 path = &filename[8];
910#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000911 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000912#endif
Daniel Veillard5cdbbd22007-06-12 09:39:14 +0000913 } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:/", 6)) {
914 /* lots of generators seems to lazy to read RFC 1738 */
915#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
916 path = &filename[6];
917#else
918 path = &filename[5];
919#endif
Gaurav Guptab8480ae2014-07-26 21:14:53 +0800920 }
Owen Taylor3473f882001-02-23 17:55:21 +0000921
Owen Taylor3473f882001-02-23 17:55:21 +0000922 if (!xmlCheckFilename(path))
923 return(NULL);
924
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000925#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
926 fd = xmlWrapOpen(path, 0);
927#else
928 fd = fopen(path, "r");
Owen Taylor3473f882001-02-23 17:55:21 +0000929#endif /* WIN32 */
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000930 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +0000931 return((void *) fd);
932}
933
934/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000935 * xmlFileOpen:
936 * @filename: the URI for matching
937 *
938 * Wrapper around xmlFileOpen_real that try it with an unescaped
939 * version of @filename, if this fails fallback to @filename
Daniel Veillard71531f32003-02-05 13:19:53 +0000940 *
941 * Returns a handler or NULL in case or failure
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000942 */
943void *
944xmlFileOpen (const char *filename) {
945 char *unescaped;
946 void *retval;
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000947
Daniel Veillardbd672bc2007-03-30 12:39:25 +0000948 retval = xmlFileOpen_real(filename);
949 if (retval == NULL) {
950 unescaped = xmlURIUnescapeString(filename, 0, NULL);
951 if (unescaped != NULL) {
952 retval = xmlFileOpen_real(unescaped);
953 xmlFree(unescaped);
954 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000955 }
Daniel Veillardbd672bc2007-03-30 12:39:25 +0000956
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000957 return retval;
958}
959
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000960#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000961/**
Owen Taylor3473f882001-02-23 17:55:21 +0000962 * xmlFileOpenW:
963 * @filename: the URI for matching
964 *
965 * output to from FILE *,
966 * if @filename is "-" then the standard output is used
967 *
968 * Returns an I/O context or NULL in case of error
969 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000970static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000971xmlFileOpenW (const char *filename) {
972 const char *path = NULL;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000973 FILE *fd;
Owen Taylor3473f882001-02-23 17:55:21 +0000974
975 if (!strcmp(filename, "-")) {
976 fd = stdout;
977 return((void *) fd);
978 }
979
Daniel Veillardf4862f02002-09-10 11:13:43 +0000980 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000981#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000982 path = &filename[17];
983#else
Owen Taylor3473f882001-02-23 17:55:21 +0000984 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000985#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000986 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000987#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000988 path = &filename[8];
989#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000990 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000991#endif
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200992 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000993 path = filename;
994
995 if (path == NULL)
996 return(NULL);
997
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000998#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
999 fd = xmlWrapOpen(path, 1);
1000#else
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001001 fd = fopen(path, "wb");
Daniel Veillard8ca85b22006-09-01 09:56:07 +00001002#endif /* WIN32 */
Daniel Veillarde5a3f372006-08-30 13:11:36 +00001003
Daniel Veillardf7416012006-04-27 08:15:20 +00001004 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +00001005 return((void *) fd);
1006}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001007#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001008
1009/**
1010 * xmlFileRead:
1011 * @context: the I/O context
1012 * @buffer: where to drop data
1013 * @len: number of bytes to write
1014 *
1015 * Read @len bytes to @buffer from the I/O channel.
1016 *
Daniel Veillardce682bc2004-11-05 17:22:25 +00001017 * Returns the number of bytes written or < 0 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +00001018 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001019int
Owen Taylor3473f882001-02-23 17:55:21 +00001020xmlFileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001021 int ret;
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001022 if ((context == NULL) || (buffer == NULL))
Daniel Veillardce682bc2004-11-05 17:22:25 +00001023 return(-1);
Daniel Veillard05d987b2003-10-08 11:54:57 +00001024 ret = fread(&buffer[0], 1, len, (FILE *) context);
1025 if (ret < 0) xmlIOErr(0, "fread()");
1026 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001027}
1028
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001029#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001030/**
1031 * xmlFileWrite:
1032 * @context: the I/O context
1033 * @buffer: where to drop data
1034 * @len: number of bytes to write
1035 *
1036 * Write @len bytes from @buffer to the I/O channel.
1037 *
1038 * Returns the number of bytes written
1039 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001040static int
Owen Taylor3473f882001-02-23 17:55:21 +00001041xmlFileWrite (void * context, const char * buffer, int len) {
Daniel Veillard4a6d39b2002-12-17 18:33:01 +00001042 int items;
1043
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001044 if ((context == NULL) || (buffer == NULL))
Daniel Veillardce682bc2004-11-05 17:22:25 +00001045 return(-1);
Daniel Veillard4a6d39b2002-12-17 18:33:01 +00001046 items = fwrite(&buffer[0], len, 1, (FILE *) context);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00001047 if ((items == 0) && (ferror((FILE *) context))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001048 xmlIOErr(0, "fwrite()");
Daniel Veillard97bf4d02003-10-08 18:58:28 +00001049 return(-1);
1050 }
Daniel Veillard4a6d39b2002-12-17 18:33:01 +00001051 return(items * len);
Owen Taylor3473f882001-02-23 17:55:21 +00001052}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001053#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001054
1055/**
1056 * xmlFileClose:
1057 * @context: the I/O context
1058 *
1059 * Close an I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001060 *
1061 * Returns 0 or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +00001062 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001063int
Owen Taylor3473f882001-02-23 17:55:21 +00001064xmlFileClose (void * context) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001065 FILE *fil;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001066 int ret;
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001067
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +00001068 if (context == NULL)
1069 return(-1);
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001070 fil = (FILE *) context;
Daniel Veillard500a1de2004-03-22 15:22:58 +00001071 if ((fil == stdout) || (fil == stderr)) {
1072 ret = fflush(fil);
1073 if (ret < 0)
1074 xmlIOErr(0, "fflush()");
1075 return(0);
1076 }
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001077 if (fil == stdin)
1078 return(0);
Daniel Veillard05d987b2003-10-08 11:54:57 +00001079 ret = ( fclose((FILE *) context) == EOF ) ? -1 : 0;
1080 if (ret < 0)
1081 xmlIOErr(0, "fclose()");
1082 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001083}
1084
1085/**
1086 * xmlFileFlush:
1087 * @context: the I/O context
1088 *
1089 * Flush an I/O channel
1090 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001091static int
Owen Taylor3473f882001-02-23 17:55:21 +00001092xmlFileFlush (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001093 int ret;
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +00001094
1095 if (context == NULL)
1096 return(-1);
Daniel Veillard05d987b2003-10-08 11:54:57 +00001097 ret = ( fflush((FILE *) context) == EOF ) ? -1 : 0;
1098 if (ret < 0)
1099 xmlIOErr(0, "fflush()");
1100 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001101}
1102
Daniel Veillard9a00fd22005-11-09 08:56:26 +00001103#ifdef LIBXML_OUTPUT_ENABLED
1104/**
1105 * xmlBufferWrite:
1106 * @context: the xmlBuffer
1107 * @buffer: the data to write
1108 * @len: number of bytes to write
1109 *
1110 * Write @len bytes from @buffer to the xml buffer
1111 *
1112 * Returns the number of bytes written
1113 */
1114static int
1115xmlBufferWrite (void * context, const char * buffer, int len) {
1116 int ret;
1117
1118 ret = xmlBufferAdd((xmlBufferPtr) context, (const xmlChar *) buffer, len);
1119 if (ret != 0)
1120 return(-1);
1121 return(len);
1122}
Daniel Veillard9a00fd22005-11-09 08:56:26 +00001123#endif
1124
Owen Taylor3473f882001-02-23 17:55:21 +00001125#ifdef HAVE_ZLIB_H
1126/************************************************************************
1127 * *
1128 * I/O for compressed file accesses *
1129 * *
1130 ************************************************************************/
1131/**
1132 * xmlGzfileMatch:
1133 * @filename: the URI for matching
1134 *
1135 * input from compressed file test
1136 *
1137 * Returns 1 if matches, 0 otherwise
1138 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001139static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00001140xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00001141 return(1);
1142}
1143
1144/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001145 * xmlGzfileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +00001146 * @filename: the URI for matching
1147 *
1148 * input from compressed file open
1149 * if @filename is " " then the standard input is used
1150 *
1151 * Returns an I/O context or NULL in case of error
1152 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001153static void *
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001154xmlGzfileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +00001155 const char *path = NULL;
1156 gzFile fd;
1157
1158 if (!strcmp(filename, "-")) {
Philip Withnall31aa3812014-06-20 21:11:40 +01001159 int duped_fd = dup(fileno(stdin));
1160 fd = gzdopen(duped_fd, "rb");
Philip Withnall21699932014-08-24 23:10:13 +01001161 if (fd == Z_NULL && duped_fd >= 0) {
Philip Withnall31aa3812014-06-20 21:11:40 +01001162 close(duped_fd); /* gzdOpen() does not close on failure */
1163 }
1164
Owen Taylor3473f882001-02-23 17:55:21 +00001165 return((void *) fd);
1166 }
1167
Daniel Veillardf4862f02002-09-10 11:13:43 +00001168 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001169#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00001170 path = &filename[17];
1171#else
Owen Taylor3473f882001-02-23 17:55:21 +00001172 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00001173#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001174 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001175#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +00001176 path = &filename[8];
1177#else
Owen Taylor3473f882001-02-23 17:55:21 +00001178 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +00001179#endif
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001180 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001181 path = filename;
1182
1183 if (path == NULL)
1184 return(NULL);
1185 if (!xmlCheckFilename(path))
1186 return(NULL);
1187
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001188#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
1189 fd = xmlWrapGzOpen(path, "rb");
1190#else
Owen Taylor3473f882001-02-23 17:55:21 +00001191 fd = gzopen(path, "rb");
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001192#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001193 return((void *) fd);
1194}
1195
1196/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001197 * xmlGzfileOpen:
1198 * @filename: the URI for matching
1199 *
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00001200 * Wrapper around xmlGzfileOpen if the open fais, it will
1201 * try to unescape @filename
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001202 */
1203static void *
1204xmlGzfileOpen (const char *filename) {
1205 char *unescaped;
1206 void *retval;
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00001207
1208 retval = xmlGzfileOpen_real(filename);
1209 if (retval == NULL) {
1210 unescaped = xmlURIUnescapeString(filename, 0, NULL);
1211 if (unescaped != NULL) {
1212 retval = xmlGzfileOpen_real(unescaped);
1213 }
1214 xmlFree(unescaped);
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001215 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001216 return retval;
1217}
1218
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001219#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001220/**
Owen Taylor3473f882001-02-23 17:55:21 +00001221 * xmlGzfileOpenW:
1222 * @filename: the URI for matching
1223 * @compression: the compression factor (0 - 9 included)
1224 *
1225 * input from compressed file open
1226 * if @filename is " " then the standard input is used
1227 *
1228 * Returns an I/O context or NULL in case of error
1229 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001230static void *
Owen Taylor3473f882001-02-23 17:55:21 +00001231xmlGzfileOpenW (const char *filename, int compression) {
1232 const char *path = NULL;
1233 char mode[15];
1234 gzFile fd;
1235
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001236 snprintf(mode, sizeof(mode), "wb%d", compression);
Owen Taylor3473f882001-02-23 17:55:21 +00001237 if (!strcmp(filename, "-")) {
Philip Withnall31aa3812014-06-20 21:11:40 +01001238 int duped_fd = dup(fileno(stdout));
1239 fd = gzdopen(duped_fd, "rb");
Philip Withnall21699932014-08-24 23:10:13 +01001240 if (fd == Z_NULL && duped_fd >= 0) {
Philip Withnall31aa3812014-06-20 21:11:40 +01001241 close(duped_fd); /* gzdOpen() does not close on failure */
1242 }
1243
Owen Taylor3473f882001-02-23 17:55:21 +00001244 return((void *) fd);
1245 }
1246
Daniel Veillardf4862f02002-09-10 11:13:43 +00001247 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001248#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00001249 path = &filename[17];
1250#else
Owen Taylor3473f882001-02-23 17:55:21 +00001251 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00001252#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001253 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001254#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +00001255 path = &filename[8];
1256#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +00001257 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +00001258#endif
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001259 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001260 path = filename;
1261
1262 if (path == NULL)
1263 return(NULL);
1264
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001265#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
1266 fd = xmlWrapGzOpen(path, mode);
1267#else
Owen Taylor3473f882001-02-23 17:55:21 +00001268 fd = gzopen(path, mode);
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001269#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001270 return((void *) fd);
1271}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001272#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001273
1274/**
1275 * xmlGzfileRead:
1276 * @context: the I/O context
1277 * @buffer: where to drop data
1278 * @len: number of bytes to write
1279 *
1280 * Read @len bytes to @buffer from the compressed I/O channel.
1281 *
1282 * Returns the number of bytes written
1283 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001284static int
Owen Taylor3473f882001-02-23 17:55:21 +00001285xmlGzfileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001286 int ret;
1287
1288 ret = gzread((gzFile) context, &buffer[0], len);
1289 if (ret < 0) xmlIOErr(0, "gzread()");
1290 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001291}
1292
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001293#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001294/**
1295 * xmlGzfileWrite:
1296 * @context: the I/O context
1297 * @buffer: where to drop data
1298 * @len: number of bytes to write
1299 *
1300 * Write @len bytes from @buffer to the compressed I/O channel.
1301 *
1302 * Returns the number of bytes written
1303 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001304static int
Owen Taylor3473f882001-02-23 17:55:21 +00001305xmlGzfileWrite (void * context, const char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001306 int ret;
1307
1308 ret = gzwrite((gzFile) context, (char *) &buffer[0], len);
1309 if (ret < 0) xmlIOErr(0, "gzwrite()");
1310 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001311}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001312#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001313
1314/**
1315 * xmlGzfileClose:
1316 * @context: the I/O context
1317 *
1318 * Close a compressed I/O channel
1319 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001320static int
Owen Taylor3473f882001-02-23 17:55:21 +00001321xmlGzfileClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001322 int ret;
1323
1324 ret = (gzclose((gzFile) context) == Z_OK ) ? 0 : -1;
1325 if (ret < 0) xmlIOErr(0, "gzclose()");
1326 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001327}
1328#endif /* HAVE_ZLIB_H */
1329
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001330#ifdef HAVE_LZMA_H
1331/************************************************************************
1332 * *
1333 * I/O for compressed file accesses *
1334 * *
1335 ************************************************************************/
Daniel Veillardadf5ec92012-01-26 16:56:22 +08001336#include "xzlib.h"
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001337/**
1338 * xmlXzfileMatch:
1339 * @filename: the URI for matching
1340 *
1341 * input from compressed file test
1342 *
1343 * Returns 1 if matches, 0 otherwise
1344 */
1345static int
1346xmlXzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
1347 return(1);
1348}
1349
1350/**
1351 * xmlXzFileOpen_real:
1352 * @filename: the URI for matching
1353 *
1354 * input from compressed file open
1355 * if @filename is " " then the standard input is used
1356 *
1357 * Returns an I/O context or NULL in case of error
1358 */
1359static void *
1360xmlXzfileOpen_real (const char *filename) {
1361 const char *path = NULL;
1362 xzFile fd;
1363
1364 if (!strcmp(filename, "-")) {
Patrick Monnerat147aaf22013-12-12 15:02:40 +08001365 fd = __libxml2_xzdopen(dup(fileno(stdin)), "rb");
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001366 return((void *) fd);
1367 }
1368
1369 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) {
1370 path = &filename[16];
1371 } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
1372 path = &filename[7];
1373 } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:/", 6)) {
1374 /* lots of generators seems to lazy to read RFC 1738 */
1375 path = &filename[5];
1376 } else
1377 path = filename;
1378
1379 if (path == NULL)
1380 return(NULL);
1381 if (!xmlCheckFilename(path))
1382 return(NULL);
1383
Daniel Veillardadf5ec92012-01-26 16:56:22 +08001384 fd = __libxml2_xzopen(path, "rb");
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001385 return((void *) fd);
1386}
1387
1388/**
1389 * xmlXzfileOpen:
1390 * @filename: the URI for matching
1391 *
1392 * Wrapper around xmlXzfileOpen_real that try it with an unescaped
1393 * version of @filename, if this fails fallback to @filename
1394 *
1395 * Returns a handler or NULL in case or failure
1396 */
1397static void *
1398xmlXzfileOpen (const char *filename) {
1399 char *unescaped;
1400 void *retval;
1401
1402 retval = xmlXzfileOpen_real(filename);
1403 if (retval == NULL) {
1404 unescaped = xmlURIUnescapeString(filename, 0, NULL);
1405 if (unescaped != NULL) {
1406 retval = xmlXzfileOpen_real(unescaped);
1407 }
1408 xmlFree(unescaped);
1409 }
1410
1411 return retval;
1412}
1413
1414/**
1415 * xmlXzfileRead:
1416 * @context: the I/O context
1417 * @buffer: where to drop data
1418 * @len: number of bytes to write
1419 *
1420 * Read @len bytes to @buffer from the compressed I/O channel.
1421 *
1422 * Returns the number of bytes written
1423 */
1424static int
1425xmlXzfileRead (void * context, char * buffer, int len) {
1426 int ret;
1427
Daniel Veillardadf5ec92012-01-26 16:56:22 +08001428 ret = __libxml2_xzread((xzFile) context, &buffer[0], len);
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001429 if (ret < 0) xmlIOErr(0, "xzread()");
1430 return(ret);
1431}
1432
1433/**
1434 * xmlXzfileClose:
1435 * @context: the I/O context
1436 *
1437 * Close a compressed I/O channel
1438 */
1439static int
1440xmlXzfileClose (void * context) {
1441 int ret;
1442
Daniel Veillardadf5ec92012-01-26 16:56:22 +08001443 ret = (__libxml2_xzclose((xzFile) context) == LZMA_OK ) ? 0 : -1;
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001444 if (ret < 0) xmlIOErr(0, "xzclose()");
1445 return(ret);
1446}
1447#endif /* HAVE_LZMA_H */
1448
Owen Taylor3473f882001-02-23 17:55:21 +00001449#ifdef LIBXML_HTTP_ENABLED
1450/************************************************************************
1451 * *
1452 * I/O for HTTP file accesses *
1453 * *
1454 ************************************************************************/
Daniel Veillardf012a642001-07-23 19:10:52 +00001455
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001456#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001457typedef struct xmlIOHTTPWriteCtxt_
1458{
1459 int compression;
1460
1461 char * uri;
1462
1463 void * doc_buff;
1464
1465} xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr;
1466
1467#ifdef HAVE_ZLIB_H
1468
1469#define DFLT_WBITS ( -15 )
1470#define DFLT_MEM_LVL ( 8 )
1471#define GZ_MAGIC1 ( 0x1f )
1472#define GZ_MAGIC2 ( 0x8b )
1473#define LXML_ZLIB_OS_CODE ( 0x03 )
1474#define INIT_HTTP_BUFF_SIZE ( 32768 )
1475#define DFLT_ZLIB_RATIO ( 5 )
1476
1477/*
1478** Data structure and functions to work with sending compressed data
1479** via HTTP.
1480*/
1481
1482typedef struct xmlZMemBuff_
1483{
1484 unsigned long size;
1485 unsigned long crc;
1486
1487 unsigned char * zbuff;
1488 z_stream zctrl;
1489
1490} xmlZMemBuff, *xmlZMemBuffPtr;
1491
1492/**
1493 * append_reverse_ulong
1494 * @buff: Compressed memory buffer
1495 * @data: Unsigned long to append
1496 *
1497 * Append a unsigned long in reverse byte order to the end of the
1498 * memory buffer.
1499 */
1500static void
1501append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) {
1502
1503 int idx;
1504
1505 if ( buff == NULL )
1506 return;
1507
1508 /*
1509 ** This is plagiarized from putLong in gzio.c (zlib source) where
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001510 ** the number "4" is hardcoded. If zlib is ever patched to
Daniel Veillardf012a642001-07-23 19:10:52 +00001511 ** support 64 bit file sizes, this code would need to be patched
1512 ** as well.
1513 */
1514
1515 for ( idx = 0; idx < 4; idx++ ) {
1516 *buff->zctrl.next_out = ( data & 0xff );
1517 data >>= 8;
1518 buff->zctrl.next_out++;
1519 }
1520
1521 return;
1522}
1523
1524/**
1525 *
1526 * xmlFreeZMemBuff
1527 * @buff: The memory buffer context to clear
1528 *
1529 * Release all the resources associated with the compressed memory buffer.
1530 */
1531static void
1532xmlFreeZMemBuff( xmlZMemBuffPtr buff ) {
William M. Brack78637da2003-07-31 14:47:38 +00001533
1534#ifdef DEBUG_HTTP
Daniel Veillardf012a642001-07-23 19:10:52 +00001535 int z_err;
William M. Brack78637da2003-07-31 14:47:38 +00001536#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001537
1538 if ( buff == NULL )
1539 return;
1540
1541 xmlFree( buff->zbuff );
Daniel Veillardf012a642001-07-23 19:10:52 +00001542#ifdef DEBUG_HTTP
William M. Brack78637da2003-07-31 14:47:38 +00001543 z_err = deflateEnd( &buff->zctrl );
Daniel Veillardf012a642001-07-23 19:10:52 +00001544 if ( z_err != Z_OK )
1545 xmlGenericError( xmlGenericErrorContext,
1546 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
1547 z_err );
William M. Brack78637da2003-07-31 14:47:38 +00001548#else
1549 deflateEnd( &buff->zctrl );
William M. Brack779af002003-08-01 15:55:39 +00001550#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001551
1552 xmlFree( buff );
1553 return;
1554}
1555
1556/**
1557 * xmlCreateZMemBuff
1558 *@compression: Compression value to use
1559 *
1560 * Create a memory buffer to hold the compressed XML document. The
1561 * compressed document in memory will end up being identical to what
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001562 * would be created if gzopen/gzwrite/gzclose were being used to
Daniel Veillardf012a642001-07-23 19:10:52 +00001563 * write the document to disk. The code for the header/trailer data to
1564 * the compression is plagiarized from the zlib source files.
1565 */
1566static void *
1567xmlCreateZMemBuff( int compression ) {
1568
1569 int z_err;
1570 int hdr_lgth;
1571 xmlZMemBuffPtr buff = NULL;
1572
1573 if ( ( compression < 1 ) || ( compression > 9 ) )
1574 return ( NULL );
1575
1576 /* Create the control and data areas */
1577
1578 buff = xmlMalloc( sizeof( xmlZMemBuff ) );
1579 if ( buff == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001580 xmlIOErrMemory("creating buffer context");
Daniel Veillardf012a642001-07-23 19:10:52 +00001581 return ( NULL );
1582 }
1583
1584 (void)memset( buff, 0, sizeof( xmlZMemBuff ) );
1585 buff->size = INIT_HTTP_BUFF_SIZE;
1586 buff->zbuff = xmlMalloc( buff->size );
1587 if ( buff->zbuff == NULL ) {
1588 xmlFreeZMemBuff( buff );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001589 xmlIOErrMemory("creating buffer");
Daniel Veillardf012a642001-07-23 19:10:52 +00001590 return ( NULL );
1591 }
1592
1593 z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
1594 DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
1595 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001596 xmlChar msg[500];
Daniel Veillardf012a642001-07-23 19:10:52 +00001597 xmlFreeZMemBuff( buff );
1598 buff = NULL;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001599 xmlStrPrintf(msg, 500,
1600 (const xmlChar *) "xmlCreateZMemBuff: %s %d\n",
1601 "Error initializing compression context. ZLIB error:",
1602 z_err );
1603 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001604 return ( NULL );
1605 }
1606
1607 /* Set the header data. The CRC will be needed for the trailer */
Daniel Veillard24505b02005-07-28 23:49:35 +00001608 buff->crc = crc32( 0L, NULL, 0 );
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001609 hdr_lgth = snprintf( (char *)buff->zbuff, buff->size,
1610 "%c%c%c%c%c%c%c%c%c%c",
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001611 GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED,
Daniel Veillardf012a642001-07-23 19:10:52 +00001612 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE );
1613 buff->zctrl.next_out = buff->zbuff + hdr_lgth;
1614 buff->zctrl.avail_out = buff->size - hdr_lgth;
1615
1616 return ( buff );
1617}
1618
1619/**
1620 * xmlZMemBuffExtend
1621 * @buff: Buffer used to compress and consolidate data.
1622 * @ext_amt: Number of bytes to extend the buffer.
1623 *
1624 * Extend the internal buffer used to store the compressed data by the
1625 * specified amount.
1626 *
1627 * Returns 0 on success or -1 on failure to extend the buffer. On failure
1628 * the original buffer still exists at the original size.
1629 */
1630static int
1631xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) {
1632
1633 int rc = -1;
1634 size_t new_size;
1635 size_t cur_used;
1636
1637 unsigned char * tmp_ptr = NULL;
1638
1639 if ( buff == NULL )
1640 return ( -1 );
1641
1642 else if ( ext_amt == 0 )
1643 return ( 0 );
1644
1645 cur_used = buff->zctrl.next_out - buff->zbuff;
1646 new_size = buff->size + ext_amt;
1647
1648#ifdef DEBUG_HTTP
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001649 if ( cur_used > new_size )
Daniel Veillardf012a642001-07-23 19:10:52 +00001650 xmlGenericError( xmlGenericErrorContext,
1651 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
1652 "Buffer overwrite detected during compressed memory",
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001653 "buffer extension. Overflowed by",
Daniel Veillardf012a642001-07-23 19:10:52 +00001654 (cur_used - new_size ) );
1655#endif
1656
1657 tmp_ptr = xmlRealloc( buff->zbuff, new_size );
1658 if ( tmp_ptr != NULL ) {
1659 rc = 0;
1660 buff->size = new_size;
1661 buff->zbuff = tmp_ptr;
1662 buff->zctrl.next_out = tmp_ptr + cur_used;
1663 buff->zctrl.avail_out = new_size - cur_used;
1664 }
1665 else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001666 xmlChar msg[500];
1667 xmlStrPrintf(msg, 500,
1668 (const xmlChar *) "xmlZMemBuffExtend: %s %lu bytes.\n",
1669 "Allocation failure extending output buffer to",
1670 new_size );
1671 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001672 }
1673
1674 return ( rc );
1675}
1676
1677/**
1678 * xmlZMemBuffAppend
1679 * @buff: Buffer used to compress and consolidate data
1680 * @src: Uncompressed source content to append to buffer
1681 * @len: Length of source data to append to buffer
1682 *
1683 * Compress and append data to the internal buffer. The data buffer
1684 * will be expanded if needed to store the additional data.
1685 *
1686 * Returns the number of bytes appended to the buffer or -1 on error.
1687 */
1688static int
1689xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) {
1690
1691 int z_err;
1692 size_t min_accept;
1693
1694 if ( ( buff == NULL ) || ( src == NULL ) )
1695 return ( -1 );
1696
1697 buff->zctrl.avail_in = len;
1698 buff->zctrl.next_in = (unsigned char *)src;
1699 while ( buff->zctrl.avail_in > 0 ) {
1700 /*
1701 ** Extend the buffer prior to deflate call if a reasonable amount
1702 ** of output buffer space is not available.
1703 */
1704 min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO;
1705 if ( buff->zctrl.avail_out <= min_accept ) {
1706 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1707 return ( -1 );
1708 }
1709
1710 z_err = deflate( &buff->zctrl, Z_NO_FLUSH );
1711 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001712 xmlChar msg[500];
1713 xmlStrPrintf(msg, 500,
1714 (const xmlChar *) "xmlZMemBuffAppend: %s %d %s - %d",
Daniel Veillardf012a642001-07-23 19:10:52 +00001715 "Compression error while appending",
1716 len, "bytes to buffer. ZLIB error", z_err );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001717 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001718 return ( -1 );
1719 }
1720 }
1721
1722 buff->crc = crc32( buff->crc, (unsigned char *)src, len );
1723
1724 return ( len );
1725}
1726
1727/**
1728 * xmlZMemBuffGetContent
1729 * @buff: Compressed memory content buffer
1730 * @data_ref: Pointer reference to point to compressed content
1731 *
1732 * Flushes the compression buffers, appends gzip file trailers and
1733 * returns the compressed content and length of the compressed data.
1734 * NOTE: The gzip trailer code here is plagiarized from zlib source.
1735 *
1736 * Returns the length of the compressed data or -1 on error.
1737 */
1738static int
1739xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) {
1740
1741 int zlgth = -1;
1742 int z_err;
1743
1744 if ( ( buff == NULL ) || ( data_ref == NULL ) )
1745 return ( -1 );
1746
1747 /* Need to loop until compression output buffers are flushed */
1748
1749 do
1750 {
1751 z_err = deflate( &buff->zctrl, Z_FINISH );
1752 if ( z_err == Z_OK ) {
1753 /* In this case Z_OK means more buffer space needed */
1754
1755 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1756 return ( -1 );
1757 }
1758 }
1759 while ( z_err == Z_OK );
1760
1761 /* If the compression state is not Z_STREAM_END, some error occurred */
1762
1763 if ( z_err == Z_STREAM_END ) {
1764
1765 /* Need to append the gzip data trailer */
1766
1767 if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) {
1768 if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 )
1769 return ( -1 );
1770 }
1771
1772 /*
1773 ** For whatever reason, the CRC and length data are pushed out
1774 ** in reverse byte order. So a memcpy can't be used here.
1775 */
1776
1777 append_reverse_ulong( buff, buff->crc );
1778 append_reverse_ulong( buff, buff->zctrl.total_in );
1779
1780 zlgth = buff->zctrl.next_out - buff->zbuff;
1781 *data_ref = (char *)buff->zbuff;
1782 }
1783
Daniel Veillard05d987b2003-10-08 11:54:57 +00001784 else {
1785 xmlChar msg[500];
1786 xmlStrPrintf(msg, 500,
1787 (const xmlChar *) "xmlZMemBuffGetContent: %s - %d\n",
1788 "Error flushing zlib buffers. Error code", z_err );
1789 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1790 }
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001791
Daniel Veillardf012a642001-07-23 19:10:52 +00001792 return ( zlgth );
1793}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001794#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001795#endif /* HAVE_ZLIB_H */
1796
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001797#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001798/**
1799 * xmlFreeHTTPWriteCtxt
1800 * @ctxt: Context to cleanup
1801 *
1802 * Free allocated memory and reclaim system resources.
1803 *
1804 * No return value.
1805 */
1806static void
1807xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt )
1808{
1809 if ( ctxt->uri != NULL )
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001810 xmlFree( ctxt->uri );
Daniel Veillardf012a642001-07-23 19:10:52 +00001811
1812 if ( ctxt->doc_buff != NULL ) {
1813
1814#ifdef HAVE_ZLIB_H
1815 if ( ctxt->compression > 0 ) {
1816 xmlFreeZMemBuff( ctxt->doc_buff );
1817 }
1818 else
1819#endif
1820 {
1821 xmlOutputBufferClose( ctxt->doc_buff );
1822 }
1823 }
1824
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001825 xmlFree( ctxt );
Daniel Veillardf012a642001-07-23 19:10:52 +00001826 return;
1827}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001828#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001829
1830
Owen Taylor3473f882001-02-23 17:55:21 +00001831/**
1832 * xmlIOHTTPMatch:
1833 * @filename: the URI for matching
1834 *
1835 * check if the URI matches an HTTP one
1836 *
1837 * Returns 1 if matches, 0 otherwise
1838 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001839int
Owen Taylor3473f882001-02-23 17:55:21 +00001840xmlIOHTTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001841 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "http://", 7))
Owen Taylor3473f882001-02-23 17:55:21 +00001842 return(1);
1843 return(0);
1844}
1845
1846/**
1847 * xmlIOHTTPOpen:
1848 * @filename: the URI for matching
1849 *
1850 * open an HTTP I/O channel
1851 *
1852 * Returns an I/O context or NULL in case of error
1853 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001854void *
Owen Taylor3473f882001-02-23 17:55:21 +00001855xmlIOHTTPOpen (const char *filename) {
1856 return(xmlNanoHTTPOpen(filename, NULL));
1857}
1858
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001859#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001860/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001861 * xmlIOHTTPOpenW:
Daniel Veillardf012a642001-07-23 19:10:52 +00001862 * @post_uri: The destination URI for the document
1863 * @compression: The compression desired for the document.
1864 *
1865 * Open a temporary buffer to collect the document for a subsequent HTTP POST
1866 * request. Non-static as is called from the output buffer creation routine.
1867 *
1868 * Returns an I/O context or NULL in case of error.
1869 */
1870
1871void *
Daniel Veillard572577e2002-01-18 16:23:55 +00001872xmlIOHTTPOpenW(const char *post_uri, int compression)
1873{
Daniel Veillardf012a642001-07-23 19:10:52 +00001874
Daniel Veillard572577e2002-01-18 16:23:55 +00001875 xmlIOHTTPWriteCtxtPtr ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001876
Daniel Veillard572577e2002-01-18 16:23:55 +00001877 if (post_uri == NULL)
1878 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001879
Daniel Veillard572577e2002-01-18 16:23:55 +00001880 ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt));
1881 if (ctxt == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001882 xmlIOErrMemory("creating HTTP output context");
Daniel Veillard572577e2002-01-18 16:23:55 +00001883 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001884 }
1885
Daniel Veillard572577e2002-01-18 16:23:55 +00001886 (void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt));
Daniel Veillardf012a642001-07-23 19:10:52 +00001887
Daniel Veillard572577e2002-01-18 16:23:55 +00001888 ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri);
1889 if (ctxt->uri == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001890 xmlIOErrMemory("copying URI");
Daniel Veillard572577e2002-01-18 16:23:55 +00001891 xmlFreeHTTPWriteCtxt(ctxt);
1892 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001893 }
1894
1895 /*
Daniel Veillard572577e2002-01-18 16:23:55 +00001896 * ** Since the document length is required for an HTTP post,
1897 * ** need to put the document into a buffer. A memory buffer
1898 * ** is being used to avoid pushing the data to disk and back.
1899 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001900
1901#ifdef HAVE_ZLIB_H
Daniel Veillard572577e2002-01-18 16:23:55 +00001902 if ((compression > 0) && (compression <= 9)) {
1903
1904 ctxt->compression = compression;
1905 ctxt->doc_buff = xmlCreateZMemBuff(compression);
1906 } else
Daniel Veillardf012a642001-07-23 19:10:52 +00001907#endif
1908 {
Daniel Veillard572577e2002-01-18 16:23:55 +00001909 /* Any character conversions should have been done before this */
Daniel Veillardf012a642001-07-23 19:10:52 +00001910
Daniel Veillardda3fee42008-09-01 13:08:57 +00001911 ctxt->doc_buff = xmlAllocOutputBufferInternal(NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001912 }
1913
Daniel Veillard572577e2002-01-18 16:23:55 +00001914 if (ctxt->doc_buff == NULL) {
1915 xmlFreeHTTPWriteCtxt(ctxt);
1916 ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001917 }
1918
Daniel Veillard572577e2002-01-18 16:23:55 +00001919 return (ctxt);
Daniel Veillardf012a642001-07-23 19:10:52 +00001920}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001921#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardda3fee42008-09-01 13:08:57 +00001922
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001923#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001924/**
1925 * xmlIOHTTPDfltOpenW
1926 * @post_uri: The destination URI for this document.
1927 *
1928 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
1929 * HTTP post command. This function should generally not be used as
1930 * the open callback is short circuited in xmlOutputBufferCreateFile.
1931 *
1932 * Returns a pointer to the new IO context.
1933 */
1934static void *
1935xmlIOHTTPDfltOpenW( const char * post_uri ) {
1936 return ( xmlIOHTTPOpenW( post_uri, 0 ) );
1937}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001938#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001939
1940/**
Owen Taylor3473f882001-02-23 17:55:21 +00001941 * xmlIOHTTPRead:
1942 * @context: the I/O context
1943 * @buffer: where to drop data
1944 * @len: number of bytes to write
1945 *
1946 * Read @len bytes to @buffer from the I/O channel.
1947 *
1948 * Returns the number of bytes written
1949 */
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001950int
Owen Taylor3473f882001-02-23 17:55:21 +00001951xmlIOHTTPRead(void * context, char * buffer, int len) {
Daniel Veillard5ea30d72004-11-08 11:54:28 +00001952 if ((buffer == NULL) || (len < 0)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001953 return(xmlNanoHTTPRead(context, &buffer[0], len));
1954}
1955
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001956#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001957/**
Daniel Veillardf012a642001-07-23 19:10:52 +00001958 * xmlIOHTTPWrite
1959 * @context: previously opened writing context
1960 * @buffer: data to output to temporary buffer
1961 * @len: bytes to output
1962 *
1963 * Collect data from memory buffer into a temporary file for later
1964 * processing.
1965 *
1966 * Returns number of bytes written.
1967 */
1968
1969static int
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001970xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001971
1972 xmlIOHTTPWriteCtxtPtr ctxt = context;
1973
1974 if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
1975 return ( -1 );
1976
1977 if ( len > 0 ) {
1978
1979 /* Use gzwrite or fwrite as previously setup in the open call */
1980
1981#ifdef HAVE_ZLIB_H
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001982 if ( ctxt->compression > 0 )
Daniel Veillardf012a642001-07-23 19:10:52 +00001983 len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len );
1984
1985 else
1986#endif
1987 len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
1988
1989 if ( len < 0 ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001990 xmlChar msg[500];
1991 xmlStrPrintf(msg, 500,
1992 (const xmlChar *) "xmlIOHTTPWrite: %s\n%s '%s'.\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001993 "Error appending to internal buffer.",
1994 "Error sending document to URI",
1995 ctxt->uri );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001996 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001997 }
1998 }
1999
2000 return ( len );
2001}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002002#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00002003
2004
2005/**
Owen Taylor3473f882001-02-23 17:55:21 +00002006 * xmlIOHTTPClose:
2007 * @context: the I/O context
2008 *
2009 * Close an HTTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00002010 *
2011 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00002012 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002013int
Owen Taylor3473f882001-02-23 17:55:21 +00002014xmlIOHTTPClose (void * context) {
2015 xmlNanoHTTPClose(context);
Daniel Veillardf012a642001-07-23 19:10:52 +00002016 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002017}
Daniel Veillardf012a642001-07-23 19:10:52 +00002018
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002019#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00002020/**
2021 * xmlIOHTTCloseWrite
2022 * @context: The I/O context
2023 * @http_mthd: The HTTP method to be used when sending the data
2024 *
2025 * Close the transmit HTTP I/O channel and actually send the data.
2026 */
2027static int
2028xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
2029
2030 int close_rc = -1;
2031 int http_rtn = 0;
2032 int content_lgth = 0;
2033 xmlIOHTTPWriteCtxtPtr ctxt = context;
2034
2035 char * http_content = NULL;
2036 char * content_encoding = NULL;
2037 char * content_type = (char *) "text/xml";
2038 void * http_ctxt = NULL;
2039
2040 if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
2041 return ( -1 );
2042
2043 /* Retrieve the content from the appropriate buffer */
2044
2045#ifdef HAVE_ZLIB_H
2046
2047 if ( ctxt->compression > 0 ) {
2048 content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
2049 content_encoding = (char *) "Content-Encoding: gzip";
2050 }
2051 else
2052#endif
2053 {
2054 /* Pull the data out of the memory output buffer */
2055
2056 xmlOutputBufferPtr dctxt = ctxt->doc_buff;
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002057 http_content = (char *) xmlBufContent(dctxt->buffer);
2058 content_lgth = xmlBufUse(dctxt->buffer);
Daniel Veillardf012a642001-07-23 19:10:52 +00002059 }
2060
2061 if ( http_content == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002062 xmlChar msg[500];
2063 xmlStrPrintf(msg, 500,
2064 (const xmlChar *) "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
2065 "Error retrieving content.\nUnable to",
2066 http_mthd, "data to URI", ctxt->uri );
2067 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00002068 }
2069
2070 else {
2071
2072 http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
Hans Breuer2ad41ca2009-08-11 17:51:22 +02002073 &content_type, content_encoding,
Daniel Veillardf012a642001-07-23 19:10:52 +00002074 content_lgth );
2075
2076 if ( http_ctxt != NULL ) {
2077#ifdef DEBUG_HTTP
2078 /* If testing/debugging - dump reply with request content */
2079
2080 FILE * tst_file = NULL;
2081 char buffer[ 4096 ];
2082 char * dump_name = NULL;
2083 int avail;
2084
2085 xmlGenericError( xmlGenericErrorContext,
2086 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
2087 http_mthd, ctxt->uri,
2088 xmlNanoHTTPReturnCode( http_ctxt ) );
2089
2090 /*
2091 ** Since either content or reply may be gzipped,
Hans Breuer2ad41ca2009-08-11 17:51:22 +02002092 ** dump them to separate files instead of the
Daniel Veillardf012a642001-07-23 19:10:52 +00002093 ** standard error context.
2094 */
2095
2096 dump_name = tempnam( NULL, "lxml" );
2097 if ( dump_name != NULL ) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002098 (void)snprintf( buffer, sizeof(buffer), "%s.content", dump_name );
Daniel Veillardf012a642001-07-23 19:10:52 +00002099
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00002100 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00002101 if ( tst_file != NULL ) {
2102 xmlGenericError( xmlGenericErrorContext,
2103 "Transmitted content saved in file: %s\n", buffer );
2104
2105 fwrite( http_content, sizeof( char ),
2106 content_lgth, tst_file );
2107 fclose( tst_file );
2108 }
2109
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002110 (void)snprintf( buffer, sizeof(buffer), "%s.reply", dump_name );
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00002111 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00002112 if ( tst_file != NULL ) {
2113 xmlGenericError( xmlGenericErrorContext,
2114 "Reply content saved in file: %s\n", buffer );
2115
2116
2117 while ( (avail = xmlNanoHTTPRead( http_ctxt,
2118 buffer, sizeof( buffer ) )) > 0 ) {
2119
2120 fwrite( buffer, sizeof( char ), avail, tst_file );
2121 }
2122
2123 fclose( tst_file );
2124 }
2125
2126 free( dump_name );
2127 }
2128#endif /* DEBUG_HTTP */
2129
2130 http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
2131 if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
2132 close_rc = 0;
Daniel Veillard05d987b2003-10-08 11:54:57 +00002133 else {
2134 xmlChar msg[500];
2135 xmlStrPrintf(msg, 500,
2136 (const xmlChar *) "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00002137 http_mthd, content_lgth,
2138 "bytes to URI", ctxt->uri,
2139 "failed. HTTP return code:", http_rtn );
Daniel Veillard05d987b2003-10-08 11:54:57 +00002140 xmlIOErr(XML_IO_WRITE, (const char *) msg);
2141 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002142
2143 xmlNanoHTTPClose( http_ctxt );
2144 xmlFree( content_type );
2145 }
2146 }
2147
2148 /* Final cleanups */
2149
2150 xmlFreeHTTPWriteCtxt( ctxt );
2151
2152 return ( close_rc );
2153}
2154
2155/**
2156 * xmlIOHTTPClosePut
2157 *
2158 * @context: The I/O context
2159 *
2160 * Close the transmit HTTP I/O channel and actually send data using a PUT
2161 * HTTP method.
2162 */
2163static int
2164xmlIOHTTPClosePut( void * ctxt ) {
2165 return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
2166}
2167
2168
2169/**
2170 * xmlIOHTTPClosePost
2171 *
2172 * @context: The I/O context
2173 *
2174 * Close the transmit HTTP I/O channel and actually send data using a POST
2175 * HTTP method.
2176 */
2177static int
2178xmlIOHTTPClosePost( void * ctxt ) {
2179 return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
2180}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002181#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00002182
Owen Taylor3473f882001-02-23 17:55:21 +00002183#endif /* LIBXML_HTTP_ENABLED */
2184
2185#ifdef LIBXML_FTP_ENABLED
2186/************************************************************************
2187 * *
2188 * I/O for FTP file accesses *
2189 * *
2190 ************************************************************************/
2191/**
2192 * xmlIOFTPMatch:
2193 * @filename: the URI for matching
2194 *
2195 * check if the URI matches an FTP one
2196 *
2197 * Returns 1 if matches, 0 otherwise
2198 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002199int
Owen Taylor3473f882001-02-23 17:55:21 +00002200xmlIOFTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002201 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "ftp://", 6))
Owen Taylor3473f882001-02-23 17:55:21 +00002202 return(1);
2203 return(0);
2204}
2205
2206/**
2207 * xmlIOFTPOpen:
2208 * @filename: the URI for matching
2209 *
2210 * open an FTP I/O channel
2211 *
2212 * Returns an I/O context or NULL in case of error
2213 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002214void *
Owen Taylor3473f882001-02-23 17:55:21 +00002215xmlIOFTPOpen (const char *filename) {
2216 return(xmlNanoFTPOpen(filename));
2217}
2218
2219/**
2220 * xmlIOFTPRead:
2221 * @context: the I/O context
2222 * @buffer: where to drop data
2223 * @len: number of bytes to write
2224 *
2225 * Read @len bytes to @buffer from the I/O channel.
2226 *
2227 * Returns the number of bytes written
2228 */
Hans Breuer2ad41ca2009-08-11 17:51:22 +02002229int
Owen Taylor3473f882001-02-23 17:55:21 +00002230xmlIOFTPRead(void * context, char * buffer, int len) {
Daniel Veillard5ea30d72004-11-08 11:54:28 +00002231 if ((buffer == NULL) || (len < 0)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002232 return(xmlNanoFTPRead(context, &buffer[0], len));
2233}
2234
2235/**
2236 * xmlIOFTPClose:
2237 * @context: the I/O context
2238 *
2239 * Close an FTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00002240 *
2241 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00002242 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002243int
Owen Taylor3473f882001-02-23 17:55:21 +00002244xmlIOFTPClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +00002245 return ( xmlNanoFTPClose(context) );
Owen Taylor3473f882001-02-23 17:55:21 +00002246}
2247#endif /* LIBXML_FTP_ENABLED */
2248
2249
2250/**
2251 * xmlRegisterInputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002252 * @matchFunc: the xmlInputMatchCallback
2253 * @openFunc: the xmlInputOpenCallback
2254 * @readFunc: the xmlInputReadCallback
2255 * @closeFunc: the xmlInputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00002256 *
2257 * Register a new set of I/O callback for handling parser input.
2258 *
2259 * Returns the registered handler number or -1 in case of error
2260 */
2261int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002262xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
2263 xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
2264 xmlInputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002265 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
2266 return(-1);
2267 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002268 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
2269 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
2270 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
2271 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00002272 xmlInputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002273 return(xmlInputCallbackNr++);
2274}
2275
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002276#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002277/**
2278 * xmlRegisterOutputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002279 * @matchFunc: the xmlOutputMatchCallback
2280 * @openFunc: the xmlOutputOpenCallback
2281 * @writeFunc: the xmlOutputWriteCallback
2282 * @closeFunc: the xmlOutputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00002283 *
2284 * Register a new set of I/O callback for handling output.
2285 *
2286 * Returns the registered handler number or -1 in case of error
2287 */
2288int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002289xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
2290 xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
2291 xmlOutputCloseCallback closeFunc) {
Daniel Veillard0d5e58f2009-08-24 13:52:23 +02002292 if (xmlOutputCallbackNr >= MAX_OUTPUT_CALLBACK) {
Owen Taylor3473f882001-02-23 17:55:21 +00002293 return(-1);
2294 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002295 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
2296 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
2297 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
2298 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00002299 xmlOutputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002300 return(xmlOutputCallbackNr++);
2301}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002302#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002303
2304/**
2305 * xmlRegisterDefaultInputCallbacks:
2306 *
2307 * Registers the default compiled-in I/O handlers.
2308 */
2309void
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +00002310xmlRegisterDefaultInputCallbacks(void) {
Owen Taylor3473f882001-02-23 17:55:21 +00002311 if (xmlInputCallbackInitialized)
2312 return;
2313
Daniel Veillard8ca85b22006-09-01 09:56:07 +00002314#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
2315 xmlInitPlatformSpecificIo();
2316#endif
2317
Owen Taylor3473f882001-02-23 17:55:21 +00002318 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
2319 xmlFileRead, xmlFileClose);
2320#ifdef HAVE_ZLIB_H
2321 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
2322 xmlGzfileRead, xmlGzfileClose);
2323#endif /* HAVE_ZLIB_H */
Anders F Bjorklundeae52612011-09-18 16:59:13 +02002324#ifdef HAVE_LZMA_H
2325 xmlRegisterInputCallbacks(xmlXzfileMatch, xmlXzfileOpen,
2326 xmlXzfileRead, xmlXzfileClose);
2327#endif /* HAVE_ZLIB_H */
Owen Taylor3473f882001-02-23 17:55:21 +00002328
2329#ifdef LIBXML_HTTP_ENABLED
2330 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
2331 xmlIOHTTPRead, xmlIOHTTPClose);
2332#endif /* LIBXML_HTTP_ENABLED */
2333
2334#ifdef LIBXML_FTP_ENABLED
2335 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
2336 xmlIOFTPRead, xmlIOFTPClose);
2337#endif /* LIBXML_FTP_ENABLED */
2338 xmlInputCallbackInitialized = 1;
2339}
2340
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002341#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002342/**
2343 * xmlRegisterDefaultOutputCallbacks:
2344 *
2345 * Registers the default compiled-in I/O handlers.
2346 */
2347void
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +00002348xmlRegisterDefaultOutputCallbacks (void) {
Owen Taylor3473f882001-02-23 17:55:21 +00002349 if (xmlOutputCallbackInitialized)
2350 return;
2351
Daniel Veillard8ca85b22006-09-01 09:56:07 +00002352#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
2353 xmlInitPlatformSpecificIo();
2354#endif
2355
Owen Taylor3473f882001-02-23 17:55:21 +00002356 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
2357 xmlFileWrite, xmlFileClose);
Daniel Veillardf012a642001-07-23 19:10:52 +00002358
2359#ifdef LIBXML_HTTP_ENABLED
2360 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
2361 xmlIOHTTPWrite, xmlIOHTTPClosePut);
2362#endif
2363
Owen Taylor3473f882001-02-23 17:55:21 +00002364/*********************************
2365 No way a-priori to distinguish between gzipped files from
2366 uncompressed ones except opening if existing then closing
2367 and saving with same compression ratio ... a pain.
2368
2369#ifdef HAVE_ZLIB_H
2370 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
2371 xmlGzfileWrite, xmlGzfileClose);
2372#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002373
2374 Nor FTP PUT ....
2375#ifdef LIBXML_FTP_ENABLED
2376 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
2377 xmlIOFTPWrite, xmlIOFTPClose);
2378#endif
2379 **********************************/
2380 xmlOutputCallbackInitialized = 1;
2381}
2382
Daniel Veillardf012a642001-07-23 19:10:52 +00002383#ifdef LIBXML_HTTP_ENABLED
2384/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00002385 * xmlRegisterHTTPPostCallbacks:
Daniel Veillardf012a642001-07-23 19:10:52 +00002386 *
2387 * By default, libxml submits HTTP output requests using the "PUT" method.
2388 * Calling this method changes the HTTP output method to use the "POST"
2389 * method instead.
2390 *
2391 */
2392void
2393xmlRegisterHTTPPostCallbacks( void ) {
2394
2395 /* Register defaults if not done previously */
2396
2397 if ( xmlOutputCallbackInitialized == 0 )
2398 xmlRegisterDefaultOutputCallbacks( );
2399
2400 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
2401 xmlIOHTTPWrite, xmlIOHTTPClosePost);
2402 return;
2403}
2404#endif
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002405#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00002406
Owen Taylor3473f882001-02-23 17:55:21 +00002407/**
2408 * xmlAllocParserInputBuffer:
2409 * @enc: the charset encoding if known
2410 *
2411 * Create a buffered parser input for progressive parsing
2412 *
2413 * Returns the new parser input or NULL
2414 */
2415xmlParserInputBufferPtr
2416xmlAllocParserInputBuffer(xmlCharEncoding enc) {
2417 xmlParserInputBufferPtr ret;
2418
2419 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2420 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002421 xmlIOErrMemory("creating input buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00002422 return(NULL);
2423 }
2424 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002425 ret->buffer = xmlBufCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00002426 if (ret->buffer == NULL) {
2427 xmlFree(ret);
2428 return(NULL);
2429 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002430 xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_DOUBLEIT);
Owen Taylor3473f882001-02-23 17:55:21 +00002431 ret->encoder = xmlGetCharEncodingHandler(enc);
2432 if (ret->encoder != NULL)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002433 ret->raw = xmlBufCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00002434 else
2435 ret->raw = NULL;
2436 ret->readcallback = NULL;
2437 ret->closecallback = NULL;
2438 ret->context = NULL;
William M. Brackc07329e2003-09-08 01:57:30 +00002439 ret->compressed = -1;
Daniel Veillard36711902004-02-11 13:25:26 +00002440 ret->rawconsumed = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002441
2442 return(ret);
2443}
2444
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002445#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002446/**
2447 * xmlAllocOutputBuffer:
2448 * @encoder: the encoding converter or NULL
2449 *
2450 * Create a buffered parser output
2451 *
2452 * Returns the new parser output or NULL
2453 */
2454xmlOutputBufferPtr
2455xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
2456 xmlOutputBufferPtr ret;
2457
2458 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
2459 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002460 xmlIOErrMemory("creating output buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00002461 return(NULL);
2462 }
2463 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002464 ret->buffer = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00002465 if (ret->buffer == NULL) {
2466 xmlFree(ret);
2467 return(NULL);
2468 }
Daniel Veillarde83e93e2008-08-30 12:52:26 +00002469
Daniel Veillard43bc89c2009-03-23 19:32:04 +00002470 /* try to avoid a performance problem with Windows realloc() */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002471 if (xmlBufGetAllocationScheme(ret->buffer) == XML_BUFFER_ALLOC_EXACT)
2472 xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_DOUBLEIT);
Daniel Veillard43bc89c2009-03-23 19:32:04 +00002473
Daniel Veillardda3fee42008-09-01 13:08:57 +00002474 ret->encoder = encoder;
2475 if (encoder != NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002476 ret->conv = xmlBufCreateSize(4000);
Daniel Veillardda3fee42008-09-01 13:08:57 +00002477 if (ret->conv == NULL) {
2478 xmlFree(ret);
2479 return(NULL);
2480 }
2481
2482 /*
2483 * This call is designed to initiate the encoder state
2484 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002485 xmlCharEncOutput(ret, 1);
Daniel Veillardda3fee42008-09-01 13:08:57 +00002486 } else
2487 ret->conv = NULL;
2488 ret->writecallback = NULL;
2489 ret->closecallback = NULL;
2490 ret->context = NULL;
2491 ret->written = 0;
2492
2493 return(ret);
2494}
2495
2496/**
2497 * xmlAllocOutputBufferInternal:
2498 * @encoder: the encoding converter or NULL
2499 *
2500 * Create a buffered parser output
2501 *
2502 * Returns the new parser output or NULL
2503 */
2504xmlOutputBufferPtr
2505xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder) {
2506 xmlOutputBufferPtr ret;
2507
2508 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
2509 if (ret == NULL) {
2510 xmlIOErrMemory("creating output buffer");
2511 return(NULL);
2512 }
2513 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002514 ret->buffer = xmlBufCreate();
Daniel Veillardda3fee42008-09-01 13:08:57 +00002515 if (ret->buffer == NULL) {
2516 xmlFree(ret);
2517 return(NULL);
2518 }
2519
2520
Daniel Veillarde83e93e2008-08-30 12:52:26 +00002521 /*
2522 * For conversion buffers we use the special IO handling
2523 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002524 xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_IO);
Daniel Veillarde83e93e2008-08-30 12:52:26 +00002525
Owen Taylor3473f882001-02-23 17:55:21 +00002526 ret->encoder = encoder;
2527 if (encoder != NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002528 ret->conv = xmlBufCreateSize(4000);
Daniel Veillarde83e93e2008-08-30 12:52:26 +00002529 if (ret->conv == NULL) {
2530 xmlFree(ret);
2531 return(NULL);
2532 }
2533
Owen Taylor3473f882001-02-23 17:55:21 +00002534 /*
2535 * This call is designed to initiate the encoder state
2536 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002537 xmlCharEncOutput(ret, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00002538 } else
2539 ret->conv = NULL;
2540 ret->writecallback = NULL;
2541 ret->closecallback = NULL;
2542 ret->context = NULL;
2543 ret->written = 0;
2544
2545 return(ret);
2546}
Daniel Veillardda3fee42008-09-01 13:08:57 +00002547
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002548#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002549
2550/**
2551 * xmlFreeParserInputBuffer:
2552 * @in: a buffered parser input
2553 *
2554 * Free up the memory used by a buffered parser input
2555 */
2556void
2557xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
Daniel Veillard8d8bf2c2003-09-17 19:36:25 +00002558 if (in == NULL) return;
2559
Owen Taylor3473f882001-02-23 17:55:21 +00002560 if (in->raw) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002561 xmlBufFree(in->raw);
Owen Taylor3473f882001-02-23 17:55:21 +00002562 in->raw = NULL;
2563 }
2564 if (in->encoder != NULL) {
2565 xmlCharEncCloseFunc(in->encoder);
2566 }
2567 if (in->closecallback != NULL) {
2568 in->closecallback(in->context);
2569 }
2570 if (in->buffer != NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002571 xmlBufFree(in->buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00002572 in->buffer = NULL;
2573 }
2574
Owen Taylor3473f882001-02-23 17:55:21 +00002575 xmlFree(in);
2576}
2577
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002578#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002579/**
2580 * xmlOutputBufferClose:
2581 * @out: a buffered output
2582 *
2583 * flushes and close the output I/O channel
2584 * and free up all the associated resources
2585 *
2586 * Returns the number of byte written or -1 in case of error.
2587 */
2588int
Daniel Veillard828ce832003-10-08 19:19:10 +00002589xmlOutputBufferClose(xmlOutputBufferPtr out)
2590{
Owen Taylor3473f882001-02-23 17:55:21 +00002591 int written;
Daniel Veillardf012a642001-07-23 19:10:52 +00002592 int err_rc = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002593
2594 if (out == NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002595 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002596 if (out->writecallback != NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002597 xmlOutputBufferFlush(out);
Owen Taylor3473f882001-02-23 17:55:21 +00002598 if (out->closecallback != NULL) {
Daniel Veillard828ce832003-10-08 19:19:10 +00002599 err_rc = out->closecallback(out->context);
Owen Taylor3473f882001-02-23 17:55:21 +00002600 }
2601 written = out->written;
2602 if (out->conv) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002603 xmlBufFree(out->conv);
Daniel Veillard828ce832003-10-08 19:19:10 +00002604 out->conv = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002605 }
2606 if (out->encoder != NULL) {
2607 xmlCharEncCloseFunc(out->encoder);
2608 }
2609 if (out->buffer != NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002610 xmlBufFree(out->buffer);
Daniel Veillard828ce832003-10-08 19:19:10 +00002611 out->buffer = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002612 }
2613
Daniel Veillard828ce832003-10-08 19:19:10 +00002614 if (out->error)
2615 err_rc = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00002616 xmlFree(out);
Daniel Veillard828ce832003-10-08 19:19:10 +00002617 return ((err_rc == 0) ? written : err_rc);
Owen Taylor3473f882001-02-23 17:55:21 +00002618}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002619#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002620
Daniel Veillard1b243b42004-06-08 10:16:42 +00002621xmlParserInputBufferPtr
Daniel Veillard0335a842004-06-02 16:18:40 +00002622__xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002623 xmlParserInputBufferPtr ret;
Daniel Veillard388236f2001-07-08 18:35:48 +00002624 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002625 void *context = NULL;
2626
2627 if (xmlInputCallbackInitialized == 0)
2628 xmlRegisterDefaultInputCallbacks();
2629
2630 if (URI == NULL) return(NULL);
2631
2632 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002633 * Try to find one of the input accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002634 * Go in reverse to give precedence to user defined handlers.
Daniel Veillard388236f2001-07-08 18:35:48 +00002635 */
2636 if (context == NULL) {
2637 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
2638 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
2639 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002640 context = xmlInputCallbackTable[i].opencallback(URI);
Daniel Veillard847332a2003-10-18 11:29:40 +00002641 if (context != NULL) {
Daniel Veillard388236f2001-07-08 18:35:48 +00002642 break;
Daniel Veillard847332a2003-10-18 11:29:40 +00002643 }
Daniel Veillard388236f2001-07-08 18:35:48 +00002644 }
Owen Taylor3473f882001-02-23 17:55:21 +00002645 }
2646 }
2647 if (context == NULL) {
2648 return(NULL);
2649 }
2650
2651 /*
2652 * Allocate the Input buffer front-end.
2653 */
2654 ret = xmlAllocParserInputBuffer(enc);
2655 if (ret != NULL) {
2656 ret->context = context;
2657 ret->readcallback = xmlInputCallbackTable[i].readcallback;
2658 ret->closecallback = xmlInputCallbackTable[i].closecallback;
William M. Brackc07329e2003-09-08 01:57:30 +00002659#ifdef HAVE_ZLIB_H
William M. Brackc5cbf992003-10-29 22:15:13 +00002660 if ((xmlInputCallbackTable[i].opencallback == xmlGzfileOpen) &&
2661 (strcmp(URI, "-") != 0)) {
Mark Adlera7e79f22010-01-19 16:28:48 +01002662#if defined(ZLIB_VERNUM) && ZLIB_VERNUM >= 0x1230
2663 ret->compressed = !gzdirect(context);
2664#else
William M. Brackc07329e2003-09-08 01:57:30 +00002665 if (((z_stream *)context)->avail_in > 4) {
2666 char *cptr, buff4[4];
Daniel Veillard07cb8222003-09-10 10:51:05 +00002667 cptr = (char *) ((z_stream *)context)->next_in;
William M. Brackc07329e2003-09-08 01:57:30 +00002668 if (gzread(context, buff4, 4) == 4) {
2669 if (strncmp(buff4, cptr, 4) == 0)
2670 ret->compressed = 0;
2671 else
2672 ret->compressed = 1;
2673 gzrewind(context);
2674 }
2675 }
Mark Adlera7e79f22010-01-19 16:28:48 +01002676#endif
William M. Brackc07329e2003-09-08 01:57:30 +00002677 }
2678#endif
Daniel Veillard63588f42013-05-10 14:01:46 +08002679#ifdef HAVE_LZMA_H
2680 if ((xmlInputCallbackTable[i].opencallback == xmlXzfileOpen) &&
2681 (strcmp(URI, "-") != 0)) {
2682 ret->compressed = __libxml2_xzcompressed(context);
2683 }
2684#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002685 }
William M. Brack42331a92004-07-29 07:07:16 +00002686 else
2687 xmlInputCallbackTable[i].closecallback (context);
2688
Owen Taylor3473f882001-02-23 17:55:21 +00002689 return(ret);
2690}
2691
2692/**
Daniel Veillard0335a842004-06-02 16:18:40 +00002693 * xmlParserInputBufferCreateFilename:
Owen Taylor3473f882001-02-23 17:55:21 +00002694 * @URI: a C string containing the URI or filename
Daniel Veillard0335a842004-06-02 16:18:40 +00002695 * @enc: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002696 *
Daniel Veillard0335a842004-06-02 16:18:40 +00002697 * Create a buffered parser input for the progressive parsing of a file
2698 * If filename is "-' then we use stdin as the input.
Owen Taylor3473f882001-02-23 17:55:21 +00002699 * Automatic support for ZLIB/Compress compressed document is provided
2700 * by default if found at compile-time.
Daniel Veillard0335a842004-06-02 16:18:40 +00002701 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
Owen Taylor3473f882001-02-23 17:55:21 +00002702 *
Daniel Veillard0335a842004-06-02 16:18:40 +00002703 * Returns the new parser input or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00002704 */
Daniel Veillard0335a842004-06-02 16:18:40 +00002705xmlParserInputBufferPtr
2706xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
2707 if ((xmlParserInputBufferCreateFilenameValue)) {
2708 return xmlParserInputBufferCreateFilenameValue(URI, enc);
2709 }
2710 return __xmlParserInputBufferCreateFilename(URI, enc);
2711}
2712
2713#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard1b243b42004-06-08 10:16:42 +00002714xmlOutputBufferPtr
Daniel Veillard0335a842004-06-02 16:18:40 +00002715__xmlOutputBufferCreateFilename(const char *URI,
Owen Taylor3473f882001-02-23 17:55:21 +00002716 xmlCharEncodingHandlerPtr encoder,
Daniel Veillard0335a842004-06-02 16:18:40 +00002717 int compression ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00002718 xmlOutputBufferPtr ret;
Daniel Veillard966a31e2004-05-09 02:58:44 +00002719 xmlURIPtr puri;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002720 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002721 void *context = NULL;
Daniel Veillard966a31e2004-05-09 02:58:44 +00002722 char *unescaped = NULL;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002723#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002724 int is_file_uri = 1;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002725#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00002726
Owen Taylor3473f882001-02-23 17:55:21 +00002727 if (xmlOutputCallbackInitialized == 0)
2728 xmlRegisterDefaultOutputCallbacks();
2729
2730 if (URI == NULL) return(NULL);
2731
Daniel Veillard966a31e2004-05-09 02:58:44 +00002732 puri = xmlParseURI(URI);
2733 if (puri != NULL) {
Daniel Veillard8fcd2ca2005-07-03 14:42:56 +00002734#ifdef HAVE_ZLIB_H
Daniel Veillard18a65092004-05-11 15:57:42 +00002735 if ((puri->scheme != NULL) &&
2736 (!xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
Daniel Veillard966a31e2004-05-09 02:58:44 +00002737 is_file_uri = 0;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002738#endif
Daniel Veillard966a31e2004-05-09 02:58:44 +00002739 /*
2740 * try to limit the damages of the URI unescaping code.
2741 */
Daniel Veillarde8967e02006-10-11 09:15:00 +00002742 if ((puri->scheme == NULL) ||
2743 (xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
Daniel Veillard966a31e2004-05-09 02:58:44 +00002744 unescaped = xmlURIUnescapeString(URI, 0, NULL);
2745 xmlFreeURI(puri);
2746 }
Owen Taylor3473f882001-02-23 17:55:21 +00002747
2748 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002749 * Try to find one of the output accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002750 * Go in reverse to give precedence to user defined handlers.
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002751 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00002752 */
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002753 if (unescaped != NULL) {
2754#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002755 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002756 context = xmlGzfileOpenW(unescaped, compression);
2757 if (context != NULL) {
Daniel Veillardda3fee42008-09-01 13:08:57 +00002758 ret = xmlAllocOutputBufferInternal(encoder);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002759 if (ret != NULL) {
2760 ret->context = context;
2761 ret->writecallback = xmlGzfileWrite;
2762 ret->closecallback = xmlGzfileClose;
2763 }
2764 xmlFree(unescaped);
2765 return(ret);
2766 }
2767 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002768#endif
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002769 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2770 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
2771 (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
2772#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2773 /* Need to pass compression parameter into HTTP open calls */
2774 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2775 context = xmlIOHTTPOpenW(unescaped, compression);
2776 else
2777#endif
2778 context = xmlOutputCallbackTable[i].opencallback(unescaped);
2779 if (context != NULL)
2780 break;
2781 }
2782 }
2783 xmlFree(unescaped);
2784 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002785
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002786 /*
2787 * If this failed try with a non-escaped URI this may be a strange
2788 * filename
2789 */
2790 if (context == NULL) {
2791#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002792 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002793 context = xmlGzfileOpenW(URI, compression);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002794 if (context != NULL) {
Daniel Veillardda3fee42008-09-01 13:08:57 +00002795 ret = xmlAllocOutputBufferInternal(encoder);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002796 if (ret != NULL) {
2797 ret->context = context;
2798 ret->writecallback = xmlGzfileWrite;
2799 ret->closecallback = xmlGzfileClose;
2800 }
2801 return(ret);
2802 }
2803 }
2804#endif
2805 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2806 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002807 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002808#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2809 /* Need to pass compression parameter into HTTP open calls */
2810 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2811 context = xmlIOHTTPOpenW(URI, compression);
2812 else
2813#endif
2814 context = xmlOutputCallbackTable[i].opencallback(URI);
2815 if (context != NULL)
2816 break;
2817 }
Owen Taylor3473f882001-02-23 17:55:21 +00002818 }
2819 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002820
Owen Taylor3473f882001-02-23 17:55:21 +00002821 if (context == NULL) {
2822 return(NULL);
2823 }
2824
2825 /*
2826 * Allocate the Output buffer front-end.
2827 */
Daniel Veillardda3fee42008-09-01 13:08:57 +00002828 ret = xmlAllocOutputBufferInternal(encoder);
Owen Taylor3473f882001-02-23 17:55:21 +00002829 if (ret != NULL) {
2830 ret->context = context;
2831 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
2832 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
2833 }
2834 return(ret);
2835}
Daniel Veillard0335a842004-06-02 16:18:40 +00002836
2837/**
2838 * xmlOutputBufferCreateFilename:
2839 * @URI: a C string containing the URI or filename
2840 * @encoder: the encoding converter or NULL
2841 * @compression: the compression ration (0 none, 9 max).
2842 *
2843 * Create a buffered output for the progressive saving of a file
2844 * If filename is "-' then we use stdout as the output.
2845 * Automatic support for ZLIB/Compress compressed document is provided
2846 * by default if found at compile-time.
2847 * TODO: currently if compression is set, the library only support
2848 * writing to a local file.
2849 *
2850 * Returns the new output or NULL
2851 */
2852xmlOutputBufferPtr
2853xmlOutputBufferCreateFilename(const char *URI,
2854 xmlCharEncodingHandlerPtr encoder,
2855 int compression ATTRIBUTE_UNUSED) {
2856 if ((xmlOutputBufferCreateFilenameValue)) {
2857 return xmlOutputBufferCreateFilenameValue(URI, encoder, compression);
2858 }
2859 return __xmlOutputBufferCreateFilename(URI, encoder, compression);
2860}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002861#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002862
2863/**
2864 * xmlParserInputBufferCreateFile:
Hans Breuer2ad41ca2009-08-11 17:51:22 +02002865 * @file: a FILE*
Owen Taylor3473f882001-02-23 17:55:21 +00002866 * @enc: the charset encoding if known
2867 *
2868 * Create a buffered parser input for the progressive parsing of a FILE *
2869 * buffered C I/O
2870 *
2871 * Returns the new parser input or NULL
2872 */
2873xmlParserInputBufferPtr
2874xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
2875 xmlParserInputBufferPtr ret;
2876
2877 if (xmlInputCallbackInitialized == 0)
2878 xmlRegisterDefaultInputCallbacks();
2879
2880 if (file == NULL) return(NULL);
2881
2882 ret = xmlAllocParserInputBuffer(enc);
2883 if (ret != NULL) {
2884 ret->context = file;
2885 ret->readcallback = xmlFileRead;
2886 ret->closecallback = xmlFileFlush;
2887 }
2888
2889 return(ret);
2890}
2891
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002892#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002893/**
2894 * xmlOutputBufferCreateFile:
Hans Breuer2ad41ca2009-08-11 17:51:22 +02002895 * @file: a FILE*
Owen Taylor3473f882001-02-23 17:55:21 +00002896 * @encoder: the encoding converter or NULL
2897 *
2898 * Create a buffered output for the progressive saving to a FILE *
2899 * buffered C I/O
2900 *
2901 * Returns the new parser output or NULL
2902 */
2903xmlOutputBufferPtr
2904xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
2905 xmlOutputBufferPtr ret;
2906
2907 if (xmlOutputCallbackInitialized == 0)
2908 xmlRegisterDefaultOutputCallbacks();
2909
2910 if (file == NULL) return(NULL);
2911
Daniel Veillardda3fee42008-09-01 13:08:57 +00002912 ret = xmlAllocOutputBufferInternal(encoder);
Owen Taylor3473f882001-02-23 17:55:21 +00002913 if (ret != NULL) {
2914 ret->context = file;
2915 ret->writecallback = xmlFileWrite;
2916 ret->closecallback = xmlFileFlush;
2917 }
2918
2919 return(ret);
2920}
Daniel Veillard9a00fd22005-11-09 08:56:26 +00002921
2922/**
2923 * xmlOutputBufferCreateBuffer:
2924 * @buffer: a xmlBufferPtr
2925 * @encoder: the encoding converter or NULL
2926 *
2927 * Create a buffered output for the progressive saving to a xmlBuffer
2928 *
2929 * Returns the new parser output or NULL
2930 */
2931xmlOutputBufferPtr
2932xmlOutputBufferCreateBuffer(xmlBufferPtr buffer,
2933 xmlCharEncodingHandlerPtr encoder) {
2934 xmlOutputBufferPtr ret;
2935
2936 if (buffer == NULL) return(NULL);
2937
Rob Richardsa44f2342005-11-09 18:03:45 +00002938 ret = xmlOutputBufferCreateIO((xmlOutputWriteCallback)
2939 xmlBufferWrite,
2940 (xmlOutputCloseCallback)
Daniel Veillard4d3866c2005-11-13 12:43:59 +00002941 NULL, (void *) buffer, encoder);
Daniel Veillard9a00fd22005-11-09 08:56:26 +00002942
2943 return(ret);
2944}
2945
Daniel Veillarde258ade2012-08-06 11:16:30 +08002946/**
2947 * xmlOutputBufferGetContent:
2948 * @out: an xmlOutputBufferPtr
2949 *
2950 * Gives a pointer to the data currently held in the output buffer
2951 *
2952 * Returns a pointer to the data or NULL in case of error
2953 */
2954const xmlChar *
2955xmlOutputBufferGetContent(xmlOutputBufferPtr out) {
2956 if ((out == NULL) || (out->buffer == NULL))
2957 return(NULL);
2958
2959 return(xmlBufContent(out->buffer));
2960}
2961
2962/**
2963 * xmlOutputBufferGetSize:
2964 * @out: an xmlOutputBufferPtr
2965 *
2966 * Gives the length of the data currently held in the output buffer
2967 *
2968 * Returns 0 in case or error or no data is held, the size otherwise
2969 */
2970size_t
2971xmlOutputBufferGetSize(xmlOutputBufferPtr out) {
2972 if ((out == NULL) || (out->buffer == NULL))
2973 return(0);
2974
2975 return(xmlBufUse(out->buffer));
2976}
2977
2978
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002979#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002980
2981/**
2982 * xmlParserInputBufferCreateFd:
2983 * @fd: a file descriptor number
2984 * @enc: the charset encoding if known
2985 *
2986 * Create a buffered parser input for the progressive parsing for the input
2987 * from a file descriptor
2988 *
2989 * Returns the new parser input or NULL
2990 */
2991xmlParserInputBufferPtr
2992xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
2993 xmlParserInputBufferPtr ret;
2994
2995 if (fd < 0) return(NULL);
2996
2997 ret = xmlAllocParserInputBuffer(enc);
2998 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002999 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00003000 ret->readcallback = xmlFdRead;
3001 ret->closecallback = xmlFdClose;
3002 }
3003
3004 return(ret);
3005}
3006
3007/**
3008 * xmlParserInputBufferCreateMem:
3009 * @mem: the memory input
3010 * @size: the length of the memory block
3011 * @enc: the charset encoding if known
3012 *
3013 * Create a buffered parser input for the progressive parsing for the input
3014 * from a memory area.
3015 *
3016 * Returns the new parser input or NULL
3017 */
3018xmlParserInputBufferPtr
3019xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
3020 xmlParserInputBufferPtr ret;
William M. Bracka3215c72004-07-31 16:24:01 +00003021 int errcode;
Owen Taylor3473f882001-02-23 17:55:21 +00003022
3023 if (size <= 0) return(NULL);
3024 if (mem == NULL) return(NULL);
3025
3026 ret = xmlAllocParserInputBuffer(enc);
3027 if (ret != NULL) {
3028 ret->context = (void *) mem;
3029 ret->readcallback = (xmlInputReadCallback) xmlNop;
3030 ret->closecallback = NULL;
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003031 errcode = xmlBufAdd(ret->buffer, (const xmlChar *) mem, size);
William M. Bracka3215c72004-07-31 16:24:01 +00003032 if (errcode != 0) {
3033 xmlFree(ret);
3034 return(NULL);
3035 }
Owen Taylor3473f882001-02-23 17:55:21 +00003036 }
3037
3038 return(ret);
3039}
3040
3041/**
Daniel Veillard53350552003-09-18 13:35:51 +00003042 * xmlParserInputBufferCreateStatic:
3043 * @mem: the memory input
3044 * @size: the length of the memory block
3045 * @enc: the charset encoding if known
3046 *
3047 * Create a buffered parser input for the progressive parsing for the input
3048 * from an immutable memory area. This will not copy the memory area to
3049 * the buffer, but the memory is expected to be available until the end of
3050 * the parsing, this is useful for example when using mmap'ed file.
3051 *
3052 * Returns the new parser input or NULL
3053 */
3054xmlParserInputBufferPtr
3055xmlParserInputBufferCreateStatic(const char *mem, int size,
3056 xmlCharEncoding enc) {
3057 xmlParserInputBufferPtr ret;
3058
3059 if (size <= 0) return(NULL);
3060 if (mem == NULL) return(NULL);
3061
3062 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
3063 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003064 xmlIOErrMemory("creating input buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00003065 return(NULL);
3066 }
3067 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003068 ret->buffer = xmlBufCreateStatic((void *)mem, (size_t) size);
Daniel Veillard53350552003-09-18 13:35:51 +00003069 if (ret->buffer == NULL) {
3070 xmlFree(ret);
3071 return(NULL);
3072 }
3073 ret->encoder = xmlGetCharEncodingHandler(enc);
3074 if (ret->encoder != NULL)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003075 ret->raw = xmlBufCreateSize(2 * xmlDefaultBufferSize);
Daniel Veillard53350552003-09-18 13:35:51 +00003076 else
3077 ret->raw = NULL;
3078 ret->compressed = -1;
3079 ret->context = (void *) mem;
3080 ret->readcallback = NULL;
3081 ret->closecallback = NULL;
3082
3083 return(ret);
3084}
3085
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003086#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard53350552003-09-18 13:35:51 +00003087/**
Owen Taylor3473f882001-02-23 17:55:21 +00003088 * xmlOutputBufferCreateFd:
3089 * @fd: a file descriptor number
3090 * @encoder: the encoding converter or NULL
3091 *
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003092 * Create a buffered output for the progressive saving
Owen Taylor3473f882001-02-23 17:55:21 +00003093 * to a file descriptor
3094 *
3095 * Returns the new parser output or NULL
3096 */
3097xmlOutputBufferPtr
3098xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
3099 xmlOutputBufferPtr ret;
3100
3101 if (fd < 0) return(NULL);
3102
Daniel Veillardda3fee42008-09-01 13:08:57 +00003103 ret = xmlAllocOutputBufferInternal(encoder);
Owen Taylor3473f882001-02-23 17:55:21 +00003104 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00003105 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00003106 ret->writecallback = xmlFdWrite;
Daniel Veillard7db38712002-02-07 16:39:11 +00003107 ret->closecallback = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003108 }
3109
3110 return(ret);
3111}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003112#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003113
3114/**
3115 * xmlParserInputBufferCreateIO:
3116 * @ioread: an I/O read function
3117 * @ioclose: an I/O close function
3118 * @ioctx: an I/O handler
3119 * @enc: the charset encoding if known
3120 *
3121 * Create a buffered parser input for the progressive parsing for the input
3122 * from an I/O handler
3123 *
3124 * Returns the new parser input or NULL
3125 */
3126xmlParserInputBufferPtr
3127xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
3128 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
3129 xmlParserInputBufferPtr ret;
3130
3131 if (ioread == NULL) return(NULL);
3132
3133 ret = xmlAllocParserInputBuffer(enc);
3134 if (ret != NULL) {
3135 ret->context = (void *) ioctx;
3136 ret->readcallback = ioread;
3137 ret->closecallback = ioclose;
3138 }
3139
3140 return(ret);
3141}
3142
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003143#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003144/**
3145 * xmlOutputBufferCreateIO:
3146 * @iowrite: an I/O write function
3147 * @ioclose: an I/O close function
3148 * @ioctx: an I/O handler
Daniel Veillard9d06d302002-01-22 18:15:52 +00003149 * @encoder: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00003150 *
3151 * Create a buffered output for the progressive saving
3152 * to an I/O handler
3153 *
3154 * Returns the new parser output or NULL
3155 */
3156xmlOutputBufferPtr
3157xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
3158 xmlOutputCloseCallback ioclose, void *ioctx,
3159 xmlCharEncodingHandlerPtr encoder) {
3160 xmlOutputBufferPtr ret;
3161
3162 if (iowrite == NULL) return(NULL);
3163
Daniel Veillardda3fee42008-09-01 13:08:57 +00003164 ret = xmlAllocOutputBufferInternal(encoder);
Owen Taylor3473f882001-02-23 17:55:21 +00003165 if (ret != NULL) {
3166 ret->context = (void *) ioctx;
3167 ret->writecallback = iowrite;
3168 ret->closecallback = ioclose;
3169 }
3170
3171 return(ret);
3172}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003173#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003174
3175/**
Daniel Veillard1b243b42004-06-08 10:16:42 +00003176 * xmlParserInputBufferCreateFilenameDefault:
3177 * @func: function pointer to the new ParserInputBufferCreateFilenameFunc
3178 *
3179 * Registers a callback for URI input file handling
3180 *
3181 * Returns the old value of the registration function
3182 */
3183xmlParserInputBufferCreateFilenameFunc
3184xmlParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func)
3185{
3186 xmlParserInputBufferCreateFilenameFunc old = xmlParserInputBufferCreateFilenameValue;
3187 if (old == NULL) {
3188 old = __xmlParserInputBufferCreateFilename;
3189 }
3190
3191 xmlParserInputBufferCreateFilenameValue = func;
3192 return(old);
3193}
3194
3195/**
3196 * xmlOutputBufferCreateFilenameDefault:
3197 * @func: function pointer to the new OutputBufferCreateFilenameFunc
3198 *
3199 * Registers a callback for URI output file handling
3200 *
3201 * Returns the old value of the registration function
3202 */
3203xmlOutputBufferCreateFilenameFunc
3204xmlOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func)
3205{
3206 xmlOutputBufferCreateFilenameFunc old = xmlOutputBufferCreateFilenameValue;
3207#ifdef LIBXML_OUTPUT_ENABLED
3208 if (old == NULL) {
3209 old = __xmlOutputBufferCreateFilename;
3210 }
3211#endif
3212 xmlOutputBufferCreateFilenameValue = func;
3213 return(old);
3214}
3215
3216/**
Owen Taylor3473f882001-02-23 17:55:21 +00003217 * xmlParserInputBufferPush:
3218 * @in: a buffered parser input
3219 * @len: the size in bytes of the array.
3220 * @buf: an char array
3221 *
3222 * Push the content of the arry in the input buffer
3223 * This routine handle the I18N transcoding to internal UTF-8
3224 * This is used when operating the parser in progressive (push) mode.
3225 *
3226 * Returns the number of chars read and stored in the buffer, or -1
3227 * in case of error.
3228 */
3229int
3230xmlParserInputBufferPush(xmlParserInputBufferPtr in,
3231 int len, const char *buf) {
3232 int nbchars = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00003233 int ret;
Owen Taylor3473f882001-02-23 17:55:21 +00003234
3235 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003236 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003237 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00003238 unsigned int use;
3239
Owen Taylor3473f882001-02-23 17:55:21 +00003240 /*
3241 * Store the data in the incoming raw buffer
3242 */
3243 if (in->raw == NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003244 in->raw = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00003245 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003246 ret = xmlBufAdd(in->raw, (const xmlChar *) buf, len);
William M. Bracka3215c72004-07-31 16:24:01 +00003247 if (ret != 0)
3248 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003249
3250 /*
3251 * convert as much as possible to the parser reading buffer.
3252 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003253 use = xmlBufUse(in->raw);
Daniel Veillardbf058dc2013-02-13 18:19:42 +08003254 nbchars = xmlCharEncInput(in, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003255 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003256 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003257 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003258 return(-1);
3259 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003260 in->rawconsumed += (use - xmlBufUse(in->raw));
Owen Taylor3473f882001-02-23 17:55:21 +00003261 } else {
3262 nbchars = len;
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003263 ret = xmlBufAdd(in->buffer, (xmlChar *) buf, nbchars);
William M. Bracka3215c72004-07-31 16:24:01 +00003264 if (ret != 0)
3265 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003266 }
3267#ifdef DEBUG_INPUT
3268 xmlGenericError(xmlGenericErrorContext,
3269 "I/O: pushed %d chars, buffer %d/%d\n",
Roumen Petrov89b6f732012-08-04 05:09:56 +03003270 nbchars, xmlBufUse(in->buffer), xmlBufLength(in->buffer));
Owen Taylor3473f882001-02-23 17:55:21 +00003271#endif
3272 return(nbchars);
3273}
3274
3275/**
Daniel Veillardddffd2a2002-03-05 20:28:20 +00003276 * endOfInput:
3277 *
3278 * When reading from an Input channel indicated end of file or error
3279 * don't reread from it again.
3280 */
3281static int
3282endOfInput (void * context ATTRIBUTE_UNUSED,
3283 char * buffer ATTRIBUTE_UNUSED,
3284 int len ATTRIBUTE_UNUSED) {
3285 return(0);
3286}
3287
3288/**
Owen Taylor3473f882001-02-23 17:55:21 +00003289 * xmlParserInputBufferGrow:
3290 * @in: a buffered parser input
3291 * @len: indicative value of the amount of chars to read
3292 *
3293 * Grow up the content of the input buffer, the old data are preserved
3294 * This routine handle the I18N transcoding to internal UTF-8
3295 * This routine is used when operating the parser in normal (pull) mode
3296 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003297 * TODO: one should be able to remove one extra copy by copying directly
Owen Taylor3473f882001-02-23 17:55:21 +00003298 * onto in->buffer or in->raw
3299 *
3300 * Returns the number of chars read and stored in the buffer, or -1
3301 * in case of error.
3302 */
3303int
3304xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
3305 char *buffer = NULL;
3306 int res = 0;
3307 int nbchars = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003308
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003309 if ((in == NULL) || (in->error)) return(-1);
Daniel Veillard6155d8a2003-08-19 15:01:28 +00003310 if ((len <= MINLEN) && (len != 4))
Owen Taylor3473f882001-02-23 17:55:21 +00003311 len = MINLEN;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00003312
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003313 if (xmlBufAvail(in->buffer) <= 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003314 xmlIOErr(XML_IO_BUFFER_FULL, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003315 in->error = XML_IO_BUFFER_FULL;
William M. Bracka3215c72004-07-31 16:24:01 +00003316 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003317 }
Owen Taylor3473f882001-02-23 17:55:21 +00003318
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003319 if (xmlBufGrow(in->buffer, len + 1) < 0) {
3320 xmlIOErrMemory("growing input buffer");
3321 in->error = XML_ERR_NO_MEMORY;
3322 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003323 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003324 buffer = (char *)xmlBufEnd(in->buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00003325
3326 /*
3327 * Call the read method for this I/O type.
3328 */
3329 if (in->readcallback != NULL) {
3330 res = in->readcallback(in->context, &buffer[0], len);
Daniel Veillardddffd2a2002-03-05 20:28:20 +00003331 if (res <= 0)
3332 in->readcallback = endOfInput;
Owen Taylor3473f882001-02-23 17:55:21 +00003333 } else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003334 xmlIOErr(XML_IO_NO_INPUT, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003335 in->error = XML_IO_NO_INPUT;
Owen Taylor3473f882001-02-23 17:55:21 +00003336 return(-1);
3337 }
3338 if (res < 0) {
Owen Taylor3473f882001-02-23 17:55:21 +00003339 return(-1);
3340 }
Daniel Veillard63588f42013-05-10 14:01:46 +08003341
3342 /*
3343 * try to establish compressed status of input if not done already
3344 */
3345 if (in->compressed == -1) {
3346#ifdef HAVE_LZMA_H
3347 if (in->readcallback == xmlXzfileRead)
3348 in->compressed = __libxml2_xzcompressed(in->context);
3349#endif
3350 }
3351
Owen Taylor3473f882001-02-23 17:55:21 +00003352 len = res;
3353 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00003354 unsigned int use;
3355
Owen Taylor3473f882001-02-23 17:55:21 +00003356 /*
3357 * Store the data in the incoming raw buffer
3358 */
3359 if (in->raw == NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003360 in->raw = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00003361 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003362 res = xmlBufAdd(in->raw, (const xmlChar *) buffer, len);
William M. Bracka3215c72004-07-31 16:24:01 +00003363 if (res != 0)
3364 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003365
3366 /*
3367 * convert as much as possible to the parser reading buffer.
3368 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003369 use = xmlBufUse(in->raw);
Daniel Veillardbf058dc2013-02-13 18:19:42 +08003370 nbchars = xmlCharEncInput(in, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003371 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003372 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003373 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003374 return(-1);
3375 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003376 in->rawconsumed += (use - xmlBufUse(in->raw));
Owen Taylor3473f882001-02-23 17:55:21 +00003377 } else {
3378 nbchars = len;
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003379 xmlBufAddLen(in->buffer, nbchars);
Owen Taylor3473f882001-02-23 17:55:21 +00003380 }
3381#ifdef DEBUG_INPUT
3382 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003383 "I/O: read %d chars, buffer %d\n",
3384 nbchars, xmlBufUse(in->buffer));
Owen Taylor3473f882001-02-23 17:55:21 +00003385#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003386 return(nbchars);
3387}
3388
3389/**
3390 * xmlParserInputBufferRead:
3391 * @in: a buffered parser input
3392 * @len: indicative value of the amount of chars to read
3393 *
3394 * Refresh the content of the input buffer, the old data are considered
3395 * consumed
3396 * This routine handle the I18N transcoding to internal UTF-8
3397 *
3398 * Returns the number of chars read and stored in the buffer, or -1
3399 * in case of error.
3400 */
3401int
3402xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003403 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003404 if (in->readcallback != NULL)
3405 return(xmlParserInputBufferGrow(in, len));
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003406 else if (xmlBufGetAllocationScheme(in->buffer) == XML_BUFFER_ALLOC_IMMUTABLE)
Daniel Veillard53350552003-09-18 13:35:51 +00003407 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003408 else
3409 return(-1);
3410}
3411
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003412#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003413/**
3414 * xmlOutputBufferWrite:
3415 * @out: a buffered parser output
3416 * @len: the size in bytes of the array.
3417 * @buf: an char array
3418 *
3419 * Write the content of the array in the output I/O buffer
3420 * This routine handle the I18N transcoding from internal UTF-8
3421 * The buffer is lossless, i.e. will store in case of partial
3422 * or delayed writes.
3423 *
3424 * Returns the number of chars immediately written, or -1
3425 * in case of error.
3426 */
3427int
3428xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
3429 int nbchars = 0; /* number of chars to output to I/O */
3430 int ret; /* return from function call */
3431 int written = 0; /* number of char written to I/O so far */
3432 int chunk; /* number of byte curreent processed from buf */
3433
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003434 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003435 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003436 if (out->error) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003437
3438 do {
3439 chunk = len;
3440 if (chunk > 4 * MINLEN)
3441 chunk = 4 * MINLEN;
3442
3443 /*
3444 * first handle encoding stuff.
3445 */
3446 if (out->encoder != NULL) {
3447 /*
3448 * Store the data in the incoming raw buffer
3449 */
3450 if (out->conv == NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003451 out->conv = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00003452 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003453 ret = xmlBufAdd(out->buffer, (const xmlChar *) buf, chunk);
William M. Bracka3215c72004-07-31 16:24:01 +00003454 if (ret != 0)
3455 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003456
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003457 if ((xmlBufUse(out->buffer) < MINLEN) && (chunk == len))
Owen Taylor3473f882001-02-23 17:55:21 +00003458 goto done;
3459
3460 /*
3461 * convert as much as possible to the parser reading buffer.
3462 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003463 ret = xmlCharEncOutput(out, 0);
Daniel Veillard809faa52003-02-10 15:43:53 +00003464 if ((ret < 0) && (ret != -3)) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003465 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003466 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003467 return(-1);
3468 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003469 nbchars = xmlBufUse(out->conv);
Owen Taylor3473f882001-02-23 17:55:21 +00003470 } else {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003471 ret = xmlBufAdd(out->buffer, (const xmlChar *) buf, chunk);
William M. Bracka3215c72004-07-31 16:24:01 +00003472 if (ret != 0)
3473 return(-1);
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003474 nbchars = xmlBufUse(out->buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00003475 }
3476 buf += chunk;
3477 len -= chunk;
3478
3479 if ((nbchars < MINLEN) && (len <= 0))
3480 goto done;
3481
3482 if (out->writecallback) {
3483 /*
3484 * second write the stuff to the I/O channel
3485 */
3486 if (out->encoder != NULL) {
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003487 ret = out->writecallback(out->context,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003488 (const char *)xmlBufContent(out->conv), nbchars);
Owen Taylor3473f882001-02-23 17:55:21 +00003489 if (ret >= 0)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003490 xmlBufShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003491 } else {
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003492 ret = out->writecallback(out->context,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003493 (const char *)xmlBufContent(out->buffer), nbchars);
Owen Taylor3473f882001-02-23 17:55:21 +00003494 if (ret >= 0)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003495 xmlBufShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003496 }
3497 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003498 xmlIOErr(XML_IO_WRITE, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003499 out->error = XML_IO_WRITE;
Owen Taylor3473f882001-02-23 17:55:21 +00003500 return(ret);
3501 }
3502 out->written += ret;
3503 }
3504 written += nbchars;
3505 } while (len > 0);
3506
3507done:
3508#ifdef DEBUG_INPUT
3509 xmlGenericError(xmlGenericErrorContext,
3510 "I/O: wrote %d chars\n", written);
3511#endif
3512 return(written);
3513}
3514
3515/**
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003516 * xmlEscapeContent:
3517 * @out: a pointer to an array of bytes to store the result
3518 * @outlen: the length of @out
3519 * @in: a pointer to an array of unescaped UTF-8 bytes
3520 * @inlen: the length of @in
3521 *
3522 * Take a block of UTF-8 chars in and escape them.
3523 * Returns 0 if success, or -1 otherwise
3524 * The value of @inlen after return is the number of octets consumed
3525 * if the return value is positive, else unpredictable.
3526 * The value of @outlen after return is the number of octets consumed.
3527 */
3528static int
3529xmlEscapeContent(unsigned char* out, int *outlen,
3530 const xmlChar* in, int *inlen) {
3531 unsigned char* outstart = out;
3532 const unsigned char* base = in;
3533 unsigned char* outend = out + *outlen;
3534 const unsigned char* inend;
3535
3536 inend = in + (*inlen);
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003537
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003538 while ((in < inend) && (out < outend)) {
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003539 if (*in == '<') {
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003540 if (outend - out < 4) break;
3541 *out++ = '&';
3542 *out++ = 'l';
3543 *out++ = 't';
3544 *out++ = ';';
3545 } else if (*in == '>') {
3546 if (outend - out < 4) break;
3547 *out++ = '&';
3548 *out++ = 'g';
3549 *out++ = 't';
3550 *out++ = ';';
3551 } else if (*in == '&') {
3552 if (outend - out < 5) break;
3553 *out++ = '&';
3554 *out++ = 'a';
3555 *out++ = 'm';
3556 *out++ = 'p';
3557 *out++ = ';';
3558 } else if (*in == '\r') {
3559 if (outend - out < 5) break;
3560 *out++ = '&';
3561 *out++ = '#';
3562 *out++ = '1';
3563 *out++ = '3';
3564 *out++ = ';';
3565 } else {
3566 *out++ = (unsigned char) *in;
3567 }
3568 ++in;
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003569 }
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003570 *outlen = out - outstart;
3571 *inlen = in - base;
3572 return(0);
3573}
3574
3575/**
3576 * xmlOutputBufferWriteEscape:
3577 * @out: a buffered parser output
3578 * @str: a zero terminated UTF-8 string
Daniel Veillardee8960b2004-05-14 03:25:14 +00003579 * @escaping: an optional escaping function (or NULL)
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003580 *
3581 * Write the content of the string in the output I/O buffer
3582 * This routine escapes the caracters and then handle the I18N
3583 * transcoding from internal UTF-8
3584 * The buffer is lossless, i.e. will store in case of partial
3585 * or delayed writes.
3586 *
3587 * Returns the number of chars immediately written, or -1
3588 * in case of error.
3589 */
3590int
Daniel Veillardee8960b2004-05-14 03:25:14 +00003591xmlOutputBufferWriteEscape(xmlOutputBufferPtr out, const xmlChar *str,
3592 xmlCharEncodingOutputFunc escaping) {
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003593 int nbchars = 0; /* number of chars to output to I/O */
3594 int ret; /* return from function call */
3595 int written = 0; /* number of char written to I/O so far */
Daniel Veillard71b95632004-08-31 12:15:36 +00003596 int oldwritten=0;/* loop guard */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003597 int chunk; /* number of byte currently processed from str */
3598 int len; /* number of bytes in str */
3599 int cons; /* byte from str consumed */
3600
Daniel Veillardce244ad2004-11-05 10:03:46 +00003601 if ((out == NULL) || (out->error) || (str == NULL) ||
3602 (out->buffer == NULL) ||
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003603 (xmlBufGetAllocationScheme(out->buffer) == XML_BUFFER_ALLOC_IMMUTABLE))
3604 return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003605 len = strlen((const char *)str);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003606 if (len < 0) return(0);
3607 if (out->error) return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003608 if (escaping == NULL) escaping = xmlEscapeContent;
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003609
3610 do {
Daniel Veillard71b95632004-08-31 12:15:36 +00003611 oldwritten = written;
3612
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003613 /*
3614 * how many bytes to consume and how many bytes to store.
3615 */
3616 cons = len;
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003617 chunk = xmlBufAvail(out->buffer) - 1;
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003618
Daniel Veillardc4ba8a42008-02-16 10:08:14 +00003619 /*
3620 * make sure we have enough room to save first, if this is
3621 * not the case force a flush, but make sure we stay in the loop
3622 */
3623 if (chunk < 40) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003624 if (xmlBufGrow(out->buffer, 100) < 0)
Daniel Veillarde83e93e2008-08-30 12:52:26 +00003625 return(-1);
3626 oldwritten = -1;
3627 continue;
Daniel Veillardc4ba8a42008-02-16 10:08:14 +00003628 }
3629
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003630 /*
3631 * first handle encoding stuff.
3632 */
3633 if (out->encoder != NULL) {
3634 /*
3635 * Store the data in the incoming raw buffer
3636 */
3637 if (out->conv == NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003638 out->conv = xmlBufCreate();
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003639 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003640 ret = escaping(xmlBufEnd(out->buffer) ,
Daniel Veillardee8960b2004-05-14 03:25:14 +00003641 &chunk, str, &cons);
William M. Brack66e40b12004-11-26 15:45:19 +00003642 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003643 return(-1);
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003644 xmlBufAddLen(out->buffer, chunk);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003645
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003646 if ((xmlBufUse(out->buffer) < MINLEN) && (cons == len))
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003647 goto done;
3648
3649 /*
3650 * convert as much as possible to the output buffer.
3651 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003652 ret = xmlCharEncOutput(out, 0);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003653 if ((ret < 0) && (ret != -3)) {
3654 xmlIOErr(XML_IO_ENCODER, NULL);
3655 out->error = XML_IO_ENCODER;
3656 return(-1);
3657 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003658 nbchars = xmlBufUse(out->conv);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003659 } else {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003660 ret = escaping(xmlBufEnd(out->buffer), &chunk, str, &cons);
William M. Brack66e40b12004-11-26 15:45:19 +00003661 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003662 return(-1);
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003663 xmlBufAddLen(out->buffer, chunk);
3664 nbchars = xmlBufUse(out->buffer);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003665 }
3666 str += cons;
3667 len -= cons;
3668
3669 if ((nbchars < MINLEN) && (len <= 0))
3670 goto done;
3671
3672 if (out->writecallback) {
3673 /*
3674 * second write the stuff to the I/O channel
3675 */
3676 if (out->encoder != NULL) {
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003677 ret = out->writecallback(out->context,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003678 (const char *)xmlBufContent(out->conv), nbchars);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003679 if (ret >= 0)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003680 xmlBufShrink(out->conv, ret);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003681 } else {
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003682 ret = out->writecallback(out->context,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003683 (const char *)xmlBufContent(out->buffer), nbchars);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003684 if (ret >= 0)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003685 xmlBufShrink(out->buffer, ret);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003686 }
3687 if (ret < 0) {
3688 xmlIOErr(XML_IO_WRITE, NULL);
3689 out->error = XML_IO_WRITE;
3690 return(ret);
3691 }
3692 out->written += ret;
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003693 } else if (xmlBufAvail(out->buffer) < MINLEN) {
3694 xmlBufGrow(out->buffer, MINLEN);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003695 }
3696 written += nbchars;
Daniel Veillard71b95632004-08-31 12:15:36 +00003697 } while ((len > 0) && (oldwritten != written));
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003698
3699done:
3700#ifdef DEBUG_INPUT
3701 xmlGenericError(xmlGenericErrorContext,
3702 "I/O: wrote %d chars\n", written);
3703#endif
3704 return(written);
3705}
3706
3707/**
Owen Taylor3473f882001-02-23 17:55:21 +00003708 * xmlOutputBufferWriteString:
3709 * @out: a buffered parser output
3710 * @str: a zero terminated C string
3711 *
3712 * Write the content of the string in the output I/O buffer
3713 * This routine handle the I18N transcoding from internal UTF-8
3714 * The buffer is lossless, i.e. will store in case of partial
3715 * or delayed writes.
3716 *
3717 * Returns the number of chars immediately written, or -1
3718 * in case of error.
3719 */
3720int
3721xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
3722 int len;
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003723
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003724 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003725 if (str == NULL)
3726 return(-1);
3727 len = strlen(str);
3728
3729 if (len > 0)
3730 return(xmlOutputBufferWrite(out, len, str));
3731 return(len);
3732}
3733
3734/**
3735 * xmlOutputBufferFlush:
3736 * @out: a buffered output
3737 *
3738 * flushes the output I/O channel
3739 *
3740 * Returns the number of byte written or -1 in case of error.
3741 */
3742int
3743xmlOutputBufferFlush(xmlOutputBufferPtr out) {
3744 int nbchars = 0, ret = 0;
3745
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003746 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003747 /*
3748 * first handle encoding stuff.
3749 */
3750 if ((out->conv != NULL) && (out->encoder != NULL)) {
3751 /*
Mikhail Titov8e2098a2013-03-27 11:00:31 +08003752 * convert as much as possible to the parser output buffer.
Owen Taylor3473f882001-02-23 17:55:21 +00003753 */
Mikhail Titov8e2098a2013-03-27 11:00:31 +08003754 do {
3755 nbchars = xmlCharEncOutput(out, 0);
3756 if (nbchars < 0) {
3757 xmlIOErr(XML_IO_ENCODER, NULL);
3758 out->error = XML_IO_ENCODER;
3759 return(-1);
3760 }
3761 } while (nbchars);
Owen Taylor3473f882001-02-23 17:55:21 +00003762 }
3763
3764 /*
3765 * second flush the stuff to the I/O channel
3766 */
3767 if ((out->conv != NULL) && (out->encoder != NULL) &&
3768 (out->writecallback != NULL)) {
3769 ret = out->writecallback(out->context,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003770 (const char *)xmlBufContent(out->conv),
3771 xmlBufUse(out->conv));
Owen Taylor3473f882001-02-23 17:55:21 +00003772 if (ret >= 0)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003773 xmlBufShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003774 } else if (out->writecallback != NULL) {
3775 ret = out->writecallback(out->context,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003776 (const char *)xmlBufContent(out->buffer),
3777 xmlBufUse(out->buffer));
Owen Taylor3473f882001-02-23 17:55:21 +00003778 if (ret >= 0)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003779 xmlBufShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003780 }
3781 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003782 xmlIOErr(XML_IO_FLUSH, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003783 out->error = XML_IO_FLUSH;
Owen Taylor3473f882001-02-23 17:55:21 +00003784 return(ret);
3785 }
3786 out->written += ret;
3787
3788#ifdef DEBUG_INPUT
3789 xmlGenericError(xmlGenericErrorContext,
3790 "I/O: flushed %d chars\n", ret);
3791#endif
3792 return(ret);
3793}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003794#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003795
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003796/**
Owen Taylor3473f882001-02-23 17:55:21 +00003797 * xmlParserGetDirectory:
3798 * @filename: the path to a file
3799 *
3800 * lookup the directory for that file
3801 *
3802 * Returns a new allocated string containing the directory, or NULL.
3803 */
3804char *
3805xmlParserGetDirectory(const char *filename) {
3806 char *ret = NULL;
3807 char dir[1024];
3808 char *cur;
Owen Taylor3473f882001-02-23 17:55:21 +00003809
Igor Zlatkovic9181cc02002-09-29 17:51:06 +00003810#ifdef _WIN32_WCE /* easy way by now ... wince does not have dirs! */
3811 return NULL;
3812#endif
3813
Owen Taylor3473f882001-02-23 17:55:21 +00003814 if (xmlInputCallbackInitialized == 0)
3815 xmlRegisterDefaultInputCallbacks();
3816
3817 if (filename == NULL) return(NULL);
Rob Richardsf779da32007-08-14 09:41:21 +00003818
Daniel Veillard3c5ed912002-01-08 10:36:16 +00003819#if defined(WIN32) && !defined(__CYGWIN__)
Rob Richardsf779da32007-08-14 09:41:21 +00003820# define IS_XMLPGD_SEP(ch) ((ch=='/')||(ch=='\\'))
3821#else
3822# define IS_XMLPGD_SEP(ch) (ch=='/')
Owen Taylor3473f882001-02-23 17:55:21 +00003823#endif
3824
3825 strncpy(dir, filename, 1023);
3826 dir[1023] = 0;
3827 cur = &dir[strlen(dir)];
3828 while (cur > dir) {
Rob Richardsf779da32007-08-14 09:41:21 +00003829 if (IS_XMLPGD_SEP(*cur)) break;
Owen Taylor3473f882001-02-23 17:55:21 +00003830 cur --;
3831 }
Rob Richardsf779da32007-08-14 09:41:21 +00003832 if (IS_XMLPGD_SEP(*cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003833 if (cur == dir) dir[1] = 0;
3834 else *cur = 0;
3835 ret = xmlMemStrdup(dir);
3836 } else {
3837 if (getcwd(dir, 1024) != NULL) {
3838 dir[1023] = 0;
3839 ret = xmlMemStrdup(dir);
3840 }
3841 }
3842 return(ret);
Rob Richardsf779da32007-08-14 09:41:21 +00003843#undef IS_XMLPGD_SEP
Owen Taylor3473f882001-02-23 17:55:21 +00003844}
3845
3846/****************************************************************
3847 * *
3848 * External entities loading *
3849 * *
3850 ****************************************************************/
3851
Daniel Veillarda840b692003-10-19 13:35:37 +00003852/**
3853 * xmlCheckHTTPInput:
3854 * @ctxt: an XML parser context
3855 * @ret: an XML parser input
3856 *
3857 * Check an input in case it was created from an HTTP stream, in that
3858 * case it will handle encoding and update of the base URL in case of
3859 * redirection. It also checks for HTTP errors in which case the input
3860 * is cleanly freed up and an appropriate error is raised in context
3861 *
3862 * Returns the input or NULL in case of HTTP error.
3863 */
3864xmlParserInputPtr
3865xmlCheckHTTPInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr ret) {
3866#ifdef LIBXML_HTTP_ENABLED
3867 if ((ret != NULL) && (ret->buf != NULL) &&
3868 (ret->buf->readcallback == xmlIOHTTPRead) &&
3869 (ret->buf->context != NULL)) {
3870 const char *encoding;
3871 const char *redir;
3872 const char *mime;
3873 int code;
3874
3875 code = xmlNanoHTTPReturnCode(ret->buf->context);
3876 if (code >= 400) {
3877 /* fatal error */
3878 if (ret->filename != NULL)
Daniel Veillarde8039df2003-10-27 11:25:13 +00003879 __xmlLoaderErr(ctxt, "failed to load HTTP resource \"%s\"\n",
Daniel Veillarda840b692003-10-19 13:35:37 +00003880 (const char *) ret->filename);
3881 else
Daniel Veillarde8039df2003-10-27 11:25:13 +00003882 __xmlLoaderErr(ctxt, "failed to load HTTP resource\n", NULL);
Daniel Veillarda840b692003-10-19 13:35:37 +00003883 xmlFreeInputStream(ret);
3884 ret = NULL;
3885 } else {
3886
3887 mime = xmlNanoHTTPMimeType(ret->buf->context);
3888 if ((xmlStrstr(BAD_CAST mime, BAD_CAST "/xml")) ||
3889 (xmlStrstr(BAD_CAST mime, BAD_CAST "+xml"))) {
3890 encoding = xmlNanoHTTPEncoding(ret->buf->context);
3891 if (encoding != NULL) {
3892 xmlCharEncodingHandlerPtr handler;
3893
3894 handler = xmlFindCharEncodingHandler(encoding);
3895 if (handler != NULL) {
3896 xmlSwitchInputEncoding(ctxt, ret, handler);
3897 } else {
3898 __xmlErrEncoding(ctxt, XML_ERR_UNKNOWN_ENCODING,
3899 "Unknown encoding %s",
3900 BAD_CAST encoding, NULL);
3901 }
3902 if (ret->encoding == NULL)
3903 ret->encoding = xmlStrdup(BAD_CAST encoding);
3904 }
3905#if 0
3906 } else if (xmlStrstr(BAD_CAST mime, BAD_CAST "html")) {
3907#endif
3908 }
3909 redir = xmlNanoHTTPRedir(ret->buf->context);
3910 if (redir != NULL) {
3911 if (ret->filename != NULL)
3912 xmlFree((xmlChar *) ret->filename);
3913 if (ret->directory != NULL) {
3914 xmlFree((xmlChar *) ret->directory);
3915 ret->directory = NULL;
3916 }
3917 ret->filename =
3918 (char *) xmlStrdup((const xmlChar *) redir);
3919 }
3920 }
3921 }
3922#endif
3923 return(ret);
3924}
3925
Daniel Veillarde5a3f372006-08-30 13:11:36 +00003926static int xmlNoNetExists(const char *URL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003927 const char *path;
3928
3929 if (URL == NULL)
3930 return(0);
3931
Daniel Veillardf4862f02002-09-10 11:13:43 +00003932 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003933#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00003934 path = &URL[17];
3935#else
Daniel Veillard6990bf32001-08-23 21:17:48 +00003936 path = &URL[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00003937#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003938 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003939#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard6990bf32001-08-23 21:17:48 +00003940 path = &URL[8];
3941#else
3942 path = &URL[7];
3943#endif
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003944 } else
Daniel Veillard6990bf32001-08-23 21:17:48 +00003945 path = URL;
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003946
Daniel Veillarde5a3f372006-08-30 13:11:36 +00003947 return xmlCheckFilename(path);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003948}
Daniel Veillard6990bf32001-08-23 21:17:48 +00003949
Daniel Veillardad4e2962006-09-21 08:36:38 +00003950#ifdef LIBXML_CATALOG_ENABLED
3951
3952/**
3953 * xmlResolveResourceFromCatalog:
3954 * @URL: the URL for the entity to load
3955 * @ID: the System ID for the entity to load
3956 * @ctxt: the context in which the entity is called or NULL
3957 *
3958 * Resolves the URL and ID against the appropriate catalog.
3959 * This function is used by xmlDefaultExternalEntityLoader and
3960 * xmlNoNetExternalEntityLoader.
3961 *
3962 * Returns a new allocated URL, or NULL.
3963 */
William M. Brack38d452a2007-05-22 16:00:06 +00003964static xmlChar *
Daniel Veillardad4e2962006-09-21 08:36:38 +00003965xmlResolveResourceFromCatalog(const char *URL, const char *ID,
3966 xmlParserCtxtPtr ctxt) {
3967 xmlChar *resource = NULL;
3968 xmlCatalogAllow pref;
3969
3970 /*
3971 * If the resource doesn't exists as a file,
3972 * try to load it from the resource pointed in the catalogs
3973 */
3974 pref = xmlCatalogGetDefaults();
3975
3976 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
3977 /*
3978 * Do a local lookup
3979 */
3980 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
3981 ((pref == XML_CATA_ALLOW_ALL) ||
3982 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3983 resource = xmlCatalogLocalResolve(ctxt->catalogs,
3984 (const xmlChar *)ID,
3985 (const xmlChar *)URL);
3986 }
3987 /*
3988 * Try a global lookup
3989 */
3990 if ((resource == NULL) &&
3991 ((pref == XML_CATA_ALLOW_ALL) ||
3992 (pref == XML_CATA_ALLOW_GLOBAL))) {
3993 resource = xmlCatalogResolve((const xmlChar *)ID,
3994 (const xmlChar *)URL);
3995 }
3996 if ((resource == NULL) && (URL != NULL))
3997 resource = xmlStrdup((const xmlChar *) URL);
3998
3999 /*
4000 * TODO: do an URI lookup on the reference
4001 */
4002 if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
4003 xmlChar *tmp = NULL;
4004
4005 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
4006 ((pref == XML_CATA_ALLOW_ALL) ||
4007 (pref == XML_CATA_ALLOW_DOCUMENT))) {
4008 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
4009 }
4010 if ((tmp == NULL) &&
4011 ((pref == XML_CATA_ALLOW_ALL) ||
4012 (pref == XML_CATA_ALLOW_GLOBAL))) {
4013 tmp = xmlCatalogResolveURI(resource);
4014 }
4015
4016 if (tmp != NULL) {
4017 xmlFree(resource);
4018 resource = tmp;
4019 }
4020 }
4021 }
4022
4023 return resource;
4024}
4025
4026#endif
4027
Daniel Veillard5e2dace2001-07-18 19:30:27 +00004028/**
Owen Taylor3473f882001-02-23 17:55:21 +00004029 * xmlDefaultExternalEntityLoader:
4030 * @URL: the URL for the entity to load
4031 * @ID: the System ID for the entity to load
4032 * @ctxt: the context in which the entity is called or NULL
4033 *
4034 * By default we don't load external entitites, yet.
4035 *
4036 * Returns a new allocated xmlParserInputPtr, or NULL.
4037 */
Daniel Veillarda840b692003-10-19 13:35:37 +00004038static xmlParserInputPtr
Owen Taylor3473f882001-02-23 17:55:21 +00004039xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
Daniel Veillarda840b692003-10-19 13:35:37 +00004040 xmlParserCtxtPtr ctxt)
4041{
Owen Taylor3473f882001-02-23 17:55:21 +00004042 xmlParserInputPtr ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00004043 xmlChar *resource = NULL;
Daniel Veillarda840b692003-10-19 13:35:37 +00004044
Owen Taylor3473f882001-02-23 17:55:21 +00004045#ifdef DEBUG_EXTERNAL_ENTITIES
4046 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda840b692003-10-19 13:35:37 +00004047 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00004048#endif
Daniel Veillard61b93382003-11-03 14:28:31 +00004049 if ((ctxt != NULL) && (ctxt->options & XML_PARSE_NONET)) {
4050 int options = ctxt->options;
4051
4052 ctxt->options -= XML_PARSE_NONET;
4053 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
4054 ctxt->options = options;
4055 return(ret);
4056 }
Daniel Veillardad4e2962006-09-21 08:36:38 +00004057#ifdef LIBXML_CATALOG_ENABLED
4058 resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
Daniel Veillard7d6fd212001-05-10 15:34:11 +00004059#endif
4060
4061 if (resource == NULL)
Daniel Veillarda840b692003-10-19 13:35:37 +00004062 resource = (xmlChar *) URL;
Daniel Veillard7d6fd212001-05-10 15:34:11 +00004063
4064 if (resource == NULL) {
Daniel Veillarda840b692003-10-19 13:35:37 +00004065 if (ID == NULL)
4066 ID = "NULL";
Daniel Veillarde8039df2003-10-27 11:25:13 +00004067 __xmlLoaderErr(ctxt, "failed to load external entity \"%s\"\n", ID);
Daniel Veillarda840b692003-10-19 13:35:37 +00004068 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004069 }
Daniel Veillarda840b692003-10-19 13:35:37 +00004070 ret = xmlNewInputFromFile(ctxt, (const char *) resource);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00004071 if ((resource != NULL) && (resource != (xmlChar *) URL))
Daniel Veillarda840b692003-10-19 13:35:37 +00004072 xmlFree(resource);
4073 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004074}
4075
4076static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
4077 xmlDefaultExternalEntityLoader;
4078
Daniel Veillard5e2dace2001-07-18 19:30:27 +00004079/**
Owen Taylor3473f882001-02-23 17:55:21 +00004080 * xmlSetExternalEntityLoader:
4081 * @f: the new entity resolver function
4082 *
4083 * Changes the defaultexternal entity resolver function for the application
4084 */
4085void
4086xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
4087 xmlCurrentExternalEntityLoader = f;
4088}
4089
Daniel Veillard5e2dace2001-07-18 19:30:27 +00004090/**
Owen Taylor3473f882001-02-23 17:55:21 +00004091 * xmlGetExternalEntityLoader:
4092 *
4093 * Get the default external entity resolver function for the application
4094 *
4095 * Returns the xmlExternalEntityLoader function pointer
4096 */
4097xmlExternalEntityLoader
4098xmlGetExternalEntityLoader(void) {
4099 return(xmlCurrentExternalEntityLoader);
4100}
4101
Daniel Veillard5e2dace2001-07-18 19:30:27 +00004102/**
Owen Taylor3473f882001-02-23 17:55:21 +00004103 * xmlLoadExternalEntity:
4104 * @URL: the URL for the entity to load
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00004105 * @ID: the Public ID for the entity to load
Owen Taylor3473f882001-02-23 17:55:21 +00004106 * @ctxt: the context in which the entity is called or NULL
4107 *
4108 * Load an external entity, note that the use of this function for
4109 * unparsed entities may generate problems
Owen Taylor3473f882001-02-23 17:55:21 +00004110 *
4111 * Returns the xmlParserInputPtr or NULL
4112 */
4113xmlParserInputPtr
4114xmlLoadExternalEntity(const char *URL, const char *ID,
4115 xmlParserCtxtPtr ctxt) {
Daniel Veillarde5a3f372006-08-30 13:11:36 +00004116 if ((URL != NULL) && (xmlNoNetExists(URL) == 0)) {
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00004117 char *canonicFilename;
4118 xmlParserInputPtr ret;
4119
4120 canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL);
4121 if (canonicFilename == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00004122 xmlIOErrMemory("building canonical path\n");
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00004123 return(NULL);
4124 }
4125
4126 ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt);
4127 xmlFree(canonicFilename);
4128 return(ret);
4129 }
Owen Taylor3473f882001-02-23 17:55:21 +00004130 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
4131}
4132
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004133/************************************************************************
Hans Breuer2ad41ca2009-08-11 17:51:22 +02004134 * *
4135 * Disabling Network access *
4136 * *
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004137 ************************************************************************/
4138
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004139/**
4140 * xmlNoNetExternalEntityLoader:
4141 * @URL: the URL for the entity to load
4142 * @ID: the System ID for the entity to load
4143 * @ctxt: the context in which the entity is called or NULL
4144 *
4145 * A specific entity loader disabling network accesses, though still
4146 * allowing local catalog accesses for resolution.
4147 *
4148 * Returns a new allocated xmlParserInputPtr, or NULL.
4149 */
4150xmlParserInputPtr
4151xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
4152 xmlParserCtxtPtr ctxt) {
4153 xmlParserInputPtr input = NULL;
4154 xmlChar *resource = NULL;
4155
4156#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillardad4e2962006-09-21 08:36:38 +00004157 resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004158#endif
Daniel Veillardad4e2962006-09-21 08:36:38 +00004159
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004160 if (resource == NULL)
4161 resource = (xmlChar *) URL;
4162
4163 if (resource != NULL) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00004164 if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
4165 (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00004166 xmlIOErr(XML_IO_NETWORK_ATTEMPT, (const char *) resource);
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004167 if (resource != (xmlChar *) URL)
4168 xmlFree(resource);
4169 return(NULL);
4170 }
4171 }
4172 input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
4173 if (resource != (xmlChar *) URL)
4174 xmlFree(resource);
4175 return(input);
4176}
4177
Daniel Veillard5d4644e2005-04-01 13:11:58 +00004178#define bottom_xmlIO
4179#include "elfgcchack.h"