blob: 1a79c09605e8b244591d5443afcada388136aba7 [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
Owen Taylor3473f882001-02-23 17:55:21 +0000929 if (!xmlCheckFilename(path))
930 return(NULL);
931
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000932#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
933 fd = xmlWrapOpen(path, 0);
934#else
935 fd = fopen(path, "r");
Owen Taylor3473f882001-02-23 17:55:21 +0000936#endif /* WIN32 */
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000937 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +0000938 return((void *) fd);
939}
940
941/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000942 * xmlFileOpen:
943 * @filename: the URI for matching
944 *
945 * Wrapper around xmlFileOpen_real that try it with an unescaped
946 * version of @filename, if this fails fallback to @filename
Daniel Veillard71531f32003-02-05 13:19:53 +0000947 *
948 * Returns a handler or NULL in case or failure
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000949 */
950void *
951xmlFileOpen (const char *filename) {
952 char *unescaped;
953 void *retval;
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000954
Daniel Veillardbd672bc2007-03-30 12:39:25 +0000955 retval = xmlFileOpen_real(filename);
956 if (retval == NULL) {
957 unescaped = xmlURIUnescapeString(filename, 0, NULL);
958 if (unescaped != NULL) {
959 retval = xmlFileOpen_real(unescaped);
960 xmlFree(unescaped);
961 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000962 }
Daniel Veillardbd672bc2007-03-30 12:39:25 +0000963
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000964 return retval;
965}
966
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000967#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000968/**
Owen Taylor3473f882001-02-23 17:55:21 +0000969 * xmlFileOpenW:
970 * @filename: the URI for matching
971 *
972 * output to from FILE *,
973 * if @filename is "-" then the standard output is used
974 *
975 * Returns an I/O context or NULL in case of error
976 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000977static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000978xmlFileOpenW (const char *filename) {
979 const char *path = NULL;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000980 FILE *fd;
Owen Taylor3473f882001-02-23 17:55:21 +0000981
982 if (!strcmp(filename, "-")) {
983 fd = stdout;
984 return((void *) fd);
985 }
986
Daniel Veillardf4862f02002-09-10 11:13:43 +0000987 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000988#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000989 path = &filename[17];
990#else
Owen Taylor3473f882001-02-23 17:55:21 +0000991 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000992#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000993 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000994#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000995 path = &filename[8];
996#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000997 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000998#endif
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200999 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001000 path = filename;
1001
1002 if (path == NULL)
1003 return(NULL);
1004
Daniel Veillard8ca85b22006-09-01 09:56:07 +00001005#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
1006 fd = xmlWrapOpen(path, 1);
1007#else
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001008 fd = fopen(path, "wb");
Daniel Veillard8ca85b22006-09-01 09:56:07 +00001009#endif /* WIN32 */
Daniel Veillarde5a3f372006-08-30 13:11:36 +00001010
Daniel Veillardf7416012006-04-27 08:15:20 +00001011 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +00001012 return((void *) fd);
1013}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001014#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001015
1016/**
1017 * xmlFileRead:
1018 * @context: the I/O context
1019 * @buffer: where to drop data
1020 * @len: number of bytes to write
1021 *
1022 * Read @len bytes to @buffer from the I/O channel.
1023 *
Daniel Veillardce682bc2004-11-05 17:22:25 +00001024 * Returns the number of bytes written or < 0 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +00001025 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001026int
Owen Taylor3473f882001-02-23 17:55:21 +00001027xmlFileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001028 int ret;
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001029 if ((context == NULL) || (buffer == NULL))
Daniel Veillardce682bc2004-11-05 17:22:25 +00001030 return(-1);
Daniel Veillard05d987b2003-10-08 11:54:57 +00001031 ret = fread(&buffer[0], 1, len, (FILE *) context);
1032 if (ret < 0) xmlIOErr(0, "fread()");
1033 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001034}
1035
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001036#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001037/**
1038 * xmlFileWrite:
1039 * @context: the I/O context
1040 * @buffer: where to drop data
1041 * @len: number of bytes to write
1042 *
1043 * Write @len bytes from @buffer to the I/O channel.
1044 *
1045 * Returns the number of bytes written
1046 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001047static int
Owen Taylor3473f882001-02-23 17:55:21 +00001048xmlFileWrite (void * context, const char * buffer, int len) {
Daniel Veillard4a6d39b2002-12-17 18:33:01 +00001049 int items;
1050
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001051 if ((context == NULL) || (buffer == NULL))
Daniel Veillardce682bc2004-11-05 17:22:25 +00001052 return(-1);
Daniel Veillard4a6d39b2002-12-17 18:33:01 +00001053 items = fwrite(&buffer[0], len, 1, (FILE *) context);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00001054 if ((items == 0) && (ferror((FILE *) context))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001055 xmlIOErr(0, "fwrite()");
Daniel Veillard97bf4d02003-10-08 18:58:28 +00001056 return(-1);
1057 }
Daniel Veillard4a6d39b2002-12-17 18:33:01 +00001058 return(items * len);
Owen Taylor3473f882001-02-23 17:55:21 +00001059}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001060#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001061
1062/**
1063 * xmlFileClose:
1064 * @context: the I/O context
1065 *
1066 * Close an I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001067 *
1068 * Returns 0 or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +00001069 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001070int
Owen Taylor3473f882001-02-23 17:55:21 +00001071xmlFileClose (void * context) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001072 FILE *fil;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001073 int ret;
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001074
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +00001075 if (context == NULL)
1076 return(-1);
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001077 fil = (FILE *) context;
Daniel Veillard500a1de2004-03-22 15:22:58 +00001078 if ((fil == stdout) || (fil == stderr)) {
1079 ret = fflush(fil);
1080 if (ret < 0)
1081 xmlIOErr(0, "fflush()");
1082 return(0);
1083 }
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001084 if (fil == stdin)
1085 return(0);
Daniel Veillard05d987b2003-10-08 11:54:57 +00001086 ret = ( fclose((FILE *) context) == EOF ) ? -1 : 0;
1087 if (ret < 0)
1088 xmlIOErr(0, "fclose()");
1089 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001090}
1091
1092/**
1093 * xmlFileFlush:
1094 * @context: the I/O context
1095 *
1096 * Flush an I/O channel
1097 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001098static int
Owen Taylor3473f882001-02-23 17:55:21 +00001099xmlFileFlush (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001100 int ret;
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +00001101
1102 if (context == NULL)
1103 return(-1);
Daniel Veillard05d987b2003-10-08 11:54:57 +00001104 ret = ( fflush((FILE *) context) == EOF ) ? -1 : 0;
1105 if (ret < 0)
1106 xmlIOErr(0, "fflush()");
1107 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001108}
1109
Daniel Veillard9a00fd22005-11-09 08:56:26 +00001110#ifdef LIBXML_OUTPUT_ENABLED
1111/**
1112 * xmlBufferWrite:
1113 * @context: the xmlBuffer
1114 * @buffer: the data to write
1115 * @len: number of bytes to write
1116 *
1117 * Write @len bytes from @buffer to the xml buffer
1118 *
1119 * Returns the number of bytes written
1120 */
1121static int
1122xmlBufferWrite (void * context, const char * buffer, int len) {
1123 int ret;
1124
1125 ret = xmlBufferAdd((xmlBufferPtr) context, (const xmlChar *) buffer, len);
1126 if (ret != 0)
1127 return(-1);
1128 return(len);
1129}
Daniel Veillard9a00fd22005-11-09 08:56:26 +00001130#endif
1131
Owen Taylor3473f882001-02-23 17:55:21 +00001132#ifdef HAVE_ZLIB_H
1133/************************************************************************
1134 * *
1135 * I/O for compressed file accesses *
1136 * *
1137 ************************************************************************/
1138/**
1139 * xmlGzfileMatch:
1140 * @filename: the URI for matching
1141 *
1142 * input from compressed file test
1143 *
1144 * Returns 1 if matches, 0 otherwise
1145 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001146static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00001147xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00001148 return(1);
1149}
1150
1151/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001152 * xmlGzfileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +00001153 * @filename: the URI for matching
1154 *
1155 * input from compressed file open
1156 * if @filename is " " then the standard input is used
1157 *
1158 * Returns an I/O context or NULL in case of error
1159 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001160static void *
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001161xmlGzfileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +00001162 const char *path = NULL;
1163 gzFile fd;
1164
1165 if (!strcmp(filename, "-")) {
Philip Withnall31aa3812014-06-20 21:11:40 +01001166 int duped_fd = dup(fileno(stdin));
1167 fd = gzdopen(duped_fd, "rb");
Philip Withnall21699932014-08-24 23:10:13 +01001168 if (fd == Z_NULL && duped_fd >= 0) {
Philip Withnall31aa3812014-06-20 21:11:40 +01001169 close(duped_fd); /* gzdOpen() does not close on failure */
1170 }
1171
Owen Taylor3473f882001-02-23 17:55:21 +00001172 return((void *) fd);
1173 }
1174
Daniel Veillardf4862f02002-09-10 11:13:43 +00001175 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001176#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00001177 path = &filename[17];
1178#else
Owen Taylor3473f882001-02-23 17:55:21 +00001179 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00001180#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001181 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001182#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +00001183 path = &filename[8];
1184#else
Owen Taylor3473f882001-02-23 17:55:21 +00001185 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +00001186#endif
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001187 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001188 path = filename;
1189
1190 if (path == NULL)
1191 return(NULL);
1192 if (!xmlCheckFilename(path))
1193 return(NULL);
1194
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001195#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
1196 fd = xmlWrapGzOpen(path, "rb");
1197#else
Owen Taylor3473f882001-02-23 17:55:21 +00001198 fd = gzopen(path, "rb");
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001199#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001200 return((void *) fd);
1201}
1202
1203/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001204 * xmlGzfileOpen:
1205 * @filename: the URI for matching
1206 *
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00001207 * Wrapper around xmlGzfileOpen if the open fais, it will
1208 * try to unescape @filename
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001209 */
1210static void *
1211xmlGzfileOpen (const char *filename) {
1212 char *unescaped;
1213 void *retval;
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00001214
1215 retval = xmlGzfileOpen_real(filename);
1216 if (retval == NULL) {
1217 unescaped = xmlURIUnescapeString(filename, 0, NULL);
1218 if (unescaped != NULL) {
1219 retval = xmlGzfileOpen_real(unescaped);
1220 }
1221 xmlFree(unescaped);
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001222 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001223 return retval;
1224}
1225
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001226#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001227/**
Owen Taylor3473f882001-02-23 17:55:21 +00001228 * xmlGzfileOpenW:
1229 * @filename: the URI for matching
1230 * @compression: the compression factor (0 - 9 included)
1231 *
1232 * input from compressed file open
1233 * if @filename is " " then the standard input is used
1234 *
1235 * Returns an I/O context or NULL in case of error
1236 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001237static void *
Owen Taylor3473f882001-02-23 17:55:21 +00001238xmlGzfileOpenW (const char *filename, int compression) {
1239 const char *path = NULL;
1240 char mode[15];
1241 gzFile fd;
1242
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001243 snprintf(mode, sizeof(mode), "wb%d", compression);
Owen Taylor3473f882001-02-23 17:55:21 +00001244 if (!strcmp(filename, "-")) {
Philip Withnall31aa3812014-06-20 21:11:40 +01001245 int duped_fd = dup(fileno(stdout));
1246 fd = gzdopen(duped_fd, "rb");
Philip Withnall21699932014-08-24 23:10:13 +01001247 if (fd == Z_NULL && duped_fd >= 0) {
Philip Withnall31aa3812014-06-20 21:11:40 +01001248 close(duped_fd); /* gzdOpen() does not close on failure */
1249 }
1250
Owen Taylor3473f882001-02-23 17:55:21 +00001251 return((void *) fd);
1252 }
1253
Daniel Veillardf4862f02002-09-10 11:13:43 +00001254 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001255#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00001256 path = &filename[17];
1257#else
Owen Taylor3473f882001-02-23 17:55:21 +00001258 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00001259#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001260 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001261#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +00001262 path = &filename[8];
1263#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +00001264 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +00001265#endif
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001266 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001267 path = filename;
1268
1269 if (path == NULL)
1270 return(NULL);
1271
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001272#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
1273 fd = xmlWrapGzOpen(path, mode);
1274#else
Owen Taylor3473f882001-02-23 17:55:21 +00001275 fd = gzopen(path, mode);
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001276#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001277 return((void *) fd);
1278}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001279#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001280
1281/**
1282 * xmlGzfileRead:
1283 * @context: the I/O context
1284 * @buffer: where to drop data
1285 * @len: number of bytes to write
1286 *
1287 * Read @len bytes to @buffer from the compressed I/O channel.
1288 *
1289 * Returns the number of bytes written
1290 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001291static int
Owen Taylor3473f882001-02-23 17:55:21 +00001292xmlGzfileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001293 int ret;
1294
1295 ret = gzread((gzFile) context, &buffer[0], len);
1296 if (ret < 0) xmlIOErr(0, "gzread()");
1297 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001298}
1299
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001300#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001301/**
1302 * xmlGzfileWrite:
1303 * @context: the I/O context
1304 * @buffer: where to drop data
1305 * @len: number of bytes to write
1306 *
1307 * Write @len bytes from @buffer to the compressed I/O channel.
1308 *
1309 * Returns the number of bytes written
1310 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001311static int
Owen Taylor3473f882001-02-23 17:55:21 +00001312xmlGzfileWrite (void * context, const char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001313 int ret;
1314
1315 ret = gzwrite((gzFile) context, (char *) &buffer[0], len);
1316 if (ret < 0) xmlIOErr(0, "gzwrite()");
1317 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001318}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001319#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001320
1321/**
1322 * xmlGzfileClose:
1323 * @context: the I/O context
1324 *
1325 * Close a compressed I/O channel
1326 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001327static int
Owen Taylor3473f882001-02-23 17:55:21 +00001328xmlGzfileClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001329 int ret;
1330
1331 ret = (gzclose((gzFile) context) == Z_OK ) ? 0 : -1;
1332 if (ret < 0) xmlIOErr(0, "gzclose()");
1333 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001334}
1335#endif /* HAVE_ZLIB_H */
1336
Daniel Veillard18b89882015-11-03 15:46:29 +08001337#ifdef LIBXML_LZMA_ENABLED
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001338/************************************************************************
1339 * *
1340 * I/O for compressed file accesses *
1341 * *
1342 ************************************************************************/
Daniel Veillardadf5ec92012-01-26 16:56:22 +08001343#include "xzlib.h"
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001344/**
1345 * xmlXzfileMatch:
1346 * @filename: the URI for matching
1347 *
1348 * input from compressed file test
1349 *
1350 * Returns 1 if matches, 0 otherwise
1351 */
1352static int
1353xmlXzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
1354 return(1);
1355}
1356
1357/**
1358 * xmlXzFileOpen_real:
1359 * @filename: the URI for matching
1360 *
1361 * input from compressed file open
1362 * if @filename is " " then the standard input is used
1363 *
1364 * Returns an I/O context or NULL in case of error
1365 */
1366static void *
1367xmlXzfileOpen_real (const char *filename) {
1368 const char *path = NULL;
1369 xzFile fd;
1370
1371 if (!strcmp(filename, "-")) {
Patrick Monnerat147aaf22013-12-12 15:02:40 +08001372 fd = __libxml2_xzdopen(dup(fileno(stdin)), "rb");
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001373 return((void *) fd);
1374 }
1375
1376 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) {
1377 path = &filename[16];
1378 } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
1379 path = &filename[7];
1380 } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:/", 6)) {
1381 /* lots of generators seems to lazy to read RFC 1738 */
1382 path = &filename[5];
1383 } else
1384 path = filename;
1385
1386 if (path == NULL)
1387 return(NULL);
1388 if (!xmlCheckFilename(path))
1389 return(NULL);
1390
Daniel Veillardadf5ec92012-01-26 16:56:22 +08001391 fd = __libxml2_xzopen(path, "rb");
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001392 return((void *) fd);
1393}
1394
1395/**
1396 * xmlXzfileOpen:
1397 * @filename: the URI for matching
1398 *
1399 * Wrapper around xmlXzfileOpen_real that try it with an unescaped
1400 * version of @filename, if this fails fallback to @filename
1401 *
1402 * Returns a handler or NULL in case or failure
1403 */
1404static void *
1405xmlXzfileOpen (const char *filename) {
1406 char *unescaped;
1407 void *retval;
1408
1409 retval = xmlXzfileOpen_real(filename);
1410 if (retval == NULL) {
1411 unescaped = xmlURIUnescapeString(filename, 0, NULL);
1412 if (unescaped != NULL) {
1413 retval = xmlXzfileOpen_real(unescaped);
1414 }
1415 xmlFree(unescaped);
1416 }
1417
1418 return retval;
1419}
1420
1421/**
1422 * xmlXzfileRead:
1423 * @context: the I/O context
1424 * @buffer: where to drop data
1425 * @len: number of bytes to write
1426 *
1427 * Read @len bytes to @buffer from the compressed I/O channel.
1428 *
1429 * Returns the number of bytes written
1430 */
1431static int
1432xmlXzfileRead (void * context, char * buffer, int len) {
1433 int ret;
1434
Daniel Veillardadf5ec92012-01-26 16:56:22 +08001435 ret = __libxml2_xzread((xzFile) context, &buffer[0], len);
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001436 if (ret < 0) xmlIOErr(0, "xzread()");
1437 return(ret);
1438}
1439
1440/**
1441 * xmlXzfileClose:
1442 * @context: the I/O context
1443 *
1444 * Close a compressed I/O channel
1445 */
1446static int
1447xmlXzfileClose (void * context) {
1448 int ret;
1449
Daniel Veillardadf5ec92012-01-26 16:56:22 +08001450 ret = (__libxml2_xzclose((xzFile) context) == LZMA_OK ) ? 0 : -1;
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001451 if (ret < 0) xmlIOErr(0, "xzclose()");
1452 return(ret);
1453}
Daniel Veillard18b89882015-11-03 15:46:29 +08001454#endif /* LIBXML_LZMA_ENABLED */
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001455
Owen Taylor3473f882001-02-23 17:55:21 +00001456#ifdef LIBXML_HTTP_ENABLED
1457/************************************************************************
1458 * *
1459 * I/O for HTTP file accesses *
1460 * *
1461 ************************************************************************/
Daniel Veillardf012a642001-07-23 19:10:52 +00001462
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001463#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001464typedef struct xmlIOHTTPWriteCtxt_
1465{
1466 int compression;
1467
1468 char * uri;
1469
1470 void * doc_buff;
1471
1472} xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr;
1473
1474#ifdef HAVE_ZLIB_H
1475
1476#define DFLT_WBITS ( -15 )
1477#define DFLT_MEM_LVL ( 8 )
1478#define GZ_MAGIC1 ( 0x1f )
1479#define GZ_MAGIC2 ( 0x8b )
1480#define LXML_ZLIB_OS_CODE ( 0x03 )
1481#define INIT_HTTP_BUFF_SIZE ( 32768 )
1482#define DFLT_ZLIB_RATIO ( 5 )
1483
1484/*
1485** Data structure and functions to work with sending compressed data
1486** via HTTP.
1487*/
1488
1489typedef struct xmlZMemBuff_
1490{
1491 unsigned long size;
1492 unsigned long crc;
1493
1494 unsigned char * zbuff;
1495 z_stream zctrl;
1496
1497} xmlZMemBuff, *xmlZMemBuffPtr;
1498
1499/**
1500 * append_reverse_ulong
1501 * @buff: Compressed memory buffer
1502 * @data: Unsigned long to append
1503 *
1504 * Append a unsigned long in reverse byte order to the end of the
1505 * memory buffer.
1506 */
1507static void
1508append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) {
1509
1510 int idx;
1511
1512 if ( buff == NULL )
1513 return;
1514
1515 /*
1516 ** This is plagiarized from putLong in gzio.c (zlib source) where
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001517 ** the number "4" is hardcoded. If zlib is ever patched to
Daniel Veillardf012a642001-07-23 19:10:52 +00001518 ** support 64 bit file sizes, this code would need to be patched
1519 ** as well.
1520 */
1521
1522 for ( idx = 0; idx < 4; idx++ ) {
1523 *buff->zctrl.next_out = ( data & 0xff );
1524 data >>= 8;
1525 buff->zctrl.next_out++;
1526 }
1527
1528 return;
1529}
1530
1531/**
1532 *
1533 * xmlFreeZMemBuff
1534 * @buff: The memory buffer context to clear
1535 *
1536 * Release all the resources associated with the compressed memory buffer.
1537 */
1538static void
1539xmlFreeZMemBuff( xmlZMemBuffPtr buff ) {
William M. Brack78637da2003-07-31 14:47:38 +00001540
1541#ifdef DEBUG_HTTP
Daniel Veillardf012a642001-07-23 19:10:52 +00001542 int z_err;
William M. Brack78637da2003-07-31 14:47:38 +00001543#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001544
1545 if ( buff == NULL )
1546 return;
1547
1548 xmlFree( buff->zbuff );
Daniel Veillardf012a642001-07-23 19:10:52 +00001549#ifdef DEBUG_HTTP
William M. Brack78637da2003-07-31 14:47:38 +00001550 z_err = deflateEnd( &buff->zctrl );
Daniel Veillardf012a642001-07-23 19:10:52 +00001551 if ( z_err != Z_OK )
1552 xmlGenericError( xmlGenericErrorContext,
1553 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
1554 z_err );
William M. Brack78637da2003-07-31 14:47:38 +00001555#else
1556 deflateEnd( &buff->zctrl );
William M. Brack779af002003-08-01 15:55:39 +00001557#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001558
1559 xmlFree( buff );
1560 return;
1561}
1562
1563/**
1564 * xmlCreateZMemBuff
1565 *@compression: Compression value to use
1566 *
1567 * Create a memory buffer to hold the compressed XML document. The
1568 * compressed document in memory will end up being identical to what
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001569 * would be created if gzopen/gzwrite/gzclose were being used to
Daniel Veillardf012a642001-07-23 19:10:52 +00001570 * write the document to disk. The code for the header/trailer data to
1571 * the compression is plagiarized from the zlib source files.
1572 */
1573static void *
1574xmlCreateZMemBuff( int compression ) {
1575
1576 int z_err;
1577 int hdr_lgth;
1578 xmlZMemBuffPtr buff = NULL;
1579
1580 if ( ( compression < 1 ) || ( compression > 9 ) )
1581 return ( NULL );
1582
1583 /* Create the control and data areas */
1584
1585 buff = xmlMalloc( sizeof( xmlZMemBuff ) );
1586 if ( buff == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001587 xmlIOErrMemory("creating buffer context");
Daniel Veillardf012a642001-07-23 19:10:52 +00001588 return ( NULL );
1589 }
1590
1591 (void)memset( buff, 0, sizeof( xmlZMemBuff ) );
1592 buff->size = INIT_HTTP_BUFF_SIZE;
1593 buff->zbuff = xmlMalloc( buff->size );
1594 if ( buff->zbuff == NULL ) {
1595 xmlFreeZMemBuff( buff );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001596 xmlIOErrMemory("creating buffer");
Daniel Veillardf012a642001-07-23 19:10:52 +00001597 return ( NULL );
1598 }
1599
1600 z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
1601 DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
1602 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001603 xmlChar msg[500];
Daniel Veillardf012a642001-07-23 19:10:52 +00001604 xmlFreeZMemBuff( buff );
1605 buff = NULL;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001606 xmlStrPrintf(msg, 500,
Xin Lia136fc22016-07-26 14:22:54 -07001607 "xmlCreateZMemBuff: %s %d\n",
Daniel Veillard05d987b2003-10-08 11:54:57 +00001608 "Error initializing compression context. ZLIB error:",
1609 z_err );
1610 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001611 return ( NULL );
1612 }
1613
1614 /* Set the header data. The CRC will be needed for the trailer */
Daniel Veillard24505b02005-07-28 23:49:35 +00001615 buff->crc = crc32( 0L, NULL, 0 );
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001616 hdr_lgth = snprintf( (char *)buff->zbuff, buff->size,
1617 "%c%c%c%c%c%c%c%c%c%c",
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001618 GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED,
Daniel Veillardf012a642001-07-23 19:10:52 +00001619 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE );
1620 buff->zctrl.next_out = buff->zbuff + hdr_lgth;
1621 buff->zctrl.avail_out = buff->size - hdr_lgth;
1622
1623 return ( buff );
1624}
1625
1626/**
1627 * xmlZMemBuffExtend
1628 * @buff: Buffer used to compress and consolidate data.
1629 * @ext_amt: Number of bytes to extend the buffer.
1630 *
1631 * Extend the internal buffer used to store the compressed data by the
1632 * specified amount.
1633 *
1634 * Returns 0 on success or -1 on failure to extend the buffer. On failure
1635 * the original buffer still exists at the original size.
1636 */
1637static int
1638xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) {
1639
1640 int rc = -1;
1641 size_t new_size;
1642 size_t cur_used;
1643
1644 unsigned char * tmp_ptr = NULL;
1645
1646 if ( buff == NULL )
1647 return ( -1 );
1648
1649 else if ( ext_amt == 0 )
1650 return ( 0 );
1651
1652 cur_used = buff->zctrl.next_out - buff->zbuff;
1653 new_size = buff->size + ext_amt;
1654
1655#ifdef DEBUG_HTTP
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001656 if ( cur_used > new_size )
Daniel Veillardf012a642001-07-23 19:10:52 +00001657 xmlGenericError( xmlGenericErrorContext,
1658 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
1659 "Buffer overwrite detected during compressed memory",
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001660 "buffer extension. Overflowed by",
Daniel Veillardf012a642001-07-23 19:10:52 +00001661 (cur_used - new_size ) );
1662#endif
1663
1664 tmp_ptr = xmlRealloc( buff->zbuff, new_size );
1665 if ( tmp_ptr != NULL ) {
1666 rc = 0;
1667 buff->size = new_size;
1668 buff->zbuff = tmp_ptr;
1669 buff->zctrl.next_out = tmp_ptr + cur_used;
1670 buff->zctrl.avail_out = new_size - cur_used;
1671 }
1672 else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001673 xmlChar msg[500];
1674 xmlStrPrintf(msg, 500,
Xin Lia136fc22016-07-26 14:22:54 -07001675 "xmlZMemBuffExtend: %s %lu bytes.\n",
Daniel Veillard05d987b2003-10-08 11:54:57 +00001676 "Allocation failure extending output buffer to",
1677 new_size );
1678 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001679 }
1680
1681 return ( rc );
1682}
1683
1684/**
1685 * xmlZMemBuffAppend
1686 * @buff: Buffer used to compress and consolidate data
1687 * @src: Uncompressed source content to append to buffer
1688 * @len: Length of source data to append to buffer
1689 *
1690 * Compress and append data to the internal buffer. The data buffer
1691 * will be expanded if needed to store the additional data.
1692 *
1693 * Returns the number of bytes appended to the buffer or -1 on error.
1694 */
1695static int
1696xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) {
1697
1698 int z_err;
1699 size_t min_accept;
1700
1701 if ( ( buff == NULL ) || ( src == NULL ) )
1702 return ( -1 );
1703
1704 buff->zctrl.avail_in = len;
1705 buff->zctrl.next_in = (unsigned char *)src;
1706 while ( buff->zctrl.avail_in > 0 ) {
1707 /*
1708 ** Extend the buffer prior to deflate call if a reasonable amount
1709 ** of output buffer space is not available.
1710 */
1711 min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO;
1712 if ( buff->zctrl.avail_out <= min_accept ) {
1713 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1714 return ( -1 );
1715 }
1716
1717 z_err = deflate( &buff->zctrl, Z_NO_FLUSH );
1718 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001719 xmlChar msg[500];
1720 xmlStrPrintf(msg, 500,
Xin Lia136fc22016-07-26 14:22:54 -07001721 "xmlZMemBuffAppend: %s %d %s - %d",
Daniel Veillardf012a642001-07-23 19:10:52 +00001722 "Compression error while appending",
1723 len, "bytes to buffer. ZLIB error", z_err );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001724 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001725 return ( -1 );
1726 }
1727 }
1728
1729 buff->crc = crc32( buff->crc, (unsigned char *)src, len );
1730
1731 return ( len );
1732}
1733
1734/**
1735 * xmlZMemBuffGetContent
1736 * @buff: Compressed memory content buffer
1737 * @data_ref: Pointer reference to point to compressed content
1738 *
1739 * Flushes the compression buffers, appends gzip file trailers and
1740 * returns the compressed content and length of the compressed data.
1741 * NOTE: The gzip trailer code here is plagiarized from zlib source.
1742 *
1743 * Returns the length of the compressed data or -1 on error.
1744 */
1745static int
1746xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) {
1747
1748 int zlgth = -1;
1749 int z_err;
1750
1751 if ( ( buff == NULL ) || ( data_ref == NULL ) )
1752 return ( -1 );
1753
1754 /* Need to loop until compression output buffers are flushed */
1755
1756 do
1757 {
1758 z_err = deflate( &buff->zctrl, Z_FINISH );
1759 if ( z_err == Z_OK ) {
1760 /* In this case Z_OK means more buffer space needed */
1761
1762 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1763 return ( -1 );
1764 }
1765 }
1766 while ( z_err == Z_OK );
1767
1768 /* If the compression state is not Z_STREAM_END, some error occurred */
1769
1770 if ( z_err == Z_STREAM_END ) {
1771
1772 /* Need to append the gzip data trailer */
1773
1774 if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) {
1775 if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 )
1776 return ( -1 );
1777 }
1778
1779 /*
1780 ** For whatever reason, the CRC and length data are pushed out
1781 ** in reverse byte order. So a memcpy can't be used here.
1782 */
1783
1784 append_reverse_ulong( buff, buff->crc );
1785 append_reverse_ulong( buff, buff->zctrl.total_in );
1786
1787 zlgth = buff->zctrl.next_out - buff->zbuff;
1788 *data_ref = (char *)buff->zbuff;
1789 }
1790
Daniel Veillard05d987b2003-10-08 11:54:57 +00001791 else {
1792 xmlChar msg[500];
1793 xmlStrPrintf(msg, 500,
Xin Lia136fc22016-07-26 14:22:54 -07001794 "xmlZMemBuffGetContent: %s - %d\n",
Daniel Veillard05d987b2003-10-08 11:54:57 +00001795 "Error flushing zlib buffers. Error code", z_err );
1796 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1797 }
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001798
Daniel Veillardf012a642001-07-23 19:10:52 +00001799 return ( zlgth );
1800}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001801#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001802#endif /* HAVE_ZLIB_H */
1803
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001804#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001805/**
1806 * xmlFreeHTTPWriteCtxt
1807 * @ctxt: Context to cleanup
1808 *
1809 * Free allocated memory and reclaim system resources.
1810 *
1811 * No return value.
1812 */
1813static void
1814xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt )
1815{
1816 if ( ctxt->uri != NULL )
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001817 xmlFree( ctxt->uri );
Daniel Veillardf012a642001-07-23 19:10:52 +00001818
1819 if ( ctxt->doc_buff != NULL ) {
1820
1821#ifdef HAVE_ZLIB_H
1822 if ( ctxt->compression > 0 ) {
1823 xmlFreeZMemBuff( ctxt->doc_buff );
1824 }
1825 else
1826#endif
1827 {
1828 xmlOutputBufferClose( ctxt->doc_buff );
1829 }
1830 }
1831
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001832 xmlFree( ctxt );
Daniel Veillardf012a642001-07-23 19:10:52 +00001833 return;
1834}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001835#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001836
1837
Owen Taylor3473f882001-02-23 17:55:21 +00001838/**
1839 * xmlIOHTTPMatch:
1840 * @filename: the URI for matching
1841 *
1842 * check if the URI matches an HTTP one
1843 *
1844 * Returns 1 if matches, 0 otherwise
1845 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001846int
Owen Taylor3473f882001-02-23 17:55:21 +00001847xmlIOHTTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001848 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "http://", 7))
Owen Taylor3473f882001-02-23 17:55:21 +00001849 return(1);
1850 return(0);
1851}
1852
1853/**
1854 * xmlIOHTTPOpen:
1855 * @filename: the URI for matching
1856 *
1857 * open an HTTP I/O channel
1858 *
1859 * Returns an I/O context or NULL in case of error
1860 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001861void *
Owen Taylor3473f882001-02-23 17:55:21 +00001862xmlIOHTTPOpen (const char *filename) {
1863 return(xmlNanoHTTPOpen(filename, NULL));
1864}
1865
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001866#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001867/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001868 * xmlIOHTTPOpenW:
Daniel Veillardf012a642001-07-23 19:10:52 +00001869 * @post_uri: The destination URI for the document
1870 * @compression: The compression desired for the document.
1871 *
1872 * Open a temporary buffer to collect the document for a subsequent HTTP POST
1873 * request. Non-static as is called from the output buffer creation routine.
1874 *
1875 * Returns an I/O context or NULL in case of error.
1876 */
1877
1878void *
Daniel Veillard572577e2002-01-18 16:23:55 +00001879xmlIOHTTPOpenW(const char *post_uri, int compression)
1880{
Daniel Veillardf012a642001-07-23 19:10:52 +00001881
Daniel Veillard572577e2002-01-18 16:23:55 +00001882 xmlIOHTTPWriteCtxtPtr ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001883
Daniel Veillard572577e2002-01-18 16:23:55 +00001884 if (post_uri == NULL)
1885 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001886
Daniel Veillard572577e2002-01-18 16:23:55 +00001887 ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt));
1888 if (ctxt == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001889 xmlIOErrMemory("creating HTTP output context");
Daniel Veillard572577e2002-01-18 16:23:55 +00001890 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001891 }
1892
Daniel Veillard572577e2002-01-18 16:23:55 +00001893 (void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt));
Daniel Veillardf012a642001-07-23 19:10:52 +00001894
Daniel Veillard572577e2002-01-18 16:23:55 +00001895 ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri);
1896 if (ctxt->uri == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001897 xmlIOErrMemory("copying URI");
Daniel Veillard572577e2002-01-18 16:23:55 +00001898 xmlFreeHTTPWriteCtxt(ctxt);
1899 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001900 }
1901
1902 /*
Daniel Veillard572577e2002-01-18 16:23:55 +00001903 * ** Since the document length is required for an HTTP post,
1904 * ** need to put the document into a buffer. A memory buffer
1905 * ** is being used to avoid pushing the data to disk and back.
1906 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001907
1908#ifdef HAVE_ZLIB_H
Daniel Veillard572577e2002-01-18 16:23:55 +00001909 if ((compression > 0) && (compression <= 9)) {
1910
1911 ctxt->compression = compression;
1912 ctxt->doc_buff = xmlCreateZMemBuff(compression);
1913 } else
Daniel Veillardf012a642001-07-23 19:10:52 +00001914#endif
1915 {
Daniel Veillard572577e2002-01-18 16:23:55 +00001916 /* Any character conversions should have been done before this */
Daniel Veillardf012a642001-07-23 19:10:52 +00001917
Daniel Veillardda3fee42008-09-01 13:08:57 +00001918 ctxt->doc_buff = xmlAllocOutputBufferInternal(NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001919 }
1920
Daniel Veillard572577e2002-01-18 16:23:55 +00001921 if (ctxt->doc_buff == NULL) {
1922 xmlFreeHTTPWriteCtxt(ctxt);
1923 ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001924 }
1925
Daniel Veillard572577e2002-01-18 16:23:55 +00001926 return (ctxt);
Daniel Veillardf012a642001-07-23 19:10:52 +00001927}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001928#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardda3fee42008-09-01 13:08:57 +00001929
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001930#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001931/**
1932 * xmlIOHTTPDfltOpenW
1933 * @post_uri: The destination URI for this document.
1934 *
1935 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
1936 * HTTP post command. This function should generally not be used as
1937 * the open callback is short circuited in xmlOutputBufferCreateFile.
1938 *
1939 * Returns a pointer to the new IO context.
1940 */
1941static void *
1942xmlIOHTTPDfltOpenW( const char * post_uri ) {
1943 return ( xmlIOHTTPOpenW( post_uri, 0 ) );
1944}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001945#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001946
1947/**
Owen Taylor3473f882001-02-23 17:55:21 +00001948 * xmlIOHTTPRead:
1949 * @context: the I/O context
1950 * @buffer: where to drop data
1951 * @len: number of bytes to write
1952 *
1953 * Read @len bytes to @buffer from the I/O channel.
1954 *
1955 * Returns the number of bytes written
1956 */
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001957int
Owen Taylor3473f882001-02-23 17:55:21 +00001958xmlIOHTTPRead(void * context, char * buffer, int len) {
Daniel Veillard5ea30d72004-11-08 11:54:28 +00001959 if ((buffer == NULL) || (len < 0)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001960 return(xmlNanoHTTPRead(context, &buffer[0], len));
1961}
1962
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001963#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001964/**
Daniel Veillardf012a642001-07-23 19:10:52 +00001965 * xmlIOHTTPWrite
1966 * @context: previously opened writing context
1967 * @buffer: data to output to temporary buffer
1968 * @len: bytes to output
1969 *
1970 * Collect data from memory buffer into a temporary file for later
1971 * processing.
1972 *
1973 * Returns number of bytes written.
1974 */
1975
1976static int
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001977xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001978
1979 xmlIOHTTPWriteCtxtPtr ctxt = context;
1980
1981 if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
1982 return ( -1 );
1983
1984 if ( len > 0 ) {
1985
1986 /* Use gzwrite or fwrite as previously setup in the open call */
1987
1988#ifdef HAVE_ZLIB_H
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001989 if ( ctxt->compression > 0 )
Daniel Veillardf012a642001-07-23 19:10:52 +00001990 len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len );
1991
1992 else
1993#endif
1994 len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
1995
1996 if ( len < 0 ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001997 xmlChar msg[500];
1998 xmlStrPrintf(msg, 500,
Xin Lia136fc22016-07-26 14:22:54 -07001999 "xmlIOHTTPWrite: %s\n%s '%s'.\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00002000 "Error appending to internal buffer.",
2001 "Error sending document to URI",
2002 ctxt->uri );
Daniel Veillard05d987b2003-10-08 11:54:57 +00002003 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00002004 }
2005 }
2006
2007 return ( len );
2008}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002009#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00002010
2011
2012/**
Owen Taylor3473f882001-02-23 17:55:21 +00002013 * xmlIOHTTPClose:
2014 * @context: the I/O context
2015 *
2016 * Close an HTTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00002017 *
2018 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00002019 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002020int
Owen Taylor3473f882001-02-23 17:55:21 +00002021xmlIOHTTPClose (void * context) {
2022 xmlNanoHTTPClose(context);
Daniel Veillardf012a642001-07-23 19:10:52 +00002023 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002024}
Daniel Veillardf012a642001-07-23 19:10:52 +00002025
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002026#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00002027/**
2028 * xmlIOHTTCloseWrite
2029 * @context: The I/O context
2030 * @http_mthd: The HTTP method to be used when sending the data
2031 *
2032 * Close the transmit HTTP I/O channel and actually send the data.
2033 */
2034static int
2035xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
2036
2037 int close_rc = -1;
2038 int http_rtn = 0;
2039 int content_lgth = 0;
2040 xmlIOHTTPWriteCtxtPtr ctxt = context;
2041
2042 char * http_content = NULL;
2043 char * content_encoding = NULL;
2044 char * content_type = (char *) "text/xml";
2045 void * http_ctxt = NULL;
2046
2047 if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
2048 return ( -1 );
2049
2050 /* Retrieve the content from the appropriate buffer */
2051
2052#ifdef HAVE_ZLIB_H
2053
2054 if ( ctxt->compression > 0 ) {
2055 content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
2056 content_encoding = (char *) "Content-Encoding: gzip";
2057 }
2058 else
2059#endif
2060 {
2061 /* Pull the data out of the memory output buffer */
2062
2063 xmlOutputBufferPtr dctxt = ctxt->doc_buff;
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002064 http_content = (char *) xmlBufContent(dctxt->buffer);
2065 content_lgth = xmlBufUse(dctxt->buffer);
Daniel Veillardf012a642001-07-23 19:10:52 +00002066 }
2067
2068 if ( http_content == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002069 xmlChar msg[500];
2070 xmlStrPrintf(msg, 500,
Xin Lia136fc22016-07-26 14:22:54 -07002071 "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
Daniel Veillard05d987b2003-10-08 11:54:57 +00002072 "Error retrieving content.\nUnable to",
2073 http_mthd, "data to URI", ctxt->uri );
2074 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00002075 }
2076
2077 else {
2078
2079 http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
Hans Breuer2ad41ca2009-08-11 17:51:22 +02002080 &content_type, content_encoding,
Daniel Veillardf012a642001-07-23 19:10:52 +00002081 content_lgth );
2082
2083 if ( http_ctxt != NULL ) {
2084#ifdef DEBUG_HTTP
2085 /* If testing/debugging - dump reply with request content */
2086
2087 FILE * tst_file = NULL;
2088 char buffer[ 4096 ];
2089 char * dump_name = NULL;
2090 int avail;
2091
2092 xmlGenericError( xmlGenericErrorContext,
2093 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
2094 http_mthd, ctxt->uri,
2095 xmlNanoHTTPReturnCode( http_ctxt ) );
2096
2097 /*
2098 ** Since either content or reply may be gzipped,
Hans Breuer2ad41ca2009-08-11 17:51:22 +02002099 ** dump them to separate files instead of the
Daniel Veillardf012a642001-07-23 19:10:52 +00002100 ** standard error context.
2101 */
2102
2103 dump_name = tempnam( NULL, "lxml" );
2104 if ( dump_name != NULL ) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002105 (void)snprintf( buffer, sizeof(buffer), "%s.content", dump_name );
Daniel Veillardf012a642001-07-23 19:10:52 +00002106
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00002107 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00002108 if ( tst_file != NULL ) {
2109 xmlGenericError( xmlGenericErrorContext,
2110 "Transmitted content saved in file: %s\n", buffer );
2111
2112 fwrite( http_content, sizeof( char ),
2113 content_lgth, tst_file );
2114 fclose( tst_file );
2115 }
2116
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002117 (void)snprintf( buffer, sizeof(buffer), "%s.reply", dump_name );
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00002118 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00002119 if ( tst_file != NULL ) {
2120 xmlGenericError( xmlGenericErrorContext,
2121 "Reply content saved in file: %s\n", buffer );
2122
2123
2124 while ( (avail = xmlNanoHTTPRead( http_ctxt,
2125 buffer, sizeof( buffer ) )) > 0 ) {
2126
2127 fwrite( buffer, sizeof( char ), avail, tst_file );
2128 }
2129
2130 fclose( tst_file );
2131 }
2132
2133 free( dump_name );
2134 }
2135#endif /* DEBUG_HTTP */
2136
2137 http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
2138 if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
2139 close_rc = 0;
Daniel Veillard05d987b2003-10-08 11:54:57 +00002140 else {
2141 xmlChar msg[500];
2142 xmlStrPrintf(msg, 500,
Xin Lia136fc22016-07-26 14:22:54 -07002143 "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00002144 http_mthd, content_lgth,
2145 "bytes to URI", ctxt->uri,
2146 "failed. HTTP return code:", http_rtn );
Daniel Veillard05d987b2003-10-08 11:54:57 +00002147 xmlIOErr(XML_IO_WRITE, (const char *) msg);
2148 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002149
2150 xmlNanoHTTPClose( http_ctxt );
2151 xmlFree( content_type );
2152 }
2153 }
2154
2155 /* Final cleanups */
2156
2157 xmlFreeHTTPWriteCtxt( ctxt );
2158
2159 return ( close_rc );
2160}
2161
2162/**
2163 * xmlIOHTTPClosePut
2164 *
2165 * @context: The I/O context
2166 *
2167 * Close the transmit HTTP I/O channel and actually send data using a PUT
2168 * HTTP method.
2169 */
2170static int
2171xmlIOHTTPClosePut( void * ctxt ) {
2172 return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
2173}
2174
2175
2176/**
2177 * xmlIOHTTPClosePost
2178 *
2179 * @context: The I/O context
2180 *
2181 * Close the transmit HTTP I/O channel and actually send data using a POST
2182 * HTTP method.
2183 */
2184static int
2185xmlIOHTTPClosePost( void * ctxt ) {
2186 return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
2187}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002188#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00002189
Owen Taylor3473f882001-02-23 17:55:21 +00002190#endif /* LIBXML_HTTP_ENABLED */
2191
2192#ifdef LIBXML_FTP_ENABLED
2193/************************************************************************
2194 * *
2195 * I/O for FTP file accesses *
2196 * *
2197 ************************************************************************/
2198/**
2199 * xmlIOFTPMatch:
2200 * @filename: the URI for matching
2201 *
2202 * check if the URI matches an FTP one
2203 *
2204 * Returns 1 if matches, 0 otherwise
2205 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002206int
Owen Taylor3473f882001-02-23 17:55:21 +00002207xmlIOFTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002208 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "ftp://", 6))
Owen Taylor3473f882001-02-23 17:55:21 +00002209 return(1);
2210 return(0);
2211}
2212
2213/**
2214 * xmlIOFTPOpen:
2215 * @filename: the URI for matching
2216 *
2217 * open an FTP I/O channel
2218 *
2219 * Returns an I/O context or NULL in case of error
2220 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002221void *
Owen Taylor3473f882001-02-23 17:55:21 +00002222xmlIOFTPOpen (const char *filename) {
2223 return(xmlNanoFTPOpen(filename));
2224}
2225
2226/**
2227 * xmlIOFTPRead:
2228 * @context: the I/O context
2229 * @buffer: where to drop data
2230 * @len: number of bytes to write
2231 *
2232 * Read @len bytes to @buffer from the I/O channel.
2233 *
2234 * Returns the number of bytes written
2235 */
Hans Breuer2ad41ca2009-08-11 17:51:22 +02002236int
Owen Taylor3473f882001-02-23 17:55:21 +00002237xmlIOFTPRead(void * context, char * buffer, int len) {
Daniel Veillard5ea30d72004-11-08 11:54:28 +00002238 if ((buffer == NULL) || (len < 0)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002239 return(xmlNanoFTPRead(context, &buffer[0], len));
2240}
2241
2242/**
2243 * xmlIOFTPClose:
2244 * @context: the I/O context
2245 *
2246 * Close an FTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00002247 *
2248 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00002249 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002250int
Owen Taylor3473f882001-02-23 17:55:21 +00002251xmlIOFTPClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +00002252 return ( xmlNanoFTPClose(context) );
Owen Taylor3473f882001-02-23 17:55:21 +00002253}
2254#endif /* LIBXML_FTP_ENABLED */
2255
2256
2257/**
2258 * xmlRegisterInputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002259 * @matchFunc: the xmlInputMatchCallback
2260 * @openFunc: the xmlInputOpenCallback
2261 * @readFunc: the xmlInputReadCallback
2262 * @closeFunc: the xmlInputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00002263 *
2264 * Register a new set of I/O callback for handling parser input.
2265 *
2266 * Returns the registered handler number or -1 in case of error
2267 */
2268int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002269xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
2270 xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
2271 xmlInputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002272 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
2273 return(-1);
2274 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002275 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
2276 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
2277 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
2278 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00002279 xmlInputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002280 return(xmlInputCallbackNr++);
2281}
2282
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002283#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002284/**
2285 * xmlRegisterOutputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002286 * @matchFunc: the xmlOutputMatchCallback
2287 * @openFunc: the xmlOutputOpenCallback
2288 * @writeFunc: the xmlOutputWriteCallback
2289 * @closeFunc: the xmlOutputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00002290 *
2291 * Register a new set of I/O callback for handling output.
2292 *
2293 * Returns the registered handler number or -1 in case of error
2294 */
2295int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002296xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
2297 xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
2298 xmlOutputCloseCallback closeFunc) {
Daniel Veillard0d5e58f2009-08-24 13:52:23 +02002299 if (xmlOutputCallbackNr >= MAX_OUTPUT_CALLBACK) {
Owen Taylor3473f882001-02-23 17:55:21 +00002300 return(-1);
2301 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002302 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
2303 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
2304 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
2305 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00002306 xmlOutputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002307 return(xmlOutputCallbackNr++);
2308}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002309#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002310
2311/**
2312 * xmlRegisterDefaultInputCallbacks:
2313 *
2314 * Registers the default compiled-in I/O handlers.
2315 */
2316void
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +00002317xmlRegisterDefaultInputCallbacks(void) {
Owen Taylor3473f882001-02-23 17:55:21 +00002318 if (xmlInputCallbackInitialized)
2319 return;
2320
Daniel Veillard8ca85b22006-09-01 09:56:07 +00002321#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
2322 xmlInitPlatformSpecificIo();
2323#endif
2324
Owen Taylor3473f882001-02-23 17:55:21 +00002325 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
2326 xmlFileRead, xmlFileClose);
2327#ifdef HAVE_ZLIB_H
2328 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
2329 xmlGzfileRead, xmlGzfileClose);
2330#endif /* HAVE_ZLIB_H */
Daniel Veillard18b89882015-11-03 15:46:29 +08002331#ifdef LIBXML_LZMA_ENABLED
Anders F Bjorklundeae52612011-09-18 16:59:13 +02002332 xmlRegisterInputCallbacks(xmlXzfileMatch, xmlXzfileOpen,
2333 xmlXzfileRead, xmlXzfileClose);
Daniel Veillard18b89882015-11-03 15:46:29 +08002334#endif /* LIBXML_LZMA_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002335
2336#ifdef LIBXML_HTTP_ENABLED
2337 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
2338 xmlIOHTTPRead, xmlIOHTTPClose);
2339#endif /* LIBXML_HTTP_ENABLED */
2340
2341#ifdef LIBXML_FTP_ENABLED
2342 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
2343 xmlIOFTPRead, xmlIOFTPClose);
2344#endif /* LIBXML_FTP_ENABLED */
2345 xmlInputCallbackInitialized = 1;
2346}
2347
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002348#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002349/**
2350 * xmlRegisterDefaultOutputCallbacks:
2351 *
2352 * Registers the default compiled-in I/O handlers.
2353 */
2354void
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +00002355xmlRegisterDefaultOutputCallbacks (void) {
Owen Taylor3473f882001-02-23 17:55:21 +00002356 if (xmlOutputCallbackInitialized)
2357 return;
2358
Daniel Veillard8ca85b22006-09-01 09:56:07 +00002359#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
2360 xmlInitPlatformSpecificIo();
2361#endif
2362
Owen Taylor3473f882001-02-23 17:55:21 +00002363 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
2364 xmlFileWrite, xmlFileClose);
Daniel Veillardf012a642001-07-23 19:10:52 +00002365
2366#ifdef LIBXML_HTTP_ENABLED
2367 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
2368 xmlIOHTTPWrite, xmlIOHTTPClosePut);
2369#endif
2370
Owen Taylor3473f882001-02-23 17:55:21 +00002371/*********************************
2372 No way a-priori to distinguish between gzipped files from
2373 uncompressed ones except opening if existing then closing
2374 and saving with same compression ratio ... a pain.
2375
2376#ifdef HAVE_ZLIB_H
2377 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
2378 xmlGzfileWrite, xmlGzfileClose);
2379#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002380
2381 Nor FTP PUT ....
2382#ifdef LIBXML_FTP_ENABLED
2383 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
2384 xmlIOFTPWrite, xmlIOFTPClose);
2385#endif
2386 **********************************/
2387 xmlOutputCallbackInitialized = 1;
2388}
2389
Daniel Veillardf012a642001-07-23 19:10:52 +00002390#ifdef LIBXML_HTTP_ENABLED
2391/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00002392 * xmlRegisterHTTPPostCallbacks:
Daniel Veillardf012a642001-07-23 19:10:52 +00002393 *
2394 * By default, libxml submits HTTP output requests using the "PUT" method.
2395 * Calling this method changes the HTTP output method to use the "POST"
2396 * method instead.
2397 *
2398 */
2399void
2400xmlRegisterHTTPPostCallbacks( void ) {
2401
2402 /* Register defaults if not done previously */
2403
2404 if ( xmlOutputCallbackInitialized == 0 )
2405 xmlRegisterDefaultOutputCallbacks( );
2406
2407 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
2408 xmlIOHTTPWrite, xmlIOHTTPClosePost);
2409 return;
2410}
2411#endif
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002412#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00002413
Owen Taylor3473f882001-02-23 17:55:21 +00002414/**
2415 * xmlAllocParserInputBuffer:
2416 * @enc: the charset encoding if known
2417 *
2418 * Create a buffered parser input for progressive parsing
2419 *
2420 * Returns the new parser input or NULL
2421 */
2422xmlParserInputBufferPtr
2423xmlAllocParserInputBuffer(xmlCharEncoding enc) {
2424 xmlParserInputBufferPtr ret;
2425
2426 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2427 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002428 xmlIOErrMemory("creating input buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00002429 return(NULL);
2430 }
2431 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002432 ret->buffer = xmlBufCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00002433 if (ret->buffer == NULL) {
2434 xmlFree(ret);
2435 return(NULL);
2436 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002437 xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_DOUBLEIT);
Owen Taylor3473f882001-02-23 17:55:21 +00002438 ret->encoder = xmlGetCharEncodingHandler(enc);
2439 if (ret->encoder != NULL)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002440 ret->raw = xmlBufCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00002441 else
2442 ret->raw = NULL;
2443 ret->readcallback = NULL;
2444 ret->closecallback = NULL;
2445 ret->context = NULL;
William M. Brackc07329e2003-09-08 01:57:30 +00002446 ret->compressed = -1;
Daniel Veillard36711902004-02-11 13:25:26 +00002447 ret->rawconsumed = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002448
2449 return(ret);
2450}
2451
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002452#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002453/**
2454 * xmlAllocOutputBuffer:
2455 * @encoder: the encoding converter or NULL
2456 *
2457 * Create a buffered parser output
2458 *
2459 * Returns the new parser output or NULL
2460 */
2461xmlOutputBufferPtr
2462xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
2463 xmlOutputBufferPtr ret;
2464
2465 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
2466 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002467 xmlIOErrMemory("creating output buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00002468 return(NULL);
2469 }
2470 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002471 ret->buffer = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00002472 if (ret->buffer == NULL) {
2473 xmlFree(ret);
2474 return(NULL);
2475 }
Daniel Veillarde83e93e2008-08-30 12:52:26 +00002476
Daniel Veillard43bc89c2009-03-23 19:32:04 +00002477 /* try to avoid a performance problem with Windows realloc() */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002478 if (xmlBufGetAllocationScheme(ret->buffer) == XML_BUFFER_ALLOC_EXACT)
2479 xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_DOUBLEIT);
Daniel Veillard43bc89c2009-03-23 19:32:04 +00002480
Daniel Veillardda3fee42008-09-01 13:08:57 +00002481 ret->encoder = encoder;
2482 if (encoder != NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002483 ret->conv = xmlBufCreateSize(4000);
Daniel Veillardda3fee42008-09-01 13:08:57 +00002484 if (ret->conv == NULL) {
2485 xmlFree(ret);
2486 return(NULL);
2487 }
2488
2489 /*
2490 * This call is designed to initiate the encoder state
2491 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002492 xmlCharEncOutput(ret, 1);
Daniel Veillardda3fee42008-09-01 13:08:57 +00002493 } else
2494 ret->conv = NULL;
2495 ret->writecallback = NULL;
2496 ret->closecallback = NULL;
2497 ret->context = NULL;
2498 ret->written = 0;
2499
2500 return(ret);
2501}
2502
2503/**
2504 * xmlAllocOutputBufferInternal:
2505 * @encoder: the encoding converter or NULL
2506 *
2507 * Create a buffered parser output
2508 *
2509 * Returns the new parser output or NULL
2510 */
2511xmlOutputBufferPtr
2512xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder) {
2513 xmlOutputBufferPtr ret;
2514
2515 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
2516 if (ret == NULL) {
2517 xmlIOErrMemory("creating output buffer");
2518 return(NULL);
2519 }
2520 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002521 ret->buffer = xmlBufCreate();
Daniel Veillardda3fee42008-09-01 13:08:57 +00002522 if (ret->buffer == NULL) {
2523 xmlFree(ret);
2524 return(NULL);
2525 }
2526
2527
Daniel Veillarde83e93e2008-08-30 12:52:26 +00002528 /*
2529 * For conversion buffers we use the special IO handling
2530 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002531 xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_IO);
Daniel Veillarde83e93e2008-08-30 12:52:26 +00002532
Owen Taylor3473f882001-02-23 17:55:21 +00002533 ret->encoder = encoder;
2534 if (encoder != NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002535 ret->conv = xmlBufCreateSize(4000);
Daniel Veillarde83e93e2008-08-30 12:52:26 +00002536 if (ret->conv == NULL) {
2537 xmlFree(ret);
2538 return(NULL);
2539 }
2540
Owen Taylor3473f882001-02-23 17:55:21 +00002541 /*
2542 * This call is designed to initiate the encoder state
2543 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002544 xmlCharEncOutput(ret, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00002545 } else
2546 ret->conv = NULL;
2547 ret->writecallback = NULL;
2548 ret->closecallback = NULL;
2549 ret->context = NULL;
2550 ret->written = 0;
2551
2552 return(ret);
2553}
Daniel Veillardda3fee42008-09-01 13:08:57 +00002554
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002555#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002556
2557/**
2558 * xmlFreeParserInputBuffer:
2559 * @in: a buffered parser input
2560 *
2561 * Free up the memory used by a buffered parser input
2562 */
2563void
2564xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
Daniel Veillard8d8bf2c2003-09-17 19:36:25 +00002565 if (in == NULL) return;
2566
Owen Taylor3473f882001-02-23 17:55:21 +00002567 if (in->raw) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002568 xmlBufFree(in->raw);
Owen Taylor3473f882001-02-23 17:55:21 +00002569 in->raw = NULL;
2570 }
2571 if (in->encoder != NULL) {
2572 xmlCharEncCloseFunc(in->encoder);
2573 }
2574 if (in->closecallback != NULL) {
2575 in->closecallback(in->context);
2576 }
2577 if (in->buffer != NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002578 xmlBufFree(in->buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00002579 in->buffer = NULL;
2580 }
2581
Owen Taylor3473f882001-02-23 17:55:21 +00002582 xmlFree(in);
2583}
2584
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002585#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002586/**
2587 * xmlOutputBufferClose:
2588 * @out: a buffered output
2589 *
2590 * flushes and close the output I/O channel
2591 * and free up all the associated resources
2592 *
2593 * Returns the number of byte written or -1 in case of error.
2594 */
2595int
Daniel Veillard828ce832003-10-08 19:19:10 +00002596xmlOutputBufferClose(xmlOutputBufferPtr out)
2597{
Owen Taylor3473f882001-02-23 17:55:21 +00002598 int written;
Daniel Veillardf012a642001-07-23 19:10:52 +00002599 int err_rc = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002600
2601 if (out == NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002602 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002603 if (out->writecallback != NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002604 xmlOutputBufferFlush(out);
Owen Taylor3473f882001-02-23 17:55:21 +00002605 if (out->closecallback != NULL) {
Daniel Veillard828ce832003-10-08 19:19:10 +00002606 err_rc = out->closecallback(out->context);
Owen Taylor3473f882001-02-23 17:55:21 +00002607 }
2608 written = out->written;
2609 if (out->conv) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002610 xmlBufFree(out->conv);
Daniel Veillard828ce832003-10-08 19:19:10 +00002611 out->conv = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002612 }
2613 if (out->encoder != NULL) {
2614 xmlCharEncCloseFunc(out->encoder);
2615 }
2616 if (out->buffer != NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002617 xmlBufFree(out->buffer);
Daniel Veillard828ce832003-10-08 19:19:10 +00002618 out->buffer = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002619 }
2620
Daniel Veillard828ce832003-10-08 19:19:10 +00002621 if (out->error)
2622 err_rc = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00002623 xmlFree(out);
Daniel Veillard828ce832003-10-08 19:19:10 +00002624 return ((err_rc == 0) ? written : err_rc);
Owen Taylor3473f882001-02-23 17:55:21 +00002625}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002626#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002627
Daniel Veillard1b243b42004-06-08 10:16:42 +00002628xmlParserInputBufferPtr
Daniel Veillard0335a842004-06-02 16:18:40 +00002629__xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002630 xmlParserInputBufferPtr ret;
Daniel Veillard388236f2001-07-08 18:35:48 +00002631 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002632 void *context = NULL;
2633
2634 if (xmlInputCallbackInitialized == 0)
2635 xmlRegisterDefaultInputCallbacks();
2636
2637 if (URI == NULL) return(NULL);
2638
2639 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002640 * Try to find one of the input accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002641 * Go in reverse to give precedence to user defined handlers.
Daniel Veillard388236f2001-07-08 18:35:48 +00002642 */
2643 if (context == NULL) {
2644 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
2645 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
2646 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002647 context = xmlInputCallbackTable[i].opencallback(URI);
Daniel Veillard847332a2003-10-18 11:29:40 +00002648 if (context != NULL) {
Daniel Veillard388236f2001-07-08 18:35:48 +00002649 break;
Daniel Veillard847332a2003-10-18 11:29:40 +00002650 }
Daniel Veillard388236f2001-07-08 18:35:48 +00002651 }
Owen Taylor3473f882001-02-23 17:55:21 +00002652 }
2653 }
2654 if (context == NULL) {
2655 return(NULL);
2656 }
2657
2658 /*
2659 * Allocate the Input buffer front-end.
2660 */
2661 ret = xmlAllocParserInputBuffer(enc);
2662 if (ret != NULL) {
2663 ret->context = context;
2664 ret->readcallback = xmlInputCallbackTable[i].readcallback;
2665 ret->closecallback = xmlInputCallbackTable[i].closecallback;
William M. Brackc07329e2003-09-08 01:57:30 +00002666#ifdef HAVE_ZLIB_H
William M. Brackc5cbf992003-10-29 22:15:13 +00002667 if ((xmlInputCallbackTable[i].opencallback == xmlGzfileOpen) &&
2668 (strcmp(URI, "-") != 0)) {
Mark Adlera7e79f22010-01-19 16:28:48 +01002669#if defined(ZLIB_VERNUM) && ZLIB_VERNUM >= 0x1230
2670 ret->compressed = !gzdirect(context);
2671#else
William M. Brackc07329e2003-09-08 01:57:30 +00002672 if (((z_stream *)context)->avail_in > 4) {
2673 char *cptr, buff4[4];
Daniel Veillard07cb8222003-09-10 10:51:05 +00002674 cptr = (char *) ((z_stream *)context)->next_in;
William M. Brackc07329e2003-09-08 01:57:30 +00002675 if (gzread(context, buff4, 4) == 4) {
2676 if (strncmp(buff4, cptr, 4) == 0)
2677 ret->compressed = 0;
2678 else
2679 ret->compressed = 1;
2680 gzrewind(context);
2681 }
2682 }
Mark Adlera7e79f22010-01-19 16:28:48 +01002683#endif
William M. Brackc07329e2003-09-08 01:57:30 +00002684 }
2685#endif
Daniel Veillard18b89882015-11-03 15:46:29 +08002686#ifdef LIBXML_LZMA_ENABLED
Daniel Veillard63588f42013-05-10 14:01:46 +08002687 if ((xmlInputCallbackTable[i].opencallback == xmlXzfileOpen) &&
2688 (strcmp(URI, "-") != 0)) {
2689 ret->compressed = __libxml2_xzcompressed(context);
2690 }
2691#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002692 }
William M. Brack42331a92004-07-29 07:07:16 +00002693 else
2694 xmlInputCallbackTable[i].closecallback (context);
2695
Owen Taylor3473f882001-02-23 17:55:21 +00002696 return(ret);
2697}
2698
2699/**
Daniel Veillard0335a842004-06-02 16:18:40 +00002700 * xmlParserInputBufferCreateFilename:
Owen Taylor3473f882001-02-23 17:55:21 +00002701 * @URI: a C string containing the URI or filename
Daniel Veillard0335a842004-06-02 16:18:40 +00002702 * @enc: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002703 *
Daniel Veillard0335a842004-06-02 16:18:40 +00002704 * Create a buffered parser input for the progressive parsing of a file
2705 * If filename is "-' then we use stdin as the input.
Owen Taylor3473f882001-02-23 17:55:21 +00002706 * Automatic support for ZLIB/Compress compressed document is provided
2707 * by default if found at compile-time.
Daniel Veillard0335a842004-06-02 16:18:40 +00002708 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
Owen Taylor3473f882001-02-23 17:55:21 +00002709 *
Daniel Veillard0335a842004-06-02 16:18:40 +00002710 * Returns the new parser input or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00002711 */
Daniel Veillard0335a842004-06-02 16:18:40 +00002712xmlParserInputBufferPtr
2713xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
2714 if ((xmlParserInputBufferCreateFilenameValue)) {
2715 return xmlParserInputBufferCreateFilenameValue(URI, enc);
2716 }
2717 return __xmlParserInputBufferCreateFilename(URI, enc);
2718}
2719
2720#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard1b243b42004-06-08 10:16:42 +00002721xmlOutputBufferPtr
Daniel Veillard0335a842004-06-02 16:18:40 +00002722__xmlOutputBufferCreateFilename(const char *URI,
Owen Taylor3473f882001-02-23 17:55:21 +00002723 xmlCharEncodingHandlerPtr encoder,
Daniel Veillard0335a842004-06-02 16:18:40 +00002724 int compression ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00002725 xmlOutputBufferPtr ret;
Daniel Veillard966a31e2004-05-09 02:58:44 +00002726 xmlURIPtr puri;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002727 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002728 void *context = NULL;
Daniel Veillard966a31e2004-05-09 02:58:44 +00002729 char *unescaped = NULL;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002730#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002731 int is_file_uri = 1;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002732#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00002733
Owen Taylor3473f882001-02-23 17:55:21 +00002734 if (xmlOutputCallbackInitialized == 0)
2735 xmlRegisterDefaultOutputCallbacks();
2736
2737 if (URI == NULL) return(NULL);
2738
Daniel Veillard966a31e2004-05-09 02:58:44 +00002739 puri = xmlParseURI(URI);
2740 if (puri != NULL) {
Daniel Veillard8fcd2ca2005-07-03 14:42:56 +00002741#ifdef HAVE_ZLIB_H
Daniel Veillard18a65092004-05-11 15:57:42 +00002742 if ((puri->scheme != NULL) &&
2743 (!xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
Daniel Veillard966a31e2004-05-09 02:58:44 +00002744 is_file_uri = 0;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002745#endif
Daniel Veillard966a31e2004-05-09 02:58:44 +00002746 /*
2747 * try to limit the damages of the URI unescaping code.
2748 */
Daniel Veillarde8967e02006-10-11 09:15:00 +00002749 if ((puri->scheme == NULL) ||
2750 (xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
Daniel Veillard966a31e2004-05-09 02:58:44 +00002751 unescaped = xmlURIUnescapeString(URI, 0, NULL);
2752 xmlFreeURI(puri);
2753 }
Owen Taylor3473f882001-02-23 17:55:21 +00002754
2755 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002756 * Try to find one of the output accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002757 * Go in reverse to give precedence to user defined handlers.
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002758 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00002759 */
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002760 if (unescaped != NULL) {
2761#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002762 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002763 context = xmlGzfileOpenW(unescaped, compression);
2764 if (context != NULL) {
Daniel Veillardda3fee42008-09-01 13:08:57 +00002765 ret = xmlAllocOutputBufferInternal(encoder);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002766 if (ret != NULL) {
2767 ret->context = context;
2768 ret->writecallback = xmlGzfileWrite;
2769 ret->closecallback = xmlGzfileClose;
2770 }
2771 xmlFree(unescaped);
2772 return(ret);
2773 }
2774 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002775#endif
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002776 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2777 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
2778 (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
2779#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2780 /* Need to pass compression parameter into HTTP open calls */
2781 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2782 context = xmlIOHTTPOpenW(unescaped, compression);
2783 else
2784#endif
2785 context = xmlOutputCallbackTable[i].opencallback(unescaped);
2786 if (context != NULL)
2787 break;
2788 }
2789 }
2790 xmlFree(unescaped);
2791 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002792
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002793 /*
2794 * If this failed try with a non-escaped URI this may be a strange
2795 * filename
2796 */
2797 if (context == NULL) {
2798#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002799 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002800 context = xmlGzfileOpenW(URI, compression);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002801 if (context != NULL) {
Daniel Veillardda3fee42008-09-01 13:08:57 +00002802 ret = xmlAllocOutputBufferInternal(encoder);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002803 if (ret != NULL) {
2804 ret->context = context;
2805 ret->writecallback = xmlGzfileWrite;
2806 ret->closecallback = xmlGzfileClose;
2807 }
2808 return(ret);
2809 }
2810 }
2811#endif
2812 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2813 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002814 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002815#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2816 /* Need to pass compression parameter into HTTP open calls */
2817 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2818 context = xmlIOHTTPOpenW(URI, compression);
2819 else
2820#endif
2821 context = xmlOutputCallbackTable[i].opencallback(URI);
2822 if (context != NULL)
2823 break;
2824 }
Owen Taylor3473f882001-02-23 17:55:21 +00002825 }
2826 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002827
Owen Taylor3473f882001-02-23 17:55:21 +00002828 if (context == NULL) {
2829 return(NULL);
2830 }
2831
2832 /*
2833 * Allocate the Output buffer front-end.
2834 */
Daniel Veillardda3fee42008-09-01 13:08:57 +00002835 ret = xmlAllocOutputBufferInternal(encoder);
Owen Taylor3473f882001-02-23 17:55:21 +00002836 if (ret != NULL) {
2837 ret->context = context;
2838 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
2839 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
2840 }
2841 return(ret);
2842}
Daniel Veillard0335a842004-06-02 16:18:40 +00002843
2844/**
2845 * xmlOutputBufferCreateFilename:
2846 * @URI: a C string containing the URI or filename
2847 * @encoder: the encoding converter or NULL
2848 * @compression: the compression ration (0 none, 9 max).
2849 *
2850 * Create a buffered output for the progressive saving of a file
2851 * If filename is "-' then we use stdout as the output.
2852 * Automatic support for ZLIB/Compress compressed document is provided
2853 * by default if found at compile-time.
2854 * TODO: currently if compression is set, the library only support
2855 * writing to a local file.
2856 *
2857 * Returns the new output or NULL
2858 */
2859xmlOutputBufferPtr
2860xmlOutputBufferCreateFilename(const char *URI,
2861 xmlCharEncodingHandlerPtr encoder,
2862 int compression ATTRIBUTE_UNUSED) {
2863 if ((xmlOutputBufferCreateFilenameValue)) {
2864 return xmlOutputBufferCreateFilenameValue(URI, encoder, compression);
2865 }
2866 return __xmlOutputBufferCreateFilename(URI, encoder, compression);
2867}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002868#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002869
2870/**
2871 * xmlParserInputBufferCreateFile:
Hans Breuer2ad41ca2009-08-11 17:51:22 +02002872 * @file: a FILE*
Owen Taylor3473f882001-02-23 17:55:21 +00002873 * @enc: the charset encoding if known
2874 *
2875 * Create a buffered parser input for the progressive parsing of a FILE *
2876 * buffered C I/O
2877 *
2878 * Returns the new parser input or NULL
2879 */
2880xmlParserInputBufferPtr
2881xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
2882 xmlParserInputBufferPtr ret;
2883
2884 if (xmlInputCallbackInitialized == 0)
2885 xmlRegisterDefaultInputCallbacks();
2886
2887 if (file == NULL) return(NULL);
2888
2889 ret = xmlAllocParserInputBuffer(enc);
2890 if (ret != NULL) {
2891 ret->context = file;
2892 ret->readcallback = xmlFileRead;
2893 ret->closecallback = xmlFileFlush;
2894 }
2895
2896 return(ret);
2897}
2898
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002899#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002900/**
2901 * xmlOutputBufferCreateFile:
Hans Breuer2ad41ca2009-08-11 17:51:22 +02002902 * @file: a FILE*
Owen Taylor3473f882001-02-23 17:55:21 +00002903 * @encoder: the encoding converter or NULL
2904 *
2905 * Create a buffered output for the progressive saving to a FILE *
2906 * buffered C I/O
2907 *
2908 * Returns the new parser output or NULL
2909 */
2910xmlOutputBufferPtr
2911xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
2912 xmlOutputBufferPtr ret;
2913
2914 if (xmlOutputCallbackInitialized == 0)
2915 xmlRegisterDefaultOutputCallbacks();
2916
2917 if (file == NULL) return(NULL);
2918
Daniel Veillardda3fee42008-09-01 13:08:57 +00002919 ret = xmlAllocOutputBufferInternal(encoder);
Owen Taylor3473f882001-02-23 17:55:21 +00002920 if (ret != NULL) {
2921 ret->context = file;
2922 ret->writecallback = xmlFileWrite;
2923 ret->closecallback = xmlFileFlush;
2924 }
2925
2926 return(ret);
2927}
Daniel Veillard9a00fd22005-11-09 08:56:26 +00002928
2929/**
2930 * xmlOutputBufferCreateBuffer:
2931 * @buffer: a xmlBufferPtr
2932 * @encoder: the encoding converter or NULL
2933 *
2934 * Create a buffered output for the progressive saving to a xmlBuffer
2935 *
2936 * Returns the new parser output or NULL
2937 */
2938xmlOutputBufferPtr
2939xmlOutputBufferCreateBuffer(xmlBufferPtr buffer,
2940 xmlCharEncodingHandlerPtr encoder) {
2941 xmlOutputBufferPtr ret;
2942
2943 if (buffer == NULL) return(NULL);
2944
Rob Richardsa44f2342005-11-09 18:03:45 +00002945 ret = xmlOutputBufferCreateIO((xmlOutputWriteCallback)
2946 xmlBufferWrite,
2947 (xmlOutputCloseCallback)
Daniel Veillard4d3866c2005-11-13 12:43:59 +00002948 NULL, (void *) buffer, encoder);
Daniel Veillard9a00fd22005-11-09 08:56:26 +00002949
2950 return(ret);
2951}
2952
Daniel Veillarde258ade2012-08-06 11:16:30 +08002953/**
2954 * xmlOutputBufferGetContent:
2955 * @out: an xmlOutputBufferPtr
2956 *
2957 * Gives a pointer to the data currently held in the output buffer
2958 *
2959 * Returns a pointer to the data or NULL in case of error
2960 */
2961const xmlChar *
2962xmlOutputBufferGetContent(xmlOutputBufferPtr out) {
2963 if ((out == NULL) || (out->buffer == NULL))
2964 return(NULL);
2965
2966 return(xmlBufContent(out->buffer));
2967}
2968
2969/**
2970 * xmlOutputBufferGetSize:
2971 * @out: an xmlOutputBufferPtr
2972 *
2973 * Gives the length of the data currently held in the output buffer
2974 *
2975 * Returns 0 in case or error or no data is held, the size otherwise
2976 */
2977size_t
2978xmlOutputBufferGetSize(xmlOutputBufferPtr out) {
2979 if ((out == NULL) || (out->buffer == NULL))
2980 return(0);
2981
2982 return(xmlBufUse(out->buffer));
2983}
2984
2985
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002986#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002987
2988/**
2989 * xmlParserInputBufferCreateFd:
2990 * @fd: a file descriptor number
2991 * @enc: the charset encoding if known
2992 *
2993 * Create a buffered parser input for the progressive parsing for the input
2994 * from a file descriptor
2995 *
2996 * Returns the new parser input or NULL
2997 */
2998xmlParserInputBufferPtr
2999xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
3000 xmlParserInputBufferPtr ret;
3001
3002 if (fd < 0) return(NULL);
3003
3004 ret = xmlAllocParserInputBuffer(enc);
3005 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00003006 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00003007 ret->readcallback = xmlFdRead;
3008 ret->closecallback = xmlFdClose;
3009 }
3010
3011 return(ret);
3012}
3013
3014/**
3015 * xmlParserInputBufferCreateMem:
3016 * @mem: the memory input
3017 * @size: the length of the memory block
3018 * @enc: the charset encoding if known
3019 *
3020 * Create a buffered parser input for the progressive parsing for the input
3021 * from a memory area.
3022 *
3023 * Returns the new parser input or NULL
3024 */
3025xmlParserInputBufferPtr
3026xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
3027 xmlParserInputBufferPtr ret;
William M. Bracka3215c72004-07-31 16:24:01 +00003028 int errcode;
Owen Taylor3473f882001-02-23 17:55:21 +00003029
3030 if (size <= 0) return(NULL);
3031 if (mem == NULL) return(NULL);
3032
3033 ret = xmlAllocParserInputBuffer(enc);
3034 if (ret != NULL) {
3035 ret->context = (void *) mem;
3036 ret->readcallback = (xmlInputReadCallback) xmlNop;
3037 ret->closecallback = NULL;
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003038 errcode = xmlBufAdd(ret->buffer, (const xmlChar *) mem, size);
William M. Bracka3215c72004-07-31 16:24:01 +00003039 if (errcode != 0) {
3040 xmlFree(ret);
3041 return(NULL);
3042 }
Owen Taylor3473f882001-02-23 17:55:21 +00003043 }
3044
3045 return(ret);
3046}
3047
3048/**
Daniel Veillard53350552003-09-18 13:35:51 +00003049 * xmlParserInputBufferCreateStatic:
3050 * @mem: the memory input
3051 * @size: the length of the memory block
3052 * @enc: the charset encoding if known
3053 *
3054 * Create a buffered parser input for the progressive parsing for the input
3055 * from an immutable memory area. This will not copy the memory area to
3056 * the buffer, but the memory is expected to be available until the end of
3057 * the parsing, this is useful for example when using mmap'ed file.
3058 *
3059 * Returns the new parser input or NULL
3060 */
3061xmlParserInputBufferPtr
3062xmlParserInputBufferCreateStatic(const char *mem, int size,
3063 xmlCharEncoding enc) {
3064 xmlParserInputBufferPtr ret;
3065
3066 if (size <= 0) return(NULL);
3067 if (mem == NULL) return(NULL);
3068
3069 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
3070 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003071 xmlIOErrMemory("creating input buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00003072 return(NULL);
3073 }
3074 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003075 ret->buffer = xmlBufCreateStatic((void *)mem, (size_t) size);
Daniel Veillard53350552003-09-18 13:35:51 +00003076 if (ret->buffer == NULL) {
3077 xmlFree(ret);
3078 return(NULL);
3079 }
3080 ret->encoder = xmlGetCharEncodingHandler(enc);
3081 if (ret->encoder != NULL)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003082 ret->raw = xmlBufCreateSize(2 * xmlDefaultBufferSize);
Daniel Veillard53350552003-09-18 13:35:51 +00003083 else
3084 ret->raw = NULL;
3085 ret->compressed = -1;
3086 ret->context = (void *) mem;
3087 ret->readcallback = NULL;
3088 ret->closecallback = NULL;
3089
3090 return(ret);
3091}
3092
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003093#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard53350552003-09-18 13:35:51 +00003094/**
Owen Taylor3473f882001-02-23 17:55:21 +00003095 * xmlOutputBufferCreateFd:
3096 * @fd: a file descriptor number
3097 * @encoder: the encoding converter or NULL
3098 *
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003099 * Create a buffered output for the progressive saving
Owen Taylor3473f882001-02-23 17:55:21 +00003100 * to a file descriptor
3101 *
3102 * Returns the new parser output or NULL
3103 */
3104xmlOutputBufferPtr
3105xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
3106 xmlOutputBufferPtr ret;
3107
3108 if (fd < 0) return(NULL);
3109
Daniel Veillardda3fee42008-09-01 13:08:57 +00003110 ret = xmlAllocOutputBufferInternal(encoder);
Owen Taylor3473f882001-02-23 17:55:21 +00003111 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00003112 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00003113 ret->writecallback = xmlFdWrite;
Daniel Veillard7db38712002-02-07 16:39:11 +00003114 ret->closecallback = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003115 }
3116
3117 return(ret);
3118}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003119#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003120
3121/**
3122 * xmlParserInputBufferCreateIO:
3123 * @ioread: an I/O read function
3124 * @ioclose: an I/O close function
3125 * @ioctx: an I/O handler
3126 * @enc: the charset encoding if known
3127 *
3128 * Create a buffered parser input for the progressive parsing for the input
3129 * from an I/O handler
3130 *
3131 * Returns the new parser input or NULL
3132 */
3133xmlParserInputBufferPtr
3134xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
3135 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
3136 xmlParserInputBufferPtr ret;
3137
3138 if (ioread == NULL) return(NULL);
3139
3140 ret = xmlAllocParserInputBuffer(enc);
3141 if (ret != NULL) {
3142 ret->context = (void *) ioctx;
3143 ret->readcallback = ioread;
3144 ret->closecallback = ioclose;
3145 }
3146
3147 return(ret);
3148}
3149
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003150#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003151/**
3152 * xmlOutputBufferCreateIO:
3153 * @iowrite: an I/O write function
3154 * @ioclose: an I/O close function
3155 * @ioctx: an I/O handler
Daniel Veillard9d06d302002-01-22 18:15:52 +00003156 * @encoder: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00003157 *
3158 * Create a buffered output for the progressive saving
3159 * to an I/O handler
3160 *
3161 * Returns the new parser output or NULL
3162 */
3163xmlOutputBufferPtr
3164xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
3165 xmlOutputCloseCallback ioclose, void *ioctx,
3166 xmlCharEncodingHandlerPtr encoder) {
3167 xmlOutputBufferPtr ret;
3168
3169 if (iowrite == NULL) return(NULL);
3170
Daniel Veillardda3fee42008-09-01 13:08:57 +00003171 ret = xmlAllocOutputBufferInternal(encoder);
Owen Taylor3473f882001-02-23 17:55:21 +00003172 if (ret != NULL) {
3173 ret->context = (void *) ioctx;
3174 ret->writecallback = iowrite;
3175 ret->closecallback = ioclose;
3176 }
3177
3178 return(ret);
3179}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003180#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003181
3182/**
Daniel Veillard1b243b42004-06-08 10:16:42 +00003183 * xmlParserInputBufferCreateFilenameDefault:
3184 * @func: function pointer to the new ParserInputBufferCreateFilenameFunc
3185 *
3186 * Registers a callback for URI input file handling
3187 *
3188 * Returns the old value of the registration function
3189 */
3190xmlParserInputBufferCreateFilenameFunc
3191xmlParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func)
3192{
3193 xmlParserInputBufferCreateFilenameFunc old = xmlParserInputBufferCreateFilenameValue;
3194 if (old == NULL) {
3195 old = __xmlParserInputBufferCreateFilename;
3196 }
3197
3198 xmlParserInputBufferCreateFilenameValue = func;
3199 return(old);
3200}
3201
3202/**
3203 * xmlOutputBufferCreateFilenameDefault:
3204 * @func: function pointer to the new OutputBufferCreateFilenameFunc
3205 *
3206 * Registers a callback for URI output file handling
3207 *
3208 * Returns the old value of the registration function
3209 */
3210xmlOutputBufferCreateFilenameFunc
3211xmlOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func)
3212{
3213 xmlOutputBufferCreateFilenameFunc old = xmlOutputBufferCreateFilenameValue;
3214#ifdef LIBXML_OUTPUT_ENABLED
3215 if (old == NULL) {
3216 old = __xmlOutputBufferCreateFilename;
3217 }
3218#endif
3219 xmlOutputBufferCreateFilenameValue = func;
3220 return(old);
3221}
3222
3223/**
Owen Taylor3473f882001-02-23 17:55:21 +00003224 * xmlParserInputBufferPush:
3225 * @in: a buffered parser input
3226 * @len: the size in bytes of the array.
3227 * @buf: an char array
3228 *
3229 * Push the content of the arry in the input buffer
3230 * This routine handle the I18N transcoding to internal UTF-8
3231 * This is used when operating the parser in progressive (push) mode.
3232 *
3233 * Returns the number of chars read and stored in the buffer, or -1
3234 * in case of error.
3235 */
3236int
3237xmlParserInputBufferPush(xmlParserInputBufferPtr in,
3238 int len, const char *buf) {
3239 int nbchars = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00003240 int ret;
Owen Taylor3473f882001-02-23 17:55:21 +00003241
3242 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003243 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003244 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00003245 unsigned int use;
3246
Owen Taylor3473f882001-02-23 17:55:21 +00003247 /*
3248 * Store the data in the incoming raw buffer
3249 */
3250 if (in->raw == NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003251 in->raw = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00003252 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003253 ret = xmlBufAdd(in->raw, (const xmlChar *) buf, len);
William M. Bracka3215c72004-07-31 16:24:01 +00003254 if (ret != 0)
3255 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003256
3257 /*
3258 * convert as much as possible to the parser reading buffer.
3259 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003260 use = xmlBufUse(in->raw);
Daniel Veillardbf058dc2013-02-13 18:19:42 +08003261 nbchars = xmlCharEncInput(in, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003262 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003263 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003264 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003265 return(-1);
3266 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003267 in->rawconsumed += (use - xmlBufUse(in->raw));
Owen Taylor3473f882001-02-23 17:55:21 +00003268 } else {
3269 nbchars = len;
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003270 ret = xmlBufAdd(in->buffer, (xmlChar *) buf, nbchars);
William M. Bracka3215c72004-07-31 16:24:01 +00003271 if (ret != 0)
3272 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003273 }
3274#ifdef DEBUG_INPUT
3275 xmlGenericError(xmlGenericErrorContext,
3276 "I/O: pushed %d chars, buffer %d/%d\n",
Roumen Petrov89b6f732012-08-04 05:09:56 +03003277 nbchars, xmlBufUse(in->buffer), xmlBufLength(in->buffer));
Owen Taylor3473f882001-02-23 17:55:21 +00003278#endif
3279 return(nbchars);
3280}
3281
3282/**
Daniel Veillardddffd2a2002-03-05 20:28:20 +00003283 * endOfInput:
3284 *
3285 * When reading from an Input channel indicated end of file or error
3286 * don't reread from it again.
3287 */
3288static int
3289endOfInput (void * context ATTRIBUTE_UNUSED,
3290 char * buffer ATTRIBUTE_UNUSED,
3291 int len ATTRIBUTE_UNUSED) {
3292 return(0);
3293}
3294
3295/**
Owen Taylor3473f882001-02-23 17:55:21 +00003296 * xmlParserInputBufferGrow:
3297 * @in: a buffered parser input
3298 * @len: indicative value of the amount of chars to read
3299 *
3300 * Grow up the content of the input buffer, the old data are preserved
3301 * This routine handle the I18N transcoding to internal UTF-8
3302 * This routine is used when operating the parser in normal (pull) mode
3303 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003304 * TODO: one should be able to remove one extra copy by copying directly
Owen Taylor3473f882001-02-23 17:55:21 +00003305 * onto in->buffer or in->raw
3306 *
3307 * Returns the number of chars read and stored in the buffer, or -1
3308 * in case of error.
3309 */
3310int
3311xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
3312 char *buffer = NULL;
3313 int res = 0;
3314 int nbchars = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003315
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003316 if ((in == NULL) || (in->error)) return(-1);
Daniel Veillard6155d8a2003-08-19 15:01:28 +00003317 if ((len <= MINLEN) && (len != 4))
Owen Taylor3473f882001-02-23 17:55:21 +00003318 len = MINLEN;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00003319
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003320 if (xmlBufAvail(in->buffer) <= 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003321 xmlIOErr(XML_IO_BUFFER_FULL, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003322 in->error = XML_IO_BUFFER_FULL;
William M. Bracka3215c72004-07-31 16:24:01 +00003323 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003324 }
Owen Taylor3473f882001-02-23 17:55:21 +00003325
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003326 if (xmlBufGrow(in->buffer, len + 1) < 0) {
3327 xmlIOErrMemory("growing input buffer");
3328 in->error = XML_ERR_NO_MEMORY;
3329 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003330 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003331 buffer = (char *)xmlBufEnd(in->buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00003332
3333 /*
3334 * Call the read method for this I/O type.
3335 */
3336 if (in->readcallback != NULL) {
3337 res = in->readcallback(in->context, &buffer[0], len);
Daniel Veillardddffd2a2002-03-05 20:28:20 +00003338 if (res <= 0)
3339 in->readcallback = endOfInput;
Owen Taylor3473f882001-02-23 17:55:21 +00003340 } else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003341 xmlIOErr(XML_IO_NO_INPUT, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003342 in->error = XML_IO_NO_INPUT;
Owen Taylor3473f882001-02-23 17:55:21 +00003343 return(-1);
3344 }
3345 if (res < 0) {
Owen Taylor3473f882001-02-23 17:55:21 +00003346 return(-1);
3347 }
Daniel Veillard63588f42013-05-10 14:01:46 +08003348
3349 /*
3350 * try to establish compressed status of input if not done already
3351 */
3352 if (in->compressed == -1) {
Daniel Veillard18b89882015-11-03 15:46:29 +08003353#ifdef LIBXML_LZMA_ENABLED
Daniel Veillard63588f42013-05-10 14:01:46 +08003354 if (in->readcallback == xmlXzfileRead)
3355 in->compressed = __libxml2_xzcompressed(in->context);
3356#endif
3357 }
3358
Owen Taylor3473f882001-02-23 17:55:21 +00003359 len = res;
3360 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00003361 unsigned int use;
3362
Owen Taylor3473f882001-02-23 17:55:21 +00003363 /*
3364 * Store the data in the incoming raw buffer
3365 */
3366 if (in->raw == NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003367 in->raw = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00003368 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003369 res = xmlBufAdd(in->raw, (const xmlChar *) buffer, len);
William M. Bracka3215c72004-07-31 16:24:01 +00003370 if (res != 0)
3371 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003372
3373 /*
3374 * convert as much as possible to the parser reading buffer.
3375 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003376 use = xmlBufUse(in->raw);
Daniel Veillardbf058dc2013-02-13 18:19:42 +08003377 nbchars = xmlCharEncInput(in, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003378 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003379 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003380 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003381 return(-1);
3382 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003383 in->rawconsumed += (use - xmlBufUse(in->raw));
Owen Taylor3473f882001-02-23 17:55:21 +00003384 } else {
3385 nbchars = len;
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003386 xmlBufAddLen(in->buffer, nbchars);
Owen Taylor3473f882001-02-23 17:55:21 +00003387 }
3388#ifdef DEBUG_INPUT
3389 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003390 "I/O: read %d chars, buffer %d\n",
3391 nbchars, xmlBufUse(in->buffer));
Owen Taylor3473f882001-02-23 17:55:21 +00003392#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003393 return(nbchars);
3394}
3395
3396/**
3397 * xmlParserInputBufferRead:
3398 * @in: a buffered parser input
3399 * @len: indicative value of the amount of chars to read
3400 *
3401 * Refresh the content of the input buffer, the old data are considered
3402 * consumed
3403 * This routine handle the I18N transcoding to internal UTF-8
3404 *
3405 * Returns the number of chars read and stored in the buffer, or -1
3406 * in case of error.
3407 */
3408int
3409xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003410 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003411 if (in->readcallback != NULL)
3412 return(xmlParserInputBufferGrow(in, len));
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003413 else if (xmlBufGetAllocationScheme(in->buffer) == XML_BUFFER_ALLOC_IMMUTABLE)
Daniel Veillard53350552003-09-18 13:35:51 +00003414 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003415 else
3416 return(-1);
3417}
3418
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003419#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003420/**
3421 * xmlOutputBufferWrite:
3422 * @out: a buffered parser output
3423 * @len: the size in bytes of the array.
3424 * @buf: an char array
3425 *
3426 * Write the content of the array in the output I/O buffer
3427 * This routine handle the I18N transcoding from internal UTF-8
3428 * The buffer is lossless, i.e. will store in case of partial
3429 * or delayed writes.
3430 *
3431 * Returns the number of chars immediately written, or -1
3432 * in case of error.
3433 */
3434int
3435xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
3436 int nbchars = 0; /* number of chars to output to I/O */
3437 int ret; /* return from function call */
3438 int written = 0; /* number of char written to I/O so far */
3439 int chunk; /* number of byte curreent processed from buf */
3440
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003441 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003442 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003443 if (out->error) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003444
3445 do {
3446 chunk = len;
3447 if (chunk > 4 * MINLEN)
3448 chunk = 4 * MINLEN;
3449
3450 /*
3451 * first handle encoding stuff.
3452 */
3453 if (out->encoder != NULL) {
3454 /*
3455 * Store the data in the incoming raw buffer
3456 */
3457 if (out->conv == NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003458 out->conv = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00003459 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003460 ret = xmlBufAdd(out->buffer, (const xmlChar *) buf, chunk);
William M. Bracka3215c72004-07-31 16:24:01 +00003461 if (ret != 0)
3462 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003463
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003464 if ((xmlBufUse(out->buffer) < MINLEN) && (chunk == len))
Owen Taylor3473f882001-02-23 17:55:21 +00003465 goto done;
3466
3467 /*
3468 * convert as much as possible to the parser reading buffer.
3469 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003470 ret = xmlCharEncOutput(out, 0);
Daniel Veillard809faa52003-02-10 15:43:53 +00003471 if ((ret < 0) && (ret != -3)) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003472 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003473 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003474 return(-1);
3475 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003476 nbchars = xmlBufUse(out->conv);
Owen Taylor3473f882001-02-23 17:55:21 +00003477 } else {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003478 ret = xmlBufAdd(out->buffer, (const xmlChar *) buf, chunk);
William M. Bracka3215c72004-07-31 16:24:01 +00003479 if (ret != 0)
3480 return(-1);
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003481 nbchars = xmlBufUse(out->buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00003482 }
3483 buf += chunk;
3484 len -= chunk;
3485
3486 if ((nbchars < MINLEN) && (len <= 0))
3487 goto done;
3488
3489 if (out->writecallback) {
3490 /*
3491 * second write the stuff to the I/O channel
3492 */
3493 if (out->encoder != NULL) {
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003494 ret = out->writecallback(out->context,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003495 (const char *)xmlBufContent(out->conv), nbchars);
Owen Taylor3473f882001-02-23 17:55:21 +00003496 if (ret >= 0)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003497 xmlBufShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003498 } else {
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->buffer), nbchars);
Owen Taylor3473f882001-02-23 17:55:21 +00003501 if (ret >= 0)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003502 xmlBufShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003503 }
3504 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003505 xmlIOErr(XML_IO_WRITE, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003506 out->error = XML_IO_WRITE;
Owen Taylor3473f882001-02-23 17:55:21 +00003507 return(ret);
3508 }
3509 out->written += ret;
3510 }
3511 written += nbchars;
3512 } while (len > 0);
3513
3514done:
3515#ifdef DEBUG_INPUT
3516 xmlGenericError(xmlGenericErrorContext,
3517 "I/O: wrote %d chars\n", written);
3518#endif
3519 return(written);
3520}
3521
3522/**
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003523 * xmlEscapeContent:
3524 * @out: a pointer to an array of bytes to store the result
3525 * @outlen: the length of @out
3526 * @in: a pointer to an array of unescaped UTF-8 bytes
3527 * @inlen: the length of @in
3528 *
3529 * Take a block of UTF-8 chars in and escape them.
3530 * Returns 0 if success, or -1 otherwise
3531 * The value of @inlen after return is the number of octets consumed
3532 * if the return value is positive, else unpredictable.
3533 * The value of @outlen after return is the number of octets consumed.
3534 */
3535static int
3536xmlEscapeContent(unsigned char* out, int *outlen,
3537 const xmlChar* in, int *inlen) {
3538 unsigned char* outstart = out;
3539 const unsigned char* base = in;
3540 unsigned char* outend = out + *outlen;
3541 const unsigned char* inend;
3542
3543 inend = in + (*inlen);
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003544
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003545 while ((in < inend) && (out < outend)) {
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003546 if (*in == '<') {
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003547 if (outend - out < 4) break;
3548 *out++ = '&';
3549 *out++ = 'l';
3550 *out++ = 't';
3551 *out++ = ';';
3552 } else if (*in == '>') {
3553 if (outend - out < 4) break;
3554 *out++ = '&';
3555 *out++ = 'g';
3556 *out++ = 't';
3557 *out++ = ';';
3558 } else if (*in == '&') {
3559 if (outend - out < 5) break;
3560 *out++ = '&';
3561 *out++ = 'a';
3562 *out++ = 'm';
3563 *out++ = 'p';
3564 *out++ = ';';
3565 } else if (*in == '\r') {
3566 if (outend - out < 5) break;
3567 *out++ = '&';
3568 *out++ = '#';
3569 *out++ = '1';
3570 *out++ = '3';
3571 *out++ = ';';
3572 } else {
3573 *out++ = (unsigned char) *in;
3574 }
3575 ++in;
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003576 }
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003577 *outlen = out - outstart;
3578 *inlen = in - base;
3579 return(0);
3580}
3581
3582/**
3583 * xmlOutputBufferWriteEscape:
3584 * @out: a buffered parser output
3585 * @str: a zero terminated UTF-8 string
Daniel Veillardee8960b2004-05-14 03:25:14 +00003586 * @escaping: an optional escaping function (or NULL)
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003587 *
3588 * Write the content of the string in the output I/O buffer
3589 * This routine escapes the caracters and then handle the I18N
3590 * transcoding from internal UTF-8
3591 * The buffer is lossless, i.e. will store in case of partial
3592 * or delayed writes.
3593 *
3594 * Returns the number of chars immediately written, or -1
3595 * in case of error.
3596 */
3597int
Daniel Veillardee8960b2004-05-14 03:25:14 +00003598xmlOutputBufferWriteEscape(xmlOutputBufferPtr out, const xmlChar *str,
3599 xmlCharEncodingOutputFunc escaping) {
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003600 int nbchars = 0; /* number of chars to output to I/O */
3601 int ret; /* return from function call */
3602 int written = 0; /* number of char written to I/O so far */
Daniel Veillard71b95632004-08-31 12:15:36 +00003603 int oldwritten=0;/* loop guard */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003604 int chunk; /* number of byte currently processed from str */
3605 int len; /* number of bytes in str */
3606 int cons; /* byte from str consumed */
3607
Daniel Veillardce244ad2004-11-05 10:03:46 +00003608 if ((out == NULL) || (out->error) || (str == NULL) ||
3609 (out->buffer == NULL) ||
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003610 (xmlBufGetAllocationScheme(out->buffer) == XML_BUFFER_ALLOC_IMMUTABLE))
3611 return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003612 len = strlen((const char *)str);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003613 if (len < 0) return(0);
3614 if (out->error) return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003615 if (escaping == NULL) escaping = xmlEscapeContent;
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003616
3617 do {
Daniel Veillard71b95632004-08-31 12:15:36 +00003618 oldwritten = written;
3619
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003620 /*
3621 * how many bytes to consume and how many bytes to store.
3622 */
3623 cons = len;
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003624 chunk = xmlBufAvail(out->buffer) - 1;
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003625
Daniel Veillardc4ba8a42008-02-16 10:08:14 +00003626 /*
3627 * make sure we have enough room to save first, if this is
3628 * not the case force a flush, but make sure we stay in the loop
3629 */
3630 if (chunk < 40) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003631 if (xmlBufGrow(out->buffer, 100) < 0)
Daniel Veillarde83e93e2008-08-30 12:52:26 +00003632 return(-1);
3633 oldwritten = -1;
3634 continue;
Daniel Veillardc4ba8a42008-02-16 10:08:14 +00003635 }
3636
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003637 /*
3638 * first handle encoding stuff.
3639 */
3640 if (out->encoder != NULL) {
3641 /*
3642 * Store the data in the incoming raw buffer
3643 */
3644 if (out->conv == NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003645 out->conv = xmlBufCreate();
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003646 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003647 ret = escaping(xmlBufEnd(out->buffer) ,
Daniel Veillardee8960b2004-05-14 03:25:14 +00003648 &chunk, str, &cons);
William M. Brack66e40b12004-11-26 15:45:19 +00003649 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003650 return(-1);
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003651 xmlBufAddLen(out->buffer, chunk);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003652
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003653 if ((xmlBufUse(out->buffer) < MINLEN) && (cons == len))
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003654 goto done;
3655
3656 /*
3657 * convert as much as possible to the output buffer.
3658 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003659 ret = xmlCharEncOutput(out, 0);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003660 if ((ret < 0) && (ret != -3)) {
3661 xmlIOErr(XML_IO_ENCODER, NULL);
3662 out->error = XML_IO_ENCODER;
3663 return(-1);
3664 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003665 nbchars = xmlBufUse(out->conv);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003666 } else {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003667 ret = escaping(xmlBufEnd(out->buffer), &chunk, str, &cons);
William M. Brack66e40b12004-11-26 15:45:19 +00003668 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003669 return(-1);
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003670 xmlBufAddLen(out->buffer, chunk);
3671 nbchars = xmlBufUse(out->buffer);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003672 }
3673 str += cons;
3674 len -= cons;
3675
3676 if ((nbchars < MINLEN) && (len <= 0))
3677 goto done;
3678
3679 if (out->writecallback) {
3680 /*
3681 * second write the stuff to the I/O channel
3682 */
3683 if (out->encoder != NULL) {
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003684 ret = out->writecallback(out->context,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003685 (const char *)xmlBufContent(out->conv), nbchars);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003686 if (ret >= 0)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003687 xmlBufShrink(out->conv, ret);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003688 } else {
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->buffer), nbchars);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003691 if (ret >= 0)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003692 xmlBufShrink(out->buffer, ret);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003693 }
3694 if (ret < 0) {
3695 xmlIOErr(XML_IO_WRITE, NULL);
3696 out->error = XML_IO_WRITE;
3697 return(ret);
3698 }
3699 out->written += ret;
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003700 } else if (xmlBufAvail(out->buffer) < MINLEN) {
3701 xmlBufGrow(out->buffer, MINLEN);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003702 }
3703 written += nbchars;
Daniel Veillard71b95632004-08-31 12:15:36 +00003704 } while ((len > 0) && (oldwritten != written));
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003705
3706done:
3707#ifdef DEBUG_INPUT
3708 xmlGenericError(xmlGenericErrorContext,
3709 "I/O: wrote %d chars\n", written);
3710#endif
3711 return(written);
3712}
3713
3714/**
Owen Taylor3473f882001-02-23 17:55:21 +00003715 * xmlOutputBufferWriteString:
3716 * @out: a buffered parser output
3717 * @str: a zero terminated C string
3718 *
3719 * Write the content of the string in the output I/O buffer
3720 * This routine handle the I18N transcoding from internal UTF-8
3721 * The buffer is lossless, i.e. will store in case of partial
3722 * or delayed writes.
3723 *
3724 * Returns the number of chars immediately written, or -1
3725 * in case of error.
3726 */
3727int
3728xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
3729 int len;
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003730
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003731 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003732 if (str == NULL)
3733 return(-1);
3734 len = strlen(str);
3735
3736 if (len > 0)
3737 return(xmlOutputBufferWrite(out, len, str));
3738 return(len);
3739}
3740
3741/**
3742 * xmlOutputBufferFlush:
3743 * @out: a buffered output
3744 *
3745 * flushes the output I/O channel
3746 *
3747 * Returns the number of byte written or -1 in case of error.
3748 */
3749int
3750xmlOutputBufferFlush(xmlOutputBufferPtr out) {
3751 int nbchars = 0, ret = 0;
3752
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003753 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003754 /*
3755 * first handle encoding stuff.
3756 */
3757 if ((out->conv != NULL) && (out->encoder != NULL)) {
3758 /*
Mikhail Titov8e2098a2013-03-27 11:00:31 +08003759 * convert as much as possible to the parser output buffer.
Owen Taylor3473f882001-02-23 17:55:21 +00003760 */
Mikhail Titov8e2098a2013-03-27 11:00:31 +08003761 do {
3762 nbchars = xmlCharEncOutput(out, 0);
3763 if (nbchars < 0) {
3764 xmlIOErr(XML_IO_ENCODER, NULL);
3765 out->error = XML_IO_ENCODER;
3766 return(-1);
3767 }
3768 } while (nbchars);
Owen Taylor3473f882001-02-23 17:55:21 +00003769 }
3770
3771 /*
3772 * second flush the stuff to the I/O channel
3773 */
3774 if ((out->conv != NULL) && (out->encoder != NULL) &&
3775 (out->writecallback != NULL)) {
3776 ret = out->writecallback(out->context,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003777 (const char *)xmlBufContent(out->conv),
3778 xmlBufUse(out->conv));
Owen Taylor3473f882001-02-23 17:55:21 +00003779 if (ret >= 0)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003780 xmlBufShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003781 } else if (out->writecallback != NULL) {
3782 ret = out->writecallback(out->context,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003783 (const char *)xmlBufContent(out->buffer),
3784 xmlBufUse(out->buffer));
Owen Taylor3473f882001-02-23 17:55:21 +00003785 if (ret >= 0)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003786 xmlBufShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003787 }
3788 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003789 xmlIOErr(XML_IO_FLUSH, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003790 out->error = XML_IO_FLUSH;
Owen Taylor3473f882001-02-23 17:55:21 +00003791 return(ret);
3792 }
3793 out->written += ret;
3794
3795#ifdef DEBUG_INPUT
3796 xmlGenericError(xmlGenericErrorContext,
3797 "I/O: flushed %d chars\n", ret);
3798#endif
3799 return(ret);
3800}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003801#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003802
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003803/**
Owen Taylor3473f882001-02-23 17:55:21 +00003804 * xmlParserGetDirectory:
3805 * @filename: the path to a file
3806 *
3807 * lookup the directory for that file
3808 *
3809 * Returns a new allocated string containing the directory, or NULL.
3810 */
3811char *
3812xmlParserGetDirectory(const char *filename) {
3813 char *ret = NULL;
3814 char dir[1024];
3815 char *cur;
Owen Taylor3473f882001-02-23 17:55:21 +00003816
Igor Zlatkovic9181cc02002-09-29 17:51:06 +00003817#ifdef _WIN32_WCE /* easy way by now ... wince does not have dirs! */
3818 return NULL;
3819#endif
3820
Owen Taylor3473f882001-02-23 17:55:21 +00003821 if (xmlInputCallbackInitialized == 0)
3822 xmlRegisterDefaultInputCallbacks();
3823
3824 if (filename == NULL) return(NULL);
Rob Richardsf779da32007-08-14 09:41:21 +00003825
Daniel Veillard3c5ed912002-01-08 10:36:16 +00003826#if defined(WIN32) && !defined(__CYGWIN__)
Rob Richardsf779da32007-08-14 09:41:21 +00003827# define IS_XMLPGD_SEP(ch) ((ch=='/')||(ch=='\\'))
3828#else
3829# define IS_XMLPGD_SEP(ch) (ch=='/')
Owen Taylor3473f882001-02-23 17:55:21 +00003830#endif
3831
3832 strncpy(dir, filename, 1023);
3833 dir[1023] = 0;
3834 cur = &dir[strlen(dir)];
3835 while (cur > dir) {
Rob Richardsf779da32007-08-14 09:41:21 +00003836 if (IS_XMLPGD_SEP(*cur)) break;
Owen Taylor3473f882001-02-23 17:55:21 +00003837 cur --;
3838 }
Rob Richardsf779da32007-08-14 09:41:21 +00003839 if (IS_XMLPGD_SEP(*cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003840 if (cur == dir) dir[1] = 0;
3841 else *cur = 0;
3842 ret = xmlMemStrdup(dir);
3843 } else {
3844 if (getcwd(dir, 1024) != NULL) {
3845 dir[1023] = 0;
3846 ret = xmlMemStrdup(dir);
3847 }
3848 }
3849 return(ret);
Rob Richardsf779da32007-08-14 09:41:21 +00003850#undef IS_XMLPGD_SEP
Owen Taylor3473f882001-02-23 17:55:21 +00003851}
3852
3853/****************************************************************
3854 * *
3855 * External entities loading *
3856 * *
3857 ****************************************************************/
3858
Daniel Veillarda840b692003-10-19 13:35:37 +00003859/**
3860 * xmlCheckHTTPInput:
3861 * @ctxt: an XML parser context
3862 * @ret: an XML parser input
3863 *
3864 * Check an input in case it was created from an HTTP stream, in that
3865 * case it will handle encoding and update of the base URL in case of
3866 * redirection. It also checks for HTTP errors in which case the input
3867 * is cleanly freed up and an appropriate error is raised in context
3868 *
3869 * Returns the input or NULL in case of HTTP error.
3870 */
3871xmlParserInputPtr
3872xmlCheckHTTPInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr ret) {
3873#ifdef LIBXML_HTTP_ENABLED
3874 if ((ret != NULL) && (ret->buf != NULL) &&
3875 (ret->buf->readcallback == xmlIOHTTPRead) &&
3876 (ret->buf->context != NULL)) {
3877 const char *encoding;
3878 const char *redir;
3879 const char *mime;
3880 int code;
3881
3882 code = xmlNanoHTTPReturnCode(ret->buf->context);
3883 if (code >= 400) {
3884 /* fatal error */
3885 if (ret->filename != NULL)
Daniel Veillarde8039df2003-10-27 11:25:13 +00003886 __xmlLoaderErr(ctxt, "failed to load HTTP resource \"%s\"\n",
Daniel Veillarda840b692003-10-19 13:35:37 +00003887 (const char *) ret->filename);
3888 else
Daniel Veillarde8039df2003-10-27 11:25:13 +00003889 __xmlLoaderErr(ctxt, "failed to load HTTP resource\n", NULL);
Daniel Veillarda840b692003-10-19 13:35:37 +00003890 xmlFreeInputStream(ret);
3891 ret = NULL;
3892 } else {
3893
3894 mime = xmlNanoHTTPMimeType(ret->buf->context);
3895 if ((xmlStrstr(BAD_CAST mime, BAD_CAST "/xml")) ||
3896 (xmlStrstr(BAD_CAST mime, BAD_CAST "+xml"))) {
3897 encoding = xmlNanoHTTPEncoding(ret->buf->context);
3898 if (encoding != NULL) {
3899 xmlCharEncodingHandlerPtr handler;
3900
3901 handler = xmlFindCharEncodingHandler(encoding);
3902 if (handler != NULL) {
3903 xmlSwitchInputEncoding(ctxt, ret, handler);
3904 } else {
3905 __xmlErrEncoding(ctxt, XML_ERR_UNKNOWN_ENCODING,
3906 "Unknown encoding %s",
3907 BAD_CAST encoding, NULL);
3908 }
3909 if (ret->encoding == NULL)
3910 ret->encoding = xmlStrdup(BAD_CAST encoding);
3911 }
3912#if 0
3913 } else if (xmlStrstr(BAD_CAST mime, BAD_CAST "html")) {
3914#endif
3915 }
3916 redir = xmlNanoHTTPRedir(ret->buf->context);
3917 if (redir != NULL) {
3918 if (ret->filename != NULL)
3919 xmlFree((xmlChar *) ret->filename);
3920 if (ret->directory != NULL) {
3921 xmlFree((xmlChar *) ret->directory);
3922 ret->directory = NULL;
3923 }
3924 ret->filename =
3925 (char *) xmlStrdup((const xmlChar *) redir);
3926 }
3927 }
3928 }
3929#endif
3930 return(ret);
3931}
3932
Daniel Veillarde5a3f372006-08-30 13:11:36 +00003933static int xmlNoNetExists(const char *URL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003934 const char *path;
3935
3936 if (URL == NULL)
3937 return(0);
3938
Daniel Veillardf4862f02002-09-10 11:13:43 +00003939 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003940#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00003941 path = &URL[17];
3942#else
Daniel Veillard6990bf32001-08-23 21:17:48 +00003943 path = &URL[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00003944#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003945 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003946#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard6990bf32001-08-23 21:17:48 +00003947 path = &URL[8];
3948#else
3949 path = &URL[7];
3950#endif
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003951 } else
Daniel Veillard6990bf32001-08-23 21:17:48 +00003952 path = URL;
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003953
Daniel Veillarde5a3f372006-08-30 13:11:36 +00003954 return xmlCheckFilename(path);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003955}
Daniel Veillard6990bf32001-08-23 21:17:48 +00003956
Daniel Veillardad4e2962006-09-21 08:36:38 +00003957#ifdef LIBXML_CATALOG_ENABLED
3958
3959/**
3960 * xmlResolveResourceFromCatalog:
3961 * @URL: the URL for the entity to load
3962 * @ID: the System ID for the entity to load
3963 * @ctxt: the context in which the entity is called or NULL
3964 *
3965 * Resolves the URL and ID against the appropriate catalog.
3966 * This function is used by xmlDefaultExternalEntityLoader and
3967 * xmlNoNetExternalEntityLoader.
3968 *
3969 * Returns a new allocated URL, or NULL.
3970 */
William M. Brack38d452a2007-05-22 16:00:06 +00003971static xmlChar *
Daniel Veillardad4e2962006-09-21 08:36:38 +00003972xmlResolveResourceFromCatalog(const char *URL, const char *ID,
3973 xmlParserCtxtPtr ctxt) {
3974 xmlChar *resource = NULL;
3975 xmlCatalogAllow pref;
3976
3977 /*
3978 * If the resource doesn't exists as a file,
3979 * try to load it from the resource pointed in the catalogs
3980 */
3981 pref = xmlCatalogGetDefaults();
3982
3983 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
3984 /*
3985 * Do a local lookup
3986 */
3987 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
3988 ((pref == XML_CATA_ALLOW_ALL) ||
3989 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3990 resource = xmlCatalogLocalResolve(ctxt->catalogs,
3991 (const xmlChar *)ID,
3992 (const xmlChar *)URL);
3993 }
3994 /*
3995 * Try a global lookup
3996 */
3997 if ((resource == NULL) &&
3998 ((pref == XML_CATA_ALLOW_ALL) ||
3999 (pref == XML_CATA_ALLOW_GLOBAL))) {
4000 resource = xmlCatalogResolve((const xmlChar *)ID,
4001 (const xmlChar *)URL);
4002 }
4003 if ((resource == NULL) && (URL != NULL))
4004 resource = xmlStrdup((const xmlChar *) URL);
4005
4006 /*
4007 * TODO: do an URI lookup on the reference
4008 */
4009 if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
4010 xmlChar *tmp = NULL;
4011
4012 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
4013 ((pref == XML_CATA_ALLOW_ALL) ||
4014 (pref == XML_CATA_ALLOW_DOCUMENT))) {
4015 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
4016 }
4017 if ((tmp == NULL) &&
4018 ((pref == XML_CATA_ALLOW_ALL) ||
4019 (pref == XML_CATA_ALLOW_GLOBAL))) {
4020 tmp = xmlCatalogResolveURI(resource);
4021 }
4022
4023 if (tmp != NULL) {
4024 xmlFree(resource);
4025 resource = tmp;
4026 }
4027 }
4028 }
4029
4030 return resource;
4031}
4032
4033#endif
4034
Daniel Veillard5e2dace2001-07-18 19:30:27 +00004035/**
Owen Taylor3473f882001-02-23 17:55:21 +00004036 * xmlDefaultExternalEntityLoader:
4037 * @URL: the URL for the entity to load
4038 * @ID: the System ID for the entity to load
4039 * @ctxt: the context in which the entity is called or NULL
4040 *
4041 * By default we don't load external entitites, yet.
4042 *
4043 * Returns a new allocated xmlParserInputPtr, or NULL.
4044 */
Daniel Veillarda840b692003-10-19 13:35:37 +00004045static xmlParserInputPtr
Owen Taylor3473f882001-02-23 17:55:21 +00004046xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
Daniel Veillarda840b692003-10-19 13:35:37 +00004047 xmlParserCtxtPtr ctxt)
4048{
Owen Taylor3473f882001-02-23 17:55:21 +00004049 xmlParserInputPtr ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00004050 xmlChar *resource = NULL;
Daniel Veillarda840b692003-10-19 13:35:37 +00004051
Owen Taylor3473f882001-02-23 17:55:21 +00004052#ifdef DEBUG_EXTERNAL_ENTITIES
4053 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda840b692003-10-19 13:35:37 +00004054 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00004055#endif
Daniel Veillard61b93382003-11-03 14:28:31 +00004056 if ((ctxt != NULL) && (ctxt->options & XML_PARSE_NONET)) {
4057 int options = ctxt->options;
4058
4059 ctxt->options -= XML_PARSE_NONET;
4060 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
4061 ctxt->options = options;
4062 return(ret);
4063 }
Daniel Veillardad4e2962006-09-21 08:36:38 +00004064#ifdef LIBXML_CATALOG_ENABLED
4065 resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
Daniel Veillard7d6fd212001-05-10 15:34:11 +00004066#endif
4067
4068 if (resource == NULL)
Daniel Veillarda840b692003-10-19 13:35:37 +00004069 resource = (xmlChar *) URL;
Daniel Veillard7d6fd212001-05-10 15:34:11 +00004070
4071 if (resource == NULL) {
Daniel Veillarda840b692003-10-19 13:35:37 +00004072 if (ID == NULL)
4073 ID = "NULL";
Daniel Veillarde8039df2003-10-27 11:25:13 +00004074 __xmlLoaderErr(ctxt, "failed to load external entity \"%s\"\n", ID);
Daniel Veillarda840b692003-10-19 13:35:37 +00004075 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004076 }
Daniel Veillarda840b692003-10-19 13:35:37 +00004077 ret = xmlNewInputFromFile(ctxt, (const char *) resource);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00004078 if ((resource != NULL) && (resource != (xmlChar *) URL))
Daniel Veillarda840b692003-10-19 13:35:37 +00004079 xmlFree(resource);
4080 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004081}
4082
4083static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
4084 xmlDefaultExternalEntityLoader;
4085
Daniel Veillard5e2dace2001-07-18 19:30:27 +00004086/**
Owen Taylor3473f882001-02-23 17:55:21 +00004087 * xmlSetExternalEntityLoader:
4088 * @f: the new entity resolver function
4089 *
4090 * Changes the defaultexternal entity resolver function for the application
4091 */
4092void
4093xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
4094 xmlCurrentExternalEntityLoader = f;
4095}
4096
Daniel Veillard5e2dace2001-07-18 19:30:27 +00004097/**
Owen Taylor3473f882001-02-23 17:55:21 +00004098 * xmlGetExternalEntityLoader:
4099 *
4100 * Get the default external entity resolver function for the application
4101 *
4102 * Returns the xmlExternalEntityLoader function pointer
4103 */
4104xmlExternalEntityLoader
4105xmlGetExternalEntityLoader(void) {
4106 return(xmlCurrentExternalEntityLoader);
4107}
4108
Daniel Veillard5e2dace2001-07-18 19:30:27 +00004109/**
Owen Taylor3473f882001-02-23 17:55:21 +00004110 * xmlLoadExternalEntity:
4111 * @URL: the URL for the entity to load
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00004112 * @ID: the Public ID for the entity to load
Owen Taylor3473f882001-02-23 17:55:21 +00004113 * @ctxt: the context in which the entity is called or NULL
4114 *
4115 * Load an external entity, note that the use of this function for
4116 * unparsed entities may generate problems
Owen Taylor3473f882001-02-23 17:55:21 +00004117 *
4118 * Returns the xmlParserInputPtr or NULL
4119 */
4120xmlParserInputPtr
4121xmlLoadExternalEntity(const char *URL, const char *ID,
4122 xmlParserCtxtPtr ctxt) {
Daniel Veillarde5a3f372006-08-30 13:11:36 +00004123 if ((URL != NULL) && (xmlNoNetExists(URL) == 0)) {
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00004124 char *canonicFilename;
4125 xmlParserInputPtr ret;
4126
4127 canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL);
4128 if (canonicFilename == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00004129 xmlIOErrMemory("building canonical path\n");
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00004130 return(NULL);
4131 }
4132
4133 ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt);
4134 xmlFree(canonicFilename);
4135 return(ret);
4136 }
Owen Taylor3473f882001-02-23 17:55:21 +00004137 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
4138}
4139
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004140/************************************************************************
Hans Breuer2ad41ca2009-08-11 17:51:22 +02004141 * *
4142 * Disabling Network access *
4143 * *
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004144 ************************************************************************/
4145
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004146/**
4147 * xmlNoNetExternalEntityLoader:
4148 * @URL: the URL for the entity to load
4149 * @ID: the System ID for the entity to load
4150 * @ctxt: the context in which the entity is called or NULL
4151 *
4152 * A specific entity loader disabling network accesses, though still
4153 * allowing local catalog accesses for resolution.
4154 *
4155 * Returns a new allocated xmlParserInputPtr, or NULL.
4156 */
4157xmlParserInputPtr
4158xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
4159 xmlParserCtxtPtr ctxt) {
4160 xmlParserInputPtr input = NULL;
4161 xmlChar *resource = NULL;
4162
4163#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillardad4e2962006-09-21 08:36:38 +00004164 resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004165#endif
Daniel Veillardad4e2962006-09-21 08:36:38 +00004166
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004167 if (resource == NULL)
4168 resource = (xmlChar *) URL;
4169
4170 if (resource != NULL) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00004171 if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
4172 (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00004173 xmlIOErr(XML_IO_NETWORK_ATTEMPT, (const char *) resource);
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004174 if (resource != (xmlChar *) URL)
4175 xmlFree(resource);
4176 return(NULL);
4177 }
4178 }
4179 input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
4180 if (resource != (xmlChar *) URL)
4181 xmlFree(resource);
4182 return(input);
4183}
4184
Daniel Veillard5d4644e2005-04-01 13:11:58 +00004185#define bottom_xmlIO
4186#include "elfgcchack.h"