blob: 6891ff9a26a3770f1889af35015a3e77e4dcc08e [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 Veillard7a72f4a2014-10-13 16:23:24 +0800803/**
804 * xmlNop:
805 *
806 * No Operation function, does nothing, no input
807 *
808 * Returns zero
809 */
Daniel Veillard153cf152012-10-26 13:50:47 +0800810int
Owen Taylor3473f882001-02-23 17:55:21 +0000811xmlNop(void) {
812 return(0);
813}
814
815/**
Owen Taylor3473f882001-02-23 17:55:21 +0000816 * xmlFdRead:
817 * @context: the I/O context
818 * @buffer: where to drop data
819 * @len: number of bytes to read
820 *
821 * Read @len bytes to @buffer from the I/O channel.
822 *
823 * Returns the number of bytes written
824 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000825static int
Owen Taylor3473f882001-02-23 17:55:21 +0000826xmlFdRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000827 int ret;
828
829 ret = read((int) (long) context, &buffer[0], len);
830 if (ret < 0) xmlIOErr(0, "read()");
831 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000832}
833
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000834#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000835/**
836 * xmlFdWrite:
837 * @context: the I/O context
838 * @buffer: where to get data
839 * @len: number of bytes to write
840 *
841 * Write @len bytes from @buffer to the I/O channel.
842 *
843 * Returns the number of bytes written
844 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000845static int
Owen Taylor3473f882001-02-23 17:55:21 +0000846xmlFdWrite (void * context, const char * buffer, int len) {
Daniel Veillard9b693b42005-10-28 14:54:17 +0000847 int ret = 0;
Daniel Veillard05d987b2003-10-08 11:54:57 +0000848
Daniel Veillard9b693b42005-10-28 14:54:17 +0000849 if (len > 0) {
850 ret = write((int) (long) context, &buffer[0], len);
851 if (ret < 0) xmlIOErr(0, "write()");
852 }
Daniel Veillard05d987b2003-10-08 11:54:57 +0000853 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000854}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000855#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000856
857/**
858 * xmlFdClose:
859 * @context: the I/O context
860 *
861 * Close an I/O channel
Daniel Veillardf012a642001-07-23 19:10:52 +0000862 *
863 * Returns 0 in case of success and error code otherwise
Owen Taylor3473f882001-02-23 17:55:21 +0000864 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000865static int
Owen Taylor3473f882001-02-23 17:55:21 +0000866xmlFdClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000867 int ret;
868 ret = close((int) (long) context);
869 if (ret < 0) xmlIOErr(0, "close()");
870 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000871}
872
873/**
874 * xmlFileMatch:
875 * @filename: the URI for matching
876 *
877 * input from FILE *
878 *
879 * Returns 1 if matches, 0 otherwise
880 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000881int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000882xmlFileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000883 return(1);
884}
885
886/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000887 * xmlFileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +0000888 * @filename: the URI for matching
889 *
890 * input from FILE *, supports compressed input
891 * if @filename is " " then the standard input is used
892 *
893 * Returns an I/O context or NULL in case of error
894 */
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000895static void *
896xmlFileOpen_real (const char *filename) {
Gaurav Guptab8480ae2014-07-26 21:14:53 +0800897 const char *path = filename;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000898 FILE *fd;
Owen Taylor3473f882001-02-23 17:55:21 +0000899
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000900 if (filename == NULL)
901 return(NULL);
902
Owen Taylor3473f882001-02-23 17:55:21 +0000903 if (!strcmp(filename, "-")) {
904 fd = stdin;
905 return((void *) fd);
906 }
907
Daniel Veillard5cdbbd22007-06-12 09:39:14 +0000908 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000909#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000910 path = &filename[17];
911#else
Owen Taylor3473f882001-02-23 17:55:21 +0000912 path = &filename[16];
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000913#endif
Daniel Veillard5cdbbd22007-06-12 09:39:14 +0000914 } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000915#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000916 path = &filename[8];
917#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000918 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000919#endif
Daniel Veillard5cdbbd22007-06-12 09:39:14 +0000920 } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:/", 6)) {
921 /* lots of generators seems to lazy to read RFC 1738 */
922#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
923 path = &filename[6];
924#else
925 path = &filename[5];
926#endif
Gaurav Guptab8480ae2014-07-26 21:14:53 +0800927 }
Owen Taylor3473f882001-02-23 17:55:21 +0000928
Stéphane Michaut454e3972017-08-28 14:30:43 +0200929 /* Do not check DDNAME on zOS ! */
930#if !defined(__MVS__)
Owen Taylor3473f882001-02-23 17:55:21 +0000931 if (!xmlCheckFilename(path))
932 return(NULL);
Stéphane Michaut454e3972017-08-28 14:30:43 +0200933#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000934
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000935#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
936 fd = xmlWrapOpen(path, 0);
937#else
938 fd = fopen(path, "r");
Owen Taylor3473f882001-02-23 17:55:21 +0000939#endif /* WIN32 */
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000940 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +0000941 return((void *) fd);
942}
943
944/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000945 * xmlFileOpen:
946 * @filename: the URI for matching
947 *
948 * Wrapper around xmlFileOpen_real that try it with an unescaped
949 * version of @filename, if this fails fallback to @filename
Daniel Veillard71531f32003-02-05 13:19:53 +0000950 *
951 * Returns a handler or NULL in case or failure
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000952 */
953void *
954xmlFileOpen (const char *filename) {
955 char *unescaped;
956 void *retval;
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000957
Daniel Veillardbd672bc2007-03-30 12:39:25 +0000958 retval = xmlFileOpen_real(filename);
959 if (retval == NULL) {
960 unescaped = xmlURIUnescapeString(filename, 0, NULL);
961 if (unescaped != NULL) {
962 retval = xmlFileOpen_real(unescaped);
963 xmlFree(unescaped);
964 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000965 }
Daniel Veillardbd672bc2007-03-30 12:39:25 +0000966
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000967 return retval;
968}
969
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000970#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000971/**
Owen Taylor3473f882001-02-23 17:55:21 +0000972 * xmlFileOpenW:
973 * @filename: the URI for matching
974 *
975 * output to from FILE *,
976 * if @filename is "-" then the standard output is used
977 *
978 * Returns an I/O context or NULL in case of error
979 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000980static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000981xmlFileOpenW (const char *filename) {
982 const char *path = NULL;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000983 FILE *fd;
Owen Taylor3473f882001-02-23 17:55:21 +0000984
985 if (!strcmp(filename, "-")) {
986 fd = stdout;
987 return((void *) fd);
988 }
989
Daniel Veillardf4862f02002-09-10 11:13:43 +0000990 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000991#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000992 path = &filename[17];
993#else
Owen Taylor3473f882001-02-23 17:55:21 +0000994 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000995#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000996 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000997#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000998 path = &filename[8];
999#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +00001000 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +00001001#endif
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001002 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001003 path = filename;
1004
1005 if (path == NULL)
1006 return(NULL);
1007
Daniel Veillard8ca85b22006-09-01 09:56:07 +00001008#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
1009 fd = xmlWrapOpen(path, 1);
Stéphane Michaut454e3972017-08-28 14:30:43 +02001010#elif(__MVS__)
1011 fd = fopen(path, "w");
Daniel Veillard8ca85b22006-09-01 09:56:07 +00001012#else
Stéphane Michaut454e3972017-08-28 14:30:43 +02001013 fd = fopen(path, "wb");
Daniel Veillard8ca85b22006-09-01 09:56:07 +00001014#endif /* WIN32 */
Daniel Veillarde5a3f372006-08-30 13:11:36 +00001015
Stéphane Michaut454e3972017-08-28 14:30:43 +02001016 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +00001017 return((void *) fd);
1018}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001019#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001020
1021/**
1022 * xmlFileRead:
1023 * @context: the I/O context
1024 * @buffer: where to drop data
1025 * @len: number of bytes to write
1026 *
1027 * Read @len bytes to @buffer from the I/O channel.
1028 *
Daniel Veillardce682bc2004-11-05 17:22:25 +00001029 * Returns the number of bytes written or < 0 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +00001030 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001031int
Owen Taylor3473f882001-02-23 17:55:21 +00001032xmlFileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001033 int ret;
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001034 if ((context == NULL) || (buffer == NULL))
Daniel Veillardce682bc2004-11-05 17:22:25 +00001035 return(-1);
Daniel Veillard05d987b2003-10-08 11:54:57 +00001036 ret = fread(&buffer[0], 1, len, (FILE *) context);
1037 if (ret < 0) xmlIOErr(0, "fread()");
1038 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001039}
1040
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001041#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001042/**
1043 * xmlFileWrite:
1044 * @context: the I/O context
1045 * @buffer: where to drop data
1046 * @len: number of bytes to write
1047 *
1048 * Write @len bytes from @buffer to the I/O channel.
1049 *
1050 * Returns the number of bytes written
1051 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001052static int
Owen Taylor3473f882001-02-23 17:55:21 +00001053xmlFileWrite (void * context, const char * buffer, int len) {
Daniel Veillard4a6d39b2002-12-17 18:33:01 +00001054 int items;
1055
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001056 if ((context == NULL) || (buffer == NULL))
Daniel Veillardce682bc2004-11-05 17:22:25 +00001057 return(-1);
Daniel Veillard4a6d39b2002-12-17 18:33:01 +00001058 items = fwrite(&buffer[0], len, 1, (FILE *) context);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00001059 if ((items == 0) && (ferror((FILE *) context))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001060 xmlIOErr(0, "fwrite()");
Daniel Veillard97bf4d02003-10-08 18:58:28 +00001061 return(-1);
1062 }
Daniel Veillard4a6d39b2002-12-17 18:33:01 +00001063 return(items * len);
Owen Taylor3473f882001-02-23 17:55:21 +00001064}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001065#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001066
1067/**
1068 * xmlFileClose:
1069 * @context: the I/O context
1070 *
1071 * Close an I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001072 *
1073 * Returns 0 or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +00001074 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001075int
Owen Taylor3473f882001-02-23 17:55:21 +00001076xmlFileClose (void * context) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001077 FILE *fil;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001078 int ret;
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001079
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +00001080 if (context == NULL)
1081 return(-1);
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001082 fil = (FILE *) context;
Daniel Veillard500a1de2004-03-22 15:22:58 +00001083 if ((fil == stdout) || (fil == stderr)) {
1084 ret = fflush(fil);
1085 if (ret < 0)
1086 xmlIOErr(0, "fflush()");
1087 return(0);
1088 }
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001089 if (fil == stdin)
1090 return(0);
Daniel Veillard05d987b2003-10-08 11:54:57 +00001091 ret = ( fclose((FILE *) context) == EOF ) ? -1 : 0;
1092 if (ret < 0)
1093 xmlIOErr(0, "fclose()");
1094 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001095}
1096
1097/**
1098 * xmlFileFlush:
1099 * @context: the I/O context
1100 *
1101 * Flush an I/O channel
1102 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001103static int
Owen Taylor3473f882001-02-23 17:55:21 +00001104xmlFileFlush (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001105 int ret;
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +00001106
1107 if (context == NULL)
1108 return(-1);
Daniel Veillard05d987b2003-10-08 11:54:57 +00001109 ret = ( fflush((FILE *) context) == EOF ) ? -1 : 0;
1110 if (ret < 0)
1111 xmlIOErr(0, "fflush()");
1112 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001113}
1114
Daniel Veillard9a00fd22005-11-09 08:56:26 +00001115#ifdef LIBXML_OUTPUT_ENABLED
1116/**
1117 * xmlBufferWrite:
1118 * @context: the xmlBuffer
1119 * @buffer: the data to write
1120 * @len: number of bytes to write
1121 *
1122 * Write @len bytes from @buffer to the xml buffer
1123 *
1124 * Returns the number of bytes written
1125 */
1126static int
1127xmlBufferWrite (void * context, const char * buffer, int len) {
1128 int ret;
1129
1130 ret = xmlBufferAdd((xmlBufferPtr) context, (const xmlChar *) buffer, len);
1131 if (ret != 0)
1132 return(-1);
1133 return(len);
1134}
Daniel Veillard9a00fd22005-11-09 08:56:26 +00001135#endif
1136
Owen Taylor3473f882001-02-23 17:55:21 +00001137#ifdef HAVE_ZLIB_H
1138/************************************************************************
1139 * *
1140 * I/O for compressed file accesses *
1141 * *
1142 ************************************************************************/
1143/**
1144 * xmlGzfileMatch:
1145 * @filename: the URI for matching
1146 *
1147 * input from compressed file test
1148 *
1149 * Returns 1 if matches, 0 otherwise
1150 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001151static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00001152xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00001153 return(1);
1154}
1155
1156/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001157 * xmlGzfileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +00001158 * @filename: the URI for matching
1159 *
1160 * input from compressed file open
1161 * if @filename is " " then the standard input is used
1162 *
1163 * Returns an I/O context or NULL in case of error
1164 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001165static void *
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001166xmlGzfileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +00001167 const char *path = NULL;
1168 gzFile fd;
1169
1170 if (!strcmp(filename, "-")) {
Philip Withnall31aa3812014-06-20 21:11:40 +01001171 int duped_fd = dup(fileno(stdin));
1172 fd = gzdopen(duped_fd, "rb");
Philip Withnall21699932014-08-24 23:10:13 +01001173 if (fd == Z_NULL && duped_fd >= 0) {
Philip Withnall31aa3812014-06-20 21:11:40 +01001174 close(duped_fd); /* gzdOpen() does not close on failure */
1175 }
1176
Owen Taylor3473f882001-02-23 17:55:21 +00001177 return((void *) fd);
1178 }
1179
Daniel Veillardf4862f02002-09-10 11:13:43 +00001180 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001181#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00001182 path = &filename[17];
1183#else
Owen Taylor3473f882001-02-23 17:55:21 +00001184 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00001185#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001186 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001187#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +00001188 path = &filename[8];
1189#else
Owen Taylor3473f882001-02-23 17:55:21 +00001190 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +00001191#endif
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001192 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001193 path = filename;
1194
1195 if (path == NULL)
1196 return(NULL);
1197 if (!xmlCheckFilename(path))
1198 return(NULL);
1199
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001200#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
1201 fd = xmlWrapGzOpen(path, "rb");
1202#else
Owen Taylor3473f882001-02-23 17:55:21 +00001203 fd = gzopen(path, "rb");
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001204#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001205 return((void *) fd);
1206}
1207
1208/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001209 * xmlGzfileOpen:
1210 * @filename: the URI for matching
1211 *
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00001212 * Wrapper around xmlGzfileOpen if the open fais, it will
1213 * try to unescape @filename
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001214 */
1215static void *
1216xmlGzfileOpen (const char *filename) {
1217 char *unescaped;
1218 void *retval;
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00001219
1220 retval = xmlGzfileOpen_real(filename);
1221 if (retval == NULL) {
1222 unescaped = xmlURIUnescapeString(filename, 0, NULL);
1223 if (unescaped != NULL) {
1224 retval = xmlGzfileOpen_real(unescaped);
1225 }
1226 xmlFree(unescaped);
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001227 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001228 return retval;
1229}
1230
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001231#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001232/**
Owen Taylor3473f882001-02-23 17:55:21 +00001233 * xmlGzfileOpenW:
1234 * @filename: the URI for matching
1235 * @compression: the compression factor (0 - 9 included)
1236 *
1237 * input from compressed file open
1238 * if @filename is " " then the standard input is used
1239 *
1240 * Returns an I/O context or NULL in case of error
1241 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001242static void *
Owen Taylor3473f882001-02-23 17:55:21 +00001243xmlGzfileOpenW (const char *filename, int compression) {
1244 const char *path = NULL;
1245 char mode[15];
1246 gzFile fd;
1247
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001248 snprintf(mode, sizeof(mode), "wb%d", compression);
Owen Taylor3473f882001-02-23 17:55:21 +00001249 if (!strcmp(filename, "-")) {
Philip Withnall31aa3812014-06-20 21:11:40 +01001250 int duped_fd = dup(fileno(stdout));
1251 fd = gzdopen(duped_fd, "rb");
Philip Withnall21699932014-08-24 23:10:13 +01001252 if (fd == Z_NULL && duped_fd >= 0) {
Philip Withnall31aa3812014-06-20 21:11:40 +01001253 close(duped_fd); /* gzdOpen() does not close on failure */
1254 }
1255
Owen Taylor3473f882001-02-23 17:55:21 +00001256 return((void *) fd);
1257 }
1258
Daniel Veillardf4862f02002-09-10 11:13:43 +00001259 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001260#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00001261 path = &filename[17];
1262#else
Owen Taylor3473f882001-02-23 17:55:21 +00001263 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00001264#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001265 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001266#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +00001267 path = &filename[8];
1268#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +00001269 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +00001270#endif
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001271 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001272 path = filename;
1273
1274 if (path == NULL)
1275 return(NULL);
1276
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001277#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
1278 fd = xmlWrapGzOpen(path, mode);
1279#else
Owen Taylor3473f882001-02-23 17:55:21 +00001280 fd = gzopen(path, mode);
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001281#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001282 return((void *) fd);
1283}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001284#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001285
1286/**
1287 * xmlGzfileRead:
1288 * @context: the I/O context
1289 * @buffer: where to drop data
1290 * @len: number of bytes to write
1291 *
1292 * Read @len bytes to @buffer from the compressed I/O channel.
1293 *
Nick Wellnhofer5a0ae662017-06-17 23:20:38 +02001294 * Returns the number of bytes read.
Owen Taylor3473f882001-02-23 17:55:21 +00001295 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001296static int
Owen Taylor3473f882001-02-23 17:55:21 +00001297xmlGzfileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001298 int ret;
1299
1300 ret = gzread((gzFile) context, &buffer[0], len);
1301 if (ret < 0) xmlIOErr(0, "gzread()");
1302 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001303}
1304
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001305#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001306/**
1307 * xmlGzfileWrite:
1308 * @context: the I/O context
1309 * @buffer: where to drop data
1310 * @len: number of bytes to write
1311 *
1312 * Write @len bytes from @buffer to the compressed I/O channel.
1313 *
1314 * Returns the number of bytes written
1315 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001316static int
Owen Taylor3473f882001-02-23 17:55:21 +00001317xmlGzfileWrite (void * context, const char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001318 int ret;
1319
1320 ret = gzwrite((gzFile) context, (char *) &buffer[0], len);
1321 if (ret < 0) xmlIOErr(0, "gzwrite()");
1322 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001323}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001324#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001325
1326/**
1327 * xmlGzfileClose:
1328 * @context: the I/O context
1329 *
1330 * Close a compressed I/O channel
1331 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001332static int
Owen Taylor3473f882001-02-23 17:55:21 +00001333xmlGzfileClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001334 int ret;
1335
1336 ret = (gzclose((gzFile) context) == Z_OK ) ? 0 : -1;
1337 if (ret < 0) xmlIOErr(0, "gzclose()");
1338 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001339}
1340#endif /* HAVE_ZLIB_H */
1341
Daniel Veillard18b89882015-11-03 15:46:29 +08001342#ifdef LIBXML_LZMA_ENABLED
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001343/************************************************************************
1344 * *
1345 * I/O for compressed file accesses *
1346 * *
1347 ************************************************************************/
Daniel Veillardadf5ec92012-01-26 16:56:22 +08001348#include "xzlib.h"
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001349/**
1350 * xmlXzfileMatch:
1351 * @filename: the URI for matching
1352 *
1353 * input from compressed file test
1354 *
1355 * Returns 1 if matches, 0 otherwise
1356 */
1357static int
1358xmlXzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
1359 return(1);
1360}
1361
1362/**
1363 * xmlXzFileOpen_real:
1364 * @filename: the URI for matching
1365 *
1366 * input from compressed file open
1367 * if @filename is " " then the standard input is used
1368 *
1369 * Returns an I/O context or NULL in case of error
1370 */
1371static void *
1372xmlXzfileOpen_real (const char *filename) {
1373 const char *path = NULL;
1374 xzFile fd;
1375
1376 if (!strcmp(filename, "-")) {
Patrick Monnerat147aaf22013-12-12 15:02:40 +08001377 fd = __libxml2_xzdopen(dup(fileno(stdin)), "rb");
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001378 return((void *) fd);
1379 }
1380
1381 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) {
1382 path = &filename[16];
1383 } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
1384 path = &filename[7];
1385 } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:/", 6)) {
1386 /* lots of generators seems to lazy to read RFC 1738 */
1387 path = &filename[5];
1388 } else
1389 path = filename;
1390
1391 if (path == NULL)
1392 return(NULL);
1393 if (!xmlCheckFilename(path))
1394 return(NULL);
1395
Daniel Veillardadf5ec92012-01-26 16:56:22 +08001396 fd = __libxml2_xzopen(path, "rb");
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001397 return((void *) fd);
1398}
1399
1400/**
1401 * xmlXzfileOpen:
1402 * @filename: the URI for matching
1403 *
1404 * Wrapper around xmlXzfileOpen_real that try it with an unescaped
1405 * version of @filename, if this fails fallback to @filename
1406 *
1407 * Returns a handler or NULL in case or failure
1408 */
1409static void *
1410xmlXzfileOpen (const char *filename) {
1411 char *unescaped;
1412 void *retval;
1413
1414 retval = xmlXzfileOpen_real(filename);
1415 if (retval == NULL) {
1416 unescaped = xmlURIUnescapeString(filename, 0, NULL);
1417 if (unescaped != NULL) {
1418 retval = xmlXzfileOpen_real(unescaped);
1419 }
1420 xmlFree(unescaped);
1421 }
1422
1423 return retval;
1424}
1425
1426/**
1427 * xmlXzfileRead:
1428 * @context: the I/O context
1429 * @buffer: where to drop data
1430 * @len: number of bytes to write
1431 *
1432 * Read @len bytes to @buffer from the compressed I/O channel.
1433 *
1434 * Returns the number of bytes written
1435 */
1436static int
1437xmlXzfileRead (void * context, char * buffer, int len) {
1438 int ret;
1439
Daniel Veillardadf5ec92012-01-26 16:56:22 +08001440 ret = __libxml2_xzread((xzFile) context, &buffer[0], len);
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001441 if (ret < 0) xmlIOErr(0, "xzread()");
1442 return(ret);
1443}
1444
1445/**
1446 * xmlXzfileClose:
1447 * @context: the I/O context
1448 *
1449 * Close a compressed I/O channel
1450 */
1451static int
1452xmlXzfileClose (void * context) {
1453 int ret;
1454
Daniel Veillardadf5ec92012-01-26 16:56:22 +08001455 ret = (__libxml2_xzclose((xzFile) context) == LZMA_OK ) ? 0 : -1;
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001456 if (ret < 0) xmlIOErr(0, "xzclose()");
1457 return(ret);
1458}
Daniel Veillard18b89882015-11-03 15:46:29 +08001459#endif /* LIBXML_LZMA_ENABLED */
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001460
Owen Taylor3473f882001-02-23 17:55:21 +00001461#ifdef LIBXML_HTTP_ENABLED
1462/************************************************************************
1463 * *
1464 * I/O for HTTP file accesses *
1465 * *
1466 ************************************************************************/
Daniel Veillardf012a642001-07-23 19:10:52 +00001467
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001468#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001469typedef struct xmlIOHTTPWriteCtxt_
1470{
1471 int compression;
1472
1473 char * uri;
1474
1475 void * doc_buff;
1476
1477} xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr;
1478
1479#ifdef HAVE_ZLIB_H
1480
1481#define DFLT_WBITS ( -15 )
1482#define DFLT_MEM_LVL ( 8 )
1483#define GZ_MAGIC1 ( 0x1f )
1484#define GZ_MAGIC2 ( 0x8b )
1485#define LXML_ZLIB_OS_CODE ( 0x03 )
1486#define INIT_HTTP_BUFF_SIZE ( 32768 )
1487#define DFLT_ZLIB_RATIO ( 5 )
1488
1489/*
1490** Data structure and functions to work with sending compressed data
1491** via HTTP.
1492*/
1493
1494typedef struct xmlZMemBuff_
1495{
1496 unsigned long size;
1497 unsigned long crc;
1498
1499 unsigned char * zbuff;
1500 z_stream zctrl;
1501
1502} xmlZMemBuff, *xmlZMemBuffPtr;
1503
1504/**
1505 * append_reverse_ulong
1506 * @buff: Compressed memory buffer
1507 * @data: Unsigned long to append
1508 *
1509 * Append a unsigned long in reverse byte order to the end of the
1510 * memory buffer.
1511 */
1512static void
1513append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) {
1514
1515 int idx;
1516
1517 if ( buff == NULL )
1518 return;
1519
1520 /*
1521 ** This is plagiarized from putLong in gzio.c (zlib source) where
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001522 ** the number "4" is hardcoded. If zlib is ever patched to
Daniel Veillardf012a642001-07-23 19:10:52 +00001523 ** support 64 bit file sizes, this code would need to be patched
1524 ** as well.
1525 */
1526
1527 for ( idx = 0; idx < 4; idx++ ) {
1528 *buff->zctrl.next_out = ( data & 0xff );
1529 data >>= 8;
1530 buff->zctrl.next_out++;
1531 }
1532
1533 return;
1534}
1535
1536/**
1537 *
1538 * xmlFreeZMemBuff
1539 * @buff: The memory buffer context to clear
1540 *
1541 * Release all the resources associated with the compressed memory buffer.
1542 */
1543static void
1544xmlFreeZMemBuff( xmlZMemBuffPtr buff ) {
William M. Brack78637da2003-07-31 14:47:38 +00001545
1546#ifdef DEBUG_HTTP
Daniel Veillardf012a642001-07-23 19:10:52 +00001547 int z_err;
William M. Brack78637da2003-07-31 14:47:38 +00001548#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001549
1550 if ( buff == NULL )
1551 return;
1552
1553 xmlFree( buff->zbuff );
Daniel Veillardf012a642001-07-23 19:10:52 +00001554#ifdef DEBUG_HTTP
William M. Brack78637da2003-07-31 14:47:38 +00001555 z_err = deflateEnd( &buff->zctrl );
Daniel Veillardf012a642001-07-23 19:10:52 +00001556 if ( z_err != Z_OK )
1557 xmlGenericError( xmlGenericErrorContext,
1558 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
1559 z_err );
William M. Brack78637da2003-07-31 14:47:38 +00001560#else
1561 deflateEnd( &buff->zctrl );
William M. Brack779af002003-08-01 15:55:39 +00001562#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001563
1564 xmlFree( buff );
1565 return;
1566}
1567
1568/**
1569 * xmlCreateZMemBuff
1570 *@compression: Compression value to use
1571 *
1572 * Create a memory buffer to hold the compressed XML document. The
1573 * compressed document in memory will end up being identical to what
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001574 * would be created if gzopen/gzwrite/gzclose were being used to
Daniel Veillardf012a642001-07-23 19:10:52 +00001575 * write the document to disk. The code for the header/trailer data to
1576 * the compression is plagiarized from the zlib source files.
1577 */
1578static void *
1579xmlCreateZMemBuff( int compression ) {
1580
1581 int z_err;
1582 int hdr_lgth;
1583 xmlZMemBuffPtr buff = NULL;
1584
1585 if ( ( compression < 1 ) || ( compression > 9 ) )
1586 return ( NULL );
1587
1588 /* Create the control and data areas */
1589
1590 buff = xmlMalloc( sizeof( xmlZMemBuff ) );
1591 if ( buff == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001592 xmlIOErrMemory("creating buffer context");
Daniel Veillardf012a642001-07-23 19:10:52 +00001593 return ( NULL );
1594 }
1595
1596 (void)memset( buff, 0, sizeof( xmlZMemBuff ) );
1597 buff->size = INIT_HTTP_BUFF_SIZE;
1598 buff->zbuff = xmlMalloc( buff->size );
1599 if ( buff->zbuff == NULL ) {
1600 xmlFreeZMemBuff( buff );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001601 xmlIOErrMemory("creating buffer");
Daniel Veillardf012a642001-07-23 19:10:52 +00001602 return ( NULL );
1603 }
1604
1605 z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
1606 DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
1607 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001608 xmlChar msg[500];
Daniel Veillardf012a642001-07-23 19:10:52 +00001609 xmlFreeZMemBuff( buff );
1610 buff = NULL;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001611 xmlStrPrintf(msg, 500,
David Kilzer4472c3a2016-05-13 15:13:17 +08001612 "xmlCreateZMemBuff: %s %d\n",
Daniel Veillard05d987b2003-10-08 11:54:57 +00001613 "Error initializing compression context. ZLIB error:",
1614 z_err );
1615 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001616 return ( NULL );
1617 }
1618
1619 /* Set the header data. The CRC will be needed for the trailer */
Daniel Veillard24505b02005-07-28 23:49:35 +00001620 buff->crc = crc32( 0L, NULL, 0 );
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001621 hdr_lgth = snprintf( (char *)buff->zbuff, buff->size,
1622 "%c%c%c%c%c%c%c%c%c%c",
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001623 GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED,
Daniel Veillardf012a642001-07-23 19:10:52 +00001624 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE );
1625 buff->zctrl.next_out = buff->zbuff + hdr_lgth;
1626 buff->zctrl.avail_out = buff->size - hdr_lgth;
1627
1628 return ( buff );
1629}
1630
1631/**
1632 * xmlZMemBuffExtend
1633 * @buff: Buffer used to compress and consolidate data.
1634 * @ext_amt: Number of bytes to extend the buffer.
1635 *
1636 * Extend the internal buffer used to store the compressed data by the
1637 * specified amount.
1638 *
1639 * Returns 0 on success or -1 on failure to extend the buffer. On failure
1640 * the original buffer still exists at the original size.
1641 */
1642static int
1643xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) {
1644
1645 int rc = -1;
1646 size_t new_size;
1647 size_t cur_used;
1648
1649 unsigned char * tmp_ptr = NULL;
1650
1651 if ( buff == NULL )
1652 return ( -1 );
1653
1654 else if ( ext_amt == 0 )
1655 return ( 0 );
1656
1657 cur_used = buff->zctrl.next_out - buff->zbuff;
1658 new_size = buff->size + ext_amt;
1659
1660#ifdef DEBUG_HTTP
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001661 if ( cur_used > new_size )
Daniel Veillardf012a642001-07-23 19:10:52 +00001662 xmlGenericError( xmlGenericErrorContext,
1663 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
1664 "Buffer overwrite detected during compressed memory",
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001665 "buffer extension. Overflowed by",
Daniel Veillardf012a642001-07-23 19:10:52 +00001666 (cur_used - new_size ) );
1667#endif
1668
1669 tmp_ptr = xmlRealloc( buff->zbuff, new_size );
1670 if ( tmp_ptr != NULL ) {
1671 rc = 0;
1672 buff->size = new_size;
1673 buff->zbuff = tmp_ptr;
1674 buff->zctrl.next_out = tmp_ptr + cur_used;
1675 buff->zctrl.avail_out = new_size - cur_used;
1676 }
1677 else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001678 xmlChar msg[500];
1679 xmlStrPrintf(msg, 500,
David Kilzer4472c3a2016-05-13 15:13:17 +08001680 "xmlZMemBuffExtend: %s %lu bytes.\n",
Daniel Veillard05d987b2003-10-08 11:54:57 +00001681 "Allocation failure extending output buffer to",
Nick Wellnhoferc2545cb2016-08-22 11:44:18 +02001682 (unsigned long) new_size );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001683 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001684 }
1685
1686 return ( rc );
1687}
1688
1689/**
1690 * xmlZMemBuffAppend
1691 * @buff: Buffer used to compress and consolidate data
1692 * @src: Uncompressed source content to append to buffer
1693 * @len: Length of source data to append to buffer
1694 *
1695 * Compress and append data to the internal buffer. The data buffer
1696 * will be expanded if needed to store the additional data.
1697 *
1698 * Returns the number of bytes appended to the buffer or -1 on error.
1699 */
1700static int
1701xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) {
1702
1703 int z_err;
1704 size_t min_accept;
1705
1706 if ( ( buff == NULL ) || ( src == NULL ) )
1707 return ( -1 );
1708
1709 buff->zctrl.avail_in = len;
1710 buff->zctrl.next_in = (unsigned char *)src;
1711 while ( buff->zctrl.avail_in > 0 ) {
1712 /*
1713 ** Extend the buffer prior to deflate call if a reasonable amount
1714 ** of output buffer space is not available.
1715 */
1716 min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO;
1717 if ( buff->zctrl.avail_out <= min_accept ) {
1718 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1719 return ( -1 );
1720 }
1721
1722 z_err = deflate( &buff->zctrl, Z_NO_FLUSH );
1723 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001724 xmlChar msg[500];
1725 xmlStrPrintf(msg, 500,
David Kilzer4472c3a2016-05-13 15:13:17 +08001726 "xmlZMemBuffAppend: %s %d %s - %d",
Daniel Veillardf012a642001-07-23 19:10:52 +00001727 "Compression error while appending",
1728 len, "bytes to buffer. ZLIB error", z_err );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001729 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001730 return ( -1 );
1731 }
1732 }
1733
1734 buff->crc = crc32( buff->crc, (unsigned char *)src, len );
1735
1736 return ( len );
1737}
1738
1739/**
1740 * xmlZMemBuffGetContent
1741 * @buff: Compressed memory content buffer
1742 * @data_ref: Pointer reference to point to compressed content
1743 *
1744 * Flushes the compression buffers, appends gzip file trailers and
1745 * returns the compressed content and length of the compressed data.
1746 * NOTE: The gzip trailer code here is plagiarized from zlib source.
1747 *
1748 * Returns the length of the compressed data or -1 on error.
1749 */
1750static int
1751xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) {
1752
1753 int zlgth = -1;
1754 int z_err;
1755
1756 if ( ( buff == NULL ) || ( data_ref == NULL ) )
1757 return ( -1 );
1758
1759 /* Need to loop until compression output buffers are flushed */
1760
1761 do
1762 {
1763 z_err = deflate( &buff->zctrl, Z_FINISH );
1764 if ( z_err == Z_OK ) {
1765 /* In this case Z_OK means more buffer space needed */
1766
1767 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1768 return ( -1 );
1769 }
1770 }
1771 while ( z_err == Z_OK );
1772
1773 /* If the compression state is not Z_STREAM_END, some error occurred */
1774
1775 if ( z_err == Z_STREAM_END ) {
1776
1777 /* Need to append the gzip data trailer */
1778
1779 if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) {
1780 if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 )
1781 return ( -1 );
1782 }
1783
1784 /*
1785 ** For whatever reason, the CRC and length data are pushed out
1786 ** in reverse byte order. So a memcpy can't be used here.
1787 */
1788
1789 append_reverse_ulong( buff, buff->crc );
1790 append_reverse_ulong( buff, buff->zctrl.total_in );
1791
1792 zlgth = buff->zctrl.next_out - buff->zbuff;
1793 *data_ref = (char *)buff->zbuff;
1794 }
1795
Daniel Veillard05d987b2003-10-08 11:54:57 +00001796 else {
1797 xmlChar msg[500];
1798 xmlStrPrintf(msg, 500,
David Kilzer4472c3a2016-05-13 15:13:17 +08001799 "xmlZMemBuffGetContent: %s - %d\n",
Daniel Veillard05d987b2003-10-08 11:54:57 +00001800 "Error flushing zlib buffers. Error code", z_err );
1801 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1802 }
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001803
Daniel Veillardf012a642001-07-23 19:10:52 +00001804 return ( zlgth );
1805}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001806#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001807#endif /* HAVE_ZLIB_H */
1808
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001809#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001810/**
1811 * xmlFreeHTTPWriteCtxt
1812 * @ctxt: Context to cleanup
1813 *
1814 * Free allocated memory and reclaim system resources.
1815 *
1816 * No return value.
1817 */
1818static void
1819xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt )
1820{
1821 if ( ctxt->uri != NULL )
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001822 xmlFree( ctxt->uri );
Daniel Veillardf012a642001-07-23 19:10:52 +00001823
1824 if ( ctxt->doc_buff != NULL ) {
1825
1826#ifdef HAVE_ZLIB_H
1827 if ( ctxt->compression > 0 ) {
1828 xmlFreeZMemBuff( ctxt->doc_buff );
1829 }
1830 else
1831#endif
1832 {
1833 xmlOutputBufferClose( ctxt->doc_buff );
1834 }
1835 }
1836
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001837 xmlFree( ctxt );
Daniel Veillardf012a642001-07-23 19:10:52 +00001838 return;
1839}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001840#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001841
1842
Owen Taylor3473f882001-02-23 17:55:21 +00001843/**
1844 * xmlIOHTTPMatch:
1845 * @filename: the URI for matching
1846 *
1847 * check if the URI matches an HTTP one
1848 *
1849 * Returns 1 if matches, 0 otherwise
1850 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001851int
Owen Taylor3473f882001-02-23 17:55:21 +00001852xmlIOHTTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001853 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "http://", 7))
Owen Taylor3473f882001-02-23 17:55:21 +00001854 return(1);
1855 return(0);
1856}
1857
1858/**
1859 * xmlIOHTTPOpen:
1860 * @filename: the URI for matching
1861 *
1862 * open an HTTP I/O channel
1863 *
1864 * Returns an I/O context or NULL in case of error
1865 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001866void *
Owen Taylor3473f882001-02-23 17:55:21 +00001867xmlIOHTTPOpen (const char *filename) {
1868 return(xmlNanoHTTPOpen(filename, NULL));
1869}
1870
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001871#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001872/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001873 * xmlIOHTTPOpenW:
Daniel Veillardf012a642001-07-23 19:10:52 +00001874 * @post_uri: The destination URI for the document
1875 * @compression: The compression desired for the document.
1876 *
1877 * Open a temporary buffer to collect the document for a subsequent HTTP POST
1878 * request. Non-static as is called from the output buffer creation routine.
1879 *
1880 * Returns an I/O context or NULL in case of error.
1881 */
1882
1883void *
Nick Wellnhofer81c01ee2017-06-17 14:12:53 +02001884xmlIOHTTPOpenW(const char *post_uri, int compression ATTRIBUTE_UNUSED)
Daniel Veillard572577e2002-01-18 16:23:55 +00001885{
Daniel Veillardf012a642001-07-23 19:10:52 +00001886
Daniel Veillard572577e2002-01-18 16:23:55 +00001887 xmlIOHTTPWriteCtxtPtr ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001888
Daniel Veillard572577e2002-01-18 16:23:55 +00001889 if (post_uri == NULL)
1890 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001891
Daniel Veillard572577e2002-01-18 16:23:55 +00001892 ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt));
1893 if (ctxt == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001894 xmlIOErrMemory("creating HTTP output context");
Daniel Veillard572577e2002-01-18 16:23:55 +00001895 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001896 }
1897
Daniel Veillard572577e2002-01-18 16:23:55 +00001898 (void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt));
Daniel Veillardf012a642001-07-23 19:10:52 +00001899
Daniel Veillard572577e2002-01-18 16:23:55 +00001900 ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri);
1901 if (ctxt->uri == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001902 xmlIOErrMemory("copying URI");
Daniel Veillard572577e2002-01-18 16:23:55 +00001903 xmlFreeHTTPWriteCtxt(ctxt);
1904 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001905 }
1906
1907 /*
Daniel Veillard572577e2002-01-18 16:23:55 +00001908 * ** Since the document length is required for an HTTP post,
1909 * ** need to put the document into a buffer. A memory buffer
1910 * ** is being used to avoid pushing the data to disk and back.
1911 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001912
1913#ifdef HAVE_ZLIB_H
Daniel Veillard572577e2002-01-18 16:23:55 +00001914 if ((compression > 0) && (compression <= 9)) {
1915
1916 ctxt->compression = compression;
1917 ctxt->doc_buff = xmlCreateZMemBuff(compression);
1918 } else
Daniel Veillardf012a642001-07-23 19:10:52 +00001919#endif
1920 {
Daniel Veillard572577e2002-01-18 16:23:55 +00001921 /* Any character conversions should have been done before this */
Daniel Veillardf012a642001-07-23 19:10:52 +00001922
Daniel Veillardda3fee42008-09-01 13:08:57 +00001923 ctxt->doc_buff = xmlAllocOutputBufferInternal(NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001924 }
1925
Daniel Veillard572577e2002-01-18 16:23:55 +00001926 if (ctxt->doc_buff == NULL) {
1927 xmlFreeHTTPWriteCtxt(ctxt);
1928 ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001929 }
1930
Daniel Veillard572577e2002-01-18 16:23:55 +00001931 return (ctxt);
Daniel Veillardf012a642001-07-23 19:10:52 +00001932}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001933#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardda3fee42008-09-01 13:08:57 +00001934
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001935#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001936/**
1937 * xmlIOHTTPDfltOpenW
1938 * @post_uri: The destination URI for this document.
1939 *
1940 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
1941 * HTTP post command. This function should generally not be used as
1942 * the open callback is short circuited in xmlOutputBufferCreateFile.
1943 *
1944 * Returns a pointer to the new IO context.
1945 */
1946static void *
1947xmlIOHTTPDfltOpenW( const char * post_uri ) {
1948 return ( xmlIOHTTPOpenW( post_uri, 0 ) );
1949}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001950#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001951
1952/**
Owen Taylor3473f882001-02-23 17:55:21 +00001953 * xmlIOHTTPRead:
1954 * @context: the I/O context
1955 * @buffer: where to drop data
1956 * @len: number of bytes to write
1957 *
1958 * Read @len bytes to @buffer from the I/O channel.
1959 *
1960 * Returns the number of bytes written
1961 */
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001962int
Owen Taylor3473f882001-02-23 17:55:21 +00001963xmlIOHTTPRead(void * context, char * buffer, int len) {
Daniel Veillard5ea30d72004-11-08 11:54:28 +00001964 if ((buffer == NULL) || (len < 0)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001965 return(xmlNanoHTTPRead(context, &buffer[0], len));
1966}
1967
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001968#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001969/**
Daniel Veillardf012a642001-07-23 19:10:52 +00001970 * xmlIOHTTPWrite
1971 * @context: previously opened writing context
1972 * @buffer: data to output to temporary buffer
1973 * @len: bytes to output
1974 *
1975 * Collect data from memory buffer into a temporary file for later
1976 * processing.
1977 *
1978 * Returns number of bytes written.
1979 */
1980
1981static int
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001982xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001983
1984 xmlIOHTTPWriteCtxtPtr ctxt = context;
1985
1986 if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
1987 return ( -1 );
1988
1989 if ( len > 0 ) {
1990
1991 /* Use gzwrite or fwrite as previously setup in the open call */
1992
1993#ifdef HAVE_ZLIB_H
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001994 if ( ctxt->compression > 0 )
Daniel Veillardf012a642001-07-23 19:10:52 +00001995 len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len );
1996
1997 else
1998#endif
1999 len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
2000
2001 if ( len < 0 ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002002 xmlChar msg[500];
2003 xmlStrPrintf(msg, 500,
David Kilzer4472c3a2016-05-13 15:13:17 +08002004 "xmlIOHTTPWrite: %s\n%s '%s'.\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00002005 "Error appending to internal buffer.",
2006 "Error sending document to URI",
2007 ctxt->uri );
Daniel Veillard05d987b2003-10-08 11:54:57 +00002008 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00002009 }
2010 }
2011
2012 return ( len );
2013}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002014#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00002015
2016
2017/**
Owen Taylor3473f882001-02-23 17:55:21 +00002018 * xmlIOHTTPClose:
2019 * @context: the I/O context
2020 *
2021 * Close an HTTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00002022 *
2023 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00002024 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002025int
Owen Taylor3473f882001-02-23 17:55:21 +00002026xmlIOHTTPClose (void * context) {
2027 xmlNanoHTTPClose(context);
Daniel Veillardf012a642001-07-23 19:10:52 +00002028 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002029}
Daniel Veillardf012a642001-07-23 19:10:52 +00002030
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002031#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00002032/**
2033 * xmlIOHTTCloseWrite
2034 * @context: The I/O context
2035 * @http_mthd: The HTTP method to be used when sending the data
2036 *
2037 * Close the transmit HTTP I/O channel and actually send the data.
2038 */
2039static int
2040xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
2041
2042 int close_rc = -1;
2043 int http_rtn = 0;
2044 int content_lgth = 0;
2045 xmlIOHTTPWriteCtxtPtr ctxt = context;
2046
2047 char * http_content = NULL;
2048 char * content_encoding = NULL;
2049 char * content_type = (char *) "text/xml";
2050 void * http_ctxt = NULL;
2051
2052 if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
2053 return ( -1 );
2054
2055 /* Retrieve the content from the appropriate buffer */
2056
2057#ifdef HAVE_ZLIB_H
2058
2059 if ( ctxt->compression > 0 ) {
2060 content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
2061 content_encoding = (char *) "Content-Encoding: gzip";
2062 }
2063 else
2064#endif
2065 {
2066 /* Pull the data out of the memory output buffer */
2067
2068 xmlOutputBufferPtr dctxt = ctxt->doc_buff;
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002069 http_content = (char *) xmlBufContent(dctxt->buffer);
2070 content_lgth = xmlBufUse(dctxt->buffer);
Daniel Veillardf012a642001-07-23 19:10:52 +00002071 }
2072
2073 if ( http_content == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002074 xmlChar msg[500];
2075 xmlStrPrintf(msg, 500,
David Kilzer4472c3a2016-05-13 15:13:17 +08002076 "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
Daniel Veillard05d987b2003-10-08 11:54:57 +00002077 "Error retrieving content.\nUnable to",
2078 http_mthd, "data to URI", ctxt->uri );
2079 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00002080 }
2081
2082 else {
2083
2084 http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
Hans Breuer2ad41ca2009-08-11 17:51:22 +02002085 &content_type, content_encoding,
Daniel Veillardf012a642001-07-23 19:10:52 +00002086 content_lgth );
2087
2088 if ( http_ctxt != NULL ) {
2089#ifdef DEBUG_HTTP
2090 /* If testing/debugging - dump reply with request content */
2091
2092 FILE * tst_file = NULL;
2093 char buffer[ 4096 ];
2094 char * dump_name = NULL;
2095 int avail;
2096
2097 xmlGenericError( xmlGenericErrorContext,
2098 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
2099 http_mthd, ctxt->uri,
2100 xmlNanoHTTPReturnCode( http_ctxt ) );
2101
2102 /*
2103 ** Since either content or reply may be gzipped,
Hans Breuer2ad41ca2009-08-11 17:51:22 +02002104 ** dump them to separate files instead of the
Daniel Veillardf012a642001-07-23 19:10:52 +00002105 ** standard error context.
2106 */
2107
2108 dump_name = tempnam( NULL, "lxml" );
2109 if ( dump_name != NULL ) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002110 (void)snprintf( buffer, sizeof(buffer), "%s.content", dump_name );
Daniel Veillardf012a642001-07-23 19:10:52 +00002111
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00002112 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00002113 if ( tst_file != NULL ) {
2114 xmlGenericError( xmlGenericErrorContext,
2115 "Transmitted content saved in file: %s\n", buffer );
2116
2117 fwrite( http_content, sizeof( char ),
2118 content_lgth, tst_file );
2119 fclose( tst_file );
2120 }
2121
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002122 (void)snprintf( buffer, sizeof(buffer), "%s.reply", dump_name );
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00002123 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00002124 if ( tst_file != NULL ) {
2125 xmlGenericError( xmlGenericErrorContext,
2126 "Reply content saved in file: %s\n", buffer );
2127
2128
2129 while ( (avail = xmlNanoHTTPRead( http_ctxt,
2130 buffer, sizeof( buffer ) )) > 0 ) {
2131
2132 fwrite( buffer, sizeof( char ), avail, tst_file );
2133 }
2134
2135 fclose( tst_file );
2136 }
2137
2138 free( dump_name );
2139 }
2140#endif /* DEBUG_HTTP */
2141
2142 http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
2143 if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
2144 close_rc = 0;
Daniel Veillard05d987b2003-10-08 11:54:57 +00002145 else {
2146 xmlChar msg[500];
2147 xmlStrPrintf(msg, 500,
David Kilzer4472c3a2016-05-13 15:13:17 +08002148 "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00002149 http_mthd, content_lgth,
2150 "bytes to URI", ctxt->uri,
2151 "failed. HTTP return code:", http_rtn );
Daniel Veillard05d987b2003-10-08 11:54:57 +00002152 xmlIOErr(XML_IO_WRITE, (const char *) msg);
2153 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002154
2155 xmlNanoHTTPClose( http_ctxt );
2156 xmlFree( content_type );
2157 }
2158 }
2159
2160 /* Final cleanups */
2161
2162 xmlFreeHTTPWriteCtxt( ctxt );
2163
2164 return ( close_rc );
2165}
2166
2167/**
2168 * xmlIOHTTPClosePut
2169 *
2170 * @context: The I/O context
2171 *
2172 * Close the transmit HTTP I/O channel and actually send data using a PUT
2173 * HTTP method.
2174 */
2175static int
2176xmlIOHTTPClosePut( void * ctxt ) {
2177 return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
2178}
2179
2180
2181/**
2182 * xmlIOHTTPClosePost
2183 *
2184 * @context: The I/O context
2185 *
2186 * Close the transmit HTTP I/O channel and actually send data using a POST
2187 * HTTP method.
2188 */
2189static int
2190xmlIOHTTPClosePost( void * ctxt ) {
2191 return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
2192}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002193#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00002194
Owen Taylor3473f882001-02-23 17:55:21 +00002195#endif /* LIBXML_HTTP_ENABLED */
2196
2197#ifdef LIBXML_FTP_ENABLED
2198/************************************************************************
2199 * *
2200 * I/O for FTP file accesses *
2201 * *
2202 ************************************************************************/
2203/**
2204 * xmlIOFTPMatch:
2205 * @filename: the URI for matching
2206 *
2207 * check if the URI matches an FTP one
2208 *
2209 * Returns 1 if matches, 0 otherwise
2210 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002211int
Owen Taylor3473f882001-02-23 17:55:21 +00002212xmlIOFTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002213 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "ftp://", 6))
Owen Taylor3473f882001-02-23 17:55:21 +00002214 return(1);
2215 return(0);
2216}
2217
2218/**
2219 * xmlIOFTPOpen:
2220 * @filename: the URI for matching
2221 *
2222 * open an FTP I/O channel
2223 *
2224 * Returns an I/O context or NULL in case of error
2225 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002226void *
Owen Taylor3473f882001-02-23 17:55:21 +00002227xmlIOFTPOpen (const char *filename) {
2228 return(xmlNanoFTPOpen(filename));
2229}
2230
2231/**
2232 * xmlIOFTPRead:
2233 * @context: the I/O context
2234 * @buffer: where to drop data
2235 * @len: number of bytes to write
2236 *
2237 * Read @len bytes to @buffer from the I/O channel.
2238 *
2239 * Returns the number of bytes written
2240 */
Hans Breuer2ad41ca2009-08-11 17:51:22 +02002241int
Owen Taylor3473f882001-02-23 17:55:21 +00002242xmlIOFTPRead(void * context, char * buffer, int len) {
Daniel Veillard5ea30d72004-11-08 11:54:28 +00002243 if ((buffer == NULL) || (len < 0)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002244 return(xmlNanoFTPRead(context, &buffer[0], len));
2245}
2246
2247/**
2248 * xmlIOFTPClose:
2249 * @context: the I/O context
2250 *
2251 * Close an FTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00002252 *
2253 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00002254 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002255int
Owen Taylor3473f882001-02-23 17:55:21 +00002256xmlIOFTPClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +00002257 return ( xmlNanoFTPClose(context) );
Owen Taylor3473f882001-02-23 17:55:21 +00002258}
2259#endif /* LIBXML_FTP_ENABLED */
2260
2261
2262/**
2263 * xmlRegisterInputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002264 * @matchFunc: the xmlInputMatchCallback
2265 * @openFunc: the xmlInputOpenCallback
2266 * @readFunc: the xmlInputReadCallback
2267 * @closeFunc: the xmlInputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00002268 *
2269 * Register a new set of I/O callback for handling parser input.
2270 *
2271 * Returns the registered handler number or -1 in case of error
2272 */
2273int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002274xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
2275 xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
2276 xmlInputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002277 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
2278 return(-1);
2279 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002280 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
2281 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
2282 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
2283 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00002284 xmlInputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002285 return(xmlInputCallbackNr++);
2286}
2287
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002288#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002289/**
2290 * xmlRegisterOutputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002291 * @matchFunc: the xmlOutputMatchCallback
2292 * @openFunc: the xmlOutputOpenCallback
2293 * @writeFunc: the xmlOutputWriteCallback
2294 * @closeFunc: the xmlOutputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00002295 *
2296 * Register a new set of I/O callback for handling output.
2297 *
2298 * Returns the registered handler number or -1 in case of error
2299 */
2300int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002301xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
2302 xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
2303 xmlOutputCloseCallback closeFunc) {
Daniel Veillard0d5e58f2009-08-24 13:52:23 +02002304 if (xmlOutputCallbackNr >= MAX_OUTPUT_CALLBACK) {
Owen Taylor3473f882001-02-23 17:55:21 +00002305 return(-1);
2306 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002307 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
2308 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
2309 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
2310 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00002311 xmlOutputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002312 return(xmlOutputCallbackNr++);
2313}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002314#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002315
2316/**
2317 * xmlRegisterDefaultInputCallbacks:
2318 *
2319 * Registers the default compiled-in I/O handlers.
2320 */
2321void
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +00002322xmlRegisterDefaultInputCallbacks(void) {
Owen Taylor3473f882001-02-23 17:55:21 +00002323 if (xmlInputCallbackInitialized)
2324 return;
2325
Daniel Veillard8ca85b22006-09-01 09:56:07 +00002326#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
2327 xmlInitPlatformSpecificIo();
2328#endif
2329
Owen Taylor3473f882001-02-23 17:55:21 +00002330 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
2331 xmlFileRead, xmlFileClose);
2332#ifdef HAVE_ZLIB_H
2333 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
2334 xmlGzfileRead, xmlGzfileClose);
2335#endif /* HAVE_ZLIB_H */
Daniel Veillard18b89882015-11-03 15:46:29 +08002336#ifdef LIBXML_LZMA_ENABLED
Anders F Bjorklundeae52612011-09-18 16:59:13 +02002337 xmlRegisterInputCallbacks(xmlXzfileMatch, xmlXzfileOpen,
2338 xmlXzfileRead, xmlXzfileClose);
Daniel Veillard18b89882015-11-03 15:46:29 +08002339#endif /* LIBXML_LZMA_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002340
2341#ifdef LIBXML_HTTP_ENABLED
2342 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
2343 xmlIOHTTPRead, xmlIOHTTPClose);
2344#endif /* LIBXML_HTTP_ENABLED */
2345
2346#ifdef LIBXML_FTP_ENABLED
2347 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
2348 xmlIOFTPRead, xmlIOFTPClose);
2349#endif /* LIBXML_FTP_ENABLED */
2350 xmlInputCallbackInitialized = 1;
2351}
2352
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002353#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002354/**
2355 * xmlRegisterDefaultOutputCallbacks:
2356 *
2357 * Registers the default compiled-in I/O handlers.
2358 */
2359void
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +00002360xmlRegisterDefaultOutputCallbacks (void) {
Owen Taylor3473f882001-02-23 17:55:21 +00002361 if (xmlOutputCallbackInitialized)
2362 return;
2363
Daniel Veillard8ca85b22006-09-01 09:56:07 +00002364#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
2365 xmlInitPlatformSpecificIo();
2366#endif
2367
Owen Taylor3473f882001-02-23 17:55:21 +00002368 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
2369 xmlFileWrite, xmlFileClose);
Daniel Veillardf012a642001-07-23 19:10:52 +00002370
2371#ifdef LIBXML_HTTP_ENABLED
2372 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
2373 xmlIOHTTPWrite, xmlIOHTTPClosePut);
2374#endif
2375
Owen Taylor3473f882001-02-23 17:55:21 +00002376/*********************************
2377 No way a-priori to distinguish between gzipped files from
2378 uncompressed ones except opening if existing then closing
2379 and saving with same compression ratio ... a pain.
2380
2381#ifdef HAVE_ZLIB_H
2382 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
2383 xmlGzfileWrite, xmlGzfileClose);
2384#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002385
2386 Nor FTP PUT ....
2387#ifdef LIBXML_FTP_ENABLED
2388 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
2389 xmlIOFTPWrite, xmlIOFTPClose);
2390#endif
2391 **********************************/
2392 xmlOutputCallbackInitialized = 1;
2393}
2394
Daniel Veillardf012a642001-07-23 19:10:52 +00002395#ifdef LIBXML_HTTP_ENABLED
2396/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00002397 * xmlRegisterHTTPPostCallbacks:
Daniel Veillardf012a642001-07-23 19:10:52 +00002398 *
2399 * By default, libxml submits HTTP output requests using the "PUT" method.
2400 * Calling this method changes the HTTP output method to use the "POST"
2401 * method instead.
2402 *
2403 */
2404void
2405xmlRegisterHTTPPostCallbacks( void ) {
2406
2407 /* Register defaults if not done previously */
2408
2409 if ( xmlOutputCallbackInitialized == 0 )
2410 xmlRegisterDefaultOutputCallbacks( );
2411
2412 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
2413 xmlIOHTTPWrite, xmlIOHTTPClosePost);
2414 return;
2415}
2416#endif
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002417#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00002418
Owen Taylor3473f882001-02-23 17:55:21 +00002419/**
2420 * xmlAllocParserInputBuffer:
2421 * @enc: the charset encoding if known
2422 *
2423 * Create a buffered parser input for progressive parsing
2424 *
2425 * Returns the new parser input or NULL
2426 */
2427xmlParserInputBufferPtr
2428xmlAllocParserInputBuffer(xmlCharEncoding enc) {
2429 xmlParserInputBufferPtr ret;
2430
2431 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2432 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002433 xmlIOErrMemory("creating input buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00002434 return(NULL);
2435 }
2436 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002437 ret->buffer = xmlBufCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00002438 if (ret->buffer == NULL) {
2439 xmlFree(ret);
2440 return(NULL);
2441 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002442 xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_DOUBLEIT);
Owen Taylor3473f882001-02-23 17:55:21 +00002443 ret->encoder = xmlGetCharEncodingHandler(enc);
2444 if (ret->encoder != NULL)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002445 ret->raw = xmlBufCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00002446 else
2447 ret->raw = NULL;
2448 ret->readcallback = NULL;
2449 ret->closecallback = NULL;
2450 ret->context = NULL;
William M. Brackc07329e2003-09-08 01:57:30 +00002451 ret->compressed = -1;
Daniel Veillard36711902004-02-11 13:25:26 +00002452 ret->rawconsumed = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002453
2454 return(ret);
2455}
2456
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002457#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002458/**
2459 * xmlAllocOutputBuffer:
2460 * @encoder: the encoding converter or NULL
2461 *
2462 * Create a buffered parser output
2463 *
2464 * Returns the new parser output or NULL
2465 */
2466xmlOutputBufferPtr
2467xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
2468 xmlOutputBufferPtr ret;
2469
2470 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
2471 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002472 xmlIOErrMemory("creating output buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00002473 return(NULL);
2474 }
2475 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002476 ret->buffer = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00002477 if (ret->buffer == NULL) {
2478 xmlFree(ret);
2479 return(NULL);
2480 }
Daniel Veillarde83e93e2008-08-30 12:52:26 +00002481
Daniel Veillard43bc89c2009-03-23 19:32:04 +00002482 /* try to avoid a performance problem with Windows realloc() */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002483 if (xmlBufGetAllocationScheme(ret->buffer) == XML_BUFFER_ALLOC_EXACT)
2484 xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_DOUBLEIT);
Daniel Veillard43bc89c2009-03-23 19:32:04 +00002485
Daniel Veillardda3fee42008-09-01 13:08:57 +00002486 ret->encoder = encoder;
2487 if (encoder != NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002488 ret->conv = xmlBufCreateSize(4000);
Daniel Veillardda3fee42008-09-01 13:08:57 +00002489 if (ret->conv == NULL) {
2490 xmlFree(ret);
2491 return(NULL);
2492 }
2493
2494 /*
2495 * This call is designed to initiate the encoder state
2496 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002497 xmlCharEncOutput(ret, 1);
Daniel Veillardda3fee42008-09-01 13:08:57 +00002498 } else
2499 ret->conv = NULL;
2500 ret->writecallback = NULL;
2501 ret->closecallback = NULL;
2502 ret->context = NULL;
2503 ret->written = 0;
2504
2505 return(ret);
2506}
2507
2508/**
2509 * xmlAllocOutputBufferInternal:
2510 * @encoder: the encoding converter or NULL
2511 *
2512 * Create a buffered parser output
2513 *
2514 * Returns the new parser output or NULL
2515 */
2516xmlOutputBufferPtr
2517xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder) {
2518 xmlOutputBufferPtr ret;
2519
2520 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
2521 if (ret == NULL) {
2522 xmlIOErrMemory("creating output buffer");
2523 return(NULL);
2524 }
2525 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002526 ret->buffer = xmlBufCreate();
Daniel Veillardda3fee42008-09-01 13:08:57 +00002527 if (ret->buffer == NULL) {
2528 xmlFree(ret);
2529 return(NULL);
2530 }
2531
2532
Daniel Veillarde83e93e2008-08-30 12:52:26 +00002533 /*
2534 * For conversion buffers we use the special IO handling
2535 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002536 xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_IO);
Daniel Veillarde83e93e2008-08-30 12:52:26 +00002537
Owen Taylor3473f882001-02-23 17:55:21 +00002538 ret->encoder = encoder;
2539 if (encoder != NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002540 ret->conv = xmlBufCreateSize(4000);
Daniel Veillarde83e93e2008-08-30 12:52:26 +00002541 if (ret->conv == NULL) {
2542 xmlFree(ret);
2543 return(NULL);
2544 }
2545
Owen Taylor3473f882001-02-23 17:55:21 +00002546 /*
2547 * This call is designed to initiate the encoder state
2548 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002549 xmlCharEncOutput(ret, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00002550 } else
2551 ret->conv = NULL;
2552 ret->writecallback = NULL;
2553 ret->closecallback = NULL;
2554 ret->context = NULL;
2555 ret->written = 0;
2556
2557 return(ret);
2558}
Daniel Veillardda3fee42008-09-01 13:08:57 +00002559
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002560#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002561
2562/**
2563 * xmlFreeParserInputBuffer:
2564 * @in: a buffered parser input
2565 *
2566 * Free up the memory used by a buffered parser input
2567 */
2568void
2569xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
Daniel Veillard8d8bf2c2003-09-17 19:36:25 +00002570 if (in == NULL) return;
2571
Owen Taylor3473f882001-02-23 17:55:21 +00002572 if (in->raw) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002573 xmlBufFree(in->raw);
Owen Taylor3473f882001-02-23 17:55:21 +00002574 in->raw = NULL;
2575 }
2576 if (in->encoder != NULL) {
2577 xmlCharEncCloseFunc(in->encoder);
2578 }
2579 if (in->closecallback != NULL) {
2580 in->closecallback(in->context);
2581 }
2582 if (in->buffer != NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002583 xmlBufFree(in->buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00002584 in->buffer = NULL;
2585 }
2586
Owen Taylor3473f882001-02-23 17:55:21 +00002587 xmlFree(in);
2588}
2589
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002590#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002591/**
2592 * xmlOutputBufferClose:
2593 * @out: a buffered output
2594 *
2595 * flushes and close the output I/O channel
2596 * and free up all the associated resources
2597 *
2598 * Returns the number of byte written or -1 in case of error.
2599 */
2600int
Daniel Veillard828ce832003-10-08 19:19:10 +00002601xmlOutputBufferClose(xmlOutputBufferPtr out)
2602{
Owen Taylor3473f882001-02-23 17:55:21 +00002603 int written;
Daniel Veillardf012a642001-07-23 19:10:52 +00002604 int err_rc = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002605
2606 if (out == NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002607 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002608 if (out->writecallback != NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002609 xmlOutputBufferFlush(out);
Owen Taylor3473f882001-02-23 17:55:21 +00002610 if (out->closecallback != NULL) {
Daniel Veillard828ce832003-10-08 19:19:10 +00002611 err_rc = out->closecallback(out->context);
Owen Taylor3473f882001-02-23 17:55:21 +00002612 }
2613 written = out->written;
2614 if (out->conv) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002615 xmlBufFree(out->conv);
Daniel Veillard828ce832003-10-08 19:19:10 +00002616 out->conv = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002617 }
2618 if (out->encoder != NULL) {
2619 xmlCharEncCloseFunc(out->encoder);
2620 }
2621 if (out->buffer != NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002622 xmlBufFree(out->buffer);
Daniel Veillard828ce832003-10-08 19:19:10 +00002623 out->buffer = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002624 }
2625
Daniel Veillard828ce832003-10-08 19:19:10 +00002626 if (out->error)
2627 err_rc = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00002628 xmlFree(out);
Daniel Veillard828ce832003-10-08 19:19:10 +00002629 return ((err_rc == 0) ? written : err_rc);
Owen Taylor3473f882001-02-23 17:55:21 +00002630}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002631#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002632
Daniel Veillard1b243b42004-06-08 10:16:42 +00002633xmlParserInputBufferPtr
Daniel Veillard0335a842004-06-02 16:18:40 +00002634__xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002635 xmlParserInputBufferPtr ret;
Daniel Veillard388236f2001-07-08 18:35:48 +00002636 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002637 void *context = NULL;
2638
2639 if (xmlInputCallbackInitialized == 0)
2640 xmlRegisterDefaultInputCallbacks();
2641
2642 if (URI == NULL) return(NULL);
2643
2644 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002645 * Try to find one of the input accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002646 * Go in reverse to give precedence to user defined handlers.
Daniel Veillard388236f2001-07-08 18:35:48 +00002647 */
2648 if (context == NULL) {
2649 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
2650 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
2651 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002652 context = xmlInputCallbackTable[i].opencallback(URI);
Daniel Veillard847332a2003-10-18 11:29:40 +00002653 if (context != NULL) {
Daniel Veillard388236f2001-07-08 18:35:48 +00002654 break;
Daniel Veillard847332a2003-10-18 11:29:40 +00002655 }
Daniel Veillard388236f2001-07-08 18:35:48 +00002656 }
Owen Taylor3473f882001-02-23 17:55:21 +00002657 }
2658 }
2659 if (context == NULL) {
2660 return(NULL);
2661 }
2662
2663 /*
2664 * Allocate the Input buffer front-end.
2665 */
2666 ret = xmlAllocParserInputBuffer(enc);
2667 if (ret != NULL) {
2668 ret->context = context;
2669 ret->readcallback = xmlInputCallbackTable[i].readcallback;
2670 ret->closecallback = xmlInputCallbackTable[i].closecallback;
William M. Brackc07329e2003-09-08 01:57:30 +00002671#ifdef HAVE_ZLIB_H
William M. Brackc5cbf992003-10-29 22:15:13 +00002672 if ((xmlInputCallbackTable[i].opencallback == xmlGzfileOpen) &&
2673 (strcmp(URI, "-") != 0)) {
Mark Adlera7e79f22010-01-19 16:28:48 +01002674#if defined(ZLIB_VERNUM) && ZLIB_VERNUM >= 0x1230
2675 ret->compressed = !gzdirect(context);
2676#else
William M. Brackc07329e2003-09-08 01:57:30 +00002677 if (((z_stream *)context)->avail_in > 4) {
2678 char *cptr, buff4[4];
Daniel Veillard07cb8222003-09-10 10:51:05 +00002679 cptr = (char *) ((z_stream *)context)->next_in;
William M. Brackc07329e2003-09-08 01:57:30 +00002680 if (gzread(context, buff4, 4) == 4) {
2681 if (strncmp(buff4, cptr, 4) == 0)
2682 ret->compressed = 0;
2683 else
2684 ret->compressed = 1;
2685 gzrewind(context);
2686 }
2687 }
Mark Adlera7e79f22010-01-19 16:28:48 +01002688#endif
William M. Brackc07329e2003-09-08 01:57:30 +00002689 }
2690#endif
Daniel Veillard18b89882015-11-03 15:46:29 +08002691#ifdef LIBXML_LZMA_ENABLED
Daniel Veillard63588f42013-05-10 14:01:46 +08002692 if ((xmlInputCallbackTable[i].opencallback == xmlXzfileOpen) &&
2693 (strcmp(URI, "-") != 0)) {
2694 ret->compressed = __libxml2_xzcompressed(context);
2695 }
2696#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002697 }
William M. Brack42331a92004-07-29 07:07:16 +00002698 else
2699 xmlInputCallbackTable[i].closecallback (context);
2700
Owen Taylor3473f882001-02-23 17:55:21 +00002701 return(ret);
2702}
2703
2704/**
Daniel Veillard0335a842004-06-02 16:18:40 +00002705 * xmlParserInputBufferCreateFilename:
Owen Taylor3473f882001-02-23 17:55:21 +00002706 * @URI: a C string containing the URI or filename
Daniel Veillard0335a842004-06-02 16:18:40 +00002707 * @enc: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002708 *
Daniel Veillard0335a842004-06-02 16:18:40 +00002709 * Create a buffered parser input for the progressive parsing of a file
2710 * If filename is "-' then we use stdin as the input.
Owen Taylor3473f882001-02-23 17:55:21 +00002711 * Automatic support for ZLIB/Compress compressed document is provided
2712 * by default if found at compile-time.
Daniel Veillard0335a842004-06-02 16:18:40 +00002713 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
Owen Taylor3473f882001-02-23 17:55:21 +00002714 *
Daniel Veillard0335a842004-06-02 16:18:40 +00002715 * Returns the new parser input or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00002716 */
Daniel Veillard0335a842004-06-02 16:18:40 +00002717xmlParserInputBufferPtr
2718xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
2719 if ((xmlParserInputBufferCreateFilenameValue)) {
2720 return xmlParserInputBufferCreateFilenameValue(URI, enc);
2721 }
2722 return __xmlParserInputBufferCreateFilename(URI, enc);
2723}
2724
2725#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard1b243b42004-06-08 10:16:42 +00002726xmlOutputBufferPtr
Daniel Veillard0335a842004-06-02 16:18:40 +00002727__xmlOutputBufferCreateFilename(const char *URI,
Owen Taylor3473f882001-02-23 17:55:21 +00002728 xmlCharEncodingHandlerPtr encoder,
Daniel Veillard0335a842004-06-02 16:18:40 +00002729 int compression ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00002730 xmlOutputBufferPtr ret;
Daniel Veillard966a31e2004-05-09 02:58:44 +00002731 xmlURIPtr puri;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002732 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002733 void *context = NULL;
Daniel Veillard966a31e2004-05-09 02:58:44 +00002734 char *unescaped = NULL;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002735#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002736 int is_file_uri = 1;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002737#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00002738
Owen Taylor3473f882001-02-23 17:55:21 +00002739 if (xmlOutputCallbackInitialized == 0)
2740 xmlRegisterDefaultOutputCallbacks();
2741
2742 if (URI == NULL) return(NULL);
2743
Daniel Veillard966a31e2004-05-09 02:58:44 +00002744 puri = xmlParseURI(URI);
2745 if (puri != NULL) {
Daniel Veillard8fcd2ca2005-07-03 14:42:56 +00002746#ifdef HAVE_ZLIB_H
Daniel Veillard18a65092004-05-11 15:57:42 +00002747 if ((puri->scheme != NULL) &&
2748 (!xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
Daniel Veillard966a31e2004-05-09 02:58:44 +00002749 is_file_uri = 0;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002750#endif
Daniel Veillard966a31e2004-05-09 02:58:44 +00002751 /*
2752 * try to limit the damages of the URI unescaping code.
2753 */
Daniel Veillarde8967e02006-10-11 09:15:00 +00002754 if ((puri->scheme == NULL) ||
2755 (xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
Daniel Veillard966a31e2004-05-09 02:58:44 +00002756 unescaped = xmlURIUnescapeString(URI, 0, NULL);
2757 xmlFreeURI(puri);
2758 }
Owen Taylor3473f882001-02-23 17:55:21 +00002759
2760 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002761 * Try to find one of the output accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002762 * Go in reverse to give precedence to user defined handlers.
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002763 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00002764 */
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002765 if (unescaped != NULL) {
2766#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002767 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002768 context = xmlGzfileOpenW(unescaped, compression);
2769 if (context != NULL) {
Daniel Veillardda3fee42008-09-01 13:08:57 +00002770 ret = xmlAllocOutputBufferInternal(encoder);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002771 if (ret != NULL) {
2772 ret->context = context;
2773 ret->writecallback = xmlGzfileWrite;
2774 ret->closecallback = xmlGzfileClose;
2775 }
2776 xmlFree(unescaped);
2777 return(ret);
2778 }
2779 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002780#endif
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002781 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2782 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
2783 (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
2784#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2785 /* Need to pass compression parameter into HTTP open calls */
2786 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2787 context = xmlIOHTTPOpenW(unescaped, compression);
2788 else
2789#endif
2790 context = xmlOutputCallbackTable[i].opencallback(unescaped);
2791 if (context != NULL)
2792 break;
2793 }
2794 }
2795 xmlFree(unescaped);
2796 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002797
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002798 /*
2799 * If this failed try with a non-escaped URI this may be a strange
2800 * filename
2801 */
2802 if (context == NULL) {
2803#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002804 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002805 context = xmlGzfileOpenW(URI, compression);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002806 if (context != NULL) {
Daniel Veillardda3fee42008-09-01 13:08:57 +00002807 ret = xmlAllocOutputBufferInternal(encoder);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002808 if (ret != NULL) {
2809 ret->context = context;
2810 ret->writecallback = xmlGzfileWrite;
2811 ret->closecallback = xmlGzfileClose;
2812 }
2813 return(ret);
2814 }
2815 }
2816#endif
2817 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2818 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002819 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002820#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2821 /* Need to pass compression parameter into HTTP open calls */
2822 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2823 context = xmlIOHTTPOpenW(URI, compression);
2824 else
2825#endif
2826 context = xmlOutputCallbackTable[i].opencallback(URI);
2827 if (context != NULL)
2828 break;
2829 }
Owen Taylor3473f882001-02-23 17:55:21 +00002830 }
2831 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002832
Owen Taylor3473f882001-02-23 17:55:21 +00002833 if (context == NULL) {
2834 return(NULL);
2835 }
2836
2837 /*
2838 * Allocate the Output buffer front-end.
2839 */
Daniel Veillardda3fee42008-09-01 13:08:57 +00002840 ret = xmlAllocOutputBufferInternal(encoder);
Owen Taylor3473f882001-02-23 17:55:21 +00002841 if (ret != NULL) {
2842 ret->context = context;
2843 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
2844 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
2845 }
2846 return(ret);
2847}
Daniel Veillard0335a842004-06-02 16:18:40 +00002848
2849/**
2850 * xmlOutputBufferCreateFilename:
2851 * @URI: a C string containing the URI or filename
2852 * @encoder: the encoding converter or NULL
2853 * @compression: the compression ration (0 none, 9 max).
2854 *
2855 * Create a buffered output for the progressive saving of a file
2856 * If filename is "-' then we use stdout as the output.
2857 * Automatic support for ZLIB/Compress compressed document is provided
2858 * by default if found at compile-time.
2859 * TODO: currently if compression is set, the library only support
2860 * writing to a local file.
2861 *
2862 * Returns the new output or NULL
2863 */
2864xmlOutputBufferPtr
2865xmlOutputBufferCreateFilename(const char *URI,
2866 xmlCharEncodingHandlerPtr encoder,
2867 int compression ATTRIBUTE_UNUSED) {
2868 if ((xmlOutputBufferCreateFilenameValue)) {
2869 return xmlOutputBufferCreateFilenameValue(URI, encoder, compression);
2870 }
2871 return __xmlOutputBufferCreateFilename(URI, encoder, compression);
2872}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002873#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002874
2875/**
2876 * xmlParserInputBufferCreateFile:
Hans Breuer2ad41ca2009-08-11 17:51:22 +02002877 * @file: a FILE*
Owen Taylor3473f882001-02-23 17:55:21 +00002878 * @enc: the charset encoding if known
2879 *
2880 * Create a buffered parser input for the progressive parsing of a FILE *
2881 * buffered C I/O
2882 *
2883 * Returns the new parser input or NULL
2884 */
2885xmlParserInputBufferPtr
2886xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
2887 xmlParserInputBufferPtr ret;
2888
2889 if (xmlInputCallbackInitialized == 0)
2890 xmlRegisterDefaultInputCallbacks();
2891
2892 if (file == NULL) return(NULL);
2893
2894 ret = xmlAllocParserInputBuffer(enc);
2895 if (ret != NULL) {
2896 ret->context = file;
2897 ret->readcallback = xmlFileRead;
2898 ret->closecallback = xmlFileFlush;
2899 }
2900
2901 return(ret);
2902}
2903
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002904#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002905/**
2906 * xmlOutputBufferCreateFile:
Hans Breuer2ad41ca2009-08-11 17:51:22 +02002907 * @file: a FILE*
Owen Taylor3473f882001-02-23 17:55:21 +00002908 * @encoder: the encoding converter or NULL
2909 *
2910 * Create a buffered output for the progressive saving to a FILE *
2911 * buffered C I/O
2912 *
2913 * Returns the new parser output or NULL
2914 */
2915xmlOutputBufferPtr
2916xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
2917 xmlOutputBufferPtr ret;
2918
2919 if (xmlOutputCallbackInitialized == 0)
2920 xmlRegisterDefaultOutputCallbacks();
2921
2922 if (file == NULL) return(NULL);
2923
Daniel Veillardda3fee42008-09-01 13:08:57 +00002924 ret = xmlAllocOutputBufferInternal(encoder);
Owen Taylor3473f882001-02-23 17:55:21 +00002925 if (ret != NULL) {
2926 ret->context = file;
2927 ret->writecallback = xmlFileWrite;
2928 ret->closecallback = xmlFileFlush;
2929 }
2930
2931 return(ret);
2932}
Daniel Veillard9a00fd22005-11-09 08:56:26 +00002933
2934/**
2935 * xmlOutputBufferCreateBuffer:
2936 * @buffer: a xmlBufferPtr
2937 * @encoder: the encoding converter or NULL
2938 *
2939 * Create a buffered output for the progressive saving to a xmlBuffer
2940 *
2941 * Returns the new parser output or NULL
2942 */
2943xmlOutputBufferPtr
2944xmlOutputBufferCreateBuffer(xmlBufferPtr buffer,
2945 xmlCharEncodingHandlerPtr encoder) {
2946 xmlOutputBufferPtr ret;
2947
2948 if (buffer == NULL) return(NULL);
2949
Rob Richardsa44f2342005-11-09 18:03:45 +00002950 ret = xmlOutputBufferCreateIO((xmlOutputWriteCallback)
2951 xmlBufferWrite,
2952 (xmlOutputCloseCallback)
Daniel Veillard4d3866c2005-11-13 12:43:59 +00002953 NULL, (void *) buffer, encoder);
Daniel Veillard9a00fd22005-11-09 08:56:26 +00002954
2955 return(ret);
2956}
2957
Daniel Veillarde258ade2012-08-06 11:16:30 +08002958/**
2959 * xmlOutputBufferGetContent:
2960 * @out: an xmlOutputBufferPtr
2961 *
2962 * Gives a pointer to the data currently held in the output buffer
2963 *
2964 * Returns a pointer to the data or NULL in case of error
2965 */
2966const xmlChar *
2967xmlOutputBufferGetContent(xmlOutputBufferPtr out) {
2968 if ((out == NULL) || (out->buffer == NULL))
2969 return(NULL);
2970
2971 return(xmlBufContent(out->buffer));
2972}
2973
2974/**
2975 * xmlOutputBufferGetSize:
2976 * @out: an xmlOutputBufferPtr
2977 *
2978 * Gives the length of the data currently held in the output buffer
2979 *
2980 * Returns 0 in case or error or no data is held, the size otherwise
2981 */
2982size_t
2983xmlOutputBufferGetSize(xmlOutputBufferPtr out) {
2984 if ((out == NULL) || (out->buffer == NULL))
2985 return(0);
2986
2987 return(xmlBufUse(out->buffer));
2988}
2989
2990
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002991#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002992
2993/**
2994 * xmlParserInputBufferCreateFd:
2995 * @fd: a file descriptor number
2996 * @enc: the charset encoding if known
2997 *
2998 * Create a buffered parser input for the progressive parsing for the input
2999 * from a file descriptor
3000 *
3001 * Returns the new parser input or NULL
3002 */
3003xmlParserInputBufferPtr
3004xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
3005 xmlParserInputBufferPtr ret;
3006
3007 if (fd < 0) return(NULL);
3008
3009 ret = xmlAllocParserInputBuffer(enc);
3010 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00003011 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00003012 ret->readcallback = xmlFdRead;
3013 ret->closecallback = xmlFdClose;
3014 }
3015
3016 return(ret);
3017}
3018
3019/**
3020 * xmlParserInputBufferCreateMem:
3021 * @mem: the memory input
3022 * @size: the length of the memory block
3023 * @enc: the charset encoding if known
3024 *
3025 * Create a buffered parser input for the progressive parsing for the input
3026 * from a memory area.
3027 *
3028 * Returns the new parser input or NULL
3029 */
3030xmlParserInputBufferPtr
3031xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
3032 xmlParserInputBufferPtr ret;
William M. Bracka3215c72004-07-31 16:24:01 +00003033 int errcode;
Owen Taylor3473f882001-02-23 17:55:21 +00003034
Nick Wellnhofer94f6ce82017-06-08 22:36:09 +02003035 if (size < 0) return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003036 if (mem == NULL) return(NULL);
3037
3038 ret = xmlAllocParserInputBuffer(enc);
3039 if (ret != NULL) {
3040 ret->context = (void *) mem;
3041 ret->readcallback = (xmlInputReadCallback) xmlNop;
3042 ret->closecallback = NULL;
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003043 errcode = xmlBufAdd(ret->buffer, (const xmlChar *) mem, size);
William M. Bracka3215c72004-07-31 16:24:01 +00003044 if (errcode != 0) {
3045 xmlFree(ret);
3046 return(NULL);
3047 }
Owen Taylor3473f882001-02-23 17:55:21 +00003048 }
3049
3050 return(ret);
3051}
3052
3053/**
Daniel Veillard53350552003-09-18 13:35:51 +00003054 * xmlParserInputBufferCreateStatic:
3055 * @mem: the memory input
3056 * @size: the length of the memory block
3057 * @enc: the charset encoding if known
3058 *
3059 * Create a buffered parser input for the progressive parsing for the input
3060 * from an immutable memory area. This will not copy the memory area to
3061 * the buffer, but the memory is expected to be available until the end of
3062 * the parsing, this is useful for example when using mmap'ed file.
3063 *
3064 * Returns the new parser input or NULL
3065 */
3066xmlParserInputBufferPtr
3067xmlParserInputBufferCreateStatic(const char *mem, int size,
3068 xmlCharEncoding enc) {
3069 xmlParserInputBufferPtr ret;
3070
Nick Wellnhofer94f6ce82017-06-08 22:36:09 +02003071 if (size < 0) return(NULL);
Daniel Veillard53350552003-09-18 13:35:51 +00003072 if (mem == NULL) return(NULL);
3073
3074 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
3075 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003076 xmlIOErrMemory("creating input buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00003077 return(NULL);
3078 }
3079 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003080 ret->buffer = xmlBufCreateStatic((void *)mem, (size_t) size);
Daniel Veillard53350552003-09-18 13:35:51 +00003081 if (ret->buffer == NULL) {
3082 xmlFree(ret);
3083 return(NULL);
3084 }
3085 ret->encoder = xmlGetCharEncodingHandler(enc);
3086 if (ret->encoder != NULL)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003087 ret->raw = xmlBufCreateSize(2 * xmlDefaultBufferSize);
Daniel Veillard53350552003-09-18 13:35:51 +00003088 else
3089 ret->raw = NULL;
3090 ret->compressed = -1;
3091 ret->context = (void *) mem;
3092 ret->readcallback = NULL;
3093 ret->closecallback = NULL;
3094
3095 return(ret);
3096}
3097
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003098#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard53350552003-09-18 13:35:51 +00003099/**
Owen Taylor3473f882001-02-23 17:55:21 +00003100 * xmlOutputBufferCreateFd:
3101 * @fd: a file descriptor number
3102 * @encoder: the encoding converter or NULL
3103 *
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003104 * Create a buffered output for the progressive saving
Owen Taylor3473f882001-02-23 17:55:21 +00003105 * to a file descriptor
3106 *
3107 * Returns the new parser output or NULL
3108 */
3109xmlOutputBufferPtr
3110xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
3111 xmlOutputBufferPtr ret;
3112
3113 if (fd < 0) return(NULL);
3114
Daniel Veillardda3fee42008-09-01 13:08:57 +00003115 ret = xmlAllocOutputBufferInternal(encoder);
Owen Taylor3473f882001-02-23 17:55:21 +00003116 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00003117 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00003118 ret->writecallback = xmlFdWrite;
Daniel Veillard7db38712002-02-07 16:39:11 +00003119 ret->closecallback = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003120 }
3121
3122 return(ret);
3123}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003124#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003125
3126/**
3127 * xmlParserInputBufferCreateIO:
3128 * @ioread: an I/O read function
3129 * @ioclose: an I/O close function
3130 * @ioctx: an I/O handler
3131 * @enc: the charset encoding if known
3132 *
3133 * Create a buffered parser input for the progressive parsing for the input
3134 * from an I/O handler
3135 *
3136 * Returns the new parser input or NULL
3137 */
3138xmlParserInputBufferPtr
3139xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
3140 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
3141 xmlParserInputBufferPtr ret;
3142
3143 if (ioread == NULL) return(NULL);
3144
3145 ret = xmlAllocParserInputBuffer(enc);
3146 if (ret != NULL) {
3147 ret->context = (void *) ioctx;
3148 ret->readcallback = ioread;
3149 ret->closecallback = ioclose;
3150 }
3151
3152 return(ret);
3153}
3154
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003155#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003156/**
3157 * xmlOutputBufferCreateIO:
3158 * @iowrite: an I/O write function
3159 * @ioclose: an I/O close function
3160 * @ioctx: an I/O handler
Daniel Veillard9d06d302002-01-22 18:15:52 +00003161 * @encoder: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00003162 *
3163 * Create a buffered output for the progressive saving
3164 * to an I/O handler
3165 *
3166 * Returns the new parser output or NULL
3167 */
3168xmlOutputBufferPtr
3169xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
3170 xmlOutputCloseCallback ioclose, void *ioctx,
3171 xmlCharEncodingHandlerPtr encoder) {
3172 xmlOutputBufferPtr ret;
3173
3174 if (iowrite == NULL) return(NULL);
3175
Daniel Veillardda3fee42008-09-01 13:08:57 +00003176 ret = xmlAllocOutputBufferInternal(encoder);
Owen Taylor3473f882001-02-23 17:55:21 +00003177 if (ret != NULL) {
3178 ret->context = (void *) ioctx;
3179 ret->writecallback = iowrite;
3180 ret->closecallback = ioclose;
3181 }
3182
3183 return(ret);
3184}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003185#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003186
3187/**
Daniel Veillard1b243b42004-06-08 10:16:42 +00003188 * xmlParserInputBufferCreateFilenameDefault:
3189 * @func: function pointer to the new ParserInputBufferCreateFilenameFunc
3190 *
3191 * Registers a callback for URI input file handling
3192 *
3193 * Returns the old value of the registration function
3194 */
3195xmlParserInputBufferCreateFilenameFunc
3196xmlParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func)
3197{
3198 xmlParserInputBufferCreateFilenameFunc old = xmlParserInputBufferCreateFilenameValue;
3199 if (old == NULL) {
3200 old = __xmlParserInputBufferCreateFilename;
3201 }
3202
3203 xmlParserInputBufferCreateFilenameValue = func;
3204 return(old);
3205}
3206
3207/**
3208 * xmlOutputBufferCreateFilenameDefault:
3209 * @func: function pointer to the new OutputBufferCreateFilenameFunc
3210 *
3211 * Registers a callback for URI output file handling
3212 *
3213 * Returns the old value of the registration function
3214 */
3215xmlOutputBufferCreateFilenameFunc
3216xmlOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func)
3217{
3218 xmlOutputBufferCreateFilenameFunc old = xmlOutputBufferCreateFilenameValue;
3219#ifdef LIBXML_OUTPUT_ENABLED
3220 if (old == NULL) {
3221 old = __xmlOutputBufferCreateFilename;
3222 }
3223#endif
3224 xmlOutputBufferCreateFilenameValue = func;
3225 return(old);
3226}
3227
3228/**
Owen Taylor3473f882001-02-23 17:55:21 +00003229 * xmlParserInputBufferPush:
3230 * @in: a buffered parser input
3231 * @len: the size in bytes of the array.
3232 * @buf: an char array
3233 *
3234 * Push the content of the arry in the input buffer
3235 * This routine handle the I18N transcoding to internal UTF-8
3236 * This is used when operating the parser in progressive (push) mode.
3237 *
3238 * Returns the number of chars read and stored in the buffer, or -1
3239 * in case of error.
3240 */
3241int
3242xmlParserInputBufferPush(xmlParserInputBufferPtr in,
3243 int len, const char *buf) {
3244 int nbchars = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00003245 int ret;
Owen Taylor3473f882001-02-23 17:55:21 +00003246
3247 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003248 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003249 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00003250 unsigned int use;
3251
Owen Taylor3473f882001-02-23 17:55:21 +00003252 /*
3253 * Store the data in the incoming raw buffer
3254 */
3255 if (in->raw == NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003256 in->raw = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00003257 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003258 ret = xmlBufAdd(in->raw, (const xmlChar *) buf, len);
William M. Bracka3215c72004-07-31 16:24:01 +00003259 if (ret != 0)
3260 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003261
3262 /*
3263 * convert as much as possible to the parser reading buffer.
3264 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003265 use = xmlBufUse(in->raw);
Daniel Veillardbf058dc2013-02-13 18:19:42 +08003266 nbchars = xmlCharEncInput(in, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003267 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003268 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003269 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003270 return(-1);
3271 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003272 in->rawconsumed += (use - xmlBufUse(in->raw));
Owen Taylor3473f882001-02-23 17:55:21 +00003273 } else {
3274 nbchars = len;
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003275 ret = xmlBufAdd(in->buffer, (xmlChar *) buf, nbchars);
William M. Bracka3215c72004-07-31 16:24:01 +00003276 if (ret != 0)
3277 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003278 }
3279#ifdef DEBUG_INPUT
3280 xmlGenericError(xmlGenericErrorContext,
3281 "I/O: pushed %d chars, buffer %d/%d\n",
Roumen Petrov89b6f732012-08-04 05:09:56 +03003282 nbchars, xmlBufUse(in->buffer), xmlBufLength(in->buffer));
Owen Taylor3473f882001-02-23 17:55:21 +00003283#endif
3284 return(nbchars);
3285}
3286
3287/**
Daniel Veillardddffd2a2002-03-05 20:28:20 +00003288 * endOfInput:
3289 *
3290 * When reading from an Input channel indicated end of file or error
3291 * don't reread from it again.
3292 */
3293static int
3294endOfInput (void * context ATTRIBUTE_UNUSED,
3295 char * buffer ATTRIBUTE_UNUSED,
3296 int len ATTRIBUTE_UNUSED) {
3297 return(0);
3298}
3299
3300/**
Owen Taylor3473f882001-02-23 17:55:21 +00003301 * xmlParserInputBufferGrow:
3302 * @in: a buffered parser input
3303 * @len: indicative value of the amount of chars to read
3304 *
3305 * Grow up the content of the input buffer, the old data are preserved
3306 * This routine handle the I18N transcoding to internal UTF-8
3307 * This routine is used when operating the parser in normal (pull) mode
3308 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003309 * TODO: one should be able to remove one extra copy by copying directly
Owen Taylor3473f882001-02-23 17:55:21 +00003310 * onto in->buffer or in->raw
3311 *
3312 * Returns the number of chars read and stored in the buffer, or -1
3313 * in case of error.
3314 */
3315int
3316xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
3317 char *buffer = NULL;
3318 int res = 0;
3319 int nbchars = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003320
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003321 if ((in == NULL) || (in->error)) return(-1);
Daniel Veillard6155d8a2003-08-19 15:01:28 +00003322 if ((len <= MINLEN) && (len != 4))
Owen Taylor3473f882001-02-23 17:55:21 +00003323 len = MINLEN;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00003324
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003325 if (xmlBufAvail(in->buffer) <= 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003326 xmlIOErr(XML_IO_BUFFER_FULL, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003327 in->error = XML_IO_BUFFER_FULL;
William M. Bracka3215c72004-07-31 16:24:01 +00003328 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003329 }
Owen Taylor3473f882001-02-23 17:55:21 +00003330
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003331 if (xmlBufGrow(in->buffer, len + 1) < 0) {
3332 xmlIOErrMemory("growing input buffer");
3333 in->error = XML_ERR_NO_MEMORY;
3334 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003335 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003336 buffer = (char *)xmlBufEnd(in->buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00003337
3338 /*
3339 * Call the read method for this I/O type.
3340 */
3341 if (in->readcallback != NULL) {
3342 res = in->readcallback(in->context, &buffer[0], len);
Daniel Veillardddffd2a2002-03-05 20:28:20 +00003343 if (res <= 0)
3344 in->readcallback = endOfInput;
Owen Taylor3473f882001-02-23 17:55:21 +00003345 } else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003346 xmlIOErr(XML_IO_NO_INPUT, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003347 in->error = XML_IO_NO_INPUT;
Owen Taylor3473f882001-02-23 17:55:21 +00003348 return(-1);
3349 }
3350 if (res < 0) {
Owen Taylor3473f882001-02-23 17:55:21 +00003351 return(-1);
3352 }
Daniel Veillard63588f42013-05-10 14:01:46 +08003353
3354 /*
3355 * try to establish compressed status of input if not done already
3356 */
3357 if (in->compressed == -1) {
Daniel Veillard18b89882015-11-03 15:46:29 +08003358#ifdef LIBXML_LZMA_ENABLED
Daniel Veillard63588f42013-05-10 14:01:46 +08003359 if (in->readcallback == xmlXzfileRead)
3360 in->compressed = __libxml2_xzcompressed(in->context);
3361#endif
3362 }
3363
Owen Taylor3473f882001-02-23 17:55:21 +00003364 len = res;
3365 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00003366 unsigned int use;
3367
Owen Taylor3473f882001-02-23 17:55:21 +00003368 /*
3369 * Store the data in the incoming raw buffer
3370 */
3371 if (in->raw == NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003372 in->raw = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00003373 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003374 res = xmlBufAdd(in->raw, (const xmlChar *) buffer, len);
William M. Bracka3215c72004-07-31 16:24:01 +00003375 if (res != 0)
3376 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003377
3378 /*
3379 * convert as much as possible to the parser reading buffer.
3380 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003381 use = xmlBufUse(in->raw);
Daniel Veillardbf058dc2013-02-13 18:19:42 +08003382 nbchars = xmlCharEncInput(in, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003383 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003384 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003385 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003386 return(-1);
3387 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003388 in->rawconsumed += (use - xmlBufUse(in->raw));
Owen Taylor3473f882001-02-23 17:55:21 +00003389 } else {
3390 nbchars = len;
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003391 xmlBufAddLen(in->buffer, nbchars);
Owen Taylor3473f882001-02-23 17:55:21 +00003392 }
3393#ifdef DEBUG_INPUT
3394 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003395 "I/O: read %d chars, buffer %d\n",
3396 nbchars, xmlBufUse(in->buffer));
Owen Taylor3473f882001-02-23 17:55:21 +00003397#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003398 return(nbchars);
3399}
3400
3401/**
3402 * xmlParserInputBufferRead:
3403 * @in: a buffered parser input
3404 * @len: indicative value of the amount of chars to read
3405 *
3406 * Refresh the content of the input buffer, the old data are considered
3407 * consumed
3408 * This routine handle the I18N transcoding to internal UTF-8
3409 *
3410 * Returns the number of chars read and stored in the buffer, or -1
3411 * in case of error.
3412 */
3413int
3414xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003415 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003416 if (in->readcallback != NULL)
3417 return(xmlParserInputBufferGrow(in, len));
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003418 else if (xmlBufGetAllocationScheme(in->buffer) == XML_BUFFER_ALLOC_IMMUTABLE)
Daniel Veillard53350552003-09-18 13:35:51 +00003419 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003420 else
3421 return(-1);
3422}
3423
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003424#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003425/**
3426 * xmlOutputBufferWrite:
3427 * @out: a buffered parser output
3428 * @len: the size in bytes of the array.
3429 * @buf: an char array
3430 *
3431 * Write the content of the array in the output I/O buffer
3432 * This routine handle the I18N transcoding from internal UTF-8
3433 * The buffer is lossless, i.e. will store in case of partial
3434 * or delayed writes.
3435 *
3436 * Returns the number of chars immediately written, or -1
3437 * in case of error.
3438 */
3439int
3440xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
3441 int nbchars = 0; /* number of chars to output to I/O */
3442 int ret; /* return from function call */
3443 int written = 0; /* number of char written to I/O so far */
3444 int chunk; /* number of byte curreent processed from buf */
3445
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003446 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003447 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003448 if (out->error) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003449
3450 do {
3451 chunk = len;
3452 if (chunk > 4 * MINLEN)
3453 chunk = 4 * MINLEN;
3454
3455 /*
3456 * first handle encoding stuff.
3457 */
3458 if (out->encoder != NULL) {
3459 /*
3460 * Store the data in the incoming raw buffer
3461 */
3462 if (out->conv == NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003463 out->conv = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00003464 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003465 ret = xmlBufAdd(out->buffer, (const xmlChar *) buf, chunk);
William M. Bracka3215c72004-07-31 16:24:01 +00003466 if (ret != 0)
3467 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003468
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003469 if ((xmlBufUse(out->buffer) < MINLEN) && (chunk == len))
Owen Taylor3473f882001-02-23 17:55:21 +00003470 goto done;
3471
3472 /*
3473 * convert as much as possible to the parser reading buffer.
3474 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003475 ret = xmlCharEncOutput(out, 0);
Daniel Veillard809faa52003-02-10 15:43:53 +00003476 if ((ret < 0) && (ret != -3)) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003477 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003478 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003479 return(-1);
3480 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003481 nbchars = xmlBufUse(out->conv);
Owen Taylor3473f882001-02-23 17:55:21 +00003482 } else {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003483 ret = xmlBufAdd(out->buffer, (const xmlChar *) buf, chunk);
William M. Bracka3215c72004-07-31 16:24:01 +00003484 if (ret != 0)
3485 return(-1);
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003486 nbchars = xmlBufUse(out->buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00003487 }
3488 buf += chunk;
3489 len -= chunk;
3490
3491 if ((nbchars < MINLEN) && (len <= 0))
3492 goto done;
3493
3494 if (out->writecallback) {
3495 /*
3496 * second write the stuff to the I/O channel
3497 */
3498 if (out->encoder != NULL) {
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003499 ret = out->writecallback(out->context,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003500 (const char *)xmlBufContent(out->conv), nbchars);
Owen Taylor3473f882001-02-23 17:55:21 +00003501 if (ret >= 0)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003502 xmlBufShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003503 } else {
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003504 ret = out->writecallback(out->context,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003505 (const char *)xmlBufContent(out->buffer), nbchars);
Owen Taylor3473f882001-02-23 17:55:21 +00003506 if (ret >= 0)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003507 xmlBufShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003508 }
3509 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003510 xmlIOErr(XML_IO_WRITE, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003511 out->error = XML_IO_WRITE;
Owen Taylor3473f882001-02-23 17:55:21 +00003512 return(ret);
3513 }
3514 out->written += ret;
3515 }
3516 written += nbchars;
3517 } while (len > 0);
3518
3519done:
3520#ifdef DEBUG_INPUT
3521 xmlGenericError(xmlGenericErrorContext,
3522 "I/O: wrote %d chars\n", written);
3523#endif
3524 return(written);
3525}
3526
3527/**
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003528 * xmlEscapeContent:
3529 * @out: a pointer to an array of bytes to store the result
3530 * @outlen: the length of @out
3531 * @in: a pointer to an array of unescaped UTF-8 bytes
3532 * @inlen: the length of @in
3533 *
3534 * Take a block of UTF-8 chars in and escape them.
3535 * Returns 0 if success, or -1 otherwise
3536 * The value of @inlen after return is the number of octets consumed
3537 * if the return value is positive, else unpredictable.
3538 * The value of @outlen after return is the number of octets consumed.
3539 */
3540static int
3541xmlEscapeContent(unsigned char* out, int *outlen,
3542 const xmlChar* in, int *inlen) {
3543 unsigned char* outstart = out;
3544 const unsigned char* base = in;
3545 unsigned char* outend = out + *outlen;
3546 const unsigned char* inend;
3547
3548 inend = in + (*inlen);
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003549
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003550 while ((in < inend) && (out < outend)) {
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003551 if (*in == '<') {
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003552 if (outend - out < 4) break;
3553 *out++ = '&';
3554 *out++ = 'l';
3555 *out++ = 't';
3556 *out++ = ';';
3557 } else if (*in == '>') {
3558 if (outend - out < 4) break;
3559 *out++ = '&';
3560 *out++ = 'g';
3561 *out++ = 't';
3562 *out++ = ';';
3563 } else if (*in == '&') {
3564 if (outend - out < 5) break;
3565 *out++ = '&';
3566 *out++ = 'a';
3567 *out++ = 'm';
3568 *out++ = 'p';
3569 *out++ = ';';
3570 } else if (*in == '\r') {
3571 if (outend - out < 5) break;
3572 *out++ = '&';
3573 *out++ = '#';
3574 *out++ = '1';
3575 *out++ = '3';
3576 *out++ = ';';
3577 } else {
3578 *out++ = (unsigned char) *in;
3579 }
3580 ++in;
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003581 }
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003582 *outlen = out - outstart;
3583 *inlen = in - base;
3584 return(0);
3585}
3586
3587/**
3588 * xmlOutputBufferWriteEscape:
3589 * @out: a buffered parser output
3590 * @str: a zero terminated UTF-8 string
Daniel Veillardee8960b2004-05-14 03:25:14 +00003591 * @escaping: an optional escaping function (or NULL)
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003592 *
3593 * Write the content of the string in the output I/O buffer
3594 * This routine escapes the caracters and then handle the I18N
3595 * transcoding from internal UTF-8
3596 * The buffer is lossless, i.e. will store in case of partial
3597 * or delayed writes.
3598 *
3599 * Returns the number of chars immediately written, or -1
3600 * in case of error.
3601 */
3602int
Daniel Veillardee8960b2004-05-14 03:25:14 +00003603xmlOutputBufferWriteEscape(xmlOutputBufferPtr out, const xmlChar *str,
3604 xmlCharEncodingOutputFunc escaping) {
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003605 int nbchars = 0; /* number of chars to output to I/O */
3606 int ret; /* return from function call */
3607 int written = 0; /* number of char written to I/O so far */
Daniel Veillard71b95632004-08-31 12:15:36 +00003608 int oldwritten=0;/* loop guard */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003609 int chunk; /* number of byte currently processed from str */
3610 int len; /* number of bytes in str */
3611 int cons; /* byte from str consumed */
3612
Daniel Veillardce244ad2004-11-05 10:03:46 +00003613 if ((out == NULL) || (out->error) || (str == NULL) ||
3614 (out->buffer == NULL) ||
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003615 (xmlBufGetAllocationScheme(out->buffer) == XML_BUFFER_ALLOC_IMMUTABLE))
3616 return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003617 len = strlen((const char *)str);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003618 if (len < 0) return(0);
3619 if (out->error) return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003620 if (escaping == NULL) escaping = xmlEscapeContent;
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003621
3622 do {
Daniel Veillard71b95632004-08-31 12:15:36 +00003623 oldwritten = written;
3624
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003625 /*
3626 * how many bytes to consume and how many bytes to store.
3627 */
3628 cons = len;
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003629 chunk = xmlBufAvail(out->buffer) - 1;
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003630
Daniel Veillardc4ba8a42008-02-16 10:08:14 +00003631 /*
3632 * make sure we have enough room to save first, if this is
3633 * not the case force a flush, but make sure we stay in the loop
3634 */
3635 if (chunk < 40) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003636 if (xmlBufGrow(out->buffer, 100) < 0)
Daniel Veillarde83e93e2008-08-30 12:52:26 +00003637 return(-1);
3638 oldwritten = -1;
3639 continue;
Daniel Veillardc4ba8a42008-02-16 10:08:14 +00003640 }
3641
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003642 /*
3643 * first handle encoding stuff.
3644 */
3645 if (out->encoder != NULL) {
3646 /*
3647 * Store the data in the incoming raw buffer
3648 */
3649 if (out->conv == NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003650 out->conv = xmlBufCreate();
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003651 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003652 ret = escaping(xmlBufEnd(out->buffer) ,
Daniel Veillardee8960b2004-05-14 03:25:14 +00003653 &chunk, str, &cons);
William M. Brack66e40b12004-11-26 15:45:19 +00003654 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003655 return(-1);
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003656 xmlBufAddLen(out->buffer, chunk);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003657
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003658 if ((xmlBufUse(out->buffer) < MINLEN) && (cons == len))
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003659 goto done;
3660
3661 /*
3662 * convert as much as possible to the output buffer.
3663 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003664 ret = xmlCharEncOutput(out, 0);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003665 if ((ret < 0) && (ret != -3)) {
3666 xmlIOErr(XML_IO_ENCODER, NULL);
3667 out->error = XML_IO_ENCODER;
3668 return(-1);
3669 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003670 nbchars = xmlBufUse(out->conv);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003671 } else {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003672 ret = escaping(xmlBufEnd(out->buffer), &chunk, str, &cons);
William M. Brack66e40b12004-11-26 15:45:19 +00003673 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003674 return(-1);
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003675 xmlBufAddLen(out->buffer, chunk);
3676 nbchars = xmlBufUse(out->buffer);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003677 }
3678 str += cons;
3679 len -= cons;
3680
3681 if ((nbchars < MINLEN) && (len <= 0))
3682 goto done;
3683
3684 if (out->writecallback) {
3685 /*
3686 * second write the stuff to the I/O channel
3687 */
3688 if (out->encoder != NULL) {
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003689 ret = out->writecallback(out->context,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003690 (const char *)xmlBufContent(out->conv), nbchars);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003691 if (ret >= 0)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003692 xmlBufShrink(out->conv, ret);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003693 } else {
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003694 ret = out->writecallback(out->context,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003695 (const char *)xmlBufContent(out->buffer), nbchars);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003696 if (ret >= 0)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003697 xmlBufShrink(out->buffer, ret);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003698 }
3699 if (ret < 0) {
3700 xmlIOErr(XML_IO_WRITE, NULL);
3701 out->error = XML_IO_WRITE;
3702 return(ret);
3703 }
3704 out->written += ret;
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003705 } else if (xmlBufAvail(out->buffer) < MINLEN) {
3706 xmlBufGrow(out->buffer, MINLEN);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003707 }
3708 written += nbchars;
Daniel Veillard71b95632004-08-31 12:15:36 +00003709 } while ((len > 0) && (oldwritten != written));
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003710
3711done:
3712#ifdef DEBUG_INPUT
3713 xmlGenericError(xmlGenericErrorContext,
3714 "I/O: wrote %d chars\n", written);
3715#endif
3716 return(written);
3717}
3718
3719/**
Owen Taylor3473f882001-02-23 17:55:21 +00003720 * xmlOutputBufferWriteString:
3721 * @out: a buffered parser output
3722 * @str: a zero terminated C string
3723 *
3724 * Write the content of the string in the output I/O buffer
3725 * This routine handle the I18N transcoding from internal UTF-8
3726 * The buffer is lossless, i.e. will store in case of partial
3727 * or delayed writes.
3728 *
3729 * Returns the number of chars immediately written, or -1
3730 * in case of error.
3731 */
3732int
3733xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
3734 int len;
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003735
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003736 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003737 if (str == NULL)
3738 return(-1);
3739 len = strlen(str);
3740
3741 if (len > 0)
3742 return(xmlOutputBufferWrite(out, len, str));
3743 return(len);
3744}
3745
3746/**
3747 * xmlOutputBufferFlush:
3748 * @out: a buffered output
3749 *
3750 * flushes the output I/O channel
3751 *
3752 * Returns the number of byte written or -1 in case of error.
3753 */
3754int
3755xmlOutputBufferFlush(xmlOutputBufferPtr out) {
3756 int nbchars = 0, ret = 0;
3757
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003758 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003759 /*
3760 * first handle encoding stuff.
3761 */
3762 if ((out->conv != NULL) && (out->encoder != NULL)) {
3763 /*
Mikhail Titov8e2098a2013-03-27 11:00:31 +08003764 * convert as much as possible to the parser output buffer.
Owen Taylor3473f882001-02-23 17:55:21 +00003765 */
Mikhail Titov8e2098a2013-03-27 11:00:31 +08003766 do {
3767 nbchars = xmlCharEncOutput(out, 0);
3768 if (nbchars < 0) {
3769 xmlIOErr(XML_IO_ENCODER, NULL);
3770 out->error = XML_IO_ENCODER;
3771 return(-1);
3772 }
3773 } while (nbchars);
Owen Taylor3473f882001-02-23 17:55:21 +00003774 }
3775
3776 /*
3777 * second flush the stuff to the I/O channel
3778 */
3779 if ((out->conv != NULL) && (out->encoder != NULL) &&
3780 (out->writecallback != NULL)) {
3781 ret = out->writecallback(out->context,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003782 (const char *)xmlBufContent(out->conv),
3783 xmlBufUse(out->conv));
Owen Taylor3473f882001-02-23 17:55:21 +00003784 if (ret >= 0)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003785 xmlBufShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003786 } else if (out->writecallback != NULL) {
3787 ret = out->writecallback(out->context,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003788 (const char *)xmlBufContent(out->buffer),
3789 xmlBufUse(out->buffer));
Owen Taylor3473f882001-02-23 17:55:21 +00003790 if (ret >= 0)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003791 xmlBufShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003792 }
3793 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003794 xmlIOErr(XML_IO_FLUSH, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003795 out->error = XML_IO_FLUSH;
Owen Taylor3473f882001-02-23 17:55:21 +00003796 return(ret);
3797 }
3798 out->written += ret;
3799
3800#ifdef DEBUG_INPUT
3801 xmlGenericError(xmlGenericErrorContext,
3802 "I/O: flushed %d chars\n", ret);
3803#endif
3804 return(ret);
3805}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003806#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003807
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003808/**
Owen Taylor3473f882001-02-23 17:55:21 +00003809 * xmlParserGetDirectory:
3810 * @filename: the path to a file
3811 *
3812 * lookup the directory for that file
3813 *
3814 * Returns a new allocated string containing the directory, or NULL.
3815 */
3816char *
3817xmlParserGetDirectory(const char *filename) {
3818 char *ret = NULL;
3819 char dir[1024];
3820 char *cur;
Owen Taylor3473f882001-02-23 17:55:21 +00003821
Igor Zlatkovic9181cc02002-09-29 17:51:06 +00003822#ifdef _WIN32_WCE /* easy way by now ... wince does not have dirs! */
3823 return NULL;
3824#endif
3825
Owen Taylor3473f882001-02-23 17:55:21 +00003826 if (xmlInputCallbackInitialized == 0)
3827 xmlRegisterDefaultInputCallbacks();
3828
3829 if (filename == NULL) return(NULL);
Rob Richardsf779da32007-08-14 09:41:21 +00003830
Daniel Veillard3c5ed912002-01-08 10:36:16 +00003831#if defined(WIN32) && !defined(__CYGWIN__)
Rob Richardsf779da32007-08-14 09:41:21 +00003832# define IS_XMLPGD_SEP(ch) ((ch=='/')||(ch=='\\'))
3833#else
3834# define IS_XMLPGD_SEP(ch) (ch=='/')
Owen Taylor3473f882001-02-23 17:55:21 +00003835#endif
3836
3837 strncpy(dir, filename, 1023);
3838 dir[1023] = 0;
3839 cur = &dir[strlen(dir)];
3840 while (cur > dir) {
Rob Richardsf779da32007-08-14 09:41:21 +00003841 if (IS_XMLPGD_SEP(*cur)) break;
Owen Taylor3473f882001-02-23 17:55:21 +00003842 cur --;
3843 }
Rob Richardsf779da32007-08-14 09:41:21 +00003844 if (IS_XMLPGD_SEP(*cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003845 if (cur == dir) dir[1] = 0;
3846 else *cur = 0;
3847 ret = xmlMemStrdup(dir);
3848 } else {
3849 if (getcwd(dir, 1024) != NULL) {
3850 dir[1023] = 0;
3851 ret = xmlMemStrdup(dir);
3852 }
3853 }
3854 return(ret);
Rob Richardsf779da32007-08-14 09:41:21 +00003855#undef IS_XMLPGD_SEP
Owen Taylor3473f882001-02-23 17:55:21 +00003856}
3857
3858/****************************************************************
3859 * *
3860 * External entities loading *
3861 * *
3862 ****************************************************************/
3863
Daniel Veillarda840b692003-10-19 13:35:37 +00003864/**
3865 * xmlCheckHTTPInput:
3866 * @ctxt: an XML parser context
3867 * @ret: an XML parser input
3868 *
3869 * Check an input in case it was created from an HTTP stream, in that
3870 * case it will handle encoding and update of the base URL in case of
3871 * redirection. It also checks for HTTP errors in which case the input
3872 * is cleanly freed up and an appropriate error is raised in context
3873 *
3874 * Returns the input or NULL in case of HTTP error.
3875 */
3876xmlParserInputPtr
3877xmlCheckHTTPInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr ret) {
3878#ifdef LIBXML_HTTP_ENABLED
3879 if ((ret != NULL) && (ret->buf != NULL) &&
3880 (ret->buf->readcallback == xmlIOHTTPRead) &&
3881 (ret->buf->context != NULL)) {
3882 const char *encoding;
3883 const char *redir;
3884 const char *mime;
3885 int code;
3886
3887 code = xmlNanoHTTPReturnCode(ret->buf->context);
3888 if (code >= 400) {
3889 /* fatal error */
3890 if (ret->filename != NULL)
Daniel Veillarde8039df2003-10-27 11:25:13 +00003891 __xmlLoaderErr(ctxt, "failed to load HTTP resource \"%s\"\n",
Daniel Veillarda840b692003-10-19 13:35:37 +00003892 (const char *) ret->filename);
3893 else
Daniel Veillarde8039df2003-10-27 11:25:13 +00003894 __xmlLoaderErr(ctxt, "failed to load HTTP resource\n", NULL);
Daniel Veillarda840b692003-10-19 13:35:37 +00003895 xmlFreeInputStream(ret);
3896 ret = NULL;
3897 } else {
3898
3899 mime = xmlNanoHTTPMimeType(ret->buf->context);
3900 if ((xmlStrstr(BAD_CAST mime, BAD_CAST "/xml")) ||
3901 (xmlStrstr(BAD_CAST mime, BAD_CAST "+xml"))) {
3902 encoding = xmlNanoHTTPEncoding(ret->buf->context);
3903 if (encoding != NULL) {
3904 xmlCharEncodingHandlerPtr handler;
3905
3906 handler = xmlFindCharEncodingHandler(encoding);
3907 if (handler != NULL) {
3908 xmlSwitchInputEncoding(ctxt, ret, handler);
3909 } else {
3910 __xmlErrEncoding(ctxt, XML_ERR_UNKNOWN_ENCODING,
3911 "Unknown encoding %s",
3912 BAD_CAST encoding, NULL);
3913 }
3914 if (ret->encoding == NULL)
3915 ret->encoding = xmlStrdup(BAD_CAST encoding);
3916 }
3917#if 0
3918 } else if (xmlStrstr(BAD_CAST mime, BAD_CAST "html")) {
3919#endif
3920 }
3921 redir = xmlNanoHTTPRedir(ret->buf->context);
3922 if (redir != NULL) {
3923 if (ret->filename != NULL)
3924 xmlFree((xmlChar *) ret->filename);
3925 if (ret->directory != NULL) {
3926 xmlFree((xmlChar *) ret->directory);
3927 ret->directory = NULL;
3928 }
3929 ret->filename =
3930 (char *) xmlStrdup((const xmlChar *) redir);
3931 }
3932 }
3933 }
3934#endif
3935 return(ret);
3936}
3937
Daniel Veillarde5a3f372006-08-30 13:11:36 +00003938static int xmlNoNetExists(const char *URL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003939 const char *path;
3940
3941 if (URL == NULL)
3942 return(0);
3943
Daniel Veillardf4862f02002-09-10 11:13:43 +00003944 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003945#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00003946 path = &URL[17];
3947#else
Daniel Veillard6990bf32001-08-23 21:17:48 +00003948 path = &URL[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00003949#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003950 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003951#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard6990bf32001-08-23 21:17:48 +00003952 path = &URL[8];
3953#else
3954 path = &URL[7];
3955#endif
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003956 } else
Daniel Veillard6990bf32001-08-23 21:17:48 +00003957 path = URL;
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003958
Daniel Veillarde5a3f372006-08-30 13:11:36 +00003959 return xmlCheckFilename(path);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003960}
Daniel Veillard6990bf32001-08-23 21:17:48 +00003961
Daniel Veillardad4e2962006-09-21 08:36:38 +00003962#ifdef LIBXML_CATALOG_ENABLED
3963
3964/**
3965 * xmlResolveResourceFromCatalog:
3966 * @URL: the URL for the entity to load
3967 * @ID: the System ID for the entity to load
3968 * @ctxt: the context in which the entity is called or NULL
3969 *
3970 * Resolves the URL and ID against the appropriate catalog.
3971 * This function is used by xmlDefaultExternalEntityLoader and
3972 * xmlNoNetExternalEntityLoader.
3973 *
3974 * Returns a new allocated URL, or NULL.
3975 */
William M. Brack38d452a2007-05-22 16:00:06 +00003976static xmlChar *
Daniel Veillardad4e2962006-09-21 08:36:38 +00003977xmlResolveResourceFromCatalog(const char *URL, const char *ID,
3978 xmlParserCtxtPtr ctxt) {
3979 xmlChar *resource = NULL;
3980 xmlCatalogAllow pref;
3981
3982 /*
3983 * If the resource doesn't exists as a file,
3984 * try to load it from the resource pointed in the catalogs
3985 */
3986 pref = xmlCatalogGetDefaults();
3987
3988 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
3989 /*
3990 * Do a local lookup
3991 */
3992 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
3993 ((pref == XML_CATA_ALLOW_ALL) ||
3994 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3995 resource = xmlCatalogLocalResolve(ctxt->catalogs,
3996 (const xmlChar *)ID,
3997 (const xmlChar *)URL);
3998 }
3999 /*
4000 * Try a global lookup
4001 */
4002 if ((resource == NULL) &&
4003 ((pref == XML_CATA_ALLOW_ALL) ||
4004 (pref == XML_CATA_ALLOW_GLOBAL))) {
4005 resource = xmlCatalogResolve((const xmlChar *)ID,
4006 (const xmlChar *)URL);
4007 }
4008 if ((resource == NULL) && (URL != NULL))
4009 resource = xmlStrdup((const xmlChar *) URL);
4010
4011 /*
4012 * TODO: do an URI lookup on the reference
4013 */
4014 if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
4015 xmlChar *tmp = NULL;
4016
4017 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
4018 ((pref == XML_CATA_ALLOW_ALL) ||
4019 (pref == XML_CATA_ALLOW_DOCUMENT))) {
4020 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
4021 }
4022 if ((tmp == NULL) &&
4023 ((pref == XML_CATA_ALLOW_ALL) ||
4024 (pref == XML_CATA_ALLOW_GLOBAL))) {
4025 tmp = xmlCatalogResolveURI(resource);
4026 }
4027
4028 if (tmp != NULL) {
4029 xmlFree(resource);
4030 resource = tmp;
4031 }
4032 }
4033 }
4034
4035 return resource;
4036}
4037
4038#endif
4039
Daniel Veillard5e2dace2001-07-18 19:30:27 +00004040/**
Owen Taylor3473f882001-02-23 17:55:21 +00004041 * xmlDefaultExternalEntityLoader:
4042 * @URL: the URL for the entity to load
4043 * @ID: the System ID for the entity to load
4044 * @ctxt: the context in which the entity is called or NULL
4045 *
4046 * By default we don't load external entitites, yet.
4047 *
4048 * Returns a new allocated xmlParserInputPtr, or NULL.
4049 */
Daniel Veillarda840b692003-10-19 13:35:37 +00004050static xmlParserInputPtr
Owen Taylor3473f882001-02-23 17:55:21 +00004051xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
Daniel Veillarda840b692003-10-19 13:35:37 +00004052 xmlParserCtxtPtr ctxt)
4053{
Owen Taylor3473f882001-02-23 17:55:21 +00004054 xmlParserInputPtr ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00004055 xmlChar *resource = NULL;
Daniel Veillarda840b692003-10-19 13:35:37 +00004056
Owen Taylor3473f882001-02-23 17:55:21 +00004057#ifdef DEBUG_EXTERNAL_ENTITIES
4058 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda840b692003-10-19 13:35:37 +00004059 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00004060#endif
Nick Wellnhofer030b1f72017-06-06 15:53:42 +02004061 if ((ctxt != NULL) && (ctxt->options & XML_PARSE_NONET)) {
Daniel Veillard61b93382003-11-03 14:28:31 +00004062 int options = ctxt->options;
4063
Nick Wellnhofer030b1f72017-06-06 15:53:42 +02004064 ctxt->options -= XML_PARSE_NONET;
4065 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
4066 ctxt->options = options;
4067 return(ret);
Daniel Veillard61b93382003-11-03 14:28:31 +00004068 }
Daniel Veillardad4e2962006-09-21 08:36:38 +00004069#ifdef LIBXML_CATALOG_ENABLED
4070 resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
Daniel Veillard7d6fd212001-05-10 15:34:11 +00004071#endif
4072
4073 if (resource == NULL)
Daniel Veillarda840b692003-10-19 13:35:37 +00004074 resource = (xmlChar *) URL;
Daniel Veillard7d6fd212001-05-10 15:34:11 +00004075
4076 if (resource == NULL) {
Daniel Veillarda840b692003-10-19 13:35:37 +00004077 if (ID == NULL)
4078 ID = "NULL";
Daniel Veillarde8039df2003-10-27 11:25:13 +00004079 __xmlLoaderErr(ctxt, "failed to load external entity \"%s\"\n", ID);
Daniel Veillarda840b692003-10-19 13:35:37 +00004080 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004081 }
Daniel Veillarda840b692003-10-19 13:35:37 +00004082 ret = xmlNewInputFromFile(ctxt, (const char *) resource);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00004083 if ((resource != NULL) && (resource != (xmlChar *) URL))
Daniel Veillarda840b692003-10-19 13:35:37 +00004084 xmlFree(resource);
4085 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004086}
4087
4088static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
4089 xmlDefaultExternalEntityLoader;
4090
Daniel Veillard5e2dace2001-07-18 19:30:27 +00004091/**
Owen Taylor3473f882001-02-23 17:55:21 +00004092 * xmlSetExternalEntityLoader:
4093 * @f: the new entity resolver function
4094 *
4095 * Changes the defaultexternal entity resolver function for the application
4096 */
4097void
4098xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
4099 xmlCurrentExternalEntityLoader = f;
4100}
4101
Daniel Veillard5e2dace2001-07-18 19:30:27 +00004102/**
Owen Taylor3473f882001-02-23 17:55:21 +00004103 * xmlGetExternalEntityLoader:
4104 *
4105 * Get the default external entity resolver function for the application
4106 *
4107 * Returns the xmlExternalEntityLoader function pointer
4108 */
4109xmlExternalEntityLoader
4110xmlGetExternalEntityLoader(void) {
4111 return(xmlCurrentExternalEntityLoader);
4112}
4113
Daniel Veillard5e2dace2001-07-18 19:30:27 +00004114/**
Owen Taylor3473f882001-02-23 17:55:21 +00004115 * xmlLoadExternalEntity:
4116 * @URL: the URL for the entity to load
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00004117 * @ID: the Public ID for the entity to load
Owen Taylor3473f882001-02-23 17:55:21 +00004118 * @ctxt: the context in which the entity is called or NULL
4119 *
4120 * Load an external entity, note that the use of this function for
4121 * unparsed entities may generate problems
Owen Taylor3473f882001-02-23 17:55:21 +00004122 *
4123 * Returns the xmlParserInputPtr or NULL
4124 */
4125xmlParserInputPtr
4126xmlLoadExternalEntity(const char *URL, const char *ID,
4127 xmlParserCtxtPtr ctxt) {
Daniel Veillarde5a3f372006-08-30 13:11:36 +00004128 if ((URL != NULL) && (xmlNoNetExists(URL) == 0)) {
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00004129 char *canonicFilename;
4130 xmlParserInputPtr ret;
4131
4132 canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL);
4133 if (canonicFilename == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00004134 xmlIOErrMemory("building canonical path\n");
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00004135 return(NULL);
4136 }
4137
4138 ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt);
4139 xmlFree(canonicFilename);
4140 return(ret);
4141 }
Owen Taylor3473f882001-02-23 17:55:21 +00004142 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
4143}
4144
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004145/************************************************************************
Hans Breuer2ad41ca2009-08-11 17:51:22 +02004146 * *
4147 * Disabling Network access *
4148 * *
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004149 ************************************************************************/
4150
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004151/**
4152 * xmlNoNetExternalEntityLoader:
4153 * @URL: the URL for the entity to load
4154 * @ID: the System ID for the entity to load
4155 * @ctxt: the context in which the entity is called or NULL
4156 *
4157 * A specific entity loader disabling network accesses, though still
4158 * allowing local catalog accesses for resolution.
4159 *
4160 * Returns a new allocated xmlParserInputPtr, or NULL.
4161 */
4162xmlParserInputPtr
4163xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
4164 xmlParserCtxtPtr ctxt) {
4165 xmlParserInputPtr input = NULL;
4166 xmlChar *resource = NULL;
4167
4168#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillardad4e2962006-09-21 08:36:38 +00004169 resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004170#endif
Daniel Veillardad4e2962006-09-21 08:36:38 +00004171
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004172 if (resource == NULL)
4173 resource = (xmlChar *) URL;
4174
4175 if (resource != NULL) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00004176 if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
4177 (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00004178 xmlIOErr(XML_IO_NETWORK_ATTEMPT, (const char *) resource);
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004179 if (resource != (xmlChar *) URL)
4180 xmlFree(resource);
4181 return(NULL);
4182 }
4183 }
4184 input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
4185 if (resource != (xmlChar *) URL)
4186 xmlFree(resource);
4187 return(input);
4188}
4189
Daniel Veillard5d4644e2005-04-01 13:11:58 +00004190#define bottom_xmlIO
4191#include "elfgcchack.h"