blob: e62561282956648094a2383c76dac3fb7ab76cd3 [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 */
Doran Moppert23040782017-04-07 16:45:56 +0200213 "Attempt to load external entity %s", /* XML_IO_ILLEGAL_XXE */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000214};
215
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000216#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
Daniel Veillardf7416012006-04-27 08:15:20 +0000217/**
218 * __xmlIOWin32UTF8ToWChar:
219 * @u8String: uft-8 string
220 *
221 * Convert a string from utf-8 to wchar (WINDOWS ONLY!)
222 */
223static wchar_t *
224__xmlIOWin32UTF8ToWChar(const char *u8String)
225{
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +0000226 wchar_t *wString = NULL;
Daniel Veillardf7416012006-04-27 08:15:20 +0000227
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +0000228 if (u8String) {
229 int wLen =
230 MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, u8String,
231 -1, NULL, 0);
232 if (wLen) {
233 wString = xmlMalloc(wLen * sizeof(wchar_t));
234 if (wString) {
235 if (MultiByteToWideChar
236 (CP_UTF8, 0, u8String, -1, wString, wLen) == 0) {
237 xmlFree(wString);
238 wString = NULL;
239 }
240 }
241 }
242 }
243
244 return wString;
Daniel Veillardf7416012006-04-27 08:15:20 +0000245}
246#endif
247
Daniel Veillard05d987b2003-10-08 11:54:57 +0000248/**
249 * xmlIOErrMemory:
250 * @extra: extra informations
251 *
252 * Handle an out of memory condition
253 */
254static void
255xmlIOErrMemory(const char *extra)
256{
257 __xmlSimpleError(XML_FROM_IO, XML_ERR_NO_MEMORY, NULL, NULL, extra);
258}
259
260/**
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000261 * __xmlIOErr:
Daniel Veillard05d987b2003-10-08 11:54:57 +0000262 * @code: the error number
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000263 * @
Daniel Veillard05d987b2003-10-08 11:54:57 +0000264 * @extra: extra informations
265 *
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000266 * Handle an I/O error
Daniel Veillard05d987b2003-10-08 11:54:57 +0000267 */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000268void
269__xmlIOErr(int domain, int code, const char *extra)
Daniel Veillard05d987b2003-10-08 11:54:57 +0000270{
271 unsigned int idx;
272
273 if (code == 0) {
274#ifdef HAVE_ERRNO_H
275 if (errno == 0) code = 0;
276#ifdef EACCES
277 else if (errno == EACCES) code = XML_IO_EACCES;
278#endif
279#ifdef EAGAIN
280 else if (errno == EAGAIN) code = XML_IO_EAGAIN;
281#endif
282#ifdef EBADF
283 else if (errno == EBADF) code = XML_IO_EBADF;
284#endif
285#ifdef EBADMSG
286 else if (errno == EBADMSG) code = XML_IO_EBADMSG;
287#endif
288#ifdef EBUSY
289 else if (errno == EBUSY) code = XML_IO_EBUSY;
290#endif
291#ifdef ECANCELED
292 else if (errno == ECANCELED) code = XML_IO_ECANCELED;
293#endif
294#ifdef ECHILD
295 else if (errno == ECHILD) code = XML_IO_ECHILD;
296#endif
297#ifdef EDEADLK
298 else if (errno == EDEADLK) code = XML_IO_EDEADLK;
299#endif
300#ifdef EDOM
301 else if (errno == EDOM) code = XML_IO_EDOM;
302#endif
303#ifdef EEXIST
304 else if (errno == EEXIST) code = XML_IO_EEXIST;
305#endif
306#ifdef EFAULT
307 else if (errno == EFAULT) code = XML_IO_EFAULT;
308#endif
309#ifdef EFBIG
310 else if (errno == EFBIG) code = XML_IO_EFBIG;
311#endif
312#ifdef EINPROGRESS
313 else if (errno == EINPROGRESS) code = XML_IO_EINPROGRESS;
314#endif
315#ifdef EINTR
316 else if (errno == EINTR) code = XML_IO_EINTR;
317#endif
318#ifdef EINVAL
319 else if (errno == EINVAL) code = XML_IO_EINVAL;
320#endif
321#ifdef EIO
322 else if (errno == EIO) code = XML_IO_EIO;
323#endif
324#ifdef EISDIR
325 else if (errno == EISDIR) code = XML_IO_EISDIR;
326#endif
327#ifdef EMFILE
328 else if (errno == EMFILE) code = XML_IO_EMFILE;
329#endif
330#ifdef EMLINK
331 else if (errno == EMLINK) code = XML_IO_EMLINK;
332#endif
333#ifdef EMSGSIZE
334 else if (errno == EMSGSIZE) code = XML_IO_EMSGSIZE;
335#endif
336#ifdef ENAMETOOLONG
337 else if (errno == ENAMETOOLONG) code = XML_IO_ENAMETOOLONG;
338#endif
339#ifdef ENFILE
340 else if (errno == ENFILE) code = XML_IO_ENFILE;
341#endif
342#ifdef ENODEV
343 else if (errno == ENODEV) code = XML_IO_ENODEV;
344#endif
345#ifdef ENOENT
346 else if (errno == ENOENT) code = XML_IO_ENOENT;
347#endif
348#ifdef ENOEXEC
349 else if (errno == ENOEXEC) code = XML_IO_ENOEXEC;
350#endif
351#ifdef ENOLCK
352 else if (errno == ENOLCK) code = XML_IO_ENOLCK;
353#endif
354#ifdef ENOMEM
355 else if (errno == ENOMEM) code = XML_IO_ENOMEM;
356#endif
357#ifdef ENOSPC
358 else if (errno == ENOSPC) code = XML_IO_ENOSPC;
359#endif
360#ifdef ENOSYS
361 else if (errno == ENOSYS) code = XML_IO_ENOSYS;
362#endif
363#ifdef ENOTDIR
364 else if (errno == ENOTDIR) code = XML_IO_ENOTDIR;
365#endif
366#ifdef ENOTEMPTY
367 else if (errno == ENOTEMPTY) code = XML_IO_ENOTEMPTY;
368#endif
369#ifdef ENOTSUP
370 else if (errno == ENOTSUP) code = XML_IO_ENOTSUP;
371#endif
372#ifdef ENOTTY
373 else if (errno == ENOTTY) code = XML_IO_ENOTTY;
374#endif
375#ifdef ENXIO
376 else if (errno == ENXIO) code = XML_IO_ENXIO;
377#endif
378#ifdef EPERM
379 else if (errno == EPERM) code = XML_IO_EPERM;
380#endif
381#ifdef EPIPE
382 else if (errno == EPIPE) code = XML_IO_EPIPE;
383#endif
384#ifdef ERANGE
385 else if (errno == ERANGE) code = XML_IO_ERANGE;
386#endif
387#ifdef EROFS
388 else if (errno == EROFS) code = XML_IO_EROFS;
389#endif
390#ifdef ESPIPE
391 else if (errno == ESPIPE) code = XML_IO_ESPIPE;
392#endif
393#ifdef ESRCH
394 else if (errno == ESRCH) code = XML_IO_ESRCH;
395#endif
396#ifdef ETIMEDOUT
397 else if (errno == ETIMEDOUT) code = XML_IO_ETIMEDOUT;
398#endif
399#ifdef EXDEV
400 else if (errno == EXDEV) code = XML_IO_EXDEV;
401#endif
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000402#ifdef ENOTSOCK
403 else if (errno == ENOTSOCK) code = XML_IO_ENOTSOCK;
404#endif
405#ifdef EISCONN
406 else if (errno == EISCONN) code = XML_IO_EISCONN;
407#endif
408#ifdef ECONNREFUSED
409 else if (errno == ECONNREFUSED) code = XML_IO_ECONNREFUSED;
410#endif
411#ifdef ETIMEDOUT
412 else if (errno == ETIMEDOUT) code = XML_IO_ETIMEDOUT;
413#endif
414#ifdef ENETUNREACH
415 else if (errno == ENETUNREACH) code = XML_IO_ENETUNREACH;
416#endif
417#ifdef EADDRINUSE
418 else if (errno == EADDRINUSE) code = XML_IO_EADDRINUSE;
419#endif
420#ifdef EINPROGRESS
421 else if (errno == EINPROGRESS) code = XML_IO_EINPROGRESS;
422#endif
423#ifdef EALREADY
424 else if (errno == EALREADY) code = XML_IO_EALREADY;
425#endif
426#ifdef EAFNOSUPPORT
427 else if (errno == EAFNOSUPPORT) code = XML_IO_EAFNOSUPPORT;
428#endif
Daniel Veillard05d987b2003-10-08 11:54:57 +0000429 else code = XML_IO_UNKNOWN;
430#endif /* HAVE_ERRNO_H */
431 }
432 idx = 0;
433 if (code >= XML_IO_UNKNOWN) idx = code - XML_IO_UNKNOWN;
434 if (idx >= (sizeof(IOerr) / sizeof(IOerr[0]))) idx = 0;
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200435
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000436 __xmlSimpleError(domain, code, NULL, IOerr[idx], extra);
437}
438
439/**
440 * xmlIOErr:
441 * @code: the error number
442 * @extra: extra informations
443 *
444 * Handle an I/O error
445 */
446static void
447xmlIOErr(int code, const char *extra)
448{
449 __xmlIOErr(XML_FROM_IO, code, extra);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000450}
451
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000452/**
Daniel Veillarde8039df2003-10-27 11:25:13 +0000453 * __xmlLoaderErr:
454 * @ctx: the parser context
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000455 * @extra: extra informations
456 *
457 * Handle a resource access error
458 */
Daniel Veillarde8039df2003-10-27 11:25:13 +0000459void
460__xmlLoaderErr(void *ctx, const char *msg, const char *filename)
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000461{
Daniel Veillarde8039df2003-10-27 11:25:13 +0000462 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000463 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000464 xmlGenericErrorFunc channel = NULL;
465 void *data = NULL;
466 xmlErrorLevel level = XML_ERR_ERROR;
467
Daniel Veillard157fee02003-10-31 10:36:03 +0000468 if ((ctxt != NULL) && (ctxt->disableSAX != 0) &&
469 (ctxt->instate == XML_PARSER_EOF))
470 return;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000471 if ((ctxt != NULL) && (ctxt->sax != NULL)) {
472 if (ctxt->validate) {
473 channel = ctxt->sax->error;
474 level = XML_ERR_ERROR;
475 } else {
476 channel = ctxt->sax->warning;
477 level = XML_ERR_WARNING;
478 }
Daniel Veillard5ea30d72004-11-08 11:54:28 +0000479 if (ctxt->sax->initialized == XML_SAX2_MAGIC)
480 schannel = ctxt->sax->serror;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000481 data = ctxt->userData;
482 }
Daniel Veillard659e71e2003-10-10 14:10:40 +0000483 __xmlRaiseError(schannel, channel, data, ctxt, NULL, XML_FROM_IO,
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000484 XML_IO_LOAD_ERROR, level, NULL, 0,
485 filename, NULL, NULL, 0, 0,
486 msg, filename);
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200487
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000488}
489
Daniel Veillard05d987b2003-10-08 11:54:57 +0000490/************************************************************************
491 * *
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200492 * Tree memory error handler *
Daniel Veillard05d987b2003-10-08 11:54:57 +0000493 * *
494 ************************************************************************/
Daniel Veillardf4862f02002-09-10 11:13:43 +0000495/**
Daniel Veillard01c13b52002-12-10 15:19:08 +0000496 * xmlNormalizeWindowsPath:
Daniel Veillard33300b42003-04-17 09:09:19 +0000497 * @path: the input file path
Daniel Veillardf4862f02002-09-10 11:13:43 +0000498 *
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +0000499 * This function is obsolete. Please see xmlURIFromPath in uri.c for
500 * a better solution.
Daniel Veillard33300b42003-04-17 09:09:19 +0000501 *
502 * Returns a canonicalized version of the path
Daniel Veillardf4862f02002-09-10 11:13:43 +0000503 */
504xmlChar *
505xmlNormalizeWindowsPath(const xmlChar *path)
506{
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +0000507 return xmlCanonicPath(path);
Daniel Veillardf4862f02002-09-10 11:13:43 +0000508}
509
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000510/**
511 * xmlCleanupInputCallbacks:
512 *
513 * clears the entire input callback table. this includes the
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200514 * compiled-in I/O.
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000515 */
516void
517xmlCleanupInputCallbacks(void)
518{
519 int i;
520
521 if (!xmlInputCallbackInitialized)
522 return;
523
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000524 for (i = xmlInputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000525 xmlInputCallbackTable[i].matchcallback = NULL;
526 xmlInputCallbackTable[i].opencallback = NULL;
527 xmlInputCallbackTable[i].readcallback = NULL;
528 xmlInputCallbackTable[i].closecallback = NULL;
529 }
530
531 xmlInputCallbackNr = 0;
Aleksey Sanin9c45ba82002-06-06 21:46:13 +0000532 xmlInputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000533}
534
Daniel Veillardaecc0dc2004-05-08 02:32:07 +0000535/**
William M. Brack4e3a9fa2004-08-03 22:41:11 +0000536 * xmlPopInputCallbacks:
Daniel Veillardaecc0dc2004-05-08 02:32:07 +0000537 *
538 * Clear the top input callback from the input stack. this includes the
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200539 * compiled-in I/O.
Daniel Veillardaecc0dc2004-05-08 02:32:07 +0000540 *
541 * Returns the number of input callback registered or -1 in case of error.
542 */
543int
544xmlPopInputCallbacks(void)
545{
546 if (!xmlInputCallbackInitialized)
547 return(-1);
548
549 if (xmlInputCallbackNr <= 0)
550 return(-1);
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200551
Daniel Veillardaecc0dc2004-05-08 02:32:07 +0000552 xmlInputCallbackNr--;
553 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = NULL;
554 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = NULL;
555 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = NULL;
556 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = NULL;
557
558 return(xmlInputCallbackNr);
559}
560
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000561#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000562/**
563 * xmlCleanupOutputCallbacks:
564 *
565 * clears the entire output callback table. this includes the
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200566 * compiled-in I/O callbacks.
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000567 */
568void
569xmlCleanupOutputCallbacks(void)
570{
571 int i;
572
573 if (!xmlOutputCallbackInitialized)
574 return;
575
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000576 for (i = xmlOutputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000577 xmlOutputCallbackTable[i].matchcallback = NULL;
578 xmlOutputCallbackTable[i].opencallback = NULL;
579 xmlOutputCallbackTable[i].writecallback = NULL;
580 xmlOutputCallbackTable[i].closecallback = NULL;
581 }
582
583 xmlOutputCallbackNr = 0;
Aleksey Sanin9c45ba82002-06-06 21:46:13 +0000584 xmlOutputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000585}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000586#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000587
Owen Taylor3473f882001-02-23 17:55:21 +0000588/************************************************************************
589 * *
590 * Standard I/O for file accesses *
591 * *
592 ************************************************************************/
593
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000594#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
595
596/**
597 * xmlWrapOpenUtf8:
598 * @path: the path in utf-8 encoding
599 * @mode: type of access (0 - read, 1 - write)
600 *
601 * function opens the file specified by @path
602 *
603 */
604static FILE*
605xmlWrapOpenUtf8(const char *path,int mode)
606{
607 FILE *fd = NULL;
608 wchar_t *wPath;
609
610 wPath = __xmlIOWin32UTF8ToWChar(path);
611 if(wPath)
612 {
613 fd = _wfopen(wPath, mode ? L"wb" : L"rb");
614 xmlFree(wPath);
615 }
Daniel Veillard0da41662006-10-10 09:05:36 +0000616 /* maybe path in native encoding */
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000617 if(fd == NULL)
618 fd = fopen(path, mode ? "wb" : "rb");
619
620 return fd;
621}
622
Rob Richards6c61e022009-08-12 11:41:27 -0400623#ifdef HAVE_ZLIB_H
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200624static gzFile
625xmlWrapGzOpenUtf8(const char *path, const char *mode)
626{
627 gzFile fd;
628 wchar_t *wPath;
629
630 fd = gzopen (path, mode);
631 if (fd)
632 return fd;
633
634 wPath = __xmlIOWin32UTF8ToWChar(path);
635 if(wPath)
636 {
637 int d, m = (strstr(mode, "r") ? O_RDONLY : O_RDWR);
638#ifdef _O_BINARY
639 m |= (strstr(mode, "b") ? _O_BINARY : 0);
640#endif
641 d = _wopen(wPath, m);
642 if (d >= 0)
643 fd = gzdopen(d, mode);
644 xmlFree(wPath);
645 }
646
647 return fd;
648}
Rob Richards6c61e022009-08-12 11:41:27 -0400649#endif
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200650
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000651/**
652 * xmlWrapStatUtf8:
653 * @path: the path in utf-8 encoding
654 * @info: structure that stores results
655 *
656 * function obtains information about the file or directory
657 *
658 */
659static int
660xmlWrapStatUtf8(const char *path,struct stat *info)
661{
662#ifdef HAVE_STAT
663 int retval = -1;
664 wchar_t *wPath;
665
666 wPath = __xmlIOWin32UTF8ToWChar(path);
667 if (wPath)
668 {
669 retval = _wstat(wPath,info);
670 xmlFree(wPath);
671 }
Daniel Veillard0da41662006-10-10 09:05:36 +0000672 /* maybe path in native encoding */
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000673 if(retval < 0)
674 retval = stat(path,info);
675 return retval;
676#else
677 return -1;
678#endif
679}
680
681/**
682 * xmlWrapOpenNative:
683 * @path: the path
684 * @mode: type of access (0 - read, 1 - write)
685 *
686 * function opens the file specified by @path
687 *
688 */
689static FILE*
690xmlWrapOpenNative(const char *path,int mode)
691{
692 return fopen(path,mode ? "wb" : "rb");
693}
694
695/**
696 * xmlWrapStatNative:
697 * @path: the path
698 * @info: structure that stores results
699 *
700 * function obtains information about the file or directory
701 *
702 */
703static int
704xmlWrapStatNative(const char *path,struct stat *info)
705{
706#ifdef HAVE_STAT
707 return stat(path,info);
708#else
709 return -1;
710#endif
711}
712
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +0000713typedef int (* xmlWrapStatFunc) (const char *f, struct stat *s);
714static xmlWrapStatFunc xmlWrapStat = xmlWrapStatNative;
715typedef FILE* (* xmlWrapOpenFunc)(const char *f,int mode);
Rob Richards6460f922006-10-12 21:08:29 +0000716static xmlWrapOpenFunc xmlWrapOpen = xmlWrapOpenNative;
Rob Richards6c61e022009-08-12 11:41:27 -0400717#ifdef HAVE_ZLIB_H
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200718typedef gzFile (* xmlWrapGzOpenFunc) (const char *f, const char *mode);
719static xmlWrapGzOpenFunc xmlWrapGzOpen = gzopen;
Rob Richards6c61e022009-08-12 11:41:27 -0400720#endif
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000721/**
722 * xmlInitPlatformSpecificIo:
723 *
724 * Initialize platform specific features.
725 */
726static void
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +0000727xmlInitPlatformSpecificIo(void)
728{
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000729 static int xmlPlatformIoInitialized = 0;
730 OSVERSIONINFO osvi;
731
732 if(xmlPlatformIoInitialized)
733 return;
734
735 osvi.dwOSVersionInfoSize = sizeof(osvi);
736
737 if(GetVersionEx(&osvi) && (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)) {
738 xmlWrapStat = xmlWrapStatUtf8;
739 xmlWrapOpen = xmlWrapOpenUtf8;
Rob Richards6c61e022009-08-12 11:41:27 -0400740#ifdef HAVE_ZLIB_H
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200741 xmlWrapGzOpen = xmlWrapGzOpenUtf8;
Rob Richards6c61e022009-08-12 11:41:27 -0400742#endif
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000743 } else {
744 xmlWrapStat = xmlWrapStatNative;
745 xmlWrapOpen = xmlWrapOpenNative;
Rob Richards6c61e022009-08-12 11:41:27 -0400746#ifdef HAVE_ZLIB_H
Hans Breuer2ad41ca2009-08-11 17:51:22 +0200747 xmlWrapGzOpen = gzopen;
Rob Richards6c61e022009-08-12 11:41:27 -0400748#endif
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000749 }
750
751 xmlPlatformIoInitialized = 1;
752 return;
753}
754
755#endif
756
Owen Taylor3473f882001-02-23 17:55:21 +0000757/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000758 * xmlCheckFilename:
Owen Taylor3473f882001-02-23 17:55:21 +0000759 * @path: the path to check
760 *
761 * function checks to see if @path is a valid source
762 * (file, socket...) for XML.
763 *
764 * if stat is not available on the target machine,
765 * returns 1. if stat fails, returns 0 (if calling
766 * stat on the filename fails, it can't be right).
767 * if stat succeeds and the file is a directory,
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000768 * returns 2. otherwise returns 1.
Owen Taylor3473f882001-02-23 17:55:21 +0000769 */
770
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000771int
Owen Taylor3473f882001-02-23 17:55:21 +0000772xmlCheckFilename (const char *path)
773{
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000774#ifdef HAVE_STAT
Michael Stahl55b899a2012-09-07 12:14:00 +0800775 struct stat stat_buffer;
Daniel Veillard0b309952006-05-02 20:34:38 +0000776#endif
Michael Stahl55b899a2012-09-07 12:14:00 +0800777 if (path == NULL)
778 return(0);
Daniel Veillarde5a3f372006-08-30 13:11:36 +0000779
Owen Taylor3473f882001-02-23 17:55:21 +0000780#ifdef HAVE_STAT
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000781#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
Michael Stahl55b899a2012-09-07 12:14:00 +0800782 /*
783 * On Windows stat and wstat do not work with long pathname,
784 * which start with '\\?\'
785 */
786 if ((path[0] == '\\') && (path[1] == '\\') && (path[2] == '?') &&
787 (path[3] == '\\') )
788 return 1;
789
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000790 if (xmlWrapStat(path, &stat_buffer) == -1)
791 return 0;
792#else
Owen Taylor3473f882001-02-23 17:55:21 +0000793 if (stat(path, &stat_buffer) == -1)
794 return 0;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000795#endif
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000796#ifdef S_ISDIR
Daniel Veillardf7416012006-04-27 08:15:20 +0000797 if (S_ISDIR(stat_buffer.st_mode))
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000798 return 2;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000799#endif
Daniel Veillardf7416012006-04-27 08:15:20 +0000800#endif /* HAVE_STAT */
Owen Taylor3473f882001-02-23 17:55:21 +0000801 return 1;
802}
803
Daniel Veillard7a72f4a2014-10-13 16:23:24 +0800804/**
805 * xmlNop:
806 *
807 * No Operation function, does nothing, no input
808 *
809 * Returns zero
810 */
Daniel Veillard153cf152012-10-26 13:50:47 +0800811int
Owen Taylor3473f882001-02-23 17:55:21 +0000812xmlNop(void) {
813 return(0);
814}
815
816/**
Owen Taylor3473f882001-02-23 17:55:21 +0000817 * xmlFdRead:
818 * @context: the I/O context
819 * @buffer: where to drop data
820 * @len: number of bytes to read
821 *
822 * Read @len bytes to @buffer from the I/O channel.
823 *
824 * Returns the number of bytes written
825 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000826static int
Owen Taylor3473f882001-02-23 17:55:21 +0000827xmlFdRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000828 int ret;
829
830 ret = read((int) (long) context, &buffer[0], len);
831 if (ret < 0) xmlIOErr(0, "read()");
832 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000833}
834
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000835#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000836/**
837 * xmlFdWrite:
838 * @context: the I/O context
839 * @buffer: where to get data
840 * @len: number of bytes to write
841 *
842 * Write @len bytes from @buffer to the I/O channel.
843 *
844 * Returns the number of bytes written
845 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000846static int
Owen Taylor3473f882001-02-23 17:55:21 +0000847xmlFdWrite (void * context, const char * buffer, int len) {
Daniel Veillard9b693b42005-10-28 14:54:17 +0000848 int ret = 0;
Daniel Veillard05d987b2003-10-08 11:54:57 +0000849
Daniel Veillard9b693b42005-10-28 14:54:17 +0000850 if (len > 0) {
851 ret = write((int) (long) context, &buffer[0], len);
852 if (ret < 0) xmlIOErr(0, "write()");
853 }
Daniel Veillard05d987b2003-10-08 11:54:57 +0000854 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000855}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000856#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000857
858/**
859 * xmlFdClose:
860 * @context: the I/O context
861 *
862 * Close an I/O channel
Daniel Veillardf012a642001-07-23 19:10:52 +0000863 *
864 * Returns 0 in case of success and error code otherwise
Owen Taylor3473f882001-02-23 17:55:21 +0000865 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000866static int
Owen Taylor3473f882001-02-23 17:55:21 +0000867xmlFdClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000868 int ret;
869 ret = close((int) (long) context);
870 if (ret < 0) xmlIOErr(0, "close()");
871 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000872}
873
874/**
875 * xmlFileMatch:
876 * @filename: the URI for matching
877 *
878 * input from FILE *
879 *
880 * Returns 1 if matches, 0 otherwise
881 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000882int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000883xmlFileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000884 return(1);
885}
886
887/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000888 * xmlFileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +0000889 * @filename: the URI for matching
890 *
891 * input from FILE *, supports compressed input
892 * if @filename is " " then the standard input is used
893 *
894 * Returns an I/O context or NULL in case of error
895 */
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000896static void *
897xmlFileOpen_real (const char *filename) {
Gaurav Guptab8480ae2014-07-26 21:14:53 +0800898 const char *path = filename;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000899 FILE *fd;
Owen Taylor3473f882001-02-23 17:55:21 +0000900
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000901 if (filename == NULL)
902 return(NULL);
903
Owen Taylor3473f882001-02-23 17:55:21 +0000904 if (!strcmp(filename, "-")) {
905 fd = stdin;
906 return((void *) fd);
907 }
908
Daniel Veillard5cdbbd22007-06-12 09:39:14 +0000909 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000910#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000911 path = &filename[17];
912#else
Owen Taylor3473f882001-02-23 17:55:21 +0000913 path = &filename[16];
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000914#endif
Daniel Veillard5cdbbd22007-06-12 09:39:14 +0000915 } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000916#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000917 path = &filename[8];
918#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000919 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000920#endif
Daniel Veillard5cdbbd22007-06-12 09:39:14 +0000921 } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:/", 6)) {
922 /* lots of generators seems to lazy to read RFC 1738 */
923#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
924 path = &filename[6];
925#else
926 path = &filename[5];
927#endif
Gaurav Guptab8480ae2014-07-26 21:14:53 +0800928 }
Owen Taylor3473f882001-02-23 17:55:21 +0000929
Owen Taylor3473f882001-02-23 17:55:21 +0000930 if (!xmlCheckFilename(path))
931 return(NULL);
932
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000933#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
934 fd = xmlWrapOpen(path, 0);
935#else
936 fd = fopen(path, "r");
Owen Taylor3473f882001-02-23 17:55:21 +0000937#endif /* WIN32 */
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000938 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +0000939 return((void *) fd);
940}
941
942/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000943 * xmlFileOpen:
944 * @filename: the URI for matching
945 *
946 * Wrapper around xmlFileOpen_real that try it with an unescaped
947 * version of @filename, if this fails fallback to @filename
Daniel Veillard71531f32003-02-05 13:19:53 +0000948 *
949 * Returns a handler or NULL in case or failure
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000950 */
951void *
952xmlFileOpen (const char *filename) {
953 char *unescaped;
954 void *retval;
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000955
Daniel Veillardbd672bc2007-03-30 12:39:25 +0000956 retval = xmlFileOpen_real(filename);
957 if (retval == NULL) {
958 unescaped = xmlURIUnescapeString(filename, 0, NULL);
959 if (unescaped != NULL) {
960 retval = xmlFileOpen_real(unescaped);
961 xmlFree(unescaped);
962 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000963 }
Daniel Veillardbd672bc2007-03-30 12:39:25 +0000964
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000965 return retval;
966}
967
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000968#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000969/**
Owen Taylor3473f882001-02-23 17:55:21 +0000970 * xmlFileOpenW:
971 * @filename: the URI for matching
972 *
973 * output to from FILE *,
974 * if @filename is "-" then the standard output is used
975 *
976 * Returns an I/O context or NULL in case of error
977 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000978static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000979xmlFileOpenW (const char *filename) {
980 const char *path = NULL;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000981 FILE *fd;
Owen Taylor3473f882001-02-23 17:55:21 +0000982
983 if (!strcmp(filename, "-")) {
984 fd = stdout;
985 return((void *) fd);
986 }
987
Daniel Veillardf4862f02002-09-10 11:13:43 +0000988 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000989#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000990 path = &filename[17];
991#else
Owen Taylor3473f882001-02-23 17:55:21 +0000992 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000993#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000994 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000995#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000996 path = &filename[8];
997#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000998 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000999#endif
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001000 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001001 path = filename;
1002
1003 if (path == NULL)
1004 return(NULL);
1005
Daniel Veillard8ca85b22006-09-01 09:56:07 +00001006#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
1007 fd = xmlWrapOpen(path, 1);
1008#else
Daniel Veillardf8e3db02012-09-11 13:26:36 +08001009 fd = fopen(path, "wb");
Daniel Veillard8ca85b22006-09-01 09:56:07 +00001010#endif /* WIN32 */
Daniel Veillarde5a3f372006-08-30 13:11:36 +00001011
Daniel Veillardf7416012006-04-27 08:15:20 +00001012 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +00001013 return((void *) fd);
1014}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001015#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001016
1017/**
1018 * xmlFileRead:
1019 * @context: the I/O context
1020 * @buffer: where to drop data
1021 * @len: number of bytes to write
1022 *
1023 * Read @len bytes to @buffer from the I/O channel.
1024 *
Daniel Veillardce682bc2004-11-05 17:22:25 +00001025 * Returns the number of bytes written or < 0 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +00001026 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001027int
Owen Taylor3473f882001-02-23 17:55:21 +00001028xmlFileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001029 int ret;
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001030 if ((context == NULL) || (buffer == NULL))
Daniel Veillardce682bc2004-11-05 17:22:25 +00001031 return(-1);
Daniel Veillard05d987b2003-10-08 11:54:57 +00001032 ret = fread(&buffer[0], 1, len, (FILE *) context);
1033 if (ret < 0) xmlIOErr(0, "fread()");
1034 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001035}
1036
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001037#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001038/**
1039 * xmlFileWrite:
1040 * @context: the I/O context
1041 * @buffer: where to drop data
1042 * @len: number of bytes to write
1043 *
1044 * Write @len bytes from @buffer to the I/O channel.
1045 *
1046 * Returns the number of bytes written
1047 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001048static int
Owen Taylor3473f882001-02-23 17:55:21 +00001049xmlFileWrite (void * context, const char * buffer, int len) {
Daniel Veillard4a6d39b2002-12-17 18:33:01 +00001050 int items;
1051
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001052 if ((context == NULL) || (buffer == NULL))
Daniel Veillardce682bc2004-11-05 17:22:25 +00001053 return(-1);
Daniel Veillard4a6d39b2002-12-17 18:33:01 +00001054 items = fwrite(&buffer[0], len, 1, (FILE *) context);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00001055 if ((items == 0) && (ferror((FILE *) context))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001056 xmlIOErr(0, "fwrite()");
Daniel Veillard97bf4d02003-10-08 18:58:28 +00001057 return(-1);
1058 }
Daniel Veillard4a6d39b2002-12-17 18:33:01 +00001059 return(items * len);
Owen Taylor3473f882001-02-23 17:55:21 +00001060}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001061#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001062
1063/**
1064 * xmlFileClose:
1065 * @context: the I/O context
1066 *
1067 * Close an I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001068 *
1069 * Returns 0 or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +00001070 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001071int
Owen Taylor3473f882001-02-23 17:55:21 +00001072xmlFileClose (void * context) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001073 FILE *fil;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001074 int ret;
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001075
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +00001076 if (context == NULL)
1077 return(-1);
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001078 fil = (FILE *) context;
Daniel Veillard500a1de2004-03-22 15:22:58 +00001079 if ((fil == stdout) || (fil == stderr)) {
1080 ret = fflush(fil);
1081 if (ret < 0)
1082 xmlIOErr(0, "fflush()");
1083 return(0);
1084 }
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001085 if (fil == stdin)
1086 return(0);
Daniel Veillard05d987b2003-10-08 11:54:57 +00001087 ret = ( fclose((FILE *) context) == EOF ) ? -1 : 0;
1088 if (ret < 0)
1089 xmlIOErr(0, "fclose()");
1090 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001091}
1092
1093/**
1094 * xmlFileFlush:
1095 * @context: the I/O context
1096 *
1097 * Flush an I/O channel
1098 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001099static int
Owen Taylor3473f882001-02-23 17:55:21 +00001100xmlFileFlush (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001101 int ret;
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +00001102
1103 if (context == NULL)
1104 return(-1);
Daniel Veillard05d987b2003-10-08 11:54:57 +00001105 ret = ( fflush((FILE *) context) == EOF ) ? -1 : 0;
1106 if (ret < 0)
1107 xmlIOErr(0, "fflush()");
1108 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001109}
1110
Daniel Veillard9a00fd22005-11-09 08:56:26 +00001111#ifdef LIBXML_OUTPUT_ENABLED
1112/**
1113 * xmlBufferWrite:
1114 * @context: the xmlBuffer
1115 * @buffer: the data to write
1116 * @len: number of bytes to write
1117 *
1118 * Write @len bytes from @buffer to the xml buffer
1119 *
1120 * Returns the number of bytes written
1121 */
1122static int
1123xmlBufferWrite (void * context, const char * buffer, int len) {
1124 int ret;
1125
1126 ret = xmlBufferAdd((xmlBufferPtr) context, (const xmlChar *) buffer, len);
1127 if (ret != 0)
1128 return(-1);
1129 return(len);
1130}
Daniel Veillard9a00fd22005-11-09 08:56:26 +00001131#endif
1132
Owen Taylor3473f882001-02-23 17:55:21 +00001133#ifdef HAVE_ZLIB_H
1134/************************************************************************
1135 * *
1136 * I/O for compressed file accesses *
1137 * *
1138 ************************************************************************/
1139/**
1140 * xmlGzfileMatch:
1141 * @filename: the URI for matching
1142 *
1143 * input from compressed file test
1144 *
1145 * Returns 1 if matches, 0 otherwise
1146 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001147static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00001148xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00001149 return(1);
1150}
1151
1152/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001153 * xmlGzfileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +00001154 * @filename: the URI for matching
1155 *
1156 * input from compressed file open
1157 * if @filename is " " then the standard input is used
1158 *
1159 * Returns an I/O context or NULL in case of error
1160 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001161static void *
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001162xmlGzfileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +00001163 const char *path = NULL;
1164 gzFile fd;
1165
1166 if (!strcmp(filename, "-")) {
Philip Withnall31aa3812014-06-20 21:11:40 +01001167 int duped_fd = dup(fileno(stdin));
1168 fd = gzdopen(duped_fd, "rb");
Philip Withnall21699932014-08-24 23:10:13 +01001169 if (fd == Z_NULL && duped_fd >= 0) {
Philip Withnall31aa3812014-06-20 21:11:40 +01001170 close(duped_fd); /* gzdOpen() does not close on failure */
1171 }
1172
Owen Taylor3473f882001-02-23 17:55:21 +00001173 return((void *) fd);
1174 }
1175
Daniel Veillardf4862f02002-09-10 11:13:43 +00001176 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001177#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00001178 path = &filename[17];
1179#else
Owen Taylor3473f882001-02-23 17:55:21 +00001180 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00001181#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001182 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001183#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +00001184 path = &filename[8];
1185#else
Owen Taylor3473f882001-02-23 17:55:21 +00001186 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +00001187#endif
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001188 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001189 path = filename;
1190
1191 if (path == NULL)
1192 return(NULL);
1193 if (!xmlCheckFilename(path))
1194 return(NULL);
1195
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001196#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
1197 fd = xmlWrapGzOpen(path, "rb");
1198#else
Owen Taylor3473f882001-02-23 17:55:21 +00001199 fd = gzopen(path, "rb");
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001200#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001201 return((void *) fd);
1202}
1203
1204/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001205 * xmlGzfileOpen:
1206 * @filename: the URI for matching
1207 *
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00001208 * Wrapper around xmlGzfileOpen if the open fais, it will
1209 * try to unescape @filename
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001210 */
1211static void *
1212xmlGzfileOpen (const char *filename) {
1213 char *unescaped;
1214 void *retval;
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00001215
1216 retval = xmlGzfileOpen_real(filename);
1217 if (retval == NULL) {
1218 unescaped = xmlURIUnescapeString(filename, 0, NULL);
1219 if (unescaped != NULL) {
1220 retval = xmlGzfileOpen_real(unescaped);
1221 }
1222 xmlFree(unescaped);
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001223 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001224 return retval;
1225}
1226
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001227#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001228/**
Owen Taylor3473f882001-02-23 17:55:21 +00001229 * xmlGzfileOpenW:
1230 * @filename: the URI for matching
1231 * @compression: the compression factor (0 - 9 included)
1232 *
1233 * input from compressed file open
1234 * if @filename is " " then the standard input is used
1235 *
1236 * Returns an I/O context or NULL in case of error
1237 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001238static void *
Owen Taylor3473f882001-02-23 17:55:21 +00001239xmlGzfileOpenW (const char *filename, int compression) {
1240 const char *path = NULL;
1241 char mode[15];
1242 gzFile fd;
1243
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001244 snprintf(mode, sizeof(mode), "wb%d", compression);
Owen Taylor3473f882001-02-23 17:55:21 +00001245 if (!strcmp(filename, "-")) {
Philip Withnall31aa3812014-06-20 21:11:40 +01001246 int duped_fd = dup(fileno(stdout));
1247 fd = gzdopen(duped_fd, "rb");
Philip Withnall21699932014-08-24 23:10:13 +01001248 if (fd == Z_NULL && duped_fd >= 0) {
Philip Withnall31aa3812014-06-20 21:11:40 +01001249 close(duped_fd); /* gzdOpen() does not close on failure */
1250 }
1251
Owen Taylor3473f882001-02-23 17:55:21 +00001252 return((void *) fd);
1253 }
1254
Daniel Veillardf4862f02002-09-10 11:13:43 +00001255 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001256#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00001257 path = &filename[17];
1258#else
Owen Taylor3473f882001-02-23 17:55:21 +00001259 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00001260#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001261 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001262#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +00001263 path = &filename[8];
1264#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +00001265 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +00001266#endif
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001267 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001268 path = filename;
1269
1270 if (path == NULL)
1271 return(NULL);
1272
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001273#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
1274 fd = xmlWrapGzOpen(path, mode);
1275#else
Owen Taylor3473f882001-02-23 17:55:21 +00001276 fd = gzopen(path, mode);
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001277#endif
Owen Taylor3473f882001-02-23 17:55:21 +00001278 return((void *) fd);
1279}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001280#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001281
1282/**
1283 * xmlGzfileRead:
1284 * @context: the I/O context
1285 * @buffer: where to drop data
1286 * @len: number of bytes to write
1287 *
1288 * Read @len bytes to @buffer from the compressed I/O channel.
1289 *
1290 * Returns the number of bytes written
1291 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001292static int
Owen Taylor3473f882001-02-23 17:55:21 +00001293xmlGzfileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001294 int ret;
1295
1296 ret = gzread((gzFile) context, &buffer[0], len);
1297 if (ret < 0) xmlIOErr(0, "gzread()");
1298 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001299}
1300
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001301#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001302/**
1303 * xmlGzfileWrite:
1304 * @context: the I/O context
1305 * @buffer: where to drop data
1306 * @len: number of bytes to write
1307 *
1308 * Write @len bytes from @buffer to the compressed I/O channel.
1309 *
1310 * Returns the number of bytes written
1311 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001312static int
Owen Taylor3473f882001-02-23 17:55:21 +00001313xmlGzfileWrite (void * context, const char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001314 int ret;
1315
1316 ret = gzwrite((gzFile) context, (char *) &buffer[0], len);
1317 if (ret < 0) xmlIOErr(0, "gzwrite()");
1318 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001319}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001320#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001321
1322/**
1323 * xmlGzfileClose:
1324 * @context: the I/O context
1325 *
1326 * Close a compressed I/O channel
1327 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001328static int
Owen Taylor3473f882001-02-23 17:55:21 +00001329xmlGzfileClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001330 int ret;
1331
1332 ret = (gzclose((gzFile) context) == Z_OK ) ? 0 : -1;
1333 if (ret < 0) xmlIOErr(0, "gzclose()");
1334 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001335}
1336#endif /* HAVE_ZLIB_H */
1337
Daniel Veillard18b89882015-11-03 15:46:29 +08001338#ifdef LIBXML_LZMA_ENABLED
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001339/************************************************************************
1340 * *
1341 * I/O for compressed file accesses *
1342 * *
1343 ************************************************************************/
Daniel Veillardadf5ec92012-01-26 16:56:22 +08001344#include "xzlib.h"
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001345/**
1346 * xmlXzfileMatch:
1347 * @filename: the URI for matching
1348 *
1349 * input from compressed file test
1350 *
1351 * Returns 1 if matches, 0 otherwise
1352 */
1353static int
1354xmlXzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
1355 return(1);
1356}
1357
1358/**
1359 * xmlXzFileOpen_real:
1360 * @filename: the URI for matching
1361 *
1362 * input from compressed file open
1363 * if @filename is " " then the standard input is used
1364 *
1365 * Returns an I/O context or NULL in case of error
1366 */
1367static void *
1368xmlXzfileOpen_real (const char *filename) {
1369 const char *path = NULL;
1370 xzFile fd;
1371
1372 if (!strcmp(filename, "-")) {
Patrick Monnerat147aaf22013-12-12 15:02:40 +08001373 fd = __libxml2_xzdopen(dup(fileno(stdin)), "rb");
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001374 return((void *) fd);
1375 }
1376
1377 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) {
1378 path = &filename[16];
1379 } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
1380 path = &filename[7];
1381 } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:/", 6)) {
1382 /* lots of generators seems to lazy to read RFC 1738 */
1383 path = &filename[5];
1384 } else
1385 path = filename;
1386
1387 if (path == NULL)
1388 return(NULL);
1389 if (!xmlCheckFilename(path))
1390 return(NULL);
1391
Daniel Veillardadf5ec92012-01-26 16:56:22 +08001392 fd = __libxml2_xzopen(path, "rb");
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001393 return((void *) fd);
1394}
1395
1396/**
1397 * xmlXzfileOpen:
1398 * @filename: the URI for matching
1399 *
1400 * Wrapper around xmlXzfileOpen_real that try it with an unescaped
1401 * version of @filename, if this fails fallback to @filename
1402 *
1403 * Returns a handler or NULL in case or failure
1404 */
1405static void *
1406xmlXzfileOpen (const char *filename) {
1407 char *unescaped;
1408 void *retval;
1409
1410 retval = xmlXzfileOpen_real(filename);
1411 if (retval == NULL) {
1412 unescaped = xmlURIUnescapeString(filename, 0, NULL);
1413 if (unescaped != NULL) {
1414 retval = xmlXzfileOpen_real(unescaped);
1415 }
1416 xmlFree(unescaped);
1417 }
1418
1419 return retval;
1420}
1421
1422/**
1423 * xmlXzfileRead:
1424 * @context: the I/O context
1425 * @buffer: where to drop data
1426 * @len: number of bytes to write
1427 *
1428 * Read @len bytes to @buffer from the compressed I/O channel.
1429 *
1430 * Returns the number of bytes written
1431 */
1432static int
1433xmlXzfileRead (void * context, char * buffer, int len) {
1434 int ret;
1435
Daniel Veillardadf5ec92012-01-26 16:56:22 +08001436 ret = __libxml2_xzread((xzFile) context, &buffer[0], len);
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001437 if (ret < 0) xmlIOErr(0, "xzread()");
1438 return(ret);
1439}
1440
1441/**
1442 * xmlXzfileClose:
1443 * @context: the I/O context
1444 *
1445 * Close a compressed I/O channel
1446 */
1447static int
1448xmlXzfileClose (void * context) {
1449 int ret;
1450
Daniel Veillardadf5ec92012-01-26 16:56:22 +08001451 ret = (__libxml2_xzclose((xzFile) context) == LZMA_OK ) ? 0 : -1;
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001452 if (ret < 0) xmlIOErr(0, "xzclose()");
1453 return(ret);
1454}
Daniel Veillard18b89882015-11-03 15:46:29 +08001455#endif /* LIBXML_LZMA_ENABLED */
Anders F Bjorklundeae52612011-09-18 16:59:13 +02001456
Owen Taylor3473f882001-02-23 17:55:21 +00001457#ifdef LIBXML_HTTP_ENABLED
1458/************************************************************************
1459 * *
1460 * I/O for HTTP file accesses *
1461 * *
1462 ************************************************************************/
Daniel Veillardf012a642001-07-23 19:10:52 +00001463
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001464#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001465typedef struct xmlIOHTTPWriteCtxt_
1466{
1467 int compression;
1468
1469 char * uri;
1470
1471 void * doc_buff;
1472
1473} xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr;
1474
1475#ifdef HAVE_ZLIB_H
1476
1477#define DFLT_WBITS ( -15 )
1478#define DFLT_MEM_LVL ( 8 )
1479#define GZ_MAGIC1 ( 0x1f )
1480#define GZ_MAGIC2 ( 0x8b )
1481#define LXML_ZLIB_OS_CODE ( 0x03 )
1482#define INIT_HTTP_BUFF_SIZE ( 32768 )
1483#define DFLT_ZLIB_RATIO ( 5 )
1484
1485/*
1486** Data structure and functions to work with sending compressed data
1487** via HTTP.
1488*/
1489
1490typedef struct xmlZMemBuff_
1491{
1492 unsigned long size;
1493 unsigned long crc;
1494
1495 unsigned char * zbuff;
1496 z_stream zctrl;
1497
1498} xmlZMemBuff, *xmlZMemBuffPtr;
1499
1500/**
1501 * append_reverse_ulong
1502 * @buff: Compressed memory buffer
1503 * @data: Unsigned long to append
1504 *
1505 * Append a unsigned long in reverse byte order to the end of the
1506 * memory buffer.
1507 */
1508static void
1509append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) {
1510
1511 int idx;
1512
1513 if ( buff == NULL )
1514 return;
1515
1516 /*
1517 ** This is plagiarized from putLong in gzio.c (zlib source) where
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001518 ** the number "4" is hardcoded. If zlib is ever patched to
Daniel Veillardf012a642001-07-23 19:10:52 +00001519 ** support 64 bit file sizes, this code would need to be patched
1520 ** as well.
1521 */
1522
1523 for ( idx = 0; idx < 4; idx++ ) {
1524 *buff->zctrl.next_out = ( data & 0xff );
1525 data >>= 8;
1526 buff->zctrl.next_out++;
1527 }
1528
1529 return;
1530}
1531
1532/**
1533 *
1534 * xmlFreeZMemBuff
1535 * @buff: The memory buffer context to clear
1536 *
1537 * Release all the resources associated with the compressed memory buffer.
1538 */
1539static void
1540xmlFreeZMemBuff( xmlZMemBuffPtr buff ) {
William M. Brack78637da2003-07-31 14:47:38 +00001541
1542#ifdef DEBUG_HTTP
Daniel Veillardf012a642001-07-23 19:10:52 +00001543 int z_err;
William M. Brack78637da2003-07-31 14:47:38 +00001544#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001545
1546 if ( buff == NULL )
1547 return;
1548
1549 xmlFree( buff->zbuff );
Daniel Veillardf012a642001-07-23 19:10:52 +00001550#ifdef DEBUG_HTTP
William M. Brack78637da2003-07-31 14:47:38 +00001551 z_err = deflateEnd( &buff->zctrl );
Daniel Veillardf012a642001-07-23 19:10:52 +00001552 if ( z_err != Z_OK )
1553 xmlGenericError( xmlGenericErrorContext,
1554 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
1555 z_err );
William M. Brack78637da2003-07-31 14:47:38 +00001556#else
1557 deflateEnd( &buff->zctrl );
William M. Brack779af002003-08-01 15:55:39 +00001558#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001559
1560 xmlFree( buff );
1561 return;
1562}
1563
1564/**
1565 * xmlCreateZMemBuff
1566 *@compression: Compression value to use
1567 *
1568 * Create a memory buffer to hold the compressed XML document. The
1569 * compressed document in memory will end up being identical to what
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001570 * would be created if gzopen/gzwrite/gzclose were being used to
Daniel Veillardf012a642001-07-23 19:10:52 +00001571 * write the document to disk. The code for the header/trailer data to
1572 * the compression is plagiarized from the zlib source files.
1573 */
1574static void *
1575xmlCreateZMemBuff( int compression ) {
1576
1577 int z_err;
1578 int hdr_lgth;
1579 xmlZMemBuffPtr buff = NULL;
1580
1581 if ( ( compression < 1 ) || ( compression > 9 ) )
1582 return ( NULL );
1583
1584 /* Create the control and data areas */
1585
1586 buff = xmlMalloc( sizeof( xmlZMemBuff ) );
1587 if ( buff == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001588 xmlIOErrMemory("creating buffer context");
Daniel Veillardf012a642001-07-23 19:10:52 +00001589 return ( NULL );
1590 }
1591
1592 (void)memset( buff, 0, sizeof( xmlZMemBuff ) );
1593 buff->size = INIT_HTTP_BUFF_SIZE;
1594 buff->zbuff = xmlMalloc( buff->size );
1595 if ( buff->zbuff == NULL ) {
1596 xmlFreeZMemBuff( buff );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001597 xmlIOErrMemory("creating buffer");
Daniel Veillardf012a642001-07-23 19:10:52 +00001598 return ( NULL );
1599 }
1600
1601 z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
1602 DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
1603 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001604 xmlChar msg[500];
Daniel Veillardf012a642001-07-23 19:10:52 +00001605 xmlFreeZMemBuff( buff );
1606 buff = NULL;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001607 xmlStrPrintf(msg, 500,
David Kilzer4472c3a2016-05-13 15:13:17 +08001608 "xmlCreateZMemBuff: %s %d\n",
Daniel Veillard05d987b2003-10-08 11:54:57 +00001609 "Error initializing compression context. ZLIB error:",
1610 z_err );
1611 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001612 return ( NULL );
1613 }
1614
1615 /* Set the header data. The CRC will be needed for the trailer */
Daniel Veillard24505b02005-07-28 23:49:35 +00001616 buff->crc = crc32( 0L, NULL, 0 );
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001617 hdr_lgth = snprintf( (char *)buff->zbuff, buff->size,
1618 "%c%c%c%c%c%c%c%c%c%c",
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001619 GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED,
Daniel Veillardf012a642001-07-23 19:10:52 +00001620 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE );
1621 buff->zctrl.next_out = buff->zbuff + hdr_lgth;
1622 buff->zctrl.avail_out = buff->size - hdr_lgth;
1623
1624 return ( buff );
1625}
1626
1627/**
1628 * xmlZMemBuffExtend
1629 * @buff: Buffer used to compress and consolidate data.
1630 * @ext_amt: Number of bytes to extend the buffer.
1631 *
1632 * Extend the internal buffer used to store the compressed data by the
1633 * specified amount.
1634 *
1635 * Returns 0 on success or -1 on failure to extend the buffer. On failure
1636 * the original buffer still exists at the original size.
1637 */
1638static int
1639xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) {
1640
1641 int rc = -1;
1642 size_t new_size;
1643 size_t cur_used;
1644
1645 unsigned char * tmp_ptr = NULL;
1646
1647 if ( buff == NULL )
1648 return ( -1 );
1649
1650 else if ( ext_amt == 0 )
1651 return ( 0 );
1652
1653 cur_used = buff->zctrl.next_out - buff->zbuff;
1654 new_size = buff->size + ext_amt;
1655
1656#ifdef DEBUG_HTTP
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001657 if ( cur_used > new_size )
Daniel Veillardf012a642001-07-23 19:10:52 +00001658 xmlGenericError( xmlGenericErrorContext,
1659 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
1660 "Buffer overwrite detected during compressed memory",
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001661 "buffer extension. Overflowed by",
Daniel Veillardf012a642001-07-23 19:10:52 +00001662 (cur_used - new_size ) );
1663#endif
1664
1665 tmp_ptr = xmlRealloc( buff->zbuff, new_size );
1666 if ( tmp_ptr != NULL ) {
1667 rc = 0;
1668 buff->size = new_size;
1669 buff->zbuff = tmp_ptr;
1670 buff->zctrl.next_out = tmp_ptr + cur_used;
1671 buff->zctrl.avail_out = new_size - cur_used;
1672 }
1673 else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001674 xmlChar msg[500];
1675 xmlStrPrintf(msg, 500,
David Kilzer4472c3a2016-05-13 15:13:17 +08001676 "xmlZMemBuffExtend: %s %lu bytes.\n",
Daniel Veillard05d987b2003-10-08 11:54:57 +00001677 "Allocation failure extending output buffer to",
Nick Wellnhoferc2545cb2016-08-22 11:44:18 +02001678 (unsigned long) new_size );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001679 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001680 }
1681
1682 return ( rc );
1683}
1684
1685/**
1686 * xmlZMemBuffAppend
1687 * @buff: Buffer used to compress and consolidate data
1688 * @src: Uncompressed source content to append to buffer
1689 * @len: Length of source data to append to buffer
1690 *
1691 * Compress and append data to the internal buffer. The data buffer
1692 * will be expanded if needed to store the additional data.
1693 *
1694 * Returns the number of bytes appended to the buffer or -1 on error.
1695 */
1696static int
1697xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) {
1698
1699 int z_err;
1700 size_t min_accept;
1701
1702 if ( ( buff == NULL ) || ( src == NULL ) )
1703 return ( -1 );
1704
1705 buff->zctrl.avail_in = len;
1706 buff->zctrl.next_in = (unsigned char *)src;
1707 while ( buff->zctrl.avail_in > 0 ) {
1708 /*
1709 ** Extend the buffer prior to deflate call if a reasonable amount
1710 ** of output buffer space is not available.
1711 */
1712 min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO;
1713 if ( buff->zctrl.avail_out <= min_accept ) {
1714 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1715 return ( -1 );
1716 }
1717
1718 z_err = deflate( &buff->zctrl, Z_NO_FLUSH );
1719 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001720 xmlChar msg[500];
1721 xmlStrPrintf(msg, 500,
David Kilzer4472c3a2016-05-13 15:13:17 +08001722 "xmlZMemBuffAppend: %s %d %s - %d",
Daniel Veillardf012a642001-07-23 19:10:52 +00001723 "Compression error while appending",
1724 len, "bytes to buffer. ZLIB error", z_err );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001725 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001726 return ( -1 );
1727 }
1728 }
1729
1730 buff->crc = crc32( buff->crc, (unsigned char *)src, len );
1731
1732 return ( len );
1733}
1734
1735/**
1736 * xmlZMemBuffGetContent
1737 * @buff: Compressed memory content buffer
1738 * @data_ref: Pointer reference to point to compressed content
1739 *
1740 * Flushes the compression buffers, appends gzip file trailers and
1741 * returns the compressed content and length of the compressed data.
1742 * NOTE: The gzip trailer code here is plagiarized from zlib source.
1743 *
1744 * Returns the length of the compressed data or -1 on error.
1745 */
1746static int
1747xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) {
1748
1749 int zlgth = -1;
1750 int z_err;
1751
1752 if ( ( buff == NULL ) || ( data_ref == NULL ) )
1753 return ( -1 );
1754
1755 /* Need to loop until compression output buffers are flushed */
1756
1757 do
1758 {
1759 z_err = deflate( &buff->zctrl, Z_FINISH );
1760 if ( z_err == Z_OK ) {
1761 /* In this case Z_OK means more buffer space needed */
1762
1763 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1764 return ( -1 );
1765 }
1766 }
1767 while ( z_err == Z_OK );
1768
1769 /* If the compression state is not Z_STREAM_END, some error occurred */
1770
1771 if ( z_err == Z_STREAM_END ) {
1772
1773 /* Need to append the gzip data trailer */
1774
1775 if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) {
1776 if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 )
1777 return ( -1 );
1778 }
1779
1780 /*
1781 ** For whatever reason, the CRC and length data are pushed out
1782 ** in reverse byte order. So a memcpy can't be used here.
1783 */
1784
1785 append_reverse_ulong( buff, buff->crc );
1786 append_reverse_ulong( buff, buff->zctrl.total_in );
1787
1788 zlgth = buff->zctrl.next_out - buff->zbuff;
1789 *data_ref = (char *)buff->zbuff;
1790 }
1791
Daniel Veillard05d987b2003-10-08 11:54:57 +00001792 else {
1793 xmlChar msg[500];
1794 xmlStrPrintf(msg, 500,
David Kilzer4472c3a2016-05-13 15:13:17 +08001795 "xmlZMemBuffGetContent: %s - %d\n",
Daniel Veillard05d987b2003-10-08 11:54:57 +00001796 "Error flushing zlib buffers. Error code", z_err );
1797 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1798 }
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001799
Daniel Veillardf012a642001-07-23 19:10:52 +00001800 return ( zlgth );
1801}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001802#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001803#endif /* HAVE_ZLIB_H */
1804
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001805#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001806/**
1807 * xmlFreeHTTPWriteCtxt
1808 * @ctxt: Context to cleanup
1809 *
1810 * Free allocated memory and reclaim system resources.
1811 *
1812 * No return value.
1813 */
1814static void
1815xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt )
1816{
1817 if ( ctxt->uri != NULL )
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001818 xmlFree( ctxt->uri );
Daniel Veillardf012a642001-07-23 19:10:52 +00001819
1820 if ( ctxt->doc_buff != NULL ) {
1821
1822#ifdef HAVE_ZLIB_H
1823 if ( ctxt->compression > 0 ) {
1824 xmlFreeZMemBuff( ctxt->doc_buff );
1825 }
1826 else
1827#endif
1828 {
1829 xmlOutputBufferClose( ctxt->doc_buff );
1830 }
1831 }
1832
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001833 xmlFree( ctxt );
Daniel Veillardf012a642001-07-23 19:10:52 +00001834 return;
1835}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001836#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001837
1838
Owen Taylor3473f882001-02-23 17:55:21 +00001839/**
1840 * xmlIOHTTPMatch:
1841 * @filename: the URI for matching
1842 *
1843 * check if the URI matches an HTTP one
1844 *
1845 * Returns 1 if matches, 0 otherwise
1846 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001847int
Owen Taylor3473f882001-02-23 17:55:21 +00001848xmlIOHTTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001849 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "http://", 7))
Owen Taylor3473f882001-02-23 17:55:21 +00001850 return(1);
1851 return(0);
1852}
1853
1854/**
1855 * xmlIOHTTPOpen:
1856 * @filename: the URI for matching
1857 *
1858 * open an HTTP I/O channel
1859 *
1860 * Returns an I/O context or NULL in case of error
1861 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001862void *
Owen Taylor3473f882001-02-23 17:55:21 +00001863xmlIOHTTPOpen (const char *filename) {
1864 return(xmlNanoHTTPOpen(filename, NULL));
1865}
1866
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001867#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001868/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001869 * xmlIOHTTPOpenW:
Daniel Veillardf012a642001-07-23 19:10:52 +00001870 * @post_uri: The destination URI for the document
1871 * @compression: The compression desired for the document.
1872 *
1873 * Open a temporary buffer to collect the document for a subsequent HTTP POST
1874 * request. Non-static as is called from the output buffer creation routine.
1875 *
1876 * Returns an I/O context or NULL in case of error.
1877 */
1878
1879void *
Daniel Veillard572577e2002-01-18 16:23:55 +00001880xmlIOHTTPOpenW(const char *post_uri, int compression)
1881{
Daniel Veillardf012a642001-07-23 19:10:52 +00001882
Daniel Veillard572577e2002-01-18 16:23:55 +00001883 xmlIOHTTPWriteCtxtPtr ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001884
Daniel Veillard572577e2002-01-18 16:23:55 +00001885 if (post_uri == NULL)
1886 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001887
Daniel Veillard572577e2002-01-18 16:23:55 +00001888 ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt));
1889 if (ctxt == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001890 xmlIOErrMemory("creating HTTP output context");
Daniel Veillard572577e2002-01-18 16:23:55 +00001891 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001892 }
1893
Daniel Veillard572577e2002-01-18 16:23:55 +00001894 (void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt));
Daniel Veillardf012a642001-07-23 19:10:52 +00001895
Daniel Veillard572577e2002-01-18 16:23:55 +00001896 ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri);
1897 if (ctxt->uri == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001898 xmlIOErrMemory("copying URI");
Daniel Veillard572577e2002-01-18 16:23:55 +00001899 xmlFreeHTTPWriteCtxt(ctxt);
1900 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001901 }
1902
1903 /*
Daniel Veillard572577e2002-01-18 16:23:55 +00001904 * ** Since the document length is required for an HTTP post,
1905 * ** need to put the document into a buffer. A memory buffer
1906 * ** is being used to avoid pushing the data to disk and back.
1907 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001908
1909#ifdef HAVE_ZLIB_H
Daniel Veillard572577e2002-01-18 16:23:55 +00001910 if ((compression > 0) && (compression <= 9)) {
1911
1912 ctxt->compression = compression;
1913 ctxt->doc_buff = xmlCreateZMemBuff(compression);
1914 } else
Daniel Veillardf012a642001-07-23 19:10:52 +00001915#endif
1916 {
Daniel Veillard572577e2002-01-18 16:23:55 +00001917 /* Any character conversions should have been done before this */
Daniel Veillardf012a642001-07-23 19:10:52 +00001918
Daniel Veillardda3fee42008-09-01 13:08:57 +00001919 ctxt->doc_buff = xmlAllocOutputBufferInternal(NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001920 }
1921
Daniel Veillard572577e2002-01-18 16:23:55 +00001922 if (ctxt->doc_buff == NULL) {
1923 xmlFreeHTTPWriteCtxt(ctxt);
1924 ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001925 }
1926
Daniel Veillard572577e2002-01-18 16:23:55 +00001927 return (ctxt);
Daniel Veillardf012a642001-07-23 19:10:52 +00001928}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001929#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardda3fee42008-09-01 13:08:57 +00001930
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001931#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001932/**
1933 * xmlIOHTTPDfltOpenW
1934 * @post_uri: The destination URI for this document.
1935 *
1936 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
1937 * HTTP post command. This function should generally not be used as
1938 * the open callback is short circuited in xmlOutputBufferCreateFile.
1939 *
1940 * Returns a pointer to the new IO context.
1941 */
1942static void *
1943xmlIOHTTPDfltOpenW( const char * post_uri ) {
1944 return ( xmlIOHTTPOpenW( post_uri, 0 ) );
1945}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001946#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001947
1948/**
Owen Taylor3473f882001-02-23 17:55:21 +00001949 * xmlIOHTTPRead:
1950 * @context: the I/O context
1951 * @buffer: where to drop data
1952 * @len: number of bytes to write
1953 *
1954 * Read @len bytes to @buffer from the I/O channel.
1955 *
1956 * Returns the number of bytes written
1957 */
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001958int
Owen Taylor3473f882001-02-23 17:55:21 +00001959xmlIOHTTPRead(void * context, char * buffer, int len) {
Daniel Veillard5ea30d72004-11-08 11:54:28 +00001960 if ((buffer == NULL) || (len < 0)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001961 return(xmlNanoHTTPRead(context, &buffer[0], len));
1962}
1963
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001964#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001965/**
Daniel Veillardf012a642001-07-23 19:10:52 +00001966 * xmlIOHTTPWrite
1967 * @context: previously opened writing context
1968 * @buffer: data to output to temporary buffer
1969 * @len: bytes to output
1970 *
1971 * Collect data from memory buffer into a temporary file for later
1972 * processing.
1973 *
1974 * Returns number of bytes written.
1975 */
1976
1977static int
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001978xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
Daniel Veillardf012a642001-07-23 19:10:52 +00001979
1980 xmlIOHTTPWriteCtxtPtr ctxt = context;
1981
1982 if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
1983 return ( -1 );
1984
1985 if ( len > 0 ) {
1986
1987 /* Use gzwrite or fwrite as previously setup in the open call */
1988
1989#ifdef HAVE_ZLIB_H
Hans Breuer2ad41ca2009-08-11 17:51:22 +02001990 if ( ctxt->compression > 0 )
Daniel Veillardf012a642001-07-23 19:10:52 +00001991 len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len );
1992
1993 else
1994#endif
1995 len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
1996
1997 if ( len < 0 ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001998 xmlChar msg[500];
1999 xmlStrPrintf(msg, 500,
David Kilzer4472c3a2016-05-13 15:13:17 +08002000 "xmlIOHTTPWrite: %s\n%s '%s'.\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00002001 "Error appending to internal buffer.",
2002 "Error sending document to URI",
2003 ctxt->uri );
Daniel Veillard05d987b2003-10-08 11:54:57 +00002004 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00002005 }
2006 }
2007
2008 return ( len );
2009}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002010#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00002011
2012
2013/**
Owen Taylor3473f882001-02-23 17:55:21 +00002014 * xmlIOHTTPClose:
2015 * @context: the I/O context
2016 *
2017 * Close an HTTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00002018 *
2019 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00002020 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002021int
Owen Taylor3473f882001-02-23 17:55:21 +00002022xmlIOHTTPClose (void * context) {
2023 xmlNanoHTTPClose(context);
Daniel Veillardf012a642001-07-23 19:10:52 +00002024 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002025}
Daniel Veillardf012a642001-07-23 19:10:52 +00002026
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002027#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00002028/**
2029 * xmlIOHTTCloseWrite
2030 * @context: The I/O context
2031 * @http_mthd: The HTTP method to be used when sending the data
2032 *
2033 * Close the transmit HTTP I/O channel and actually send the data.
2034 */
2035static int
2036xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
2037
2038 int close_rc = -1;
2039 int http_rtn = 0;
2040 int content_lgth = 0;
2041 xmlIOHTTPWriteCtxtPtr ctxt = context;
2042
2043 char * http_content = NULL;
2044 char * content_encoding = NULL;
2045 char * content_type = (char *) "text/xml";
2046 void * http_ctxt = NULL;
2047
2048 if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
2049 return ( -1 );
2050
2051 /* Retrieve the content from the appropriate buffer */
2052
2053#ifdef HAVE_ZLIB_H
2054
2055 if ( ctxt->compression > 0 ) {
2056 content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
2057 content_encoding = (char *) "Content-Encoding: gzip";
2058 }
2059 else
2060#endif
2061 {
2062 /* Pull the data out of the memory output buffer */
2063
2064 xmlOutputBufferPtr dctxt = ctxt->doc_buff;
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002065 http_content = (char *) xmlBufContent(dctxt->buffer);
2066 content_lgth = xmlBufUse(dctxt->buffer);
Daniel Veillardf012a642001-07-23 19:10:52 +00002067 }
2068
2069 if ( http_content == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002070 xmlChar msg[500];
2071 xmlStrPrintf(msg, 500,
David Kilzer4472c3a2016-05-13 15:13:17 +08002072 "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
Daniel Veillard05d987b2003-10-08 11:54:57 +00002073 "Error retrieving content.\nUnable to",
2074 http_mthd, "data to URI", ctxt->uri );
2075 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00002076 }
2077
2078 else {
2079
2080 http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
Hans Breuer2ad41ca2009-08-11 17:51:22 +02002081 &content_type, content_encoding,
Daniel Veillardf012a642001-07-23 19:10:52 +00002082 content_lgth );
2083
2084 if ( http_ctxt != NULL ) {
2085#ifdef DEBUG_HTTP
2086 /* If testing/debugging - dump reply with request content */
2087
2088 FILE * tst_file = NULL;
2089 char buffer[ 4096 ];
2090 char * dump_name = NULL;
2091 int avail;
2092
2093 xmlGenericError( xmlGenericErrorContext,
2094 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
2095 http_mthd, ctxt->uri,
2096 xmlNanoHTTPReturnCode( http_ctxt ) );
2097
2098 /*
2099 ** Since either content or reply may be gzipped,
Hans Breuer2ad41ca2009-08-11 17:51:22 +02002100 ** dump them to separate files instead of the
Daniel Veillardf012a642001-07-23 19:10:52 +00002101 ** standard error context.
2102 */
2103
2104 dump_name = tempnam( NULL, "lxml" );
2105 if ( dump_name != NULL ) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002106 (void)snprintf( buffer, sizeof(buffer), "%s.content", dump_name );
Daniel Veillardf012a642001-07-23 19:10:52 +00002107
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00002108 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00002109 if ( tst_file != NULL ) {
2110 xmlGenericError( xmlGenericErrorContext,
2111 "Transmitted content saved in file: %s\n", buffer );
2112
2113 fwrite( http_content, sizeof( char ),
2114 content_lgth, tst_file );
2115 fclose( tst_file );
2116 }
2117
Aleksey Sanin49cc9752002-06-14 17:07:10 +00002118 (void)snprintf( buffer, sizeof(buffer), "%s.reply", dump_name );
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00002119 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00002120 if ( tst_file != NULL ) {
2121 xmlGenericError( xmlGenericErrorContext,
2122 "Reply content saved in file: %s\n", buffer );
2123
2124
2125 while ( (avail = xmlNanoHTTPRead( http_ctxt,
2126 buffer, sizeof( buffer ) )) > 0 ) {
2127
2128 fwrite( buffer, sizeof( char ), avail, tst_file );
2129 }
2130
2131 fclose( tst_file );
2132 }
2133
2134 free( dump_name );
2135 }
2136#endif /* DEBUG_HTTP */
2137
2138 http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
2139 if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
2140 close_rc = 0;
Daniel Veillard05d987b2003-10-08 11:54:57 +00002141 else {
2142 xmlChar msg[500];
2143 xmlStrPrintf(msg, 500,
David Kilzer4472c3a2016-05-13 15:13:17 +08002144 "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00002145 http_mthd, content_lgth,
2146 "bytes to URI", ctxt->uri,
2147 "failed. HTTP return code:", http_rtn );
Daniel Veillard05d987b2003-10-08 11:54:57 +00002148 xmlIOErr(XML_IO_WRITE, (const char *) msg);
2149 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002150
2151 xmlNanoHTTPClose( http_ctxt );
2152 xmlFree( content_type );
2153 }
2154 }
2155
2156 /* Final cleanups */
2157
2158 xmlFreeHTTPWriteCtxt( ctxt );
2159
2160 return ( close_rc );
2161}
2162
2163/**
2164 * xmlIOHTTPClosePut
2165 *
2166 * @context: The I/O context
2167 *
2168 * Close the transmit HTTP I/O channel and actually send data using a PUT
2169 * HTTP method.
2170 */
2171static int
2172xmlIOHTTPClosePut( void * ctxt ) {
2173 return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
2174}
2175
2176
2177/**
2178 * xmlIOHTTPClosePost
2179 *
2180 * @context: The I/O context
2181 *
2182 * Close the transmit HTTP I/O channel and actually send data using a POST
2183 * HTTP method.
2184 */
2185static int
2186xmlIOHTTPClosePost( void * ctxt ) {
2187 return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
2188}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002189#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00002190
Owen Taylor3473f882001-02-23 17:55:21 +00002191#endif /* LIBXML_HTTP_ENABLED */
2192
2193#ifdef LIBXML_FTP_ENABLED
2194/************************************************************************
2195 * *
2196 * I/O for FTP file accesses *
2197 * *
2198 ************************************************************************/
2199/**
2200 * xmlIOFTPMatch:
2201 * @filename: the URI for matching
2202 *
2203 * check if the URI matches an FTP one
2204 *
2205 * Returns 1 if matches, 0 otherwise
2206 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002207int
Owen Taylor3473f882001-02-23 17:55:21 +00002208xmlIOFTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002209 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "ftp://", 6))
Owen Taylor3473f882001-02-23 17:55:21 +00002210 return(1);
2211 return(0);
2212}
2213
2214/**
2215 * xmlIOFTPOpen:
2216 * @filename: the URI for matching
2217 *
2218 * open an FTP I/O channel
2219 *
2220 * Returns an I/O context or NULL in case of error
2221 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002222void *
Owen Taylor3473f882001-02-23 17:55:21 +00002223xmlIOFTPOpen (const char *filename) {
2224 return(xmlNanoFTPOpen(filename));
2225}
2226
2227/**
2228 * xmlIOFTPRead:
2229 * @context: the I/O context
2230 * @buffer: where to drop data
2231 * @len: number of bytes to write
2232 *
2233 * Read @len bytes to @buffer from the I/O channel.
2234 *
2235 * Returns the number of bytes written
2236 */
Hans Breuer2ad41ca2009-08-11 17:51:22 +02002237int
Owen Taylor3473f882001-02-23 17:55:21 +00002238xmlIOFTPRead(void * context, char * buffer, int len) {
Daniel Veillard5ea30d72004-11-08 11:54:28 +00002239 if ((buffer == NULL) || (len < 0)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002240 return(xmlNanoFTPRead(context, &buffer[0], len));
2241}
2242
2243/**
2244 * xmlIOFTPClose:
2245 * @context: the I/O context
2246 *
2247 * Close an FTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00002248 *
2249 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00002250 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002251int
Owen Taylor3473f882001-02-23 17:55:21 +00002252xmlIOFTPClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +00002253 return ( xmlNanoFTPClose(context) );
Owen Taylor3473f882001-02-23 17:55:21 +00002254}
2255#endif /* LIBXML_FTP_ENABLED */
2256
2257
2258/**
2259 * xmlRegisterInputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002260 * @matchFunc: the xmlInputMatchCallback
2261 * @openFunc: the xmlInputOpenCallback
2262 * @readFunc: the xmlInputReadCallback
2263 * @closeFunc: the xmlInputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00002264 *
2265 * Register a new set of I/O callback for handling parser input.
2266 *
2267 * Returns the registered handler number or -1 in case of error
2268 */
2269int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002270xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
2271 xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
2272 xmlInputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002273 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
2274 return(-1);
2275 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002276 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
2277 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
2278 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
2279 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00002280 xmlInputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002281 return(xmlInputCallbackNr++);
2282}
2283
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002284#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002285/**
2286 * xmlRegisterOutputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002287 * @matchFunc: the xmlOutputMatchCallback
2288 * @openFunc: the xmlOutputOpenCallback
2289 * @writeFunc: the xmlOutputWriteCallback
2290 * @closeFunc: the xmlOutputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00002291 *
2292 * Register a new set of I/O callback for handling output.
2293 *
2294 * Returns the registered handler number or -1 in case of error
2295 */
2296int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002297xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
2298 xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
2299 xmlOutputCloseCallback closeFunc) {
Daniel Veillard0d5e58f2009-08-24 13:52:23 +02002300 if (xmlOutputCallbackNr >= MAX_OUTPUT_CALLBACK) {
Owen Taylor3473f882001-02-23 17:55:21 +00002301 return(-1);
2302 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002303 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
2304 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
2305 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
2306 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00002307 xmlOutputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002308 return(xmlOutputCallbackNr++);
2309}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002310#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002311
2312/**
2313 * xmlRegisterDefaultInputCallbacks:
2314 *
2315 * Registers the default compiled-in I/O handlers.
2316 */
2317void
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +00002318xmlRegisterDefaultInputCallbacks(void) {
Owen Taylor3473f882001-02-23 17:55:21 +00002319 if (xmlInputCallbackInitialized)
2320 return;
2321
Daniel Veillard8ca85b22006-09-01 09:56:07 +00002322#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
2323 xmlInitPlatformSpecificIo();
2324#endif
2325
Owen Taylor3473f882001-02-23 17:55:21 +00002326 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
2327 xmlFileRead, xmlFileClose);
2328#ifdef HAVE_ZLIB_H
2329 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
2330 xmlGzfileRead, xmlGzfileClose);
2331#endif /* HAVE_ZLIB_H */
Daniel Veillard18b89882015-11-03 15:46:29 +08002332#ifdef LIBXML_LZMA_ENABLED
Anders F Bjorklundeae52612011-09-18 16:59:13 +02002333 xmlRegisterInputCallbacks(xmlXzfileMatch, xmlXzfileOpen,
2334 xmlXzfileRead, xmlXzfileClose);
Daniel Veillard18b89882015-11-03 15:46:29 +08002335#endif /* LIBXML_LZMA_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002336
2337#ifdef LIBXML_HTTP_ENABLED
2338 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
2339 xmlIOHTTPRead, xmlIOHTTPClose);
2340#endif /* LIBXML_HTTP_ENABLED */
2341
2342#ifdef LIBXML_FTP_ENABLED
2343 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
2344 xmlIOFTPRead, xmlIOFTPClose);
2345#endif /* LIBXML_FTP_ENABLED */
2346 xmlInputCallbackInitialized = 1;
2347}
2348
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002349#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002350/**
2351 * xmlRegisterDefaultOutputCallbacks:
2352 *
2353 * Registers the default compiled-in I/O handlers.
2354 */
2355void
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +00002356xmlRegisterDefaultOutputCallbacks (void) {
Owen Taylor3473f882001-02-23 17:55:21 +00002357 if (xmlOutputCallbackInitialized)
2358 return;
2359
Daniel Veillard8ca85b22006-09-01 09:56:07 +00002360#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
2361 xmlInitPlatformSpecificIo();
2362#endif
2363
Owen Taylor3473f882001-02-23 17:55:21 +00002364 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
2365 xmlFileWrite, xmlFileClose);
Daniel Veillardf012a642001-07-23 19:10:52 +00002366
2367#ifdef LIBXML_HTTP_ENABLED
2368 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
2369 xmlIOHTTPWrite, xmlIOHTTPClosePut);
2370#endif
2371
Owen Taylor3473f882001-02-23 17:55:21 +00002372/*********************************
2373 No way a-priori to distinguish between gzipped files from
2374 uncompressed ones except opening if existing then closing
2375 and saving with same compression ratio ... a pain.
2376
2377#ifdef HAVE_ZLIB_H
2378 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
2379 xmlGzfileWrite, xmlGzfileClose);
2380#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002381
2382 Nor FTP PUT ....
2383#ifdef LIBXML_FTP_ENABLED
2384 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
2385 xmlIOFTPWrite, xmlIOFTPClose);
2386#endif
2387 **********************************/
2388 xmlOutputCallbackInitialized = 1;
2389}
2390
Daniel Veillardf012a642001-07-23 19:10:52 +00002391#ifdef LIBXML_HTTP_ENABLED
2392/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00002393 * xmlRegisterHTTPPostCallbacks:
Daniel Veillardf012a642001-07-23 19:10:52 +00002394 *
2395 * By default, libxml submits HTTP output requests using the "PUT" method.
2396 * Calling this method changes the HTTP output method to use the "POST"
2397 * method instead.
2398 *
2399 */
2400void
2401xmlRegisterHTTPPostCallbacks( void ) {
2402
2403 /* Register defaults if not done previously */
2404
2405 if ( xmlOutputCallbackInitialized == 0 )
2406 xmlRegisterDefaultOutputCallbacks( );
2407
2408 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
2409 xmlIOHTTPWrite, xmlIOHTTPClosePost);
2410 return;
2411}
2412#endif
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002413#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00002414
Owen Taylor3473f882001-02-23 17:55:21 +00002415/**
2416 * xmlAllocParserInputBuffer:
2417 * @enc: the charset encoding if known
2418 *
2419 * Create a buffered parser input for progressive parsing
2420 *
2421 * Returns the new parser input or NULL
2422 */
2423xmlParserInputBufferPtr
2424xmlAllocParserInputBuffer(xmlCharEncoding enc) {
2425 xmlParserInputBufferPtr ret;
2426
2427 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2428 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002429 xmlIOErrMemory("creating input buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00002430 return(NULL);
2431 }
2432 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002433 ret->buffer = xmlBufCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00002434 if (ret->buffer == NULL) {
2435 xmlFree(ret);
2436 return(NULL);
2437 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002438 xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_DOUBLEIT);
Owen Taylor3473f882001-02-23 17:55:21 +00002439 ret->encoder = xmlGetCharEncodingHandler(enc);
2440 if (ret->encoder != NULL)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002441 ret->raw = xmlBufCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00002442 else
2443 ret->raw = NULL;
2444 ret->readcallback = NULL;
2445 ret->closecallback = NULL;
2446 ret->context = NULL;
William M. Brackc07329e2003-09-08 01:57:30 +00002447 ret->compressed = -1;
Daniel Veillard36711902004-02-11 13:25:26 +00002448 ret->rawconsumed = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002449
2450 return(ret);
2451}
2452
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002453#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002454/**
2455 * xmlAllocOutputBuffer:
2456 * @encoder: the encoding converter or NULL
2457 *
2458 * Create a buffered parser output
2459 *
2460 * Returns the new parser output or NULL
2461 */
2462xmlOutputBufferPtr
2463xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
2464 xmlOutputBufferPtr ret;
2465
2466 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
2467 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002468 xmlIOErrMemory("creating output buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00002469 return(NULL);
2470 }
2471 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002472 ret->buffer = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00002473 if (ret->buffer == NULL) {
2474 xmlFree(ret);
2475 return(NULL);
2476 }
Daniel Veillarde83e93e2008-08-30 12:52:26 +00002477
Daniel Veillard43bc89c2009-03-23 19:32:04 +00002478 /* try to avoid a performance problem with Windows realloc() */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002479 if (xmlBufGetAllocationScheme(ret->buffer) == XML_BUFFER_ALLOC_EXACT)
2480 xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_DOUBLEIT);
Daniel Veillard43bc89c2009-03-23 19:32:04 +00002481
Daniel Veillardda3fee42008-09-01 13:08:57 +00002482 ret->encoder = encoder;
2483 if (encoder != NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002484 ret->conv = xmlBufCreateSize(4000);
Daniel Veillardda3fee42008-09-01 13:08:57 +00002485 if (ret->conv == NULL) {
2486 xmlFree(ret);
2487 return(NULL);
2488 }
2489
2490 /*
2491 * This call is designed to initiate the encoder state
2492 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002493 xmlCharEncOutput(ret, 1);
Daniel Veillardda3fee42008-09-01 13:08:57 +00002494 } else
2495 ret->conv = NULL;
2496 ret->writecallback = NULL;
2497 ret->closecallback = NULL;
2498 ret->context = NULL;
2499 ret->written = 0;
2500
2501 return(ret);
2502}
2503
2504/**
2505 * xmlAllocOutputBufferInternal:
2506 * @encoder: the encoding converter or NULL
2507 *
2508 * Create a buffered parser output
2509 *
2510 * Returns the new parser output or NULL
2511 */
2512xmlOutputBufferPtr
2513xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder) {
2514 xmlOutputBufferPtr ret;
2515
2516 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
2517 if (ret == NULL) {
2518 xmlIOErrMemory("creating output buffer");
2519 return(NULL);
2520 }
2521 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002522 ret->buffer = xmlBufCreate();
Daniel Veillardda3fee42008-09-01 13:08:57 +00002523 if (ret->buffer == NULL) {
2524 xmlFree(ret);
2525 return(NULL);
2526 }
2527
2528
Daniel Veillarde83e93e2008-08-30 12:52:26 +00002529 /*
2530 * For conversion buffers we use the special IO handling
2531 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002532 xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_IO);
Daniel Veillarde83e93e2008-08-30 12:52:26 +00002533
Owen Taylor3473f882001-02-23 17:55:21 +00002534 ret->encoder = encoder;
2535 if (encoder != NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002536 ret->conv = xmlBufCreateSize(4000);
Daniel Veillarde83e93e2008-08-30 12:52:26 +00002537 if (ret->conv == NULL) {
2538 xmlFree(ret);
2539 return(NULL);
2540 }
2541
Owen Taylor3473f882001-02-23 17:55:21 +00002542 /*
2543 * This call is designed to initiate the encoder state
2544 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002545 xmlCharEncOutput(ret, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00002546 } else
2547 ret->conv = NULL;
2548 ret->writecallback = NULL;
2549 ret->closecallback = NULL;
2550 ret->context = NULL;
2551 ret->written = 0;
2552
2553 return(ret);
2554}
Daniel Veillardda3fee42008-09-01 13:08:57 +00002555
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002556#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002557
2558/**
2559 * xmlFreeParserInputBuffer:
2560 * @in: a buffered parser input
2561 *
2562 * Free up the memory used by a buffered parser input
2563 */
2564void
2565xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
Daniel Veillard8d8bf2c2003-09-17 19:36:25 +00002566 if (in == NULL) return;
2567
Owen Taylor3473f882001-02-23 17:55:21 +00002568 if (in->raw) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002569 xmlBufFree(in->raw);
Owen Taylor3473f882001-02-23 17:55:21 +00002570 in->raw = NULL;
2571 }
2572 if (in->encoder != NULL) {
2573 xmlCharEncCloseFunc(in->encoder);
2574 }
2575 if (in->closecallback != NULL) {
2576 in->closecallback(in->context);
2577 }
2578 if (in->buffer != NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002579 xmlBufFree(in->buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00002580 in->buffer = NULL;
2581 }
2582
Owen Taylor3473f882001-02-23 17:55:21 +00002583 xmlFree(in);
2584}
2585
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002586#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002587/**
2588 * xmlOutputBufferClose:
2589 * @out: a buffered output
2590 *
2591 * flushes and close the output I/O channel
2592 * and free up all the associated resources
2593 *
2594 * Returns the number of byte written or -1 in case of error.
2595 */
2596int
Daniel Veillard828ce832003-10-08 19:19:10 +00002597xmlOutputBufferClose(xmlOutputBufferPtr out)
2598{
Owen Taylor3473f882001-02-23 17:55:21 +00002599 int written;
Daniel Veillardf012a642001-07-23 19:10:52 +00002600 int err_rc = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002601
2602 if (out == NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002603 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002604 if (out->writecallback != NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002605 xmlOutputBufferFlush(out);
Owen Taylor3473f882001-02-23 17:55:21 +00002606 if (out->closecallback != NULL) {
Daniel Veillard828ce832003-10-08 19:19:10 +00002607 err_rc = out->closecallback(out->context);
Owen Taylor3473f882001-02-23 17:55:21 +00002608 }
2609 written = out->written;
2610 if (out->conv) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002611 xmlBufFree(out->conv);
Daniel Veillard828ce832003-10-08 19:19:10 +00002612 out->conv = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002613 }
2614 if (out->encoder != NULL) {
2615 xmlCharEncCloseFunc(out->encoder);
2616 }
2617 if (out->buffer != NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08002618 xmlBufFree(out->buffer);
Daniel Veillard828ce832003-10-08 19:19:10 +00002619 out->buffer = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002620 }
2621
Daniel Veillard828ce832003-10-08 19:19:10 +00002622 if (out->error)
2623 err_rc = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00002624 xmlFree(out);
Daniel Veillard828ce832003-10-08 19:19:10 +00002625 return ((err_rc == 0) ? written : err_rc);
Owen Taylor3473f882001-02-23 17:55:21 +00002626}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002627#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002628
Daniel Veillard1b243b42004-06-08 10:16:42 +00002629xmlParserInputBufferPtr
Daniel Veillard0335a842004-06-02 16:18:40 +00002630__xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002631 xmlParserInputBufferPtr ret;
Daniel Veillard388236f2001-07-08 18:35:48 +00002632 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002633 void *context = NULL;
2634
2635 if (xmlInputCallbackInitialized == 0)
2636 xmlRegisterDefaultInputCallbacks();
2637
2638 if (URI == NULL) return(NULL);
2639
2640 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002641 * Try to find one of the input accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002642 * Go in reverse to give precedence to user defined handlers.
Daniel Veillard388236f2001-07-08 18:35:48 +00002643 */
2644 if (context == NULL) {
2645 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
2646 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
2647 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002648 context = xmlInputCallbackTable[i].opencallback(URI);
Daniel Veillard847332a2003-10-18 11:29:40 +00002649 if (context != NULL) {
Daniel Veillard388236f2001-07-08 18:35:48 +00002650 break;
Daniel Veillard847332a2003-10-18 11:29:40 +00002651 }
Daniel Veillard388236f2001-07-08 18:35:48 +00002652 }
Owen Taylor3473f882001-02-23 17:55:21 +00002653 }
2654 }
2655 if (context == NULL) {
2656 return(NULL);
2657 }
2658
2659 /*
2660 * Allocate the Input buffer front-end.
2661 */
2662 ret = xmlAllocParserInputBuffer(enc);
2663 if (ret != NULL) {
2664 ret->context = context;
2665 ret->readcallback = xmlInputCallbackTable[i].readcallback;
2666 ret->closecallback = xmlInputCallbackTable[i].closecallback;
William M. Brackc07329e2003-09-08 01:57:30 +00002667#ifdef HAVE_ZLIB_H
William M. Brackc5cbf992003-10-29 22:15:13 +00002668 if ((xmlInputCallbackTable[i].opencallback == xmlGzfileOpen) &&
2669 (strcmp(URI, "-") != 0)) {
Mark Adlera7e79f22010-01-19 16:28:48 +01002670#if defined(ZLIB_VERNUM) && ZLIB_VERNUM >= 0x1230
2671 ret->compressed = !gzdirect(context);
2672#else
William M. Brackc07329e2003-09-08 01:57:30 +00002673 if (((z_stream *)context)->avail_in > 4) {
2674 char *cptr, buff4[4];
Daniel Veillard07cb8222003-09-10 10:51:05 +00002675 cptr = (char *) ((z_stream *)context)->next_in;
William M. Brackc07329e2003-09-08 01:57:30 +00002676 if (gzread(context, buff4, 4) == 4) {
2677 if (strncmp(buff4, cptr, 4) == 0)
2678 ret->compressed = 0;
2679 else
2680 ret->compressed = 1;
2681 gzrewind(context);
2682 }
2683 }
Mark Adlera7e79f22010-01-19 16:28:48 +01002684#endif
William M. Brackc07329e2003-09-08 01:57:30 +00002685 }
2686#endif
Daniel Veillard18b89882015-11-03 15:46:29 +08002687#ifdef LIBXML_LZMA_ENABLED
Daniel Veillard63588f42013-05-10 14:01:46 +08002688 if ((xmlInputCallbackTable[i].opencallback == xmlXzfileOpen) &&
2689 (strcmp(URI, "-") != 0)) {
2690 ret->compressed = __libxml2_xzcompressed(context);
2691 }
2692#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002693 }
William M. Brack42331a92004-07-29 07:07:16 +00002694 else
2695 xmlInputCallbackTable[i].closecallback (context);
2696
Owen Taylor3473f882001-02-23 17:55:21 +00002697 return(ret);
2698}
2699
2700/**
Daniel Veillard0335a842004-06-02 16:18:40 +00002701 * xmlParserInputBufferCreateFilename:
Owen Taylor3473f882001-02-23 17:55:21 +00002702 * @URI: a C string containing the URI or filename
Daniel Veillard0335a842004-06-02 16:18:40 +00002703 * @enc: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002704 *
Daniel Veillard0335a842004-06-02 16:18:40 +00002705 * Create a buffered parser input for the progressive parsing of a file
2706 * If filename is "-' then we use stdin as the input.
Owen Taylor3473f882001-02-23 17:55:21 +00002707 * Automatic support for ZLIB/Compress compressed document is provided
2708 * by default if found at compile-time.
Daniel Veillard0335a842004-06-02 16:18:40 +00002709 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
Owen Taylor3473f882001-02-23 17:55:21 +00002710 *
Daniel Veillard0335a842004-06-02 16:18:40 +00002711 * Returns the new parser input or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00002712 */
Daniel Veillard0335a842004-06-02 16:18:40 +00002713xmlParserInputBufferPtr
2714xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
2715 if ((xmlParserInputBufferCreateFilenameValue)) {
2716 return xmlParserInputBufferCreateFilenameValue(URI, enc);
2717 }
2718 return __xmlParserInputBufferCreateFilename(URI, enc);
2719}
2720
2721#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard1b243b42004-06-08 10:16:42 +00002722xmlOutputBufferPtr
Daniel Veillard0335a842004-06-02 16:18:40 +00002723__xmlOutputBufferCreateFilename(const char *URI,
Owen Taylor3473f882001-02-23 17:55:21 +00002724 xmlCharEncodingHandlerPtr encoder,
Daniel Veillard0335a842004-06-02 16:18:40 +00002725 int compression ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00002726 xmlOutputBufferPtr ret;
Daniel Veillard966a31e2004-05-09 02:58:44 +00002727 xmlURIPtr puri;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002728 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002729 void *context = NULL;
Daniel Veillard966a31e2004-05-09 02:58:44 +00002730 char *unescaped = NULL;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002731#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002732 int is_file_uri = 1;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002733#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00002734
Owen Taylor3473f882001-02-23 17:55:21 +00002735 if (xmlOutputCallbackInitialized == 0)
2736 xmlRegisterDefaultOutputCallbacks();
2737
2738 if (URI == NULL) return(NULL);
2739
Daniel Veillard966a31e2004-05-09 02:58:44 +00002740 puri = xmlParseURI(URI);
2741 if (puri != NULL) {
Daniel Veillard8fcd2ca2005-07-03 14:42:56 +00002742#ifdef HAVE_ZLIB_H
Daniel Veillard18a65092004-05-11 15:57:42 +00002743 if ((puri->scheme != NULL) &&
2744 (!xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
Daniel Veillard966a31e2004-05-09 02:58:44 +00002745 is_file_uri = 0;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002746#endif
Daniel Veillard966a31e2004-05-09 02:58:44 +00002747 /*
2748 * try to limit the damages of the URI unescaping code.
2749 */
Daniel Veillarde8967e02006-10-11 09:15:00 +00002750 if ((puri->scheme == NULL) ||
2751 (xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
Daniel Veillard966a31e2004-05-09 02:58:44 +00002752 unescaped = xmlURIUnescapeString(URI, 0, NULL);
2753 xmlFreeURI(puri);
2754 }
Owen Taylor3473f882001-02-23 17:55:21 +00002755
2756 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002757 * Try to find one of the output accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002758 * Go in reverse to give precedence to user defined handlers.
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002759 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00002760 */
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002761 if (unescaped != NULL) {
2762#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002763 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002764 context = xmlGzfileOpenW(unescaped, compression);
2765 if (context != NULL) {
Daniel Veillardda3fee42008-09-01 13:08:57 +00002766 ret = xmlAllocOutputBufferInternal(encoder);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002767 if (ret != NULL) {
2768 ret->context = context;
2769 ret->writecallback = xmlGzfileWrite;
2770 ret->closecallback = xmlGzfileClose;
2771 }
2772 xmlFree(unescaped);
2773 return(ret);
2774 }
2775 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002776#endif
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002777 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2778 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
2779 (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
2780#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2781 /* Need to pass compression parameter into HTTP open calls */
2782 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2783 context = xmlIOHTTPOpenW(unescaped, compression);
2784 else
2785#endif
2786 context = xmlOutputCallbackTable[i].opencallback(unescaped);
2787 if (context != NULL)
2788 break;
2789 }
2790 }
2791 xmlFree(unescaped);
2792 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002793
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002794 /*
2795 * If this failed try with a non-escaped URI this may be a strange
2796 * filename
2797 */
2798 if (context == NULL) {
2799#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002800 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002801 context = xmlGzfileOpenW(URI, compression);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002802 if (context != NULL) {
Daniel Veillardda3fee42008-09-01 13:08:57 +00002803 ret = xmlAllocOutputBufferInternal(encoder);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002804 if (ret != NULL) {
2805 ret->context = context;
2806 ret->writecallback = xmlGzfileWrite;
2807 ret->closecallback = xmlGzfileClose;
2808 }
2809 return(ret);
2810 }
2811 }
2812#endif
2813 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2814 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002815 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002816#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2817 /* Need to pass compression parameter into HTTP open calls */
2818 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2819 context = xmlIOHTTPOpenW(URI, compression);
2820 else
2821#endif
2822 context = xmlOutputCallbackTable[i].opencallback(URI);
2823 if (context != NULL)
2824 break;
2825 }
Owen Taylor3473f882001-02-23 17:55:21 +00002826 }
2827 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002828
Owen Taylor3473f882001-02-23 17:55:21 +00002829 if (context == NULL) {
2830 return(NULL);
2831 }
2832
2833 /*
2834 * Allocate the Output buffer front-end.
2835 */
Daniel Veillardda3fee42008-09-01 13:08:57 +00002836 ret = xmlAllocOutputBufferInternal(encoder);
Owen Taylor3473f882001-02-23 17:55:21 +00002837 if (ret != NULL) {
2838 ret->context = context;
2839 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
2840 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
2841 }
2842 return(ret);
2843}
Daniel Veillard0335a842004-06-02 16:18:40 +00002844
2845/**
2846 * xmlOutputBufferCreateFilename:
2847 * @URI: a C string containing the URI or filename
2848 * @encoder: the encoding converter or NULL
2849 * @compression: the compression ration (0 none, 9 max).
2850 *
2851 * Create a buffered output for the progressive saving of a file
2852 * If filename is "-' then we use stdout as the output.
2853 * Automatic support for ZLIB/Compress compressed document is provided
2854 * by default if found at compile-time.
2855 * TODO: currently if compression is set, the library only support
2856 * writing to a local file.
2857 *
2858 * Returns the new output or NULL
2859 */
2860xmlOutputBufferPtr
2861xmlOutputBufferCreateFilename(const char *URI,
2862 xmlCharEncodingHandlerPtr encoder,
2863 int compression ATTRIBUTE_UNUSED) {
2864 if ((xmlOutputBufferCreateFilenameValue)) {
2865 return xmlOutputBufferCreateFilenameValue(URI, encoder, compression);
2866 }
2867 return __xmlOutputBufferCreateFilename(URI, encoder, compression);
2868}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002869#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002870
2871/**
2872 * xmlParserInputBufferCreateFile:
Hans Breuer2ad41ca2009-08-11 17:51:22 +02002873 * @file: a FILE*
Owen Taylor3473f882001-02-23 17:55:21 +00002874 * @enc: the charset encoding if known
2875 *
2876 * Create a buffered parser input for the progressive parsing of a FILE *
2877 * buffered C I/O
2878 *
2879 * Returns the new parser input or NULL
2880 */
2881xmlParserInputBufferPtr
2882xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
2883 xmlParserInputBufferPtr ret;
2884
2885 if (xmlInputCallbackInitialized == 0)
2886 xmlRegisterDefaultInputCallbacks();
2887
2888 if (file == NULL) return(NULL);
2889
2890 ret = xmlAllocParserInputBuffer(enc);
2891 if (ret != NULL) {
2892 ret->context = file;
2893 ret->readcallback = xmlFileRead;
2894 ret->closecallback = xmlFileFlush;
2895 }
2896
2897 return(ret);
2898}
2899
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002900#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002901/**
2902 * xmlOutputBufferCreateFile:
Hans Breuer2ad41ca2009-08-11 17:51:22 +02002903 * @file: a FILE*
Owen Taylor3473f882001-02-23 17:55:21 +00002904 * @encoder: the encoding converter or NULL
2905 *
2906 * Create a buffered output for the progressive saving to a FILE *
2907 * buffered C I/O
2908 *
2909 * Returns the new parser output or NULL
2910 */
2911xmlOutputBufferPtr
2912xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
2913 xmlOutputBufferPtr ret;
2914
2915 if (xmlOutputCallbackInitialized == 0)
2916 xmlRegisterDefaultOutputCallbacks();
2917
2918 if (file == NULL) return(NULL);
2919
Daniel Veillardda3fee42008-09-01 13:08:57 +00002920 ret = xmlAllocOutputBufferInternal(encoder);
Owen Taylor3473f882001-02-23 17:55:21 +00002921 if (ret != NULL) {
2922 ret->context = file;
2923 ret->writecallback = xmlFileWrite;
2924 ret->closecallback = xmlFileFlush;
2925 }
2926
2927 return(ret);
2928}
Daniel Veillard9a00fd22005-11-09 08:56:26 +00002929
2930/**
2931 * xmlOutputBufferCreateBuffer:
2932 * @buffer: a xmlBufferPtr
2933 * @encoder: the encoding converter or NULL
2934 *
2935 * Create a buffered output for the progressive saving to a xmlBuffer
2936 *
2937 * Returns the new parser output or NULL
2938 */
2939xmlOutputBufferPtr
2940xmlOutputBufferCreateBuffer(xmlBufferPtr buffer,
2941 xmlCharEncodingHandlerPtr encoder) {
2942 xmlOutputBufferPtr ret;
2943
2944 if (buffer == NULL) return(NULL);
2945
Rob Richardsa44f2342005-11-09 18:03:45 +00002946 ret = xmlOutputBufferCreateIO((xmlOutputWriteCallback)
2947 xmlBufferWrite,
2948 (xmlOutputCloseCallback)
Daniel Veillard4d3866c2005-11-13 12:43:59 +00002949 NULL, (void *) buffer, encoder);
Daniel Veillard9a00fd22005-11-09 08:56:26 +00002950
2951 return(ret);
2952}
2953
Daniel Veillarde258ade2012-08-06 11:16:30 +08002954/**
2955 * xmlOutputBufferGetContent:
2956 * @out: an xmlOutputBufferPtr
2957 *
2958 * Gives a pointer to the data currently held in the output buffer
2959 *
2960 * Returns a pointer to the data or NULL in case of error
2961 */
2962const xmlChar *
2963xmlOutputBufferGetContent(xmlOutputBufferPtr out) {
2964 if ((out == NULL) || (out->buffer == NULL))
2965 return(NULL);
2966
2967 return(xmlBufContent(out->buffer));
2968}
2969
2970/**
2971 * xmlOutputBufferGetSize:
2972 * @out: an xmlOutputBufferPtr
2973 *
2974 * Gives the length of the data currently held in the output buffer
2975 *
2976 * Returns 0 in case or error or no data is held, the size otherwise
2977 */
2978size_t
2979xmlOutputBufferGetSize(xmlOutputBufferPtr out) {
2980 if ((out == NULL) || (out->buffer == NULL))
2981 return(0);
2982
2983 return(xmlBufUse(out->buffer));
2984}
2985
2986
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002987#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002988
2989/**
2990 * xmlParserInputBufferCreateFd:
2991 * @fd: a file descriptor number
2992 * @enc: the charset encoding if known
2993 *
2994 * Create a buffered parser input for the progressive parsing for the input
2995 * from a file descriptor
2996 *
2997 * Returns the new parser input or NULL
2998 */
2999xmlParserInputBufferPtr
3000xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
3001 xmlParserInputBufferPtr ret;
3002
3003 if (fd < 0) return(NULL);
3004
3005 ret = xmlAllocParserInputBuffer(enc);
3006 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00003007 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00003008 ret->readcallback = xmlFdRead;
3009 ret->closecallback = xmlFdClose;
3010 }
3011
3012 return(ret);
3013}
3014
3015/**
3016 * xmlParserInputBufferCreateMem:
3017 * @mem: the memory input
3018 * @size: the length of the memory block
3019 * @enc: the charset encoding if known
3020 *
3021 * Create a buffered parser input for the progressive parsing for the input
3022 * from a memory area.
3023 *
3024 * Returns the new parser input or NULL
3025 */
3026xmlParserInputBufferPtr
3027xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
3028 xmlParserInputBufferPtr ret;
William M. Bracka3215c72004-07-31 16:24:01 +00003029 int errcode;
Owen Taylor3473f882001-02-23 17:55:21 +00003030
3031 if (size <= 0) return(NULL);
3032 if (mem == NULL) return(NULL);
3033
3034 ret = xmlAllocParserInputBuffer(enc);
3035 if (ret != NULL) {
3036 ret->context = (void *) mem;
3037 ret->readcallback = (xmlInputReadCallback) xmlNop;
3038 ret->closecallback = NULL;
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003039 errcode = xmlBufAdd(ret->buffer, (const xmlChar *) mem, size);
William M. Bracka3215c72004-07-31 16:24:01 +00003040 if (errcode != 0) {
3041 xmlFree(ret);
3042 return(NULL);
3043 }
Owen Taylor3473f882001-02-23 17:55:21 +00003044 }
3045
3046 return(ret);
3047}
3048
3049/**
Daniel Veillard53350552003-09-18 13:35:51 +00003050 * xmlParserInputBufferCreateStatic:
3051 * @mem: the memory input
3052 * @size: the length of the memory block
3053 * @enc: the charset encoding if known
3054 *
3055 * Create a buffered parser input for the progressive parsing for the input
3056 * from an immutable memory area. This will not copy the memory area to
3057 * the buffer, but the memory is expected to be available until the end of
3058 * the parsing, this is useful for example when using mmap'ed file.
3059 *
3060 * Returns the new parser input or NULL
3061 */
3062xmlParserInputBufferPtr
3063xmlParserInputBufferCreateStatic(const char *mem, int size,
3064 xmlCharEncoding enc) {
3065 xmlParserInputBufferPtr ret;
3066
3067 if (size <= 0) return(NULL);
3068 if (mem == NULL) return(NULL);
3069
3070 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
3071 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003072 xmlIOErrMemory("creating input buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00003073 return(NULL);
3074 }
3075 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003076 ret->buffer = xmlBufCreateStatic((void *)mem, (size_t) size);
Daniel Veillard53350552003-09-18 13:35:51 +00003077 if (ret->buffer == NULL) {
3078 xmlFree(ret);
3079 return(NULL);
3080 }
3081 ret->encoder = xmlGetCharEncodingHandler(enc);
3082 if (ret->encoder != NULL)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003083 ret->raw = xmlBufCreateSize(2 * xmlDefaultBufferSize);
Daniel Veillard53350552003-09-18 13:35:51 +00003084 else
3085 ret->raw = NULL;
3086 ret->compressed = -1;
3087 ret->context = (void *) mem;
3088 ret->readcallback = NULL;
3089 ret->closecallback = NULL;
3090
3091 return(ret);
3092}
3093
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003094#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard53350552003-09-18 13:35:51 +00003095/**
Owen Taylor3473f882001-02-23 17:55:21 +00003096 * xmlOutputBufferCreateFd:
3097 * @fd: a file descriptor number
3098 * @encoder: the encoding converter or NULL
3099 *
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003100 * Create a buffered output for the progressive saving
Owen Taylor3473f882001-02-23 17:55:21 +00003101 * to a file descriptor
3102 *
3103 * Returns the new parser output or NULL
3104 */
3105xmlOutputBufferPtr
3106xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
3107 xmlOutputBufferPtr ret;
3108
3109 if (fd < 0) return(NULL);
3110
Daniel Veillardda3fee42008-09-01 13:08:57 +00003111 ret = xmlAllocOutputBufferInternal(encoder);
Owen Taylor3473f882001-02-23 17:55:21 +00003112 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00003113 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00003114 ret->writecallback = xmlFdWrite;
Daniel Veillard7db38712002-02-07 16:39:11 +00003115 ret->closecallback = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00003116 }
3117
3118 return(ret);
3119}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003120#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003121
3122/**
3123 * xmlParserInputBufferCreateIO:
3124 * @ioread: an I/O read function
3125 * @ioclose: an I/O close function
3126 * @ioctx: an I/O handler
3127 * @enc: the charset encoding if known
3128 *
3129 * Create a buffered parser input for the progressive parsing for the input
3130 * from an I/O handler
3131 *
3132 * Returns the new parser input or NULL
3133 */
3134xmlParserInputBufferPtr
3135xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
3136 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
3137 xmlParserInputBufferPtr ret;
3138
3139 if (ioread == NULL) return(NULL);
3140
3141 ret = xmlAllocParserInputBuffer(enc);
3142 if (ret != NULL) {
3143 ret->context = (void *) ioctx;
3144 ret->readcallback = ioread;
3145 ret->closecallback = ioclose;
3146 }
3147
3148 return(ret);
3149}
3150
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003151#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003152/**
3153 * xmlOutputBufferCreateIO:
3154 * @iowrite: an I/O write function
3155 * @ioclose: an I/O close function
3156 * @ioctx: an I/O handler
Daniel Veillard9d06d302002-01-22 18:15:52 +00003157 * @encoder: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00003158 *
3159 * Create a buffered output for the progressive saving
3160 * to an I/O handler
3161 *
3162 * Returns the new parser output or NULL
3163 */
3164xmlOutputBufferPtr
3165xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
3166 xmlOutputCloseCallback ioclose, void *ioctx,
3167 xmlCharEncodingHandlerPtr encoder) {
3168 xmlOutputBufferPtr ret;
3169
3170 if (iowrite == NULL) return(NULL);
3171
Daniel Veillardda3fee42008-09-01 13:08:57 +00003172 ret = xmlAllocOutputBufferInternal(encoder);
Owen Taylor3473f882001-02-23 17:55:21 +00003173 if (ret != NULL) {
3174 ret->context = (void *) ioctx;
3175 ret->writecallback = iowrite;
3176 ret->closecallback = ioclose;
3177 }
3178
3179 return(ret);
3180}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003181#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003182
3183/**
Daniel Veillard1b243b42004-06-08 10:16:42 +00003184 * xmlParserInputBufferCreateFilenameDefault:
3185 * @func: function pointer to the new ParserInputBufferCreateFilenameFunc
3186 *
3187 * Registers a callback for URI input file handling
3188 *
3189 * Returns the old value of the registration function
3190 */
3191xmlParserInputBufferCreateFilenameFunc
3192xmlParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func)
3193{
3194 xmlParserInputBufferCreateFilenameFunc old = xmlParserInputBufferCreateFilenameValue;
3195 if (old == NULL) {
3196 old = __xmlParserInputBufferCreateFilename;
3197 }
3198
3199 xmlParserInputBufferCreateFilenameValue = func;
3200 return(old);
3201}
3202
3203/**
3204 * xmlOutputBufferCreateFilenameDefault:
3205 * @func: function pointer to the new OutputBufferCreateFilenameFunc
3206 *
3207 * Registers a callback for URI output file handling
3208 *
3209 * Returns the old value of the registration function
3210 */
3211xmlOutputBufferCreateFilenameFunc
3212xmlOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func)
3213{
3214 xmlOutputBufferCreateFilenameFunc old = xmlOutputBufferCreateFilenameValue;
3215#ifdef LIBXML_OUTPUT_ENABLED
3216 if (old == NULL) {
3217 old = __xmlOutputBufferCreateFilename;
3218 }
3219#endif
3220 xmlOutputBufferCreateFilenameValue = func;
3221 return(old);
3222}
3223
3224/**
Owen Taylor3473f882001-02-23 17:55:21 +00003225 * xmlParserInputBufferPush:
3226 * @in: a buffered parser input
3227 * @len: the size in bytes of the array.
3228 * @buf: an char array
3229 *
3230 * Push the content of the arry in the input buffer
3231 * This routine handle the I18N transcoding to internal UTF-8
3232 * This is used when operating the parser in progressive (push) mode.
3233 *
3234 * Returns the number of chars read and stored in the buffer, or -1
3235 * in case of error.
3236 */
3237int
3238xmlParserInputBufferPush(xmlParserInputBufferPtr in,
3239 int len, const char *buf) {
3240 int nbchars = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00003241 int ret;
Owen Taylor3473f882001-02-23 17:55:21 +00003242
3243 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003244 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003245 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00003246 unsigned int use;
3247
Owen Taylor3473f882001-02-23 17:55:21 +00003248 /*
3249 * Store the data in the incoming raw buffer
3250 */
3251 if (in->raw == NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003252 in->raw = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00003253 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003254 ret = xmlBufAdd(in->raw, (const xmlChar *) buf, len);
William M. Bracka3215c72004-07-31 16:24:01 +00003255 if (ret != 0)
3256 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003257
3258 /*
3259 * convert as much as possible to the parser reading buffer.
3260 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003261 use = xmlBufUse(in->raw);
Daniel Veillardbf058dc2013-02-13 18:19:42 +08003262 nbchars = xmlCharEncInput(in, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003263 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003264 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003265 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003266 return(-1);
3267 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003268 in->rawconsumed += (use - xmlBufUse(in->raw));
Owen Taylor3473f882001-02-23 17:55:21 +00003269 } else {
3270 nbchars = len;
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003271 ret = xmlBufAdd(in->buffer, (xmlChar *) buf, nbchars);
William M. Bracka3215c72004-07-31 16:24:01 +00003272 if (ret != 0)
3273 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003274 }
3275#ifdef DEBUG_INPUT
3276 xmlGenericError(xmlGenericErrorContext,
3277 "I/O: pushed %d chars, buffer %d/%d\n",
Roumen Petrov89b6f732012-08-04 05:09:56 +03003278 nbchars, xmlBufUse(in->buffer), xmlBufLength(in->buffer));
Owen Taylor3473f882001-02-23 17:55:21 +00003279#endif
3280 return(nbchars);
3281}
3282
3283/**
Daniel Veillardddffd2a2002-03-05 20:28:20 +00003284 * endOfInput:
3285 *
3286 * When reading from an Input channel indicated end of file or error
3287 * don't reread from it again.
3288 */
3289static int
3290endOfInput (void * context ATTRIBUTE_UNUSED,
3291 char * buffer ATTRIBUTE_UNUSED,
3292 int len ATTRIBUTE_UNUSED) {
3293 return(0);
3294}
3295
3296/**
Owen Taylor3473f882001-02-23 17:55:21 +00003297 * xmlParserInputBufferGrow:
3298 * @in: a buffered parser input
3299 * @len: indicative value of the amount of chars to read
3300 *
3301 * Grow up the content of the input buffer, the old data are preserved
3302 * This routine handle the I18N transcoding to internal UTF-8
3303 * This routine is used when operating the parser in normal (pull) mode
3304 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003305 * TODO: one should be able to remove one extra copy by copying directly
Owen Taylor3473f882001-02-23 17:55:21 +00003306 * onto in->buffer or in->raw
3307 *
3308 * Returns the number of chars read and stored in the buffer, or -1
3309 * in case of error.
3310 */
3311int
3312xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
3313 char *buffer = NULL;
3314 int res = 0;
3315 int nbchars = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003316
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003317 if ((in == NULL) || (in->error)) return(-1);
Daniel Veillard6155d8a2003-08-19 15:01:28 +00003318 if ((len <= MINLEN) && (len != 4))
Owen Taylor3473f882001-02-23 17:55:21 +00003319 len = MINLEN;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00003320
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003321 if (xmlBufAvail(in->buffer) <= 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003322 xmlIOErr(XML_IO_BUFFER_FULL, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003323 in->error = XML_IO_BUFFER_FULL;
William M. Bracka3215c72004-07-31 16:24:01 +00003324 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003325 }
Owen Taylor3473f882001-02-23 17:55:21 +00003326
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003327 if (xmlBufGrow(in->buffer, len + 1) < 0) {
3328 xmlIOErrMemory("growing input buffer");
3329 in->error = XML_ERR_NO_MEMORY;
3330 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003331 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003332 buffer = (char *)xmlBufEnd(in->buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00003333
3334 /*
3335 * Call the read method for this I/O type.
3336 */
3337 if (in->readcallback != NULL) {
3338 res = in->readcallback(in->context, &buffer[0], len);
Daniel Veillardddffd2a2002-03-05 20:28:20 +00003339 if (res <= 0)
3340 in->readcallback = endOfInput;
Owen Taylor3473f882001-02-23 17:55:21 +00003341 } else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003342 xmlIOErr(XML_IO_NO_INPUT, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003343 in->error = XML_IO_NO_INPUT;
Owen Taylor3473f882001-02-23 17:55:21 +00003344 return(-1);
3345 }
3346 if (res < 0) {
Owen Taylor3473f882001-02-23 17:55:21 +00003347 return(-1);
3348 }
Daniel Veillard63588f42013-05-10 14:01:46 +08003349
3350 /*
3351 * try to establish compressed status of input if not done already
3352 */
3353 if (in->compressed == -1) {
Daniel Veillard18b89882015-11-03 15:46:29 +08003354#ifdef LIBXML_LZMA_ENABLED
Daniel Veillard63588f42013-05-10 14:01:46 +08003355 if (in->readcallback == xmlXzfileRead)
3356 in->compressed = __libxml2_xzcompressed(in->context);
3357#endif
3358 }
3359
Owen Taylor3473f882001-02-23 17:55:21 +00003360 len = res;
3361 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00003362 unsigned int use;
3363
Owen Taylor3473f882001-02-23 17:55:21 +00003364 /*
3365 * Store the data in the incoming raw buffer
3366 */
3367 if (in->raw == NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003368 in->raw = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00003369 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003370 res = xmlBufAdd(in->raw, (const xmlChar *) buffer, len);
William M. Bracka3215c72004-07-31 16:24:01 +00003371 if (res != 0)
3372 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003373
3374 /*
3375 * convert as much as possible to the parser reading buffer.
3376 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003377 use = xmlBufUse(in->raw);
Daniel Veillardbf058dc2013-02-13 18:19:42 +08003378 nbchars = xmlCharEncInput(in, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00003379 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003380 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003381 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003382 return(-1);
3383 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003384 in->rawconsumed += (use - xmlBufUse(in->raw));
Owen Taylor3473f882001-02-23 17:55:21 +00003385 } else {
3386 nbchars = len;
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003387 xmlBufAddLen(in->buffer, nbchars);
Owen Taylor3473f882001-02-23 17:55:21 +00003388 }
3389#ifdef DEBUG_INPUT
3390 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003391 "I/O: read %d chars, buffer %d\n",
3392 nbchars, xmlBufUse(in->buffer));
Owen Taylor3473f882001-02-23 17:55:21 +00003393#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003394 return(nbchars);
3395}
3396
3397/**
3398 * xmlParserInputBufferRead:
3399 * @in: a buffered parser input
3400 * @len: indicative value of the amount of chars to read
3401 *
3402 * Refresh the content of the input buffer, the old data are considered
3403 * consumed
3404 * This routine handle the I18N transcoding to internal UTF-8
3405 *
3406 * Returns the number of chars read and stored in the buffer, or -1
3407 * in case of error.
3408 */
3409int
3410xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003411 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003412 if (in->readcallback != NULL)
3413 return(xmlParserInputBufferGrow(in, len));
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003414 else if (xmlBufGetAllocationScheme(in->buffer) == XML_BUFFER_ALLOC_IMMUTABLE)
Daniel Veillard53350552003-09-18 13:35:51 +00003415 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003416 else
3417 return(-1);
3418}
3419
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003420#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003421/**
3422 * xmlOutputBufferWrite:
3423 * @out: a buffered parser output
3424 * @len: the size in bytes of the array.
3425 * @buf: an char array
3426 *
3427 * Write the content of the array in the output I/O buffer
3428 * This routine handle the I18N transcoding from internal UTF-8
3429 * The buffer is lossless, i.e. will store in case of partial
3430 * or delayed writes.
3431 *
3432 * Returns the number of chars immediately written, or -1
3433 * in case of error.
3434 */
3435int
3436xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
3437 int nbchars = 0; /* number of chars to output to I/O */
3438 int ret; /* return from function call */
3439 int written = 0; /* number of char written to I/O so far */
3440 int chunk; /* number of byte curreent processed from buf */
3441
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003442 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003443 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003444 if (out->error) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003445
3446 do {
3447 chunk = len;
3448 if (chunk > 4 * MINLEN)
3449 chunk = 4 * MINLEN;
3450
3451 /*
3452 * first handle encoding stuff.
3453 */
3454 if (out->encoder != NULL) {
3455 /*
3456 * Store the data in the incoming raw buffer
3457 */
3458 if (out->conv == NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003459 out->conv = xmlBufCreate();
Owen Taylor3473f882001-02-23 17:55:21 +00003460 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003461 ret = xmlBufAdd(out->buffer, (const xmlChar *) buf, chunk);
William M. Bracka3215c72004-07-31 16:24:01 +00003462 if (ret != 0)
3463 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003464
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003465 if ((xmlBufUse(out->buffer) < MINLEN) && (chunk == len))
Owen Taylor3473f882001-02-23 17:55:21 +00003466 goto done;
3467
3468 /*
3469 * convert as much as possible to the parser reading buffer.
3470 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003471 ret = xmlCharEncOutput(out, 0);
Daniel Veillard809faa52003-02-10 15:43:53 +00003472 if ((ret < 0) && (ret != -3)) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003473 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003474 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003475 return(-1);
3476 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003477 nbchars = xmlBufUse(out->conv);
Owen Taylor3473f882001-02-23 17:55:21 +00003478 } else {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003479 ret = xmlBufAdd(out->buffer, (const xmlChar *) buf, chunk);
William M. Bracka3215c72004-07-31 16:24:01 +00003480 if (ret != 0)
3481 return(-1);
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003482 nbchars = xmlBufUse(out->buffer);
Owen Taylor3473f882001-02-23 17:55:21 +00003483 }
3484 buf += chunk;
3485 len -= chunk;
3486
3487 if ((nbchars < MINLEN) && (len <= 0))
3488 goto done;
3489
3490 if (out->writecallback) {
3491 /*
3492 * second write the stuff to the I/O channel
3493 */
3494 if (out->encoder != NULL) {
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003495 ret = out->writecallback(out->context,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003496 (const char *)xmlBufContent(out->conv), nbchars);
Owen Taylor3473f882001-02-23 17:55:21 +00003497 if (ret >= 0)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003498 xmlBufShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003499 } else {
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003500 ret = out->writecallback(out->context,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003501 (const char *)xmlBufContent(out->buffer), nbchars);
Owen Taylor3473f882001-02-23 17:55:21 +00003502 if (ret >= 0)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003503 xmlBufShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003504 }
3505 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003506 xmlIOErr(XML_IO_WRITE, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003507 out->error = XML_IO_WRITE;
Owen Taylor3473f882001-02-23 17:55:21 +00003508 return(ret);
3509 }
3510 out->written += ret;
3511 }
3512 written += nbchars;
3513 } while (len > 0);
3514
3515done:
3516#ifdef DEBUG_INPUT
3517 xmlGenericError(xmlGenericErrorContext,
3518 "I/O: wrote %d chars\n", written);
3519#endif
3520 return(written);
3521}
3522
3523/**
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003524 * xmlEscapeContent:
3525 * @out: a pointer to an array of bytes to store the result
3526 * @outlen: the length of @out
3527 * @in: a pointer to an array of unescaped UTF-8 bytes
3528 * @inlen: the length of @in
3529 *
3530 * Take a block of UTF-8 chars in and escape them.
3531 * Returns 0 if success, or -1 otherwise
3532 * The value of @inlen after return is the number of octets consumed
3533 * if the return value is positive, else unpredictable.
3534 * The value of @outlen after return is the number of octets consumed.
3535 */
3536static int
3537xmlEscapeContent(unsigned char* out, int *outlen,
3538 const xmlChar* in, int *inlen) {
3539 unsigned char* outstart = out;
3540 const unsigned char* base = in;
3541 unsigned char* outend = out + *outlen;
3542 const unsigned char* inend;
3543
3544 inend = in + (*inlen);
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003545
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003546 while ((in < inend) && (out < outend)) {
Daniel Veillardf8e3db02012-09-11 13:26:36 +08003547 if (*in == '<') {
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003548 if (outend - out < 4) break;
3549 *out++ = '&';
3550 *out++ = 'l';
3551 *out++ = 't';
3552 *out++ = ';';
3553 } else if (*in == '>') {
3554 if (outend - out < 4) break;
3555 *out++ = '&';
3556 *out++ = 'g';
3557 *out++ = 't';
3558 *out++ = ';';
3559 } else if (*in == '&') {
3560 if (outend - out < 5) break;
3561 *out++ = '&';
3562 *out++ = 'a';
3563 *out++ = 'm';
3564 *out++ = 'p';
3565 *out++ = ';';
3566 } else if (*in == '\r') {
3567 if (outend - out < 5) break;
3568 *out++ = '&';
3569 *out++ = '#';
3570 *out++ = '1';
3571 *out++ = '3';
3572 *out++ = ';';
3573 } else {
3574 *out++ = (unsigned char) *in;
3575 }
3576 ++in;
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003577 }
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003578 *outlen = out - outstart;
3579 *inlen = in - base;
3580 return(0);
3581}
3582
3583/**
3584 * xmlOutputBufferWriteEscape:
3585 * @out: a buffered parser output
3586 * @str: a zero terminated UTF-8 string
Daniel Veillardee8960b2004-05-14 03:25:14 +00003587 * @escaping: an optional escaping function (or NULL)
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003588 *
3589 * Write the content of the string in the output I/O buffer
3590 * This routine escapes the caracters and then handle the I18N
3591 * transcoding from internal UTF-8
3592 * The buffer is lossless, i.e. will store in case of partial
3593 * or delayed writes.
3594 *
3595 * Returns the number of chars immediately written, or -1
3596 * in case of error.
3597 */
3598int
Daniel Veillardee8960b2004-05-14 03:25:14 +00003599xmlOutputBufferWriteEscape(xmlOutputBufferPtr out, const xmlChar *str,
3600 xmlCharEncodingOutputFunc escaping) {
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003601 int nbchars = 0; /* number of chars to output to I/O */
3602 int ret; /* return from function call */
3603 int written = 0; /* number of char written to I/O so far */
Daniel Veillard71b95632004-08-31 12:15:36 +00003604 int oldwritten=0;/* loop guard */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003605 int chunk; /* number of byte currently processed from str */
3606 int len; /* number of bytes in str */
3607 int cons; /* byte from str consumed */
3608
Daniel Veillardce244ad2004-11-05 10:03:46 +00003609 if ((out == NULL) || (out->error) || (str == NULL) ||
3610 (out->buffer == NULL) ||
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003611 (xmlBufGetAllocationScheme(out->buffer) == XML_BUFFER_ALLOC_IMMUTABLE))
3612 return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003613 len = strlen((const char *)str);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003614 if (len < 0) return(0);
3615 if (out->error) return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003616 if (escaping == NULL) escaping = xmlEscapeContent;
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003617
3618 do {
Daniel Veillard71b95632004-08-31 12:15:36 +00003619 oldwritten = written;
3620
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003621 /*
3622 * how many bytes to consume and how many bytes to store.
3623 */
3624 cons = len;
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003625 chunk = xmlBufAvail(out->buffer) - 1;
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003626
Daniel Veillardc4ba8a42008-02-16 10:08:14 +00003627 /*
3628 * make sure we have enough room to save first, if this is
3629 * not the case force a flush, but make sure we stay in the loop
3630 */
3631 if (chunk < 40) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003632 if (xmlBufGrow(out->buffer, 100) < 0)
Daniel Veillarde83e93e2008-08-30 12:52:26 +00003633 return(-1);
3634 oldwritten = -1;
3635 continue;
Daniel Veillardc4ba8a42008-02-16 10:08:14 +00003636 }
3637
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003638 /*
3639 * first handle encoding stuff.
3640 */
3641 if (out->encoder != NULL) {
3642 /*
3643 * Store the data in the incoming raw buffer
3644 */
3645 if (out->conv == NULL) {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003646 out->conv = xmlBufCreate();
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003647 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003648 ret = escaping(xmlBufEnd(out->buffer) ,
Daniel Veillardee8960b2004-05-14 03:25:14 +00003649 &chunk, str, &cons);
William M. Brack66e40b12004-11-26 15:45:19 +00003650 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003651 return(-1);
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003652 xmlBufAddLen(out->buffer, chunk);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003653
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003654 if ((xmlBufUse(out->buffer) < MINLEN) && (cons == len))
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003655 goto done;
3656
3657 /*
3658 * convert as much as possible to the output buffer.
3659 */
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003660 ret = xmlCharEncOutput(out, 0);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003661 if ((ret < 0) && (ret != -3)) {
3662 xmlIOErr(XML_IO_ENCODER, NULL);
3663 out->error = XML_IO_ENCODER;
3664 return(-1);
3665 }
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003666 nbchars = xmlBufUse(out->conv);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003667 } else {
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003668 ret = escaping(xmlBufEnd(out->buffer), &chunk, str, &cons);
William M. Brack66e40b12004-11-26 15:45:19 +00003669 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003670 return(-1);
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003671 xmlBufAddLen(out->buffer, chunk);
3672 nbchars = xmlBufUse(out->buffer);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003673 }
3674 str += cons;
3675 len -= cons;
3676
3677 if ((nbchars < MINLEN) && (len <= 0))
3678 goto done;
3679
3680 if (out->writecallback) {
3681 /*
3682 * second write the stuff to the I/O channel
3683 */
3684 if (out->encoder != NULL) {
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003685 ret = out->writecallback(out->context,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003686 (const char *)xmlBufContent(out->conv), nbchars);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003687 if (ret >= 0)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003688 xmlBufShrink(out->conv, ret);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003689 } else {
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003690 ret = out->writecallback(out->context,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003691 (const char *)xmlBufContent(out->buffer), nbchars);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003692 if (ret >= 0)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003693 xmlBufShrink(out->buffer, ret);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003694 }
3695 if (ret < 0) {
3696 xmlIOErr(XML_IO_WRITE, NULL);
3697 out->error = XML_IO_WRITE;
3698 return(ret);
3699 }
3700 out->written += ret;
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003701 } else if (xmlBufAvail(out->buffer) < MINLEN) {
3702 xmlBufGrow(out->buffer, MINLEN);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003703 }
3704 written += nbchars;
Daniel Veillard71b95632004-08-31 12:15:36 +00003705 } while ((len > 0) && (oldwritten != written));
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003706
3707done:
3708#ifdef DEBUG_INPUT
3709 xmlGenericError(xmlGenericErrorContext,
3710 "I/O: wrote %d chars\n", written);
3711#endif
3712 return(written);
3713}
3714
3715/**
Owen Taylor3473f882001-02-23 17:55:21 +00003716 * xmlOutputBufferWriteString:
3717 * @out: a buffered parser output
3718 * @str: a zero terminated C string
3719 *
3720 * Write the content of the string in the output I/O buffer
3721 * This routine handle the I18N transcoding from internal UTF-8
3722 * The buffer is lossless, i.e. will store in case of partial
3723 * or delayed writes.
3724 *
3725 * Returns the number of chars immediately written, or -1
3726 * in case of error.
3727 */
3728int
3729xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
3730 int len;
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003731
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003732 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003733 if (str == NULL)
3734 return(-1);
3735 len = strlen(str);
3736
3737 if (len > 0)
3738 return(xmlOutputBufferWrite(out, len, str));
3739 return(len);
3740}
3741
3742/**
3743 * xmlOutputBufferFlush:
3744 * @out: a buffered output
3745 *
3746 * flushes the output I/O channel
3747 *
3748 * Returns the number of byte written or -1 in case of error.
3749 */
3750int
3751xmlOutputBufferFlush(xmlOutputBufferPtr out) {
3752 int nbchars = 0, ret = 0;
3753
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003754 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003755 /*
3756 * first handle encoding stuff.
3757 */
3758 if ((out->conv != NULL) && (out->encoder != NULL)) {
3759 /*
Mikhail Titov8e2098a2013-03-27 11:00:31 +08003760 * convert as much as possible to the parser output buffer.
Owen Taylor3473f882001-02-23 17:55:21 +00003761 */
Mikhail Titov8e2098a2013-03-27 11:00:31 +08003762 do {
3763 nbchars = xmlCharEncOutput(out, 0);
3764 if (nbchars < 0) {
3765 xmlIOErr(XML_IO_ENCODER, NULL);
3766 out->error = XML_IO_ENCODER;
3767 return(-1);
3768 }
3769 } while (nbchars);
Owen Taylor3473f882001-02-23 17:55:21 +00003770 }
3771
3772 /*
3773 * second flush the stuff to the I/O channel
3774 */
3775 if ((out->conv != NULL) && (out->encoder != NULL) &&
3776 (out->writecallback != NULL)) {
3777 ret = out->writecallback(out->context,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003778 (const char *)xmlBufContent(out->conv),
3779 xmlBufUse(out->conv));
Owen Taylor3473f882001-02-23 17:55:21 +00003780 if (ret >= 0)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003781 xmlBufShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003782 } else if (out->writecallback != NULL) {
3783 ret = out->writecallback(out->context,
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003784 (const char *)xmlBufContent(out->buffer),
3785 xmlBufUse(out->buffer));
Owen Taylor3473f882001-02-23 17:55:21 +00003786 if (ret >= 0)
Daniel Veillarda6a6e702012-07-16 14:22:54 +08003787 xmlBufShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003788 }
3789 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003790 xmlIOErr(XML_IO_FLUSH, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003791 out->error = XML_IO_FLUSH;
Owen Taylor3473f882001-02-23 17:55:21 +00003792 return(ret);
3793 }
3794 out->written += ret;
3795
3796#ifdef DEBUG_INPUT
3797 xmlGenericError(xmlGenericErrorContext,
3798 "I/O: flushed %d chars\n", ret);
3799#endif
3800 return(ret);
3801}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003802#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003803
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003804/**
Owen Taylor3473f882001-02-23 17:55:21 +00003805 * xmlParserGetDirectory:
3806 * @filename: the path to a file
3807 *
3808 * lookup the directory for that file
3809 *
3810 * Returns a new allocated string containing the directory, or NULL.
3811 */
3812char *
3813xmlParserGetDirectory(const char *filename) {
3814 char *ret = NULL;
3815 char dir[1024];
3816 char *cur;
Owen Taylor3473f882001-02-23 17:55:21 +00003817
Igor Zlatkovic9181cc02002-09-29 17:51:06 +00003818#ifdef _WIN32_WCE /* easy way by now ... wince does not have dirs! */
3819 return NULL;
3820#endif
3821
Owen Taylor3473f882001-02-23 17:55:21 +00003822 if (xmlInputCallbackInitialized == 0)
3823 xmlRegisterDefaultInputCallbacks();
3824
3825 if (filename == NULL) return(NULL);
Rob Richardsf779da32007-08-14 09:41:21 +00003826
Daniel Veillard3c5ed912002-01-08 10:36:16 +00003827#if defined(WIN32) && !defined(__CYGWIN__)
Rob Richardsf779da32007-08-14 09:41:21 +00003828# define IS_XMLPGD_SEP(ch) ((ch=='/')||(ch=='\\'))
3829#else
3830# define IS_XMLPGD_SEP(ch) (ch=='/')
Owen Taylor3473f882001-02-23 17:55:21 +00003831#endif
3832
3833 strncpy(dir, filename, 1023);
3834 dir[1023] = 0;
3835 cur = &dir[strlen(dir)];
3836 while (cur > dir) {
Rob Richardsf779da32007-08-14 09:41:21 +00003837 if (IS_XMLPGD_SEP(*cur)) break;
Owen Taylor3473f882001-02-23 17:55:21 +00003838 cur --;
3839 }
Rob Richardsf779da32007-08-14 09:41:21 +00003840 if (IS_XMLPGD_SEP(*cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003841 if (cur == dir) dir[1] = 0;
3842 else *cur = 0;
3843 ret = xmlMemStrdup(dir);
3844 } else {
3845 if (getcwd(dir, 1024) != NULL) {
3846 dir[1023] = 0;
3847 ret = xmlMemStrdup(dir);
3848 }
3849 }
3850 return(ret);
Rob Richardsf779da32007-08-14 09:41:21 +00003851#undef IS_XMLPGD_SEP
Owen Taylor3473f882001-02-23 17:55:21 +00003852}
3853
3854/****************************************************************
3855 * *
3856 * External entities loading *
3857 * *
3858 ****************************************************************/
3859
Daniel Veillarda840b692003-10-19 13:35:37 +00003860/**
3861 * xmlCheckHTTPInput:
3862 * @ctxt: an XML parser context
3863 * @ret: an XML parser input
3864 *
3865 * Check an input in case it was created from an HTTP stream, in that
3866 * case it will handle encoding and update of the base URL in case of
3867 * redirection. It also checks for HTTP errors in which case the input
3868 * is cleanly freed up and an appropriate error is raised in context
3869 *
3870 * Returns the input or NULL in case of HTTP error.
3871 */
3872xmlParserInputPtr
3873xmlCheckHTTPInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr ret) {
3874#ifdef LIBXML_HTTP_ENABLED
3875 if ((ret != NULL) && (ret->buf != NULL) &&
3876 (ret->buf->readcallback == xmlIOHTTPRead) &&
3877 (ret->buf->context != NULL)) {
3878 const char *encoding;
3879 const char *redir;
3880 const char *mime;
3881 int code;
3882
3883 code = xmlNanoHTTPReturnCode(ret->buf->context);
3884 if (code >= 400) {
3885 /* fatal error */
3886 if (ret->filename != NULL)
Daniel Veillarde8039df2003-10-27 11:25:13 +00003887 __xmlLoaderErr(ctxt, "failed to load HTTP resource \"%s\"\n",
Daniel Veillarda840b692003-10-19 13:35:37 +00003888 (const char *) ret->filename);
3889 else
Daniel Veillarde8039df2003-10-27 11:25:13 +00003890 __xmlLoaderErr(ctxt, "failed to load HTTP resource\n", NULL);
Daniel Veillarda840b692003-10-19 13:35:37 +00003891 xmlFreeInputStream(ret);
3892 ret = NULL;
3893 } else {
3894
3895 mime = xmlNanoHTTPMimeType(ret->buf->context);
3896 if ((xmlStrstr(BAD_CAST mime, BAD_CAST "/xml")) ||
3897 (xmlStrstr(BAD_CAST mime, BAD_CAST "+xml"))) {
3898 encoding = xmlNanoHTTPEncoding(ret->buf->context);
3899 if (encoding != NULL) {
3900 xmlCharEncodingHandlerPtr handler;
3901
3902 handler = xmlFindCharEncodingHandler(encoding);
3903 if (handler != NULL) {
3904 xmlSwitchInputEncoding(ctxt, ret, handler);
3905 } else {
3906 __xmlErrEncoding(ctxt, XML_ERR_UNKNOWN_ENCODING,
3907 "Unknown encoding %s",
3908 BAD_CAST encoding, NULL);
3909 }
3910 if (ret->encoding == NULL)
3911 ret->encoding = xmlStrdup(BAD_CAST encoding);
3912 }
3913#if 0
3914 } else if (xmlStrstr(BAD_CAST mime, BAD_CAST "html")) {
3915#endif
3916 }
3917 redir = xmlNanoHTTPRedir(ret->buf->context);
3918 if (redir != NULL) {
3919 if (ret->filename != NULL)
3920 xmlFree((xmlChar *) ret->filename);
3921 if (ret->directory != NULL) {
3922 xmlFree((xmlChar *) ret->directory);
3923 ret->directory = NULL;
3924 }
3925 ret->filename =
3926 (char *) xmlStrdup((const xmlChar *) redir);
3927 }
3928 }
3929 }
3930#endif
3931 return(ret);
3932}
3933
Daniel Veillarde5a3f372006-08-30 13:11:36 +00003934static int xmlNoNetExists(const char *URL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003935 const char *path;
3936
3937 if (URL == NULL)
3938 return(0);
3939
Daniel Veillardf4862f02002-09-10 11:13:43 +00003940 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003941#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00003942 path = &URL[17];
3943#else
Daniel Veillard6990bf32001-08-23 21:17:48 +00003944 path = &URL[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00003945#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003946 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003947#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard6990bf32001-08-23 21:17:48 +00003948 path = &URL[8];
3949#else
3950 path = &URL[7];
3951#endif
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003952 } else
Daniel Veillard6990bf32001-08-23 21:17:48 +00003953 path = URL;
Hans Breuer2ad41ca2009-08-11 17:51:22 +02003954
Daniel Veillarde5a3f372006-08-30 13:11:36 +00003955 return xmlCheckFilename(path);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003956}
Daniel Veillard6990bf32001-08-23 21:17:48 +00003957
Daniel Veillardad4e2962006-09-21 08:36:38 +00003958#ifdef LIBXML_CATALOG_ENABLED
3959
3960/**
3961 * xmlResolveResourceFromCatalog:
3962 * @URL: the URL for the entity to load
3963 * @ID: the System ID for the entity to load
3964 * @ctxt: the context in which the entity is called or NULL
3965 *
3966 * Resolves the URL and ID against the appropriate catalog.
3967 * This function is used by xmlDefaultExternalEntityLoader and
3968 * xmlNoNetExternalEntityLoader.
3969 *
3970 * Returns a new allocated URL, or NULL.
3971 */
William M. Brack38d452a2007-05-22 16:00:06 +00003972static xmlChar *
Daniel Veillardad4e2962006-09-21 08:36:38 +00003973xmlResolveResourceFromCatalog(const char *URL, const char *ID,
3974 xmlParserCtxtPtr ctxt) {
3975 xmlChar *resource = NULL;
3976 xmlCatalogAllow pref;
3977
3978 /*
3979 * If the resource doesn't exists as a file,
3980 * try to load it from the resource pointed in the catalogs
3981 */
3982 pref = xmlCatalogGetDefaults();
3983
3984 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
3985 /*
3986 * Do a local lookup
3987 */
3988 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
3989 ((pref == XML_CATA_ALLOW_ALL) ||
3990 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3991 resource = xmlCatalogLocalResolve(ctxt->catalogs,
3992 (const xmlChar *)ID,
3993 (const xmlChar *)URL);
3994 }
3995 /*
3996 * Try a global lookup
3997 */
3998 if ((resource == NULL) &&
3999 ((pref == XML_CATA_ALLOW_ALL) ||
4000 (pref == XML_CATA_ALLOW_GLOBAL))) {
4001 resource = xmlCatalogResolve((const xmlChar *)ID,
4002 (const xmlChar *)URL);
4003 }
4004 if ((resource == NULL) && (URL != NULL))
4005 resource = xmlStrdup((const xmlChar *) URL);
4006
4007 /*
4008 * TODO: do an URI lookup on the reference
4009 */
4010 if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
4011 xmlChar *tmp = NULL;
4012
4013 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
4014 ((pref == XML_CATA_ALLOW_ALL) ||
4015 (pref == XML_CATA_ALLOW_DOCUMENT))) {
4016 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
4017 }
4018 if ((tmp == NULL) &&
4019 ((pref == XML_CATA_ALLOW_ALL) ||
4020 (pref == XML_CATA_ALLOW_GLOBAL))) {
4021 tmp = xmlCatalogResolveURI(resource);
4022 }
4023
4024 if (tmp != NULL) {
4025 xmlFree(resource);
4026 resource = tmp;
4027 }
4028 }
4029 }
4030
4031 return resource;
4032}
4033
4034#endif
4035
Daniel Veillard5e2dace2001-07-18 19:30:27 +00004036/**
Owen Taylor3473f882001-02-23 17:55:21 +00004037 * xmlDefaultExternalEntityLoader:
4038 * @URL: the URL for the entity to load
4039 * @ID: the System ID for the entity to load
4040 * @ctxt: the context in which the entity is called or NULL
4041 *
4042 * By default we don't load external entitites, yet.
4043 *
4044 * Returns a new allocated xmlParserInputPtr, or NULL.
4045 */
Daniel Veillarda840b692003-10-19 13:35:37 +00004046static xmlParserInputPtr
Owen Taylor3473f882001-02-23 17:55:21 +00004047xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
Daniel Veillarda840b692003-10-19 13:35:37 +00004048 xmlParserCtxtPtr ctxt)
4049{
Owen Taylor3473f882001-02-23 17:55:21 +00004050 xmlParserInputPtr ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00004051 xmlChar *resource = NULL;
Daniel Veillarda840b692003-10-19 13:35:37 +00004052
Owen Taylor3473f882001-02-23 17:55:21 +00004053#ifdef DEBUG_EXTERNAL_ENTITIES
4054 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda840b692003-10-19 13:35:37 +00004055 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00004056#endif
Doran Moppert23040782017-04-07 16:45:56 +02004057 if (ctxt != NULL) {
Daniel Veillard61b93382003-11-03 14:28:31 +00004058 int options = ctxt->options;
4059
Doran Moppert23040782017-04-07 16:45:56 +02004060 if (options & XML_PARSE_NOXXE) {
4061 ctxt->options -= XML_PARSE_NOXXE;
4062 ret = xmlNoXxeExternalEntityLoader(URL, ID, ctxt);
4063 ctxt->options = options;
4064 return(ret);
4065 }
4066
4067 if (options & XML_PARSE_NONET) {
4068 ctxt->options -= XML_PARSE_NONET;
4069 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
4070 ctxt->options = options;
4071 return(ret);
4072 }
Daniel Veillard61b93382003-11-03 14:28:31 +00004073 }
Daniel Veillardad4e2962006-09-21 08:36:38 +00004074#ifdef LIBXML_CATALOG_ENABLED
4075 resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
Daniel Veillard7d6fd212001-05-10 15:34:11 +00004076#endif
4077
4078 if (resource == NULL)
Daniel Veillarda840b692003-10-19 13:35:37 +00004079 resource = (xmlChar *) URL;
Daniel Veillard7d6fd212001-05-10 15:34:11 +00004080
4081 if (resource == NULL) {
Daniel Veillarda840b692003-10-19 13:35:37 +00004082 if (ID == NULL)
4083 ID = "NULL";
Daniel Veillarde8039df2003-10-27 11:25:13 +00004084 __xmlLoaderErr(ctxt, "failed to load external entity \"%s\"\n", ID);
Daniel Veillarda840b692003-10-19 13:35:37 +00004085 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004086 }
Daniel Veillarda840b692003-10-19 13:35:37 +00004087 ret = xmlNewInputFromFile(ctxt, (const char *) resource);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00004088 if ((resource != NULL) && (resource != (xmlChar *) URL))
Daniel Veillarda840b692003-10-19 13:35:37 +00004089 xmlFree(resource);
4090 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00004091}
4092
4093static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
4094 xmlDefaultExternalEntityLoader;
4095
Daniel Veillard5e2dace2001-07-18 19:30:27 +00004096/**
Owen Taylor3473f882001-02-23 17:55:21 +00004097 * xmlSetExternalEntityLoader:
4098 * @f: the new entity resolver function
4099 *
4100 * Changes the defaultexternal entity resolver function for the application
4101 */
4102void
4103xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
4104 xmlCurrentExternalEntityLoader = f;
4105}
4106
Daniel Veillard5e2dace2001-07-18 19:30:27 +00004107/**
Owen Taylor3473f882001-02-23 17:55:21 +00004108 * xmlGetExternalEntityLoader:
4109 *
4110 * Get the default external entity resolver function for the application
4111 *
4112 * Returns the xmlExternalEntityLoader function pointer
4113 */
4114xmlExternalEntityLoader
4115xmlGetExternalEntityLoader(void) {
4116 return(xmlCurrentExternalEntityLoader);
4117}
4118
Daniel Veillard5e2dace2001-07-18 19:30:27 +00004119/**
Owen Taylor3473f882001-02-23 17:55:21 +00004120 * xmlLoadExternalEntity:
4121 * @URL: the URL for the entity to load
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00004122 * @ID: the Public ID for the entity to load
Owen Taylor3473f882001-02-23 17:55:21 +00004123 * @ctxt: the context in which the entity is called or NULL
4124 *
4125 * Load an external entity, note that the use of this function for
4126 * unparsed entities may generate problems
Owen Taylor3473f882001-02-23 17:55:21 +00004127 *
4128 * Returns the xmlParserInputPtr or NULL
4129 */
4130xmlParserInputPtr
4131xmlLoadExternalEntity(const char *URL, const char *ID,
4132 xmlParserCtxtPtr ctxt) {
Daniel Veillarde5a3f372006-08-30 13:11:36 +00004133 if ((URL != NULL) && (xmlNoNetExists(URL) == 0)) {
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00004134 char *canonicFilename;
4135 xmlParserInputPtr ret;
4136
4137 canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL);
4138 if (canonicFilename == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00004139 xmlIOErrMemory("building canonical path\n");
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00004140 return(NULL);
4141 }
4142
4143 ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt);
4144 xmlFree(canonicFilename);
4145 return(ret);
4146 }
Owen Taylor3473f882001-02-23 17:55:21 +00004147 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
4148}
4149
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004150/************************************************************************
Hans Breuer2ad41ca2009-08-11 17:51:22 +02004151 * *
4152 * Disabling Network access *
4153 * *
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004154 ************************************************************************/
4155
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004156/**
4157 * xmlNoNetExternalEntityLoader:
4158 * @URL: the URL for the entity to load
4159 * @ID: the System ID for the entity to load
4160 * @ctxt: the context in which the entity is called or NULL
4161 *
4162 * A specific entity loader disabling network accesses, though still
4163 * allowing local catalog accesses for resolution.
4164 *
4165 * Returns a new allocated xmlParserInputPtr, or NULL.
4166 */
4167xmlParserInputPtr
4168xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
4169 xmlParserCtxtPtr ctxt) {
4170 xmlParserInputPtr input = NULL;
4171 xmlChar *resource = NULL;
4172
Doran Moppert23040782017-04-07 16:45:56 +02004173 if (ctxt == NULL) {
4174 return(NULL);
4175 }
4176 if (ctxt->input_id == 1) {
4177 return xmlDefaultExternalEntityLoader((const char *) URL, ID, ctxt);
4178 }
4179
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004180#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillardad4e2962006-09-21 08:36:38 +00004181 resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004182#endif
Daniel Veillardad4e2962006-09-21 08:36:38 +00004183
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004184 if (resource == NULL)
4185 resource = (xmlChar *) URL;
4186
4187 if (resource != NULL) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00004188 if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
4189 (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00004190 xmlIOErr(XML_IO_NETWORK_ATTEMPT, (const char *) resource);
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00004191 if (resource != (xmlChar *) URL)
4192 xmlFree(resource);
4193 return(NULL);
4194 }
4195 }
4196 input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
4197 if (resource != (xmlChar *) URL)
4198 xmlFree(resource);
4199 return(input);
4200}
4201
Doran Moppert23040782017-04-07 16:45:56 +02004202xmlParserInputPtr
4203xmlNoXxeExternalEntityLoader(const char *URL, const char *ID,
4204 xmlParserCtxtPtr ctxt) {
4205 if (ctxt == NULL) {
4206 return(NULL);
4207 }
4208 if (ctxt->input_id == 1) {
4209 return xmlDefaultExternalEntityLoader((const char *) URL, ID, ctxt);
4210 }
4211 xmlIOErr(XML_IO_ILLEGAL_XXE, (const char *) URL);
4212 return(NULL);
4213}
4214
Daniel Veillard5d4644e2005-04-01 13:11:58 +00004215#define bottom_xmlIO
4216#include "elfgcchack.h"